pax_global_header00006660000000000000000000000064142536175370014527gustar00rootroot0000000000000052 comment=90e68c109e8fde6cb13a39ab0ba84ca0d2c31346 zuluCrypt-6.2.0/000077500000000000000000000000001425361753700135555ustar00rootroot00000000000000zuluCrypt-6.2.0/.gitignore000066400000000000000000000000211425361753700155360ustar00rootroot00000000000000CMakeLists.txt.* zuluCrypt-6.2.0/ABOUT ME000066400000000000000000000075641425361753700146500ustar00rootroot00000000000000 Name : Francis Banyikwa Email : mhogomchungu@gmail.com git repo: https://github.com/mhogomchungu gpg public key: -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1 mQINBFX2u/UBEADAeacwlUtm2jKJBGyYIWD1h1EpUglAqh8bn7rHmdvs1IZWZEmE xMoc1jujrGdBx6mguuKWY0VLGzgKhdrVv/rYsVbYlqH3Vz4mamBHOBjIcR317PVI jV7xdGu76VQkIw1MiJR2TKADFYfe12mEMCTLG6lLAYcxaaIr6jPSZbaP+PUvAhQB nCHqyA4uSlJnnzyfQuWnTxaedG2Qc0FAUHOnet/7wk3j/TTRXg7mFJVA+EXBwjUy dJ2V3H/A1UDQ1FRhMw3L2Pjk4/Ast4f1yWmpJwNB8Zk9H8ezTFgnZW72Uo5wIGXN mkA44skhWCB7cK7kCg/m9MCP6WCSVwqrSps5h1sM2ks32CyRikVXgK0Nbv3bB4+r PY+ZEVvvts+Wj2KF+94OUUuAyklpb1M51JlScEcouV2oxDB0ijqqCaHugziLCifu 3gjtNacKP3lbBeGh4YjrXmrXpLOYhkrKLWCdv1rt2dcsehNhj7cRMkWoP4h28wbS MQPgQW25w6QsDGU2uagsNg6It5hJGRuASRyqf/KddmUtSoaxmUwh/4aJo+R9oymQ wYiHbxgx5OUTeCUv0Qjv2WPPYeYZkwxZbdYWiAPczC+PRXTGa00RgVBxOBMHcJl9 ZcxbC9QgUExPeh8ntK7rG+dpDj3GJ2qk8JUyWm7r2Ar3nCtfYl9LmV0JZQARAQAB tClGcmFuY2lzIEJhbnlpa3dhIDxtaG9nb21jaHVuZ3VAZ21haWwuY29tPokCOAQT AQIAIgUCVfa79QIbLwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQPh84BCel 08rtahAAkdotOv7TfLJga/UgIU0AbBVEGgty41JFuILeUjA6TiHUCRDbAW73aiBw poLe5Z3ZJH4UDEo3SWpilXks7PEBArP75EvG7XabPGQOjQ8ys8AcIpXHSUAvgYD/ OM6Bvcb1gNV81hqNl/Wh3mIvnk0hbyqecrRSm5a2cExJeHAuIdb991CI69oOgDBu UcoI1FqBbcfuyBRAIl0WkvTcxHLGZLfRd/ZrSWB2FMt+Sj26V1VGGy4Jtb2S47Fw xMkOOI6R5MH88I/jokNB7kCNUR33uNDVO2ugS4WpLStC0fX7GJY/RUMBH81OXKIy dlPOjmpU/Ga3UgM6PeJJgrKjKSLuAFFynp0MogNU2o0bFrCR8PI0ZQxbN2h3X6Lb uRqbqrNkPcBLtlRgp3uzia2/bzCSfZWcgmakW2yBxL6NSVMoDnYq5bXrWZOwE6n5 F2dHj40kZTa7nl4rDaAal791SIFWPKtt4g/CsMn5qxIZ3OQ0JD/ZsdSJ5BehNFdD tJjPtk8fPdwY2t0JjaQeBYF04DMpT79f3S92fOqLYhIlkpxpdOEtp5hnjDuSHijP PkkXWcTqDzm/B00EbMV/TL/2bTODHKVX4F2nDJfP9Qycu8wNc4FMS0knG+13sgte bBIkAJ67KdfI0ex2/6YcrzgLlHSh0YypsvWb1L/usayLF9eRnRi5Ag0EVfa79QEQ ANef8DH/z21+WdQuBs+/rSWMt3TnQbu+6ClZatBgQNb/Eedo6dY7v81NveLJLB/4 nwC3hJvmQCT/Lo8iiKr5/rq2ETfog8CVNGk4413X5SI5Y+WEMeimuJQOnPNemPEE +aEyIwSWr2h30XzXJ89Q7chwj4M9minfnCGN8YndLljNWXXTuVCt30MvvdToxcw8 j0Gz+IdcdiTaq8r3S5ADk95hlVOztnL16agcX4YLZi1BpNBIle/ErCaHEmMdOtJl vjH2I2metqOsd6i3TPgH/S2+U6HDPAL2G9bn68CNTOywwdGlAakNL91AAqxbbEBJ 4iNJ8mSoDrsq0PbFWYMR/BMR5tzRQnocl8jlZGEY0C32uidXzkK/NtrBm47WkedJ VWyktUO29qB8MX2e1k4aJoZ4ODLZyXLybGVlIbLithonekH6X0H0UOMgHzeW7P6n xn3gw5QALkmJ4w/C9g1n3EkoCCNbkSBzeE6ZJK535aSl8jQxcN07o8Y9MnB4qvyF KNsv+82+ScdWOSi8M2KeHqS8t8PSiNgn9ckD5oyV7HoiQo90LrWvpmeBpS+jetAR luTnwbfy7HwSjLerGPJtSul6q3wD93iLkljy9TOzaj+Wv7jZvhkhXhBWez/+x3Z8 ZFAHllKKJIWcdFr+AVADfmF4EgfllVpY3qTpV8mvXABBABEBAAGJBD4EGAECAAkF AlX2u/UCGy4CKQkQPh84BCel08rBXSAEGQECAAYFAlX2u/UACgkQX5amBsT3KQV1 Rw//X3gGgdB1TNLuewZ3+y0kDBGSwwH/IxBTSn2IMoiwh+QdRQy/xmayQ4097iAk 3gHFtt49EPAl6ohWkKeGYRfq+3/hg5xKfmzwWMw5yRoHKZ8QhpJ5YpZBCRR0edeu RNg6Qyx6cgr9mDIvB1k45DMpgNtMFfmSTigVvyTA+mfCGOdz2w9E6PRPTnddR7Gp 6HZvwvHBfshZuPGI1KTchfa07ibHazMpZKlw43V0vz0nz6wjmzjgGWsnbdbIT47+ mvAbFcG9lyDHoXlI02skvuqmImIvoKlRSTYdxsbZHGus0USFJXw0E7JkA42KFf5M YbuwDD706Zbl672+yXxKkRKmp8c8zePL7PEwgADFHrxlrgaM+Qc8WDTCvy6FA6qd LAkr9mOztO40sge92C9zmjFjwr3PJ7yxlIZh5wLAQD5tCFahKu1JdQG8DCTK6o6F +oqTX1v4j2psfAxoQ0b0wkG1T/B8HSmp+oNZh/VRG7mTX6azqaIIPlyjKBN3w5xq UVYqy2FNOyft5q5iuEeTcw4gxGGffDOieHdzoHcDKpmBzr0iJC52ajKC+PEnNxiA CcvkpU34nbuPIGEbiL/TdWe88H7g0YJDkBqxmQxN5eJDSavi9MQ0fGP2khD1CDIk dIC4qOr/GQ2NRqV6m5BsMDMVCX7kqn/xvACDc3XgoMWb+AXsIw/+Ka4NTdof18zP 5iGVMuLG6PBls6VcRNy8Ypr/spNJ1xHWl2f1yNyNX0MeZ8MswbWlE6ESZJ/PcVtD dxjqZdhm3Z91CVbE9AxNhfSLsb3llLIK75J90Mo2Hx+GfLHCEbajpJfdfRENxIHb HsE3QHDdDToY9NuCg40yOGdH+H/x+Qun9iuL7MuNZiibZfY1MD0ThlCUBmXDOdLV l37Na2UvN3tBWsuOCSHqFZeivArfyv1Ez9ziVofmEPVQw3XkMVblxj8FvuIJzs8W KrvShO4WLi69tTql4fVC9PzfhspgEphSo9wVuXuYj/CsxgF8wn6d27Oox3LR+Grs w/oimllTMiNc7On5oZluZpHMyxMfgemsOs6XQXknbXA6lTYZo5JF7mUlf+4IoNlw SdvbY7S+4enblKFmZ/ndsccFUOv3tpGBRhYu+7AszhZngB2P02vXBkdjhatK2FZH zfdIrSpp0gs1J+xOdF/clQOPFn2oXdTcaBCUCp4d5rDszW4ItRyAgmhvMNbYZvVK h/19Gl88Dj49v7SS83DqAtURjtXny2lo37uTAAZYgqMVeMff4Y8UJnYSomNwoBqf pEH3RYyz2GwvaLpUvPUZvVr0x+dFSrHr3ze6v/q48OlmOTCkyukjYqsSOFgMIwBR i/gJN6mX3AIU7HHEHnP5ty8mwbb8ROc= =VDxL -----END PGP PUBLIC KEY BLOCK----- zuluCrypt-6.2.0/BUILD_INSTRUCTIONS000066400000000000000000000144341425361753700163710ustar00rootroot00000000000000 look in "rpm" folder for information on how to build an rpm package of zuluCrypt. look in "debian" or "debian_package_info" folder for information on how to build a debian package. below instructions are for those who want to build from source old school style :-) This tool depends on the following packages installed to build, their precise name may differ in your distro. 1. libpwquality-devel( optional dependency used to check the quality of passwords when creating volumes ) 2. libblkid-devel 3. For Qt4 build(libqt4-devel or a package that provides libqt4-network-devel,libqtcore4-devel,libqtgui4-devel) For Qt5 build(qt5-base-devel or a packages that provides Qt5Core-devel,Qt5Gui-devel,Qt5Network-devel) Above packages are required if building GUI components. 4. gcc 5. gcc-c++ 6. cryptsetup-devel 7. cmake 8. 9. libgcrypt-devel 10.libsecret-devel( optional dependency to store keys in gnome's libsecret ) 11.kde-devel( optional dependency to store keys in kde's kwallet ) 12.pkg-config 13.libdevmapper-devel aka device-mapper-devel. 14.uuid-devel The precise names of the above packages in debian are: 1. libpwquality-dev( optional dependency used to check the quality of passwords when creating volumes ) 2. libblkid-dev 3. libqt4-dev( optional dependency used when building GUI components ) libqt4-network libqtcore4 libqtgui4 4. gcc 5. g++ 6. libcryptsetup-dev 7. cmake 8. 9. libgcrypt20-dev(or libgcrypt11-dev if you are using the old version) 10.libsecret-1-dev( optional dependency used to store and retrieve volume keys using gnome's libsecret ) 11.not sure of the package name( optional dependency used to store and retrieve volume keys using kde's kwallet ) 12.pkg-config 13.libdevmapper-dev 14.uuid-dev 15.libudev-dev 16.chrpath 17.bzip2 18.debhelper The project is made up of two components,the command line "pure C" based backend components and GUI Qt/C++ based front end components. After you have above packages installed,run these 5 command to build and install. The last command depends on your distribution,go with the one recommended by disto. To build zuluCrypt with default options,run these 5 commands from inside the zuluCrypt source folder. ***************************************************************************************************** mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/usr -DSHARE_MOUNT_PREFIX=default -DUDEVSUPPORT=true -DNOGUI=false -DQT5=true -DHOMEMOUNTPREFIX=false -DREUSEMOUNTPOINT=false -DNOGNOME=false -DINTERNAL_ZULUPLAY=false -DNOKDE=false -DINTERNAL_LXQT_WALLET=false -DUSE_POLKIT=false -DCMAKE_BUILD_TYPE=RELEASE . .. make make install( or sudo make install ) ***************************************************************************************************** After you have it installed,run "zuluCrypt-cli --test" to make sure everything is working as expected. The build system now uses GNUInstallDirs (https://cmake.org/cmake/help/v3.5/module/GNUInstallDirs.html), so pretty much all directories can be controlled properly. meaning of different options: -DCMAKE_INSTALL_PREFIX=/usr/ This option tells the build process to install project's files in "/usr/". -DCMAKE_INSTALL_LIBDIR=lib This option specifies the base directory where libraries should be installed. Normally, this is automatically detected. -DCMAKE_BUILD_TYPE=RELEASE This option tells the build process to build the project in release mode.This mode is most suitable for non developers. -DUDEVSUPPORT=true This option tell zuluCrypt to ask for udev's opinion when deciding if a volume is system or not.Section 7 of the FAQ has more information about udev's problem.Set the option to "false" to ignore udev's opinion. The FAQ is located at: https://github.com/mhogomchungu/zuluCrypt/wiki/Frequently-Asked-Questions -DNOGUI=false This option tells the build process to build GUI components.Set this option to "true" if you do not want GUI components. -DQT5=false This option tells the build process to build GUI components using Qt4.Set the option to "true" if you want to build using Qt5. -DHOMEMOUNTPREFIX=false This option tells zuluCrypt to create mount paths at "/run/media/private/$USER".Set this option to "true" if you want mount points to be created in user's home directory. -DNOGNOME=false This option tells the build process to add gnome's libsecret secure storage of passwords.Set this option to "true" if you do not want libsecret's support. -DNOKDE=false This option tells the build process to add KDE's secure storage of passwords.Set this option to "true" if you do not want KDE wallet support. -DSHARE_MOUNT_PREFIX=default zuluMount has an ability to create a publicly accessible mount point in addition to the default private one and this option controls where the public share should be created.The "default" values sets a default value of "/run/media/public". Set this variable to another path if you want to change the default location of where share mount point should be created. -DREUSEMOUNTPOINT=false By default,the project demands exclusive control over the mount point path causing it to complain when it finds the path to already be taken when mounting and to unconditionally delete it on unmount. Set this option to "true" if you want to overide the above behavior and this ability seems useful when mounting volumes in a directory(like home directory) and wanting folder count to remain unchanged between volumes mounts. -DINTERNAL_LXQT_WALLET=false This project depends on lxqt_wallet project and it ships with an internal copy of the project. Set this option to "true" if you want zuluCrypt to unconditionally use the internal copy of the project or to "false" to make the build process use a system installed version if found. -DINTERNAL_ZULUPLAY=false Set this option to "true" if you want to unconditionally an external library of this project. A value of "false" will cause the build system to to use system wide library if it is found. -DUSE_POLKIT=false Set this option to "true" if project's CLI components are to be installed with suid bit NOT set. This option will cause GUI components to generate polkit prompt that requires a root's password and CLI components will be unusable from normal user account. Build errors/test fails/feature requests/recommendations can be reported at: https://github.com/mhogomchungu/zuluCrypt/issues or using my private email address at: mhogomchungu@gmail.com zuluCrypt-6.2.0/CMakeLists.txt000066400000000000000000000550021425361753700163170ustar00rootroot00000000000000 cmake_minimum_required(VERSION 3.0.2) set_property(GLOBAL PROPERTY ALLOW_DUPLICATE_CUSTOM_TARGETS ON) project(zuluCrypt) INCLUDE(GNUInstallDirs) set( PGR_VERSION "6.2.0" ) set( LIB_VERSION "1.2.0" ) set( LIB_PLUGIN_VERSION "1.0.0" ) set( COPYRIGHT_YEARS "2011-2022" ) #add_definitions( -D_DEFAULT_SOURCE -fstack-protector-all -D_FORTIFY_SOURCE=2 --param ssp-buffer-size=4 ) add_definitions( -D_DEFAULT_SOURCE -fstack-protector-all --param ssp-buffer-size=4 ) include_directories( ${PROJECT_BINARY_DIR} ) if( LIB_SUFFIX ) set( CMAKE_INSTALL_LIBDIR "${LIB_SUFFIX}" ) set( CMAKE_INSTALL_FULL_LIBDIR "${CMAKE_INSTALL_PREFIX}/${LIB_SUFFIX}" ) endif() # These variables are used but they dont always appear to be set and we set them if we found them to be not set if( NOT CMAKE_INSTALL_DOCDIR ) set( CMAKE_INSTALL_DOCDIR "share/doc/zuluCrypt" ) endif() if( NOT CMAKE_INSTALL_MANDIR ) set( CMAKE_INSTALL_MANDIR "share/man" ) endif() if( NOT CMAKE_INSTALL_DATADIR ) set( CMAKE_INSTALL_DATADIR "share" ) endif() if( NOT DEFINED QT5 ) set( QT5 "true" ) endif() # uninstall target configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY ) add_custom_target( uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake ) INCLUDE(CMakeDependentOption) INCLUDE(FindPkgConfig) # options option(NOGUI "Don't build the GUI" OFF) cmake_dependent_option(WITH_PWQUALITY "Build with pwquality support" ON "NOT NOGUI" OFF) option(NOGNOME "Build without gnome support" OFF) cmake_dependent_option(NOKDE "Build without kde support" OFF "NOT NOGUI" ON) option(UDEVSUPPORT "Build without udev support" ON) if( NOT NOGNOME ) pkg_check_modules( LIBSECRET libsecret-1 ) else( NOT NOGNOME ) set( NOSECRETSUPPORT "true" ) endif( NOT NOGNOME ) if( NOKDE ) set( NOKDESUPPORT "true" ) endif( NOKDE ) pkg_check_modules( CRYPTSETUP libcryptsetup ) pkg_check_modules( BLKID blkid ) pkg_check_modules( DEVMAPPER devmapper ) pkg_check_modules( UUID uuid ) pkg_check_modules( UUID-OSSP ossp-uuid ) pkg_check_modules( MCHUNGU_TASK mhogomchungu_task ) if ( WITH_PWQUALITY ) pkg_check_modules( PWQUALITY pwquality ) endif ( WITH_PWQUALITY ) file( WRITE ${PROJECT_BINARY_DIR}/version_1.h " #ifndef THIS_VERSION #define THIS_VERSION \"${PGR_VERSION}\" #endif \n" ) file( WRITE ${PROJECT_BINARY_DIR}/version.h " #ifndef ZULUCRYPT_VERSION #define ZULUCRYPT_VERSION #define VERSION_STRING \"Version : ${PGR_VERSION}\\nCopyright: ${COPYRIGHT_YEARS} Francis Banyikwa,mhogomchungu@gmail.com\\nLicense : GPLv2+\" #endif \n" ) if( NOT DEVMAPPER_FOUND ) message( FATAL_ERROR "ERROR: could not find devmapper package" ) else( ) find_library( devmapper_lib libdevmapper.so ) if( NOT devmapper_lib ) message( FATAL_ERROR "ERROR: could not find libdevmapper.so" ) else() message( STATUS "found version \"${DEVMAPPER_VERSION}\" of libdevmapper library at: ${devmapper_lib}" ) endif() endif() if( NOT UUID_FOUND ) if( NOT UUID-OSSP_FOUND ) message( FATAL_ERROR "ERROR: could not find uuid package" ) else() find_library( uuid_lib libossp-uuid.so ) if( NOT uuid_lib ) message( FATAL_ERROR "could not find libossp-uuid.so" ) else() message( STATUS "found version \"${UUID-OSSP_VERSION}\" of ossp-uuid library at: ${uuid_lib}" ) endif() endif() else( ) find_library( uuid_lib libuuid.so ) if( NOT uuid_lib ) message( FATAL_ERROR "could not find libuuid.so" ) else() message( STATUS "found version \"${UUID_VERSION}\" of uuid library at: ${uuid_lib}" ) endif() endif() if( NOT BLKID_FOUND ) message( FATAL_ERROR "ERROR: could not find blkid package" ) else( NOT BLKID_FOUND ) #add_definitions( "${BLKID_CFLAGS}" ) find_library( blkid_lib libblkid.so ) if( blkid_lib ) set( blkid "${blkid_lib}" ) message( STATUS "found version \"${BLKID_VERSION}\" of blkid library at: ${blkid_lib}" ) else( blkid_lib ) message( FATAL_ERROR "ERROR: could not find libblkid.so" ) endif( blkid_lib ) endif( NOT BLKID_FOUND ) if( NOT CRYPTSETUP_FOUND ) message( FATAL_ERROR "ERROR: could not find cryptsetup package" ) else( NOT CRYPTSETUP_FOUND ) #add_definitions( "${CRYPTSETUP_CFLAGS}" ) find_library( cryptsetup_lib libcryptsetup.so ) #set( cryptsetup_lib "${CRYPTSETUP_LIBDIR}/libcryptsetup.so" ) MESSAGE( STATUS "found version \"${CRYPTSETUP_VERSION}\" of cryptsetup library at: ${cryptsetup_lib}" ) if( NOT cryptsetup_lib ) message( FATAL_ERROR "ERROR: could not find libcryptsetup.so" ) endif( NOT cryptsetup_lib ) get_filename_component(libcrypsetupFullPath ${cryptsetup_lib} REALPATH) MESSAGE( STATUS "commiting to cryptsetup library path of: ${libcrypsetupFullPath}" ) file( WRITE ${PROJECT_BINARY_DIR}/cryptsetup_library_path.h "\n#define CRYPTSETUP_LIBRARY_PATH \"${libcrypsetupFullPath}\"" ) endif( NOT CRYPTSETUP_FOUND ) find_file( GCRYPT_INCLUDE_FILE gcrypt.h ) find_library( GCRYPT_LIBRARY gcrypt ) if( NOT GCRYPT_INCLUDE_FILE ) MESSAGE( FATAL_ERROR "could not find gcrypt header file" ) else() MESSAGE( STATUS "found gcrypt header file: ${GCRYPT_INCLUDE_FILE}" ) endif() if( NOT GCRYPT_LIBRARY ) MESSAGE( FATAL_ERROR "could not find gcrypt library(libgcrypt.so)" ) else() MESSAGE( STATUS "found gcrypt library: ${GCRYPT_LIBRARY}" ) endif() if( WITH_PWQUALITY ) pkg_check_modules( PWQUALITY pwquality ) endif( WITH_PWQUALITY ) file( WRITE ${PROJECT_BINARY_DIR}/install_prefix.h "\n#define INSTALL_PREFIX \"${CMAKE_INSTALL_PREFIX}/\"\n" ) if( REUSEMOUNTPOINT ) file( WRITE ${PROJECT_BINARY_DIR}/reuse_mount_point.h "\n#define REUSE_MOUNT_POINT 1\n" ) else() file( WRITE ${PROJECT_BINARY_DIR}/reuse_mount_point.h "\n#define REUSE_MOUNT_POINT 0\n" ) endif() set( PLUGINPATH "${CMAKE_INSTALL_FULL_LIBDIR}/zuluCrypt" ) file( WRITE ${PROJECT_BINARY_DIR}/plugin_path.h "\n#define ZULUCRYPTpluginPath \"${PLUGINPATH}/\"\n" ) file( APPEND ${PROJECT_BINARY_DIR}/plugin_path.h "\n#define ZULUCRYPTTestPlugin \"${PLUGINPATH}/zuluCrypt-testKey\"\n" ) set( BUILD_TCPLAY "true" ) set( TCPLAY_NEW_API "true" ) if( NOT DEFINED INTERNAL_ZULUPLAY ) set( INTERNAL_ZULUPLAY "false" ) endif() if( INTERNAL_ZULUPLAY ) message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "internal version of zuluplay will be used to create TrueCrypt and VeraCrypt volumes." ) message( STATUS "internal version of zuluplay will be used to create and restore TrueCrypt and VeraCrypt volume headers." ) message( STATUS "unlocking of TrueCrypt and VeraCrypt volumes will be done by cryptsetup." ) message( STATUS "creation and restoration of VeraCrypt volume headers is currently disabled." ) message( STATUS "---------------------------------------------------------------------------" ) set( STATIC_ZULUPLAY "true" ) else() pkg_check_modules( ZULUPLAY zuluplay ) if( ZULUPLAY_FOUND ) if( ZULUPLAY_VERSION VERSION_GREATER "1.2" ) include_directories( ${ZULUPLAY_INCLUDEDIR} ) link_directories( ${ZULUPLAY_LIBDIR} ) message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "external version of zuluplay will be used to create TrueCrypt and VeraCrypt volumes." ) message( STATUS "external version of zuluplay will be used to create and restore TrueCrypt volume headers." ) message( STATUS "unlocking of TrueCrypt and VeraCrypt volumes will be done by cryptsetup." ) message( STATUS "creation and restoration of VeraCrypt volume headers is currently disabled." ) message( STATUS "---------------------------------------------------------------------------" ) set( STATIC_ZULUPLAY "false" ) else() message( FATAL_ERROR "---------------------------------------------------------------------------\nInstalled version of zuluplay is too old(<1.3)\nPlease install a more receant version from: https://github.com/mhogomchungu/zuluplay\n---------------------------------------------------------------------------" ) endif() else() message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "internal version of zuluplay will be used to create TrueCrypt and VeraCrypt volumes." ) message( STATUS "internal version of zuluplay will be used to create and restore TrueCrypt volume headers." ) message( STATUS "unlocking of TrueCrypt and VeraCrypt volumes will be done by cryptsetup." ) message( STATUS "creation and restoration of VeraCrypt volume headers is currently disabled." ) message( STATUS "---------------------------------------------------------------------------" ) set( STATIC_ZULUPLAY "true" ) endif() endif() if( STATIC_ZULUPLAY ) set( ZULUPLAY_STATIC_ONLY "true" ) ADD_SUBDIRECTORY( ${PROJECT_SOURCE_DIR}/external_libraries/tcplay ) include_directories( ${PROJECT_SOURCE_DIR}/external_libraries/tcplay ) endif() if( SHARE_MOUNT_PREFIX ) if( "${SHARE_MOUNT_PREFIX}" STREQUAL "default" ) file( WRITE ${PROJECT_BINARY_DIR}/share_mount_prefix_path.h "\n#define SHARE_MOUNT_PREFIX \"/run/media/public\"\n" ) elseif( "${SHARE_MOUNT_PREFIX}" STREQUAL "" ) file( WRITE ${PROJECT_BINARY_DIR}/share_mount_prefix_path.h "\n#define SHARE_MOUNT_PREFIX \"/run/media/public\"\n" ) else() file( WRITE ${PROJECT_BINARY_DIR}/share_mount_prefix_path.h "\n#define SHARE_MOUNT_PREFIX \"${SHARE_MOUNT_PREFIX}\"\n" ) endif() else() file( WRITE ${PROJECT_BINARY_DIR}/share_mount_prefix_path.h "\n#define SHARE_MOUNT_PREFIX \"/run/media/public\"\n" ) endif() if( HOMEMOUNTPREFIX ) file( WRITE ${PROJECT_BINARY_DIR}/mount_prefix_path.h "\n#define USE_HOME_PATH_AS_MOUNT_PREFIX 1\n" ) else() file( WRITE ${PROJECT_BINARY_DIR}/mount_prefix_path.h "\n#define USE_HOME_PATH_AS_MOUNT_PREFIX 0\n" ) endif() #add_library( crypt_buffer STATIC plugins/network_key/crypt_buffer.c zuluCrypt-cli/utility/socket/socket.c ) #set_target_properties( crypt_buffer PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) #TARGET_LINK_LIBRARIES( crypt_buffer -lgcrypt ) ADD_SUBDIRECTORY( zuluCrypt-cli ) if( NOT DEFINED INTERNAL_LXQT_WALLET ) set( INTERNAL_LXQT_WALLET "false" ) endif() add_subdirectory( zuluSafe ) if( NOT NOGUI ) if( INTERNAL_LXQT_WALLET ) message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "lxqt wallet support will be provided by an internal library" ) message( STATUS "---------------------------------------------------------------------------" ) include_directories( external_libraries/lxqt_wallet ) include_directories( external_libraries/lxqt_wallet/frontend ) include_directories( external_libraries/lxqt_wallet/backend ) include_directories( ${PROJECT_BINARY_DIR}/external_libraries/lxqt_wallet/lxqt_wallet ) include_directories( ${PROJECT_BINARY_DIR}/external_libraries/lxqt_wallet/lxqt_wallet/frontend ) include_directories( ${PROJECT_BINARY_DIR}/external_libraries/lxqt_wallet/lxqt_wallet/backend ) add_subdirectory( external_libraries/lxqt_wallet ) else() pkg_check_modules( LXQT_WALLET lxqt-wallet ) if( NOT LXQT_WALLET_FOUND ) message( STATUS "ERROR: could not find lxqt_wallet package" ) message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "lxqt wallet support will be provided by an internal library" ) message( STATUS "---------------------------------------------------------------------------" ) include_directories( external_libraries/lxqt_wallet ) include_directories( external_libraries/lxqt_wallet/frontend ) include_directories( external_libraries/lxqt_wallet/backend ) include_directories( ${PROJECT_BINARY_DIR}/external_libraries/lxqt_wallet ) include_directories( ${PROJECT_BINARY_DIR}/external_libraries/lxqt_wallet/frontend ) include_directories( ${PROJECT_BINARY_DIR}/external_libraries/lxqt_wallet/backend ) add_subdirectory( external_libraries/lxqt_wallet ) else() if( LXQT_WALLET_VERSION VERSION_GREATER "3.1.0" ) include_directories( ${LXQT_WALLET_INCLUDEDIR} ) link_directories( ${LXQT_WALLET_LIBDIR} ) message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "lxqt wallet support will be provided by an external libary" ) message( STATUS "---------------------------------------------------------------------------" ) else() message( FATAL_ERROR "---------------------------------------------------------------------------\nInstalled version of lxqt_wallet is too old(<3.2.0)\nPlease install a more receant version from: https://github.com/lxqt/lxqt_wallet\n---------------------------------------------------------------------------" ) endif() endif() endif() if( WITH_PWQUALITY AND PWQUALITY_FOUND ) find_file ( header_pwquality pwquality.h PATHS ${PWQUALITY_INCLUDE_DIRS} ) find_library ( library_pwquality libpwquality.so ) set( BUILDPWQUALITY "true" ) if( library_pwquality ) if( header_pwquality ) file( WRITE ${PROJECT_BINARY_DIR}/can_build_pwquality.h "#define BUILD_PWQUALITY 1\n" ) file( APPEND ${PROJECT_BINARY_DIR}/can_build_pwquality.h "extern \"C\"\n{\n#include <${header_pwquality}>\n}" ) else( header_pwquality ) file( WRITE ${PROJECT_BINARY_DIR}/can_build_pwquality.h "#define BUILD_PWQUALITY 0\n" ) endif( header_pwquality ) else( library_pwquality ) file( WRITE ${PROJECT_BINARY_DIR}/can_build_pwquality.h "#define BUILD_PWQUALITY 0\n" ) endif( library_pwquality ) else( WITH_PWQUALITY AND PWQUALITY_FOUND ) file( WRITE ${PROJECT_BINARY_DIR}/can_build_pwquality.h "#define BUILD_PWQUALITY 0\n" ) endif( WITH_PWQUALITY AND PWQUALITY_FOUND ) if( QT5 ) find_package( Qt5Widgets REQUIRED ) find_package( Qt5Core REQUIRED ) find_package( Qt5Network REQUIRED ) message( STATUS "Found Qt5Widgets, version ${Qt5Widgets_VERSION}" ) message( STATUS "Found Qt5Core, version ${Qt5Core_VERSION}" ) message( STATUS "Found Qt5Network, version ${Qt5Network_VERSION}" ) set( CMAKE_INCLUDE_CURRENT_DIR ON ) include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Core_INCLUDE_DIRS} ) add_definitions( ${Qt5Widgets_DEFINITIONS} ) else() find_package( Qt4 REQUIRED QtCore QtGui QtNetwork ) add_definitions( -I${Qt4_INCLUDE_DIR} ) add_definitions( -I${QT_HEADERS_DIR} ) INCLUDE( ${QT_USE_FILE} ) endif() if( MCHUNGU_TASK_FOUND ) message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "mhogomchungu_task library will be provided by an external library" ) message( STATUS "---------------------------------------------------------------------------" ) include_directories( "${MCHUNGU_TASK_INCLUDEDIR}" ) link_directories( "${MCHUNGU_TASK_LIBDIR}" ) else() message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "mhogomchungu_task library will be provided by an internal library" ) message( STATUS "---------------------------------------------------------------------------" ) include_directories( ${PROJECT_SOURCE_DIR}/external_libraries/tasks ) ADD_SUBDIRECTORY( ${PROJECT_SOURCE_DIR}/external_libraries/tasks ) endif() if( CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0.0) set( CMAKE_CXX_STANDARD 20 ) MESSAGE( STATUS "Setting C++ version to C++20" ) else() set( CMAKE_CXX_STANDARD 14 ) MESSAGE( STATUS "Setting C++ version to C++14" ) endif() set( CMAKE_CXX_STANDARD_REQUIRED ON ) set( CMAKE_CXX_EXTENSIONS OFF) ADD_SUBDIRECTORY( zuluCrypt-gui/sharedObjects ) ADD_SUBDIRECTORY( zuluCrypt-gui ) ADD_SUBDIRECTORY( plugins ) ADD_SUBDIRECTORY( zuluMount-gui ) file( WRITE ${PROJECT_BINARY_DIR}/zuluPolkit.h "#define POLKIT_SUPPORT 1" ) if( USE_POLKIT ) file( APPEND ${PROJECT_BINARY_DIR}/zuluPolkit.h "\n#define AUTO_ENABLE_POLKIT_SUPPORT 1" ) else() file( APPEND ${PROJECT_BINARY_DIR}/zuluPolkit.h "\n#define AUTO_ENABLE_POLKIT_SUPPORT 0" ) endif() ADD_SUBDIRECTORY( zuluPolkit ) else( NOT NOGUI ) if( QT5 ) #adding this one just to silence a warning endif() endif( NOT NOGUI ) file( WRITE ${PROJECT_BINARY_DIR}/locale_path.h "\n#define TRANSLATION_PATH \"${CMAKE_INSTALL_FULL_DATADIR}/zuluCrypt/translations/\"\n") message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "optional functionality that will be build" ) if( NOT NOGUI ) message( STATUS "GUI front ends,zuluCrypt-gui and zuluMount-gui" ) endif( NOT NOGUI ) if( BUILDPWQUALITY ) message( STATUS "pwquality library support to give passphrase strength measure" ) endif( BUILDPWQUALITY ) if( UDEVSUPPORT ) message( STATUS "udev support will be enabled" ) endif( UDEVSUPPORT ) if( BUILD_TCPLAY ) message( STATUS "zuluplay adds the ability to create truecrypt compatible encrypted containers" ) endif( BUILD_TCPLAY ) if( CRYPTSETUP_VERSION VERSION_GREATER "1.6.3" ) file( WRITE ${PROJECT_BINARY_DIR}/support_whirlpool.h "\n#define SUPPORT_WHIRLPOOL 1\n" ) else() file( WRITE ${PROJECT_BINARY_DIR}/support_whirlpool.h "\n#define SUPPORT_WHIRLPOOL 0\n" ) endif() if( ( CRYPTSETUP_VERSION VERSION_GREATER "2.0.0" ) OR ( CRYPTSETUP_VERSION VERSION_EQUAL "2.0.0" ) ) file( WRITE ${PROJECT_BINARY_DIR}/veracrypt_pim.h "\n#define SUPPORT_VERACRYPT_PIM 1\n" ) else() file( WRITE ${PROJECT_BINARY_DIR}/veracrypt_pim.h "\n#define SUPPORT_VERACRYPT_PIM 0\n" ) endif() if( ( CRYPTSETUP_VERSION VERSION_GREATER "2.0.3" ) OR ( CRYPTSETUP_VERSION VERSION_EQUAL "2.0.3" ) ) file( WRITE ${PROJECT_BINARY_DIR}/luks2_support.h "\n#define SUPPORT_crypt_get_pbkdf_default 1\n" ) else() file( WRITE ${PROJECT_BINARY_DIR}/luks2_support.h "\n#define SUPPORT_crypt_get_pbkdf_default 0\n" ) endif() if( ( CRYPTSETUP_VERSION VERSION_GREATER "2.1.0" ) OR ( CRYPTSETUP_VERSION VERSION_EQUAL "2.1.0" ) ) file( WRITE ${PROJECT_BINARY_DIR}/luks_slot_status.h "\n#define SUPPORT_crypt_keyslot_get_pbkdf 1\n" ) else() file( WRITE ${PROJECT_BINARY_DIR}/luks_slot_status.h "\n#define SUPPORT_crypt_keyslot_get_pbkdf 0\n" ) endif() if( CRYPTSETUP_VERSION VERSION_GREATER "1.6.0" ) file( WRITE ${PROJECT_BINARY_DIR}/check_tcrypt.h "\n#define CHECK_TCRYPT 1\n" ) else() file( WRITE ${PROJECT_BINARY_DIR}/check_tcrypt.h "\n#define CHECK_TCRYPT 0\n" ) endif() message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "optional functionality that will NOT be build" ) if( NOGUI ) message( STATUS "GUI front ends,zuluCrypt-gui and zuluMount-gui\n" ) endif( NOGUI ) if( NOT BUILDPWQUALITY ) message( STATUS "pwquality library used to measure passphrase strength" ) message( STATUS "sources can be found at: https://fedorahosted.org/libpwquality/\n" ) endif( NOT BUILDPWQUALITY ) if( NOT UDEVSUPPORT ) message( STATUS "udev support\n" ) endif( NOT UDEVSUPPORT ) message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "\n" ) if( CRYPTSETUP_VERSION VERSION_GREATER "1.4.0" ) file( WRITE ${PROJECT_BINARY_DIR}/luks_external_header.h "\n#define LUKS_EXTERNAL_HEADER 1\n" ) else( CRYPTSETUP_VERSION VERSION_GREATER "1.4.0" ) file( WRITE ${PROJECT_BINARY_DIR}/luks_external_header.h "\n#define LUKS_EXTERNAL_HEADER 0\n" ) endif( CRYPTSETUP_VERSION VERSION_GREATER "1.4.0" ) if( UDEVSUPPORT ) file( WRITE ${PROJECT_BINARY_DIR}/udev_support.h "\n#define UDEV_SUPPORT 1\n") message( STATUS "udev will be consulted when deciding if a volume is system or not." ) message( STATUS "please read \"udev_support\" file for more information about udev support and associated problems.\n" ) else( UDEVSUPPORT ) file( WRITE ${PROJECT_BINARY_DIR}/udev_support.h "\n#define UDEV_SUPPORT 0\n") message( STATUS "udev will NOT be consulted when deciding if a volume is system or not." ) message( STATUS "please read \"udev_support\" file for more information about udev support and how to enable it." ) message( STATUS "It is probably a good idea to enable it if you are creating a package for distribution.\n" ) endif( UDEVSUPPORT ) if( NOT NOGUI ) if( QT5 ) message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "Building GUI components using Qt5" ) message( STATUS "---------------------------------------------------------------------------\n\n" ) else() message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "Building GUI components using Qt4" ) message( STATUS "---------------------------------------------------------------------------\n\n" ) endif() else() message( STATUS "---------------------------------------------------------------------------" ) message( STATUS "Not building GUI components" ) message( STATUS "---------------------------------------------------------------------------\n\n" ) endif() install ( FILES zuluCrypt.xml DESTINATION "${CMAKE_INSTALL_PREFIX}/share/mime/packages/" ) install ( FILES zuluCrypt-cli.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 ) install ( FILES zuluCrypt-gui.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 ) install ( FILES zuluMount-cli.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 ) install ( FILES zuluMount-gui.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 ) install ( FILES zuluSafe-cli.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 ) install ( FILES docs/zuluCrypt.pdf DESTINATION ${CMAKE_INSTALL_DOCDIR} ) file( WRITE ${PROJECT_BINARY_DIR}/pdf_path.h "\n#define PDF_PATH \"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DOCDIR}/zuluCrypt.pdf\"\n" ) install ( FILES translations/zuluCrypt/de_DE.qm DESTINATION ${CMAKE_INSTALL_DATADIR}/zuluCrypt/translations/zuluCrypt-gui ) install ( FILES translations/zuluCrypt/fr_FR.qm DESTINATION ${CMAKE_INSTALL_DATADIR}/zuluCrypt/translations/zuluCrypt-gui ) install ( FILES translations/zuluCrypt/en_US.qm DESTINATION ${CMAKE_INSTALL_DATADIR}/zuluCrypt/translations/zuluCrypt-gui ) install ( FILES translations/zuluCrypt/ar_SA.qm DESTINATION ${CMAKE_INSTALL_DATADIR}/zuluCrypt/translations/zuluCrypt-gui ) install ( FILES translations/zuluMount/de_DE.qm DESTINATION ${CMAKE_INSTALL_DATADIR}/zuluCrypt/translations/zuluMount-gui ) install ( FILES translations/zuluMount/en_US.qm DESTINATION ${CMAKE_INSTALL_DATADIR}/zuluCrypt/translations/zuluMount-gui ) install ( FILES translations/zuluMount/fr_FR.qm DESTINATION ${CMAKE_INSTALL_DATADIR}/zuluCrypt/translations/zuluMount-gui ) install ( FILES translations/zuluMount/ar_SA.qm DESTINATION ${CMAKE_INSTALL_DATADIR}/zuluCrypt/translations/zuluMount-gui ) #install ( FILES translations/zuluMount/de_DE.qm DESTINATION ${CMAKE_INSTALL_DATADIR}/zuluCrypt/translations/zuluMount-gui ) zuluCrypt-6.2.0/COPYING000066400000000000000000000012651425361753700146140ustar00rootroot00000000000000 copyright (c) 2011-2015 name : Francis Banyikwa email: mhogomchungu@gmail.com 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, see . zuluCrypt-6.2.0/GPLv2000066400000000000000000000445621425361753700144050ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ----- In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. zuluCrypt-6.2.0/GPLv3000066400000000000000000001045131425361753700143770ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . zuluCrypt-6.2.0/LICENSE000066400000000000000000000012651425361753700145660ustar00rootroot00000000000000 copyright (c) 2011-2015 name : Francis Banyikwa email: mhogomchungu@gmail.com 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, see . zuluCrypt-6.2.0/README000066400000000000000000000007161425361753700144410ustar00rootroot00000000000000zuluCrypt ========= zuluCrypt is a simple,feature rich and powerful solution for hard drives encryption. Project's frontpage is at: https://mhogomchungu.github.io/zuluCrypt bugs,wishes and comments can be reported at: https://github.com/mhogomchungu/zuluCrypt/issues or to my private email address at: mhogomchungu@gmail.com [![Build Status](https://api.travis-ci.org/mhogomchungu/zuluCrypt.svg?branch=master)](https://travis-ci.org/mhogomchungu/zuluCrypt) zuluCrypt-6.2.0/README.md000066400000000000000000000007171425361753700150410ustar00rootroot00000000000000zuluCrypt ========== zuluCrypt is a simple,feature rich and powerful solution for hard drives encryption. Project's frontpage is at: https://mhogomchungu.github.io/zuluCrypt bugs,wishes and comments can be reported at: https://github.com/mhogomchungu/zuluCrypt/issues or to my private email address at: mhogomchungu@gmail.com [![Build Status](https://api.travis-ci.org/mhogomchungu/zuluCrypt.svg?branch=master)](https://travis-ci.org/mhogomchungu/zuluCrypt) zuluCrypt-6.2.0/TODO000066400000000000000000000033401425361753700142450ustar00rootroot00000000000000 version 1.0 zuluCrypt-cli --open, close, create volumes and check for info of opened ones. - DONE zuluCrypt --open and close volumes and and check for info of opened ones. - DONE version 2.0 -- add support to managing luks keys in the cli and GUI. - DONE version 3.0 zuluCrypt -- add support for creation of volumes - DONE zuluCrypt-cli -- see if it is possible to safely create volumes resising in "/dev" - DONE version 4.0 -- host UI blocking code to threads to remove/minimize UI freezes - DONE -- allow a user to select what random number generator to use - DONE -- transition away from using cryptsetup on the cli to using the library - DONE -- Allow a user to select what font size and type to use - DONE -- add support for favorite volumes - DONE -- warn on attempt to delete a key when there is only one key left - DONE -- refuse to attemp tp add more keys when key slots are full. - DONE -- implement tray icon to minimize to tray - DONE -- provide a complete docs in a header file and associated shared and static library for others to use - DONE -- include partitions in /etc/crypttab in a list of system partitions. - DONE -- use cmake for building and installation. - DONE version 4.3.1 -- This version marks the status change to "maintanance mode". The project to the most partitions will be fixing bugs when found as it can now do all of what it is meant to do. -- New featues will be added in a form of transitions if people start submitting them. 4.0 going up -- just maintainig the tool,all features are in. X.Y -- add a plugin to retrieve keys from smart cards -- add mtp based devices support to zuluMount zuluCrypt-6.2.0/changelog000066400000000000000000000506161425361753700154370ustar00rootroot00000000000000 version 1.0.1 fix bug: - On interactive mode, checking if the two passphrases are the same fails something when stdin buffer isnt emptied before reading the first password. ","(comma) is not a valid mount point path. the cli prevents this but the GUI just fails without informing a user why. Added a dialog to inform a user when they select comma as a mount point. comma as a mount point is disallowed because it sits right next to "dot" button and most people(ie. me) usually press "."(dot) key to mean "present working directory" but will miss the key and press comma key and start wondering why things arent they way they are supposed to be. The comma key should have been on the other side of the keyboard!!! version 2.0 add support for adding and deleting keys in luks based volumes in the cli and gui. version 3.0 add support for creating both plain and luks based volumes in both files and partitions. version 4.0 -- host UI blocking code in a different threads to remove/minimize UI freezes -- use only cryptsetup.so library to interface with cryptsetup -- allow a user to select what random number generator to use -- add the ability to create key files -- Font size and type are now configurable -- add support for favorite volumes -- warn in the UI on attempt to delete a key when there is only one key left -- refuse to attemp to add more keys when key slots are full. -- implement tray icon to minimize to tray -- provide a complete docs in a header file on how to interface with libzuluCrypt.so -- include partitions in /etc/crypttab in a list of system partitions. version 4.1.0 -- minor update, fix bugs comming from mishandling of files and paths with empty spaces in them. version 4.2.0 -- minor update, volume in the favorite list could not be mounted, this version fix it. version 4.3.0 -- fix bugs in zulucrypt-gui triggered by use of double quotes in file and path names -- fix a bug. fat based volumes mounted with wrong permissions and only root user could write to the opened volume -- volumw property now displays file system type, volume size, volume size used, volume size available and percentage used. -- Fix a bug that prevented adding a new key from key file to a luks volume when the existing key was from a passphrase. -- The password dialog had a bug and did not reset properly when the previous operation involved opening a keyfile. -- Add an option to close all opened volumes with a single click. -- Created volumes with extX file systems now use 1% reserved space instead of the default 5%. -- Encrypted files can now be created using "/dev/random","/dev/urandom" or "/dev/zero" -- Add a UI option to select a random number generator to use to all dialogs that deals with features that need it. -- Add option to just minimize or minimize to tray the main window. -- various other UI and functionality fixes. version 4.3.1 -- A bit more UI effects when opening and closing of volumes. -- Context menu on opened volumes can now be triggered with CTRL+M or or menu key for better keyboard only management of the tool -- Device addresses can be given in a form of "/dev/XYZN" or "UUID=bla-bla-bla". -- various fixes -- A separate window to manage favorite volumes version 4.3.2 -- ext3/ext4 can not be mounted with user specified permissions and they use the permissions set when the volume was last mounted. This creates a problem on freshly created volumes because they always end up owned by root. This update fix the problem by setting permissions everytime a volume is opened in read/write mode. If a volume open with root as owner, then reopen the volume in read/write mode and permissions will be set properly(0700 with the owner being the user who opened the volume) version 4.3.3 -- fix a bug that caused improper reading of key files if they were not made up of C strings. -- fix a bug triggered when attempting to open a plain type volume using aes-cbc-plain cypher( opening plain volume in legacy mode ). version 4.3.4 -- fix a compilation bug on some system -- support libmount both above and below version 2.18 version 4.4.0 -- lots of code added to increase security and reliability of the tool,updating strongly advised. -- when creating a volume, use mkfs.xxx tools installed on the system and not hard code a subset of them. -- use ntfs-3g to mount volumes that use ntfs file system. -- major cli interface change, run zulucrypt-cli --help for more info. -- normal users can not create volumes in system partitions but root user now can. system partition is defined as a partition with active entry(not commented out) in /etc/fstab and /etc/crypttab. version 4.5.0 -- add support for creating backups of luks headers and restoring luks headers -- add support for first writing random data to partitions before creating an encryped container in them. -- add support for "/etc/zuluCrypttab". A place to add additional paths to devices to be considered system devices. -- various security related fixes. -- add support for encrypting stand alone files version 4.5.1 -- add the ability to manage system volumes in the UI,the GUI must be running from root account for the ability to be enabled -- by default, volumes are opened in read/write mode. version 4.5.2 -- a quick update to fix a regression in stand alone file encryption. version 4.5.3 -- add a plug in architecture. Its now possible to send zulucrypt-cli passphrases through different means, default plugins can retrieve passphrases from kde kwallet,gnome keyring,gpg encryped key files and a combination of keyfile and passphrase. -- show a dialog to warn a user the volume will be opened in read only mode when whey tick the option for the first time. -- passphrases are sent to the back end in a more secure way using unix local socket. -- small attempt to hide passphrases from ps command if they are passed through the command line argument. -- passphrases stored in kde kwallet can be managed from within zulucrypt-gui if their support is enabled at build time. version 4.6.0 -- add support for opening and closing of truecrypt volumes,this feature need cryptsetup >= 1.6.0 version 4.6.1 -- fix a regression that caused volumes presented by their UUID not to working version 4.6.2 -- add config option to not build KDE and/or GNOME support even when the system has support for them -- add support for LVM volumes -- add support for consulting udev in addition to fstab when deciding if a system is system or not -- add tcplay as an optional dependency to allow creation of truecrypt volumes -- fix bug:truecrypt volumes with multiple ciphers did not close properly -- fix bug:volumes did not close properly if mount point had a space character among others in it -- feature added:users who are members of "zulumount-exec" group will have their volumes opened with "exec" mount option. This will allow them to be able to execute commands from the mount point.The default and recommended option is not mount with "noexec" option. -- feature added:A "-M" option is added that will create a publicly accessible "mirror" of a mount point in "/run/share" from the private original one created in "/run/media/$USER.This option is there to allow a user to mount a volume and have it accessible from other users of the system. -- zuluMount-gui now adds and removed from its list as devices are added and removed from the system.A right click context menu option can be set to allow unencrypted volumes to also be automounted. -- add a command line option to zuluMount-gui to start it up without showing the GUI version 4.6.3 -- fix a build issue on some systems -- when automounting devices,use device LABEL if present -- its now possible to create truecrypt volumes using a keyfile -- its now possible to open a truecrypt hidden volume -- add explicit support md raid based volumes -- add context menu entry in zuluMount-gui to open shared mount point folder -- its now possible to initiate volume mounting process of volumes in files by drag and drop them on zuluCrypt-gui and zuluMount-gui UI. -- various bug fixes. -- add ability to create and open truecrypt hidden volumes in the GUI version 4.6.4 -- fix a build issue on some systems version 4.6.5 -- add support for opening truecrypt system volumes -- add internatiolization support -- zuluMount-gui is now aware of volumes that are mounted or unmounted outside of it.This gives zuluMount-gui an ability to automount newly attached devices. -- encrypted volumes that reside in files can be opened simply by drag and drop them in zuluCrypt-gui or zuluMount-gui windows version 4.6.6 -- fix a regression,retrieving keys from kwallet using volume UUID broke. -- volumes in gnome are now stored in libsecret and no longer in libgnome-keyring -- add a GUI window in zuluCrypt-gui to manage keys in libsecret wallet,internal wallet and kde kwallet. -- add an internal system that can securely store keys independently of kde kwallet and gnome libsecret.Useful to those who want to store keys securely but dont want gnome or kde dependencies -- add compile time option to use mount points in user home directory instead of "/run/media/private" -- NOTE: changes in management of wallets are not backward compatible and hence volumes will have to be readded after the update.My apologies for the inconvenience. -- drop support for updating /etc/mtab and remove libmount as a required dependency -- add a Qt5 port,see build instrunctions on how to build Qt5 version version 4.6.7 -- fix packaging issues -- fix a regression on zuluMount-gui that caused a hang when checking for properties of an opened volume opened by a different user version 4.6.8 -- store partition id in wallets by device hardware id on volumes that do not have UUID( non LUKS volumes ) -- add support for exfat file system. -- add support for creating a backup and restoring from backup truecrypt volume headers(tcplay >=2.0.0 required) -- add a simple CLI tool(zuluSafe-cli) that can be used to store multiple files securely in a single wallet file. -- add support in zuluMount for opening a plain volume at a user specified offset.This ability will allow hidden volume type functionality.In one of the prompts in zuluMount-gui,press "ctrl+f" to bring up the dialog that accepts the offset. -- add support for multi device btrfs volumes. version 4.6.9 -- move config files to "/etc/zuluCrypt" from "/etc" -- add a config file "/etc/zuluCrypt/fs_options" where default file system mount options can be specified per UUID. -format is:one entry per line,example entry: UUID="abcf" uid=500 -- fix a bug,if udev is enabled,mounted image files were always treated as system volumes. -- use libgcrypt for stand alone file encryption instead of cryptsetup.Newer stand alone encrypted files will have an extension of ".zC" to distinguish them from previous ones that use ".zc".Older versions of zuluCrypt(<4.6.9) will not be able to open encrypted files that end with ".zC". -- add an option in zuluCrypt GUI to specify a truecrypt volume type when saving or restoring a truecrypt header from a backup header file version 4.7.0 -- various changes and improvements -- add a plugin named "steghide" that retrives passphrases embeded in other files using "steghide" tool. -- add a plugin named "luks" that allows opening a LUKS volume using a backup/detached header. -- add a plugin named "tomb" that allows opening of LUKS volumes from tomb project using keys securely stored in image files. version 4.7.1 -- fix a build issue in gcc 4.9 version 4.7.2 -- add support for opening TrueCrypt volumes using a passphrase together with one or more keyfiles. version 4.7.3 -- fix issues with Qt5 build -- show devices even when they have neither partitions nor recognizable file systems.This is useful for TrueCrypt system volumes or normal TrueCrypt volumes that are not in partitions. -- add an ability to change TrueCrypt volume key. -- add ability to create volumes with different crypto options version 4.7.4 -- fix a bug that hanged zuluMount-gui on failed attempt at unlocking a plain dm-crypt volume at a none zero offset.a plain dm-crypt volume at a none zero offset can be used as a hidden volume ala TrueCrypt hidden volume feature.No protetcion of hidden volume though. version 4.7.5 -- add abilities in zuluMount-gui to hide useless entries like windows recovery partitions from view. These entries can be set to show/hide through tray icon context menu. -- add ability to mount and unmount encfs volumes in zuluMount-gui.A folder with encrypted files can be unlocked by dragging it and then dropping it on zuluMount-gui main window. -- add ablity to create TrueCrypt volumes using a passphrase together with one or more keyfiles.Previous versions allowed creation of volumes using either a passphrase or a single keyfile. -- add support for opening of VeraCrypt volumes(cryptsetup > 1.6.6 required). version 4.7.6 -- add "hmac" plugin.This plugin produces a key as follows: key = hmac-sha256( passphrase,keyfile-contents ). this plugin can be used when unlocking a volume requires a passphrase and a keyfile. -- use "tcrypt" to refer to TrueCrypt volumes and "vcrypt" to refer to VeraCrypt volumes. -- add ability to create VeraCrypt volumes. version 4.7.7 -- add support for creating and opening VeraCrypt volumes that use dynamic mode. -- make zuluCrypt-gui window and zuluMount-gui window resizable with the new sizes surviving restarts. version 4.7.8 -- add support for usage of keys that are made up by a combination of a passphrase and a keyfile."hmac" plugin should be used to unlock volumes generated by this combination. -- fix problems caused by updated versions of certain utilities we rely on. version 4.8.0 -- fix bug,private mount points were not created with proper permissions. version 4.9.0 -- add support for unlocking cryfs(https://www.cryfs.org/) encrypted volumes in zuluMount. -- various fixes and improvements version 5.0.0 -- add support for creating LUKS volumes that only uses a detached header.The detached header will be created in the user home directory and the volume can not be unlocked without this detached header.The detached header can be reattached later on through zuluCrypt-gui->menu->Volumes->Restore Volume Header. -- its now possible to create a shared mount point when unlocking a volume in zuluCrypt-gui -- its now possible to unlock VeraCrypt volumes from favorite feature in zuluCrypt-gui -- add complete French translation to both zuluCrypt-gui and zuluMount-gui -- try to silently solve problems caused by other tools mounting zuluCrypt's encryption mapper. -- add support for creating a "plain dm-crypt" volume at a "none zero offset".This type of volume is useful as a "poor man's version of a hidden volume feature in TrueCrypt and VeraCrypt".Best thing about this type of hidden volume is that the outer volume can be anything including an "exposed file system".Currently,only zuluMount-gui can open this type of volume by clicking "options" followed by "Set Volume Offset" on the mounting dialog prompt. -- Qt5 is now the default Qt dependency. version 5.0.1 -- languages can be changed without requiring a restart. -- add ability to use custom icons. Icons can be changed in zuluCrypt-gui through "menu->options->select icons" and in zuluMount-gui through "menu->select icons". User specific icons can be added by placing them at "$INSTALL_PREFIX/icons/hicolor/48x48/apps". zuluCrypt-gui icons must be in "zuluCrypt.ICON_NAME.png" format and zuluMount-gui icons must be in "zuluMount.ICON_NAME.png" format. -- zuluMount-gui can now unlock cryfs,encfs,gocryptfs and securefs based encrypted volumes. -- add full support for German translation. version 5.0.2 -- add support for unlocking ecryptfs volumes in zuluMount-gui(ecryptfs-simple tool must already be installed) -- fix permission related problems in configuration files when running in mixed mode. version 5.1.0 -- make it possible to unlock folder based encrypted volumes when running in mixed mode. -- add ability in zuluCrypt-gui to unlock VeraCrypt volumes that use PIM value. -- add ability in zuluCrypt-gui to unlock plain dm-crypt volumes that uses an offset. -- add ability in zuluCrypt-gui to create plain dm-crypt volumes using user configurable crypto options. -- add ability in zuluCrypt-gui to unlock plain dm-crypt volumes using user configurable crypto options. -- add ability in zuluCrypt-gui to backup and restore VeraCrypt headers. -- add ability in zuluCrypt-gui to change VeraCrypt volume key. -- add ability in zuluCrypt-gui to create a VeraCrypt volume that uses a PIM value. -- add ability in zuluMount-gui to unlock folder based encrypted volumes when running in mixed mode. version 5.2.0 -- add ability to select a file manager to use to open mount points. A file manager can be set through zuluCrypt-gui->menu->options->set file manager. -- dont run zuluCrypt-gui and zuluMount-gui from root's account when running in mixed mode. -- add arabic translation. version 5.3.0 -- fix a build time error when build with certain new compilers and a runtime crush when build with other newer compilers. -- add more support for wayland sessions by not requiring GUI to run from root's account to perform some operations. -- add support for creating LUKS2 volumes(libcryptsetup >=2.0.0 is required) -- add support for unlocking of TrueCrypt and VeraCrypt volumes without mounting their file system. -- unlocking of a TrueCrypt volume is done by command: zuluCrypt-cli -O -d /dev/sdXX -t tcrypt -- unlocking of a VeraCrypt volume is done by command: zuluCrypt-cli -O -d /dev/sdXX -t vcrypt version 5.4.0 -- fix a bug that caused a wrong password to be used when creating a TrueCrypt/VeraCrypt volume from zuluCrypt-gui. Easiest way to notice this was that a just created volume could not be unlocked. -- fix a build issue on some distributions. version 5.5.0 -- Add support for unlocking bitlocker volumes using dislocker(https://github.com/Aorimn/dislocker) -- Fix a build issue on some distributions. -- Add ability to create a plain dm-crypt volume at the end of a regular file(steganography). -- Various fixes and improvements. version 5.6.0 -- Add ability to create volume keys using YubiKey's challenge-response feature. -- Add GUI options to clear dead mount points(these are unused mount folders located at /run/media/private/$USER). CLI users should call CLI components with "--clear-dead-mount-points" -- Fix a race condition bug introduced in version 5.5.0 that prevented volumes from getting mounted under certain circumstances. version 5.7.0 -- Fix a bug introduced in 5.6.0 that prevents unlocking PLAIN dm-crypt volume that use non default crypto options because the selection button in is zuluCrypt-gui always disabled. -- Update French translations. -- Dont resolve loop device paths to their backing file if they are partitioned. -- Fix a bug that prevented restoring a LUKS2 volume header. -- Identify authenticated luks2 volumes as luks2+. -- Add support for creating authenticated luks2 volumes(the support in Currently in zuluCrypt-cli only). -- Default to using 512bit keys when creating LUKS volumes. version 5.7.1 -- Use cryptsetup instead of zuluplay to unlock TrueCrypt volumes if installed version of cryptsetup >= 1.6.0(released on January 14,2013). -- Use cryptsetup instead of zuluplay to unlock VeraCrypt volumes if installed version of cryptsetup >= 1.6.7(released on March 23, 2015). -- The two changes above will hopefully solve long standing problems around unlocking TrueCrypt/VeraCrypt volumes that use preboot authentication. -- Use cryptsetup by default instead of dislocker to unlock BitLocker volumes if installed version of cryptsetup >= 2.3.0(released on February 3,2020). Users of cryptsetup >= 2.3.0 who prefer to use dislocker to unlock BitLocker volumes should create a text file at "/etc/zuluCrypt/dislocker". version 6.0.0 -- Add ability to show used LUKS key slots and their properties in zuluCrypt-gui. -- Fix a bug that caused zuluCrypt to not set user specified digest hash when creating LUKS2 volumes. -- Default to creating LUKS2 volumes if installed version of cryptsetup supports it. -- Make it buildable again on some systems. version 6.1.0 -- Add a GUI way to set advanced LUKS2 options when creating a LUKS2 volume. -- Add a GUI way to set advanced LUKS2 options when adding a key to a LUKS2 volume. version 6.2.0 -- Update French translations. -- Fix a bug that caused existing favorite entries to accidentally be deleted and new ones to not get saved. -- Fix a bug that caused saved passwords in libsecret to not be visible. -- Version 6.1.0 modernized favorites functionality and moved saved password UI to the favorites window and changes in both places introduced above bugs. zuluCrypt-6.2.0/cmake_uninstall.cmake.in000066400000000000000000000020251425361753700203340ustar00rootroot00000000000000 cmake_policy(SET CMP0007 NEW) if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") list(REVERSE files) foreach (file ${files}) message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") if (EXISTS "$ENV{DESTDIR}${file}") execute_process( COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" OUTPUT_VARIABLE rm_out RESULT_VARIABLE rm_retval ) if(NOT ${rm_retval} EQUAL 0) message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") endif (NOT ${rm_retval} EQUAL 0) else (EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") endif (EXISTS "$ENV{DESTDIR}${file}") endforeach(file) zuluCrypt-6.2.0/copyright000066400000000000000000000202441425361753700155120ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: zulucrypt Source: http://mhogomchungu.github.io/zuluCrypt/ Files: * Copyright: 2011-2015 Francis Banyikwa, aka Mhogo Mchungu License: GPL-2+ Files: debian_package_info/* Copyright: 2013 Balint Reczey 2013 Laszlo Boszormenyi (GCS) 2013-2014 Francis Banyikwa License: GPL-2+ Files: plugins/network_key/crypt_buffer.* plugins/network_key/network_key.h plugins/network_key/server.c Copyright: 2014-2015 Francis Banyikwa License: BSD-2-clause Files: zuluCrypt-gui/networkAccessManager.hpp Copyright: 2016 Francis Banyikwa License: BSD-2-clause Files: zuluCrypt-cli/lib/canonicalize/canonicalize.c Copyright: 1993 Rick Sladkey License: LGPL-2+ Files: zuluCrypt-gui/lxqt_wallet/* Copyright: 2013-2015 Francis Banyikwa License: BSD-2-clause Files: zuluCrypt-gui/md5/md5* Copyright: 2001 Alexander Peslyak License: public-domain Files: external_libraries/tc-play/* Copyright: 2011 Alex Hornung License: BSD-2-clause Files: external_libraries/tc-play/tcplay.3 external_libraries/tc-play/tcplay.8 Copyright: 2011 DragonFly Project License: BSD-3-clause Files: external_libraries/tc-play/generic_xts* Copyright: 2008 Damien Miller 2011 Alex Hornung License: special Files: external_libraries/tc-play/crc32.c Copyright: 1986 Gary S. Brown License: special2 Files: debian/* Copyright: 2015-2016 Marcio de Souza Oliveira License: GPL-3+ License: GPL-2+ This package 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 package 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, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". License: public-domain This software was written by Alexander Peslyak in 2001. No copyright is claimed, and the software is hereby placed in the public domain. In case this attempt to disclaim copyright and place the software in the public domain is deemed null and void, then the software is Copyright (c) 2001 Alexander Peslyak and it is hereby released to the general public under the following terms: . Redistribution and use in source and binary forms, with or without modification, are permitted. . There's ABSOLUTELY NO WARRANTY, express or implied. . (This is a heavily cut-down "BSD license".) License: BSD-2-clause All rights reserved. . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. . THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: LGPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This package 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 Lesser General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . . On Debian systems, the complete text of the GNU Lesser General Public License can be found in "/usr/share/common-licenses/LGPL-2". License: GPL-3+ 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 3 of the License, or (at your option) any later version. . This package 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, see . . On Debian systems, the complete text of the GNU General Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". License: special Permission to use, copy, and modify this software with or without fee is hereby granted, provided that this entire notice is included in all copies of any software which is or includes a copy or modification of this software. . You may use this code under GNU General Public License if you so wish. Please contribute changes back to the authors under this freer than GPL license so that we may further the use of strong encryption without limitations to all. . THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. License: BSD-3-clause All rights reserved. . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: special2 You may use this program, or code or tables extracted from it, as desired without restriction. zuluCrypt-6.2.0/debian.upstream/000077500000000000000000000000001425361753700166365ustar00rootroot00000000000000zuluCrypt-6.2.0/debian.upstream/BINARY_INSTALL_INSTRUCTIONS000066400000000000000000000014341425361753700227610ustar00rootroot00000000000000 This package contains debian packages for 32 bit systems and 64 bit systems. Packages for 32 bit systems are in i386 folder. Packages for 64 bit systems are in amd64 folder. Use packages that match your computer architecture. To install these packages,just click on them and see if your system understands how to install debian packages.If it does,then install them in this order: 1. libzuluCrypt1 2. libzuluCrypt-dev 3. zuluCrypt-cli 4. zuluCrypt-gui If your system does not understand how to install debian packages by clicking on them,then install them using the following steps: 1. Open the terminal. 2. Change directories to where the debian packages are. 3. Run the following command to install them: su -c "dpkg -i *.deb && apt-get install -f" 4. Enter root's password when asked. zuluCrypt-6.2.0/debian.upstream/BUILD_INSTRUCTIONS000066400000000000000000000120421425361753700214430ustar00rootroot00000000000000 1. If this folder is named "debian.upstream" then rename it to "debian" before proceeding. These instructions starts with howto on ubuntu or any other debian based distribtion that use "sudo" command to gain root's privileges and then ends with howto on debian or any other debian based distribtion that use "su" command to gain root's privileges. ps: copy and paste all commands to make sure you dont mistype them. ps: at step 4,make sure the version number on the command matches the version number of zuluCrypt you are building. HOW TO BUILD A ZULUCRYPT PACKAGE ON UBUNTU OR ANY OTHER DEBIAN BASED DISTRIBUTION THAT USES "SUDO". 2. Install a package called "build-essential" by running the following command: ****************************************************************************************************** sudo apt-get install build-essential ****************************************************************************************************** 3. Run the following command to make sure all required packages are installed: ****************************************************************************************************** sudo apt-get -f install tar xz-utils libpwquality-dev libblkid-dev qtbase5-dev qttools5-dev gcc g++ libcryptsetup-dev cmake libgcrypt11-dev libsecret-1-dev pkg-config libdevmapper-dev uuid-dev libudev-dev chrpath bzip2 debhelper ****************************************************************************************************** 4. While on zuluCrypt's source folder,create a debian archive by running the following command: ****************************************************************************************************** tar cf - . | xz -zf - > ../zulucrypt_5.3.0.orig.tar.xz ****************************************************************************************************** 5. While still on zuluCrypt's source folder,create debian packages by runnning the following command: ****************************************************************************************************** dpkg-buildpackage -uc -us ****************************************************************************************************** 6. Wait for the build process to finish and then look at zuluCrypt's source folder's parent folder for zuluCrypt debian packages. 7. While still on zuluCrypt's source folder,install zuluCrypt debian packages by running the following command: ****************************************************************************************************** sudo dpkg --install ../*.deb ****************************************************************************************************** 8. zuluCrypt should now be installed and you can access it from desktop environment's application launcher. HOW TO BUILD A ZULUCRYPT PACKAGE ON DEBIAN OR ANY OTHER DEBIAN BASED DISTRIBUTION THAT USES "SU". 2. Install a package called "build-essential" by running the following command: ****************************************************************************************************** su -c "apt-get install build-essential" ****************************************************************************************************** 3. Run the following command to make sure all required packages are installed: ****************************************************************************************************** su -c "apt-get -f install tar xz-utils libpwquality-dev libblkid-dev qtbase5-dev qttools5-dev gcc g++ libcryptsetup-dev cmake libgcrypt11-dev libsecret-1-dev pkg-config libdevmapper-dev uuid-dev libudev-dev chrpath bzip2 debhelper" ****************************************************************************************************** 4. While on zuluCrypt's source folder,create a debian archive by running the following command: ****************************************************************************************************** tar cf - . | xz -zf - > ../zulucrypt_5.3.0.orig.tar.xz ****************************************************************************************************** 5. While still on zuluCrypt's source folder,create debian packages by runnning the following command: ****************************************************************************************************** dpkg-buildpackage -uc -us ****************************************************************************************************** 6. Wait for the build process to finish and then look at zuluCrypt's source folder's parent folder for zuluCrypt debian packages. 7. While still on zuluCrypt's source folder,install zuluCrypt debian packages by running the following command: ****************************************************************************************************** su -c "dpkg --install ../*.deb && apt-get install -f" ****************************************************************************************************** 8. zuluCrypt should now be installed and you can access it from desktop environment's application launcher. zuluCrypt-6.2.0/debian.upstream/TODO000066400000000000000000000002611425361753700173250ustar00rootroot00000000000000split plugins to separate packages find a safe but comfortable way of runing *-cli as a regular user - RPM package sets setuid bit, but it may be give much privilege to anyone zuluCrypt-6.2.0/debian.upstream/changelog000066400000000000000000000261261425361753700205170ustar00rootroot00000000000000zulucrypt (5.4.0-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- fix a bug that caused a wrong password to be used when creating a TrueCrypt/VeraCrypt volume from zuluCrypt-gui. Easiest way to notice this was that a just created volume could not be unlocked. -- fix a build issue on some distributions. -- Mhogo Mchungu Sun, 19 Nov 2017 16:38:48 +0000 zulucrypt (5.3.0-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- fix a build time error when build with certain new compilers and a runtime crush when build with other newer compilers. -- add more support for wayland sessions by not requiring GUI to run from root's account to perform some operations. -- add support for creating LUKS2 volumes(libcryptsetup >=2.0.0 is required) -- add support for unlocking of TrueCrypt and VeraCrypt volumes without mounting their file system. -- unlocking of a TrueCrypt volume is done by command: zuluCrypt-cli -O -d /dev/sdXX -t tcrypt -- unlocking of a VeraCrypt volume is done by command: zuluCrypt-cli -O -d /dev/sdXX -t vcrypt -- Mhogo Mchungu Wed, 1 Nov 2017 16:38:48 +0000 zulucrypt (5.2.0-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- add ability to select a file manager to use to open mount points. A file manager can be set through zuluCrypt-gui->menu->options->set file manager. -- dont run zuluCrypt-gui and zuluMount-gui from root's account when running in mixed mode. -- Mhogo Mchungu Sat, 1 Jul 2017 16:38:48 +0000 zulucrypt (5.1.0-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- make it possible to unlock folder based encrypted volumes when running in mixed mode. -- add ability in zuluCrypt-gui to unlock VeraCrypt volumes that use PIM value. -- add ability in zuluCrypt-gui to unlock plain dm-crypt volumes that uses an offset. -- add ability in zuluCrypt-gui to create plain dm-crypt volumes using user configurable crypto options. -- add ability in zuluCrypt-gui to unlock plain dm-crypt volumes using user configurable crypto options. -- add ability in zuluCrypt-gui to backup and restore VeraCrypt headers. -- add ability in zuluCrypt-gui to change VeraCrypt volume key. -- add ability in zuluCrypt-gui to create a VeraCrypt volume that uses a PIM value. -- add ability in zuluMount-gui to unlock folder based encrypted volumes when running in mixed mode. -- Mhogo Mchungu Sun, 1 Jan 2017 16:38:48 +0000 zulucrypt (5.0.2-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- add support for unlocking ecryptfs volumes in zuluMount-gui through ecryptfs-simple backend. -- fix a hand when creating/unlocking volumes some users where experiencing. -- Mhogo Mchungu Thu, 1 Dec 2016 16:38:48 +0000 zulucrypt (5.0.1-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- languages can be changed without requiring a restart. -- add ability to use custom icons. Icons can be changed in zuluCrypt-gui through "menu->options->select icons" and in zuluMount-gui through "menu->select icons". User specific icons can be added by placing them at "$INSTALL_PREFIX/icons/hicolor/48x48/apps". zuluCrypt-gui icons must be in "zuluCrypt.ICON_NAME.png" format and zuluMount-gui icons must be in "zuluMount.ICON_NAME.png" format. -- zuluMount-gui can now unlock cryfs,encfs,gocryptfs and securefs based encrypted volumes. -- Mhogo Mchungu Wed, 31 Aug 2016 16:38:48 +0000 zulucrypt (5.0.0-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- add support for creating LUKS volumes that only uses a detached header.The detached header will be created in the user home directory and the volume can not be unlocked without this detached header.The detached header can be reattached later on through zuluCrypt-gui->menu->Volumes->Restore Volume Header. -- its now possible to create a shared mount point when unlocking a volume in zuluCrypt-gui -- its now possible to unlock VeraCrypt volumes from favorite feature in zuluCrypt-gui -- add complete French translation to both zuluCrypt-gui and zuluMount-gui -- try to silently solve problems caused by other tools mounting zuluCrypt's encryption mapper. -- add support for creating a "plain dm-crypt" volume at a "none zero offset".This type of volume is useful as a "poor man's version of a hidden volume feature in TrueCrypt and VeraCrypt".Best thing about this type of hidden volume is that the outer volume can be anything including an "exposed file system".Currently,only zuluMount-gui can open this type of volume by clicking "options" followed by "Set Volume Offset" on the mounting dialog prompt. -- Mhogo Mchungu Sun, 1 May 2016 16:38:48 +0000 zulucrypt (4.9.0-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- add support for unlocking cryfs[1][2] encrypted folders in zuluMount. [1] https://github.com/cryfs [2] https://www.cryfs.org/ -- Mhogo Mchungu Tue, 1 Mar 2015 16:38:48 +0000 zulucrypt (4.8.0-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- Fix bug,mount point was not created with proper permissions. -- Mhogo Mchungu Wed, 2 Dec 2015 16:38:48 +0000 zulucrypt (4.7.8-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- add support for usage of keys that are made up by a combination of a passphrase and a keyfile."hmac" plugin should be used to unlock volumes generated by this combination. -- fix problems caused by updated versions of certain utilities we rely on. -- Mhogo Mchungu Mon, 30 Nov 2015 16:38:48 +0000 zulucrypt (4.7.7-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- add ability to create and open VeraCrypt volumes in dynamic mode. -- make zuluCrypt-gui window and zuluMount-gui window resizable with the new sizes surviving restarts. -- Mhogo Mchungu Tue, 1 Sep 2015 16:38:48 +0000 zulucrypt (4.7.6-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- add "hmac" plugin.This plugin produces a key as follows: key = hmac-sha256( passphrase,keyfile-contents ). this plugin can be used when unlocking a volume requires a passphrase and a keyfile. -- use "tcrypt" to refer to TrueCrypt volumes and "vcrypt" to refer to VeraCrypt volumes. -- add ability to create VeraCrypt volumes(cryptsetup > 1.6.6 required). -- Mhogo Mchungu Mon, 1 Jun 2015 16:38:48 +0000 zulucrypt (4.7.5-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features -- add abilities in zuluMount-gui to hide useless entries like windows recovery partitions from view. These entries can be set to show/hide through tray icon context menu. -- add ability to mount and unmount encfs volumes in zuluMount-gui.A folder with encrypted files can be unlocked by dragging it and then dropping it on zuluMount-gui main window. -- add ablity to create TrueCrypt volumes using a passphrase together with one or more keyfiles.Previous versions allowed creation of volumes using either a passphrase or a single keyfile. -- add support for opening of VeraCrypt volumes(cryptsetup > 1.6.6 required). -- Mhogo Mchungu Sun, 1 Mar 2014 16:38:48 +0000 zulucrypt (4.7.4-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features - fix a bug that hanged zuluMount-gui on failed attempt at unlocking a plain dm-crypt volume at a none zero offset. -- Mhogo Mchungu Mon, 6 Oct 2014 16:38:48 +0000 zulucrypt (4.7.3-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features - fix build issues on Qt5. - add an ability to change TrueCrypt volume key. - show devices even when they have neither partitions nor recognizable file systems.This is useful for TrueCrypt system volumes or normal TrueCrypt volumes that are not in partitions. - add ability to create volumes with different crypto options. -- Mhogo Mchungu Wed, 1 Oct 2014 16:38:48 +0000 zulucrypt (4.7.2-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features - add an ability to open a TrueCrypt volume using a combination of a passphrases and one or more keyfiles -- Mhogo Mchungu Sat, 7 Jun 2014 16:38:48 +0000 zulucrypt (4.7.1-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features - fix a build issue with gcc 4.9 -- Mhogo Mchungu Sat, 3 May 2014 16:38:48 +0000 zulucrypt (4.7.0-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New Features - various changes and improvements - add a plugin named "steghide" that retrives passphrases embeded in other files using "steghide" tool. - add a plugin named "luks" that allows opening a LUKS volume using a backup/detached header. - add a plugin named "tomb" that allows opening of LUKS volumes from tomb project using keys securely stored in image files. -- Mhogo Mchungu Thu, 1 May 2014 16:38:48 +0000 zulucrypt (4.6.9-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New features - move config files to "/etc/zuluCrypt" from "/etc" - add a config file "/etc/zuluCrypt/fs_options" where default file system mount options can be specified per UUID. -format is:one entry per line,example entry: UUID="abcf" uid=500 - fix a bug,if udev is enabled,mounted image files were always treated as system volumes. - use libgcrypt for stand alone file encryption instead of cryptsetup.Newer stand alone encrypted files will have an extension of ".zC" to distinguish them from previous ones that use ".zc".Older versions of zuluCrypt(<4.6.9) will not be able to open encrypted files that end with ".zC". - add an option in zuluCrypt GUI to specify a truecrypt volume type when saving or restoring a truecrypt header from a backup header file -- Mhogo Mchungu Sat, 1 Mar 2014 16:38:48 +0000 zulucrypt (4.6.8-1) UNRELEASED; urgency=low [Mhogo Mchungu] * New features - add zuluSafe-cli,a simple tool to securely store files - add ability to save and restore truecrypt volume headers -- Mhogo Mchungu Sun, 19 Jan 2014 16:38:48 +0000 zulucrypt (4.6.7-2) UNRELEASED; urgency=low [Balint Reczey] * Hand over maintenance to Mhogo Mchungu - the package is maintained outside of Debian for now -- Mhogo Mchungu Sat, 30 Nov 2013 11:49:55 +0100 zulucrypt (4.6.7-1) unstable; urgency=low [Balint Reczey] * Initial release (Closes: #703911) * Conversion to use multiarch [Laszlo Boszormenyi (GCS)] * Various packaging fixes - Add .install files - Proper install target in debian/rules - Finish debian/copyright - Add build dependencies and binary dependencies -- Balint Reczey Sat, 23 Nov 2013 11:46:39 +0100 zuluCrypt-6.2.0/debian.upstream/compat000066400000000000000000000000021425361753700200340ustar00rootroot000000000000009 zuluCrypt-6.2.0/debian.upstream/control000066400000000000000000000042021425361753700202370ustar00rootroot00000000000000Source: zulucrypt Section: admin Priority: extra Maintainer: Mhogo Mchungu Uploaders: Build-Depends: chrpath, debhelper (>= 9), cmake, pkg-config, libcryptsetup-dev, libblkid-dev, libdevmapper-dev, uuid-dev, libgcrypt11-dev, libudev-dev, bzip2, qtbase5-dev, qttools5-dev, libsecret-1-dev, libpwquality-dev Standards-Version: 3.9.8 Homepage: http://mhogomchungu.github.io/zuluCrypt/ Vcs-Git: git://git@github.com:mhogomchungu/zuluCrypt.git Vcs-Browser: https://github.com/mhogomchungu/zuluCrypt Package: zulucrypt Architecture: all Depends: zulucrypt-gui, zulucrypt-cli Description: front-end for cryptsetup and tcplay ZuluCrypt makes it easier to use cryptsetup by providing a Qt based GUI and a simpler to use cli front end to cryptsetup. . This metapackage installs the gui and the cli components. Package: zulucrypt-gui Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, zulucrypt-cli (= ${binary:Version}) Description: graphical front-end for cryptsetup and tcplay ZuluCrypt makes it easier to use cryptsetup by providing a Qt based GUI and a simpler to use cli front end to cryptsetup. . This package contains the graphical applications. Package: zulucrypt-cli Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libzulucrypt1 (= ${binary:Version}) Description: console front-end for cryptsetup and tcplay ZuluCrypt makes it easier to use cryptsetup by providing a Qt based GUI and a simpler to use cli front end to cryptsetup. . This package contains the console applications. Package: libzulucrypt1 Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} Depends: ${shlibs:Depends}, ${misc:Depends} Description: shared libraries for cryptsetup and tcplay ZuluCrypt makes it easier to use cryptsetup by providing a Qt based GUI and a simpler to use cli front end to cryptsetup. . This package contains the shared libraries. Package: libzulucrypt-dev Pre-Depends: ${misc:Pre-Depends} Depends: ${misc:Depends} Architecture: any Section: libdevel Description: development files for zulucrypt This package contains development files and libraries necessary to build programs around zulucrypt zuluCrypt-6.2.0/debian.upstream/copyright000066400000000000000000000064641425361753700206030ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: zulucrypt Source: http://mhogomchungu.github.io/zuluCrypt/ Files: * Copyright: 2011-2015 Mhogo Mchungu License: GPL-2+ Files: zuluCrypt-cli/lib/canonicalize/canonicalize.c Copyright: 1993 Rick Sladkey License: GPL-2+ Files: zuluCrypt-gui/md5/md5.? Copyright: 2001 Alexander Peslyak License: public-domain License: public-domain This software was written by Alexander Peslyak in 2001. No copyright is claimed, and the software is hereby placed in the public domain. In case this attempt to disclaim copyright and place the software in the public domain is deemed null and void, then the software is Copyright (c) 2001 Alexander Peslyak and it is hereby released to the general public under the following terms: . Redistribution and use in source and binary forms, with or without modification, are permitted. . There's ABSOLUTELY NO WARRANTY, express or implied. . (This is a heavily cut-down "BSD license".) Files: zuluCrypt-gui/lxqt_wallet/* Copyright: 2013 Mhogo Mchungu License: BSD-2-clause All rights reserved. . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. . THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Files: debian/* Copyright: 2013 Balint Reczey 2013 Laszlo Boszormenyi (GCS) License: GPL-2+ License: GPL-2+ This package 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 package 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, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". zuluCrypt-6.2.0/debian.upstream/docs000066400000000000000000000000101425361753700175000ustar00rootroot00000000000000README zuluCrypt-6.2.0/debian.upstream/libzulucrypt-dev.install000066400000000000000000000000611425361753700235470ustar00rootroot00000000000000usr/include/ usr/lib/*/*.so usr/lib/*/pkgconfig/ zuluCrypt-6.2.0/debian.upstream/libzulucrypt1.install000066400000000000000000000000241425361753700230530ustar00rootroot00000000000000usr/lib/*/lib*.so.* zuluCrypt-6.2.0/debian.upstream/libzulucrypt1.lintian-overrides000066400000000000000000000000701425361753700250440ustar00rootroot00000000000000libzulucrypt1 binary: package-name-doesnt-match-sonames zuluCrypt-6.2.0/debian.upstream/menu000066400000000000000000000004031425361753700175220ustar00rootroot00000000000000?package(zulucrypt-gui):needs="X11" section="Applications/System/Security"\ title="ZuluCrypt" command="/usr/bin/zuluCrypt-gui" ?package(zulucrypt-gui):needs="X11" section="Applications/System/Security"\ title="ZuluMount" command="/usr/bin/zuluMount-gui" zuluCrypt-6.2.0/debian.upstream/patches/000077500000000000000000000000001425361753700202655ustar00rootroot00000000000000zuluCrypt-6.2.0/debian.upstream/patches/series000066400000000000000000000000001425361753700214700ustar00rootroot00000000000000zuluCrypt-6.2.0/debian.upstream/postinst000066400000000000000000000001361425361753700204440ustar00rootroot00000000000000#!/bin/bash chmod 4755 /usr/bin/zuluCrypt-cli chmod 4755 /usr/bin/zuluMount-cli #DEBHELPER# zuluCrypt-6.2.0/debian.upstream/rules000077500000000000000000000013121425361753700177130ustar00rootroot00000000000000#!/usr/bin/make -f # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # This has to be exported to make some magic below work. export DH_OPTIONS DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) override_dh_auto_configure: dh_auto_configure -- -DCMAKE_INSTALL_PREFIX=/usr/ -DCMAKE_INSTALL_LIBDIR=lib/$(DEB_HOST_MULTIARCH) -DUDEVSUPPORT=true -DNOGUI=false -DQT5=true -DREUSEMOUNTPOINT=false -DHOMEMOUNTPREFIX=false -DNOGNOME=false -DNOKDE=true override_dh_install: chrpath -d $(CURDIR)/debian/tmp/usr/bin/* chrpath -d $(CURDIR)/debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/zuluCrypt/* dh_install --list-missing %: dh $@ .PHONY: override_dh_auto_configure override_dh_install zuluCrypt-6.2.0/debian.upstream/source/000077500000000000000000000000001425361753700201365ustar00rootroot00000000000000zuluCrypt-6.2.0/debian.upstream/source/format000066400000000000000000000000141425361753700213440ustar00rootroot000000000000003.0 (quilt) zuluCrypt-6.2.0/debian.upstream/watch000066400000000000000000000003051425361753700176650ustar00rootroot00000000000000# Compulsory line, this is a version 3 file version=3 opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/zuluCrypt-$1\.tar\.gz/ \ https://github.com/mhogomchungu/zuluCrypt/tags .*/v?(\d\S*)\.tar\.gz zuluCrypt-6.2.0/debian.upstream/zulucrypt-cli.install000066400000000000000000000000761425361753700230570ustar00rootroot00000000000000usr/bin/*-cli usr/lib/*/zuluCrypt/ usr/share/man/man1/*-cli.* zuluCrypt-6.2.0/debian.upstream/zulucrypt-gui.install000066400000000000000000000004111425361753700230650ustar00rootroot00000000000000usr/bin/*-gui usr/bin/zuluPolkit usr/share/applications/ usr/share/icons/ usr/share/pixmaps/ usr/share/man/man1/*-gui.* usr/share/zuluCrypt/* usr/share/doc/zuluCrypt/* usr/share/polkit-1/actions/org.zulucrypt.zulupolkit.policy usr/share/mime/packages/zuluCrypt.xml zuluCrypt-6.2.0/docs/000077500000000000000000000000001425361753700145055ustar00rootroot00000000000000zuluCrypt-6.2.0/docs/README000066400000000000000000000001201425361753700153560ustar00rootroot00000000000000 Look at the .jpg image files to get an over view of the backend architecture zuluCrypt-6.2.0/docs/library dependency flow chart.jpg000066400000000000000000002166441425361753700230010ustar00rootroot00000000000000ÿØÿàJFIFÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿ 0"ÿÄÿÄÿÚ ïÀbÅfÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FДR+Èëæ à=ø;qÃØ)äuóð 9µ¥ñòoÜjòK-¹mµ¼‡±eO˜ä% Î[6wÑ û¹¶æ=ËÒ!ú³wv´½;›Ø«ˆ¿ÚE}IÙ44ü÷Ô!äÖl9«•³†o³{?=–[ŽwÙ[fËY~Üpö Ey|Á¼a3Åfu/.ø“î˜Á£½œù*²Éi%ƒ¿µ”“î˜ÒÅIdÏ’ÌͺI¹·0¬»^}Y¥©a,¿´Äº…“üSK¥«\JØÝ$ú€ñïÁÛŽÀ!Hë5ýüy·HÖy·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9·H9¿?ˆæèO¡7Y€ðìæöÕõ \ç·…{xÞ1Æw…{xÇÞíà{ððv㇬Ü/LKxusûxÁM&ÓCÛ½µsÇ·…{xÞM½>‡Hg@›Jn³ÎŽÎYy|1¹Û8~ã[ú»?5–§‰~â÷”Á³¯ˆôù²fÁç^²Ó•Q6|{ñéÞCõ>g‡²ÆMßdõ=@OPÔõ< OPÔõ=@Oã?CçŽzÍMLH\Éu&ç^åÑÑÆ±ïëf6´7¦Wª3²Çܸqòž¾`t”'Ðãê èijk<²ƒ«žz€ž '¨9-%ž ²z€ž '㨉Yh þ)ü®”qõúè!]™¼sÊŸ êz€ž 'êÚK=AdíK‰g¨,ž *PÕÚäè  +6š£iª6š£iª6š£iª6š£iª6š£iª6š£iª0мm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5FÓTm5r™D )äuóð³ÏžíŽ^Šò:ùƒx‰k£î˶Óùfë‘I‹ ¶•ž]äýË25FÒEp,cYóݱËÒB‘^G_0o íLêFæÏœß:»Íož·+N}\ÑïÆ¾Ö¤ý+sñ¯™|nY¯SSoY @f5Ÿ=Û½ 5M¤ñA€'ОPr}:)äuó47ÚÎÍäOײ]l;ë!e°Í›æ§š“³¾!]ÔÛ'ëØ>ÖrÑ÷s¬ÐÕ³æYžé Yö„ñ+íA«¡_Ñ¡¯\IV}ÔùiçY ßTURêm–,Ƴnb¨åé ô'ÐúÊ ô'Ð!H¯#¯™ãÞŽ³£±‡SÏuñk}­ÌSýE&žÅ™5¾üZz?|Y—Þžh£7n-VǧµI´ìkxÅ/Ÿ>¥ÉâNr¦ÄúÛÌïz~ó}}Ñ}fš)ëêìVqìÜÆÆÇÐkæÖ}ýÓÕ––Ê-SÓ 1¬ùîØåé ô'ÐúÊ ô'Ð!H¯#¯˜7Œ>ý—$yñ•g—¡ï°Å”yz 9†?^„Êd¬YVcõèyñ”¾} ;{Ú_>2ªnÿ´xó•gŸ¿G™?^†/¹ ãFŠŘÖ|÷lrô€úè} åúè¤t3º|'¨7‰êz€ž '¨ êz€ž '¨ êz€ž '¶³Ôõ=@OPÔõ=@OPÔõ=@OPìëRÆéopŸB}O¡< ŸB} ô'Ð'П@èO("íPÔõ=@OPÔõ=@OPÔü›“Ê ô1é”ÅñA„ú>„úŸBy@ _…鈯n®ocÃØðö<=cÃØðö<=cÇÌƒÃØðö<=cÃØðö<=cÃØðö„ò€èO(B» ÓŽžÎ·§žml–eÓXÉëá÷KkfU9zÎ,ÚÛÙÕ)ão9bÜ—ç½ÿ^ðjeÅ—ÒmË¥.²{ŵ.ºþŒ~ðf­=¼vzõ÷ÅimëäÍ÷‡c@Û÷‡f°øó–‡ ÝËpsû€)äuóðçÑæRøñ˜yz&/~†, ü¸áìŸB}} ô>„ò€èO(B» ÓW3Wi(XæT¡gÍMÄ¡`,G±Ü ¯¯Adõ“Ôõ=@OùF :ÿç«“Ôõ=@OPþQO¡>>„úŸBy@ ô'”!]Ŭò©íåʺ¡Êº¡Êº¡Êº¡Êº¡Êº¡Êº¡Êº¡Êº¡Êº­ª«ª«ª«ª«ª«ª«ª«ª«ª«ª­ŠYs¬£ÇÔhï_¨Ÿ@ ô'Ð'П@èO(>„ò€>„ò€ ô'Ð} ô ô'ÐúÊO¡< jí êz€ž¡ÏSñÛ€ ô'Ð} ô ô'ÐúÊO¡< û(8篗bã‡bã‡bã‡bã‡bã‡bã‡bã‡bã‡bã‡bã‡b㇎Óúv.8v.8v.8v.8v.8v.8v.8v.8v.8v.8v.8v./´ÆÃ'П@ ô'Ð'П@èO(>„ò€N£;Yçg(=K•ƒ=€> UÚhï@X1™^% ÁžÀ YCÙs4÷°„úúè} å'ОP Ôgk<àìå y|1¹ÔtXÖ]Í:ž~FöYlߟó-|ðõ1{÷5Öj×2òøÀyó‰SÔØk3÷t¶3­J~5lÜÕËš¼aÔÉ›»å†Ï¬ye§°{yŽßˆíü=ƒÃØŸB}'П@ŸB}O¡< úÊ:Œígœœ¾0çTÍ9CÖ†¯ŸRìßËÍÒͤŸòÊ-U°ÔÍf¶|:Õ|²ö,ÜLÈ›íezÔñ±›ºÒЫŒVTOôoyŸŠZíO6bØ•¿PKÙÞvüëΖϮw¢YñÛñ¿‡°x{èO úèèO  ô'”ŸBy@'Q¬óƒ³•.§™f©%‘¥Òc—ÔúžužV•_¸Ôüu¼ÙnÞégQ$k]ø³fôyNw5¦‚—Ë&â¯ð•êŸÈÔÓâ]´~ÙÝ?Q;$ù}1eá¯í#èô~å‡{}@Ö|vüGoáìÀúè>„úúè} å'ОP Ôgk<àìå1{«ßÖÅ::/>¤ë;qqg}ž{nÊÞùý³4-X«NÝL^¤hæôya\Ôò—†+d‰¯/Iê^öó÷ÆŽ®u±SŸÜ–§¨¬µ–ud,¿Ûø{‡°>„úO¡>>„úŸBy@ ô'”uÚÏ8;9@ _©elî#¦ú´1TK n‡£C&ÚÍ]mÌòʪY5½â_8¾Y¯ò‚5ujx4)/khLÙÚ(#SPñÛñ¿‡°x{èO úèèO  ô'”ŸBy@'Q¬óƒ³”3ëK5çמóøÍ­g¼?>Mn{Å’çSgÎSæ†î¬»„úúè} å'І\OÅñA„úúè} å'ОP ô'”>„úO¡>>„úŸBy@ ô'”§†lþ‰Î®z'::'::'::'::'::'::'::'::'::'7èèœî¨Ó’:'::'::'::'6:G::'::'::'::'::'::'::'::'::½˜W|=ƒ: ô'Ð} ô ô'ÐúÊO¡< n} ýœ¡¬€ -ØyÖMí9ÖÎÞž4oD´¾´¶ðY³­;r]<‚Ĭ¸,ù·§–*LW» ï/Hyì'П@ ô'Ð'П@èO(>„ò€9¹ô'ör†² ™6uU‹Å› Yl&Зֿœ£Î@ù9óO‡¼o¦ÝÔ¿=Yï½}ç²Òòo±û³éˆÊÇôöدvÞ^óØO¡>€èO O¡>€4w„õ?Fôð 9]Zû9CY%øÝcsýoxˆÝ$Êu/½ˆçèæÚ—K÷Ë4±WŸ-ˆ—´·= 1­F÷Ë5K* \=àÓÖ‹ˆŸ ˆßjljØKX%ëËÑ’õš‰úRÝië¥D¬kgÄ¿E‘}Å31Õ|Xpœî̶QòÙM'ÁS,O2ÝIÚ³pk5î»ËÒ{} ô ô'ÐO¡< n} ýœ¨ÖsûÔ’Åñu¶šœæÝ†l-šŠWhJÇdsîƒ[6w‹Ÿl—ê’¹÷@•"»Y™ö’Y¸,êÆ–ZJòÖ¬²6ª{I)«K%œîŦl¬6Õfç½ÞK3…¬×» ï/Hyì ô'Ð'П@>„ò€5pÐ\ÏPTõ=@OPÔõ=@OPÔõ=@OPÔõ=@OPÔõ=@OPÔõ=@OPÔõ¯°f‚€>„úúè'ОP>T êz€ž '¨ êz€ž '¨ êz€ž '¨ àŸB}úÊ} ô'П@>„ò€1i}ç=¼º':Þ:'::'::'::'::'::'::'::'::'::'::':+ns£¢s£¢s£¢s£¢s£¢s£¢s£¢s£¢s£¢s£¢s£¢s£¢s£«Ù‰oÃÚ} ô3 èO(w9Ñó<áëæÉéÏîcU5uæ/K5¢^ÓÔÂ_HÅeÄÝrÖ u¥­[™gûŠCy,Û‰o“¦} ô1°èO(w9Ñó<áëæ=)h´·C[#.Ø¥±U,œv„-Ú?ÚâJ°‹·¾40Všu}½oâ2±eÖ@ 6â[äéŸB} lú&òx ž('Š â‚x ž('Š â‚x ž('Š â‚xùÎW‘Óξ`—R^u÷_™¹õ=O—£Jv¦Þ·©ù´75°Ù±‹J„¹²Hè5ŽÿšÕнå56õhY7æçÅÔû¼IÿYåÀßÃZÒ/êæãÏ›%Ÿ0m|ÔÕÕ¯Ž]i´ö¥ÕÕ¥0hÝòLõŸdÒ¯§¹©fÜK|Þ္βo¿ŒU¦ñhEZV„U¡hEZV„U¡hEZV„U¡hEZV„U¡hEZV„U¡hEZV„U¡òÞŽ÷?¸g@ÿÄ23@ 0245P!$"#1E`%pÿÚÿà$ɬ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,z¼Cßÿ1?g©Ä=ÿóözœCßÜOŽe$YJÏÿÅR¹«ùÄYNÇŒIÚªY¿”²x3rž÷ò{‰û=N!ïî,|hû˜,n ÿÙp‚«6ÍŸT8!Y?÷¯Z:Ñ%h‘Ú—ì20XÜB/ŒhmerN™ƒó€ãhÕÿ°HmerN™ƒó€ÚÑ^C¬Y5‚*Àn…ÝëXjCV=Më¸ö(äÜ6@Õ¡9Fb˜]®›ýS¸Ÿ³Ôâþà±y…«ÏÅÀhÚjÓx½}T¤$«Î@3EÃBîÞ,À±F¤š¶Ý‚M˜¿¨ãÙ'ZN+‘YÂQ”¥ Ä6E Ö“ŠÀ¤Vp”e¶ãÃÇàÈB”,Bœš³„æ{uœîz®[#©aã `Ïf¸¤'˜‰—ÜOÙêq~PŒÞfbOH‚£´cøiû=N!ïÿ˜Ÿ³Ô(e…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖu…]aWXUÖuƒ_ÿëW]ã[TÖ©­SZ¦µMjšÕ5ªkTÖ©­SZ¦µMjšÕ5ªkTÖ©­SZ¦µMJdh÷wå&–©­SZ¦µMjšÕ5ªkTÖ©­SZ¦µMjšÕ5ªkTÖ©­STÝÞ¯à/|^E,Dš~$ bqyœ‘Œù¹#ùgìîø‡¿™K&Ÿ‰XœD$Ee,EèRø¿€½ñy]ÿ$¥n”lJ®\æ8µ”r°i€ï±3'#×V G¿¼Bg jÌÄ 3•á’R¶æ&äÜë„›ÁSö[ã¡­+váïUÚΦ³©¬êk:šÎ¦³©¬êk:šÎ¦³©¬êk:šÎ¦³©¬êk:šÎ¦³©¬êk:šÎ¦³©®-ÄÈ+•ÿôŽf›ßð2JVéFĪÙ$ÏBs3L{ñ-yZ°Ìï9R¹Z×ð«o/‹ø ß•ÈÊL(É®Ô!]«”pb”¥©EìŽYWüXEyÚQ²OÞMXIü&ÖP°ï \ð" ÈÕ+‹d ~ÂfüýR¨GL=;ß_é]á0¿f¿©Yq;‘”˜Q“]¨B¼ë“ôù<÷FB”Ô1Õp 4–ɯm>w’—Åüï‹è œ;Þ#¸!Cl\§ìõ¯}©Ä=þpì“þìm¿’—Åü‘9„u„u„u„u„u„u„u„u„u„u„u„u„u„u„u„u„u„u„u„u„tôíë^úÿRÝy™ðްްްްްްްްްްްްްްްްްޫ Äø[ß_ÿ2@k$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 퀽 ,,,,,,,,,,,,,,,,,,,,,,,,,(ü÷þR‡»òCßùJïÈqå({¿!Ä=ý“KùžBÐI9ÚæÖÀð™"1šNÖàH‘JÄp oFYÕü5ÅÇ’&aØŸ-³»*ïÈqe.©¼…öf¯`ï² ½ð òéû´îTšb‰£#pø¶§jöa ›_±ÿÚvT=ßâþÉëÅå:°˜cRžwZ»hz#”$È’© A6·þ‚ÜÖËr7ÏâÑ(+êÔbMJ;í )JœÆQ€ó™H8ØEf¸Ló œ`ªÒjæ”çeÇ!ñ4íŬÌAsA†S¼•dwv®Ð+ÒÝ!ÝõÕ6×ÿ©=[dœ`2Ì“—„ëÛŽ»&¦Òk7%8‹•‡"q4ë¶9v¦yµÉJ-"ìœÀ$jWøÅ×;âÔ+‚iÛŒžs¯R:kr©Uk~ÙW¶ûy‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚Y‚ñì'öfá`» TfâþD¥nàäZ¶Ç"TÚžkµÆáܳå\¯ZMd‚˜_|â&FƒÎÕaÈodZ®#{ÚK‰ë(ÕyÆÞÜÚÄ$ɬ/ 0å°X6ƒÓ#vÀܵÞ6']‚MF¥kA€j£,Lv+ÁÄCc”m½i¾6öÉUÚ¡c`éëH…›[pÅâ ¹gíË>=eóÙ­­Ê‡¸ô«YTè ks¡ØOì<Ôú ˆ{ù»³3;;yÚQwä:ñý&”eèÊMòëŠ×F‡»¶¹Ðì'öj}Ä=ü§&„ fr«m×…‡rÊÓäBÓ;eM¢[L7…™oJÄ·iÏrÉKíN KZ+2Îl8=¢4 e„,©D6ë„ÛÈÆ`Ç&Q–²þ¦Î3¸82§{3§(–ÖÝXy6æfkS›ãŸL…c\²æñ¶YIGÅãâѳfm‰•(ÊV¥¿“7”mj,’ccÅêŽO1ò¡îí®t; ý‡šŸAq+yÔ5‘J‹ÇÂQˆ² X‰²&û8|ÐN!=9´í^gÙ³`Rª8¼o´²I ¹ž8Åø—Å©=c€{ ·ý¸H^-)OüÊ.á+lÍám‘ÔÆ¿R:¸ekWgý.QfºÐ„Ê "…;3Ô6—TϦ…²ÀÁÏÜr^jü]/¹Î‡»¶¹Ðì'öj}Ä=üö‡ã¦:cAD6™š-´=O»¼bï(Bi£ºa/¦:´ÇRa+nÉN1×ùQ ž“´cÑŒSqwŒ]Ô„ò½Æ Æ â¥r(Þ“F1ƒ8Æò”ZLÌÌÚ"´CÁ‡¾˜´¤1ÉôAxiˆ`Iwms¡ØOì<Ôú ˆ{ÿ)CÝÛ\èvû5>‚âÿÊP÷v×:„þÃÍO ­×™Ÿëëëëëëëëëëëëëëëëëëëëëëëë赌áaaaaaaaaaaaaaaaaaaaaaaaaaUÂýµÎ‡a?°óSèww¾¿ò7:„þÃÍO¡ÝÞúÿÈÜèvû0Ã0K0K0K0K0K0K0K0K0K0K0K0K0K0K0K0K0K0K0K0HvFBy¯}änt; ý‡w?°óN ðİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİζ™ú÷:„þûŸØ~"¿_×¹Ðì'öÜþÃñúþ½Î‡a?°òñgžˆ­Z"´EhŠÑ¢+DVˆ­Z"´EhŠÑ¢+DVˆ­Z"´EhŠÑ¢+DVˆ­Z"´EhŠÑ¢+DVˆ­Z"´EhŠÑ¢+DVˆ­Z"¸{3K²¯×õît; ý‡—ˆ{ÿCßÙWëú÷:„þÃËÄ=ÿ‹¡ïì«õý{ÂaåâÿJÇÆK…~"HÊëB1Më·¯s¡ØOì9ÎÀFEÄ=þI´¥ äFÁÜÕê±!ãûä9FÒ[’Ï9&:ÌH;¼ã܃Æ$„Ó˜LšM&i4“»E£8Íœ£‹¼£Ä„¤¤QÁjm;£O&‹HßÊNH3Ô$‰R$„Ô¥4dÒmÑêòÐ÷ù¯ÊM-sZæµÍkš×5®k\Ö¹­sZæµÍjš×5®k\Ö¹­sZæµÍkš×5®jD#GÉs¡ØOì9ñ¹­P—EËóçñƒlö{nâàÿi?†jâ"¶ñÄ­âÜB¨¡2D˜£®=˜·ö„"Á á÷ðëB€GmÜ€?Ó!ýãLP,ž! qJÿ®½ÁÀ"#Êw 2ïha.Ï%G3O]Å®â×q›Õùq™Ý™µÁj‹ÉÝ™™ÙÙå­QyJMZ¢ÒóOÙä¹Ðì'öëÕYq–aÖ{ßü äµIÁ†8ˆ{?Êz~!Ä“´Ã¨ÅÌU÷‚¤F…‹ÈÀÝxÖþ¨Õ›E©øáÞå³]°ìÿêÿn5e±$ÌÔÛR‘+ê$*·Ž$ôEš1òP÷ó£õ÷ø³Pµ_‹Ò°¸‡¿Ícã qŒX’‡‘÷k†ÌãVÔšcŒâ;„?ðÊ}´ä”ø‡š~ÃY v±ÿ¢%¨jçC°ŸØs§Ð\CÞ„X—БcùÞÈÚ„cèÄ­"óbFS1X"rxLe‰|²ž™ó¡ïæÔCñN{ëÿæâÊÅaUóØøÑ÷@›±J"ƒÂ‘+ïÜ9·¸a…vd8—š~Ë<­‡±ÿŸ´%Ež,®t; ý‡:}Ä=ð‘ì ÅVf ZÉKë0 ǙԭMè–vB#ngbLjJMÃ$ã²=yÈàš„e „(Ù¦Ô'#‚e4œà<·êJÁÆiLJRC.D ZÀËZk¼Cà’Šìi'&À^Ì‚IœC)Êîò(#È…ËœD9šJ‡¿ÍÄ=þgfvÑロÓ´?Œd´Å¥´7O“0àÞyû9Wë«ÂaΟAqxžuc åWð›[ժѠ8×D߇܌¥H±˜ÏâBÞœuŒE à$Ar2“!<êF°çã“äe&(´ZxšŒe –>0NF©0Hu¬Âo#<íÆ1×n „‘¥(õõ輩–2{A™HŽ{: úkÅž»BZ=·ÐbíΪ‡¿ÍÄ=ý´ýœ«õÕ·a?°çO ¸‡¿™¬Ý‘#¸!Cl\Ÿü)zô=þb€fXUÖu…]aWXUÖu…]aWXUÖu…]›…¸/C ºÂ®°«¬*ë ºÂ®°«¬*ë ºÂ®°kó¯×W:„þÃ>‚âÿÅÐ÷ö¼ýž~¿«_®®t; ý‡:}-ï‹æ»þIJÝ(Ø•QÌ–A íV$ˆû’%q’QF$£j¯õ‚Qfgº)’w§&ƒÛ{ssð÷žÅû¨´¬Iò§Ù•ªà1%C•ƒL¥™8u_í’Õn{îJ¦‘%^V¬WŒj®bÚÌsÄ×”%©Ê¨¢Hù§ìôkõýZýus¡ØOì9Óèyo|_5ÈÊL(É®Ô!]÷ëÖ¯8Š#y×( Lg"9<ËqÚuÏ)Ì´Ëõ+Þ0ŽÞ× ÈÕ ^QáÔKËL¿RιbÌ7M2VTà§b[¡.ìl`·(1,i ¬j%i•ÊÑ‹eá`VeÊ”¥ÃßPÌ}¤3ÊDgÆÜ»ÚœfÒbA€X†7LG«Î~ÏF¿_Õ¯×W:„þÃ>‡–÷ÅçþÒ÷ø»þ#û[ñ€Áy ??ÇO ¶X/ö„+ÊÕ}?¨ðï…¥÷IƒÄ51îÖ°(ÕxIè•¶H…ìT$渇Á½ð#& íLn f¿l²nhØÿiþÒ¡`ð÷Ô;{N✡jŸùv}»6*¥þÌÊXû³íß8§Sœýž~¿«_®®t; ý‡:}-ï‹ÏLu‡–ÈœÀÂ:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:zvôkõýZýus¡ØOì9ÓèÀWëúµúêçC°ŸØs§Ðÿ€¯×õkõÕ·a?°çO¡ÿ_¯ê×ë«ÂaΟCþ¿_Õ¯×W:„þÃku†<êk:šÎ¦³©¬êk:šÎ¦³©¬êk:šÎ¦³©¬êk:šÎ¦³©¬êk:šÎ¦³©¬êk:šÎ¦³©¬êk:šÎ¦³©¬êhg ¿_¯ê×ë«ÂaΟC½‡Ø~ ¿_Õ¯×W:„þÃ>‡{°ü~¿«_®®t; ý‡:}öaø*ýV¿]\èvûtúì>ÃðUúþ­~º¹Ðì'öéô9ȃ,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à,à(Û\ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÆoB¿_Õ¯×W:„þÃ>‡+¿+µÕ\œ£‹ú(³ê‹Ë²áþÿ=~¿«_®®t; ý‡:}W~We22k¯Žslƒý˜Mº‹jRj†0® ap…/VvöÚ6e»Ze{¿áeÍâI±-q{]—÷ùëõýZýus¡ØOì9Óèr»ò»+Þ-­Ãîr£þʱ "F.PFØ% Å™›‡|-/¹rq“Î&8ŸùŽ#m‚È¡Nr×`??²áþÿ=~¿«_®®t; ý‡:}W~Wdà ¼G-‘xiާ$íÅ8†î´´ F0¥;1„ ´Eäœcy‡+¿+ÑÙþQüŽåŽÛ¸“ÑhÆUem;Sðü§^[ë·`ÆãqJú‰Ò‹áÇuÞm ï»(ÉêAëʤææ’xÓŒãOBjsˆÞ»k•wÜ6‘Er|iÄ‘§¡lÿPÛ¡Ãýý­~º¹Ðí)ô9]ù^b"æ"ľ}ØïùcÁ‘‹ Ñœ´BbC”£ɧØï½˜Æ¿–׿áþþÖ¿]\èv”ú®ü®SßrÄÜZ­=YØ“ŠÃ%P‘ì B«<v\…å¾3Êž™I`;Ÿ©1æu+Sz2•¨ v\„å¾9X4ÚÙ½ØØ…U¬Ç0K=êòµb½R¹ëÚ)`mf…+$${*'›ƒ&oP>³¥ßzuM[ý¤É"ðy=¡†e)-K#ƹ¦öE+&Tâ9˜k“¼ø¿µ¯×W:¥>‡+¿+–6!&Œ¿Mq€iäByÕŒYV)Hq86 ñ,ÿ®5£8W–°ZäïÀq®7 ™ PH ¼MR2‹ìC¶BºmuLÎv(ÆP©F2…K(Ù}VR2‹‰çR- µ}¯èk‡å'öÝ·iO¡Ý‘3€³€³€³€³€³€³€³€³€³€³€³€³€³€³€³€³€³€³€³€³€³€³€³€³€¥lOs8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8G¹\èv”úÕï‹ù:ås¡ÚSèwW¾/i\ÛáF·³fRhÆ­Œ˜yFX—ž÷ò‡)J…r¹Ðí)ô;«ß°“j‰†ûª7õKõ(ÉãÁ®JQ¥`{¶¦Múƒ&À1˵3È•®JQo –è5nRhí ØæÛÿgFRN‡¹\èv”úÕï‹ØæÂ®Ç ß ÷aZoÃMG­·<àWœ-B´¤/{dªíP±°t1Ê6Æ9FØBí2W„ü¹jMv˜ä*½…r¹Ðí)ô;«ßÏ9ÄpήšØ^ r;¼·#º H“×whó"XL‘aCÜ®t;J}ê÷Åô óø‡Á‘ì{¯›  >¨SˆÆ•©°'bÀàR¥6 {˜¬5ç"„Æ”g&Ìq´ŒA‹x›˜¤,ì’l–A­wsT¦}B1ô¥cÆß G0=Ò„=ëM ÎAŽpØ´p€»áóÐ÷+ÒTêÊX4Ö 5ƒM`ÓX4Ö 5ƒM`ÓX4Ö 5ƒM`ÓX4Ö 5ƒM`ÓX4Ö 5ƒM`ÓX4Ö 5ƒM`ÓX4Ö 5n¥aƒÐ7Ïâ÷Àÿe'®ê¶æ9‰µÄ£,›“øw¾™x;MzŸù³FÃ7ƒ[rDÕÞÄšvecM³U™ HÕ1¤K4íZi\ý RBV+hn!JÔUá(€ÃnVˆ\ö†å­šÛe—òkhn!þø^zµÂiàÓMJ¬eøûßµ€Hçïh{¿#{â¢aB8̳køkŽ‹VÇ*È–®MË9•õL°FqNÐG(ɧ‹Øb\%ØÃ³+©–ˆÎ#)Y $2Œ±5°¸€îõÈa…†a™žØ"¡8’$$дNv‚9NÈF†H œ#TvBYà ÉŠ‘÷ÀyI­¼›`6ÂÂ!Æ%”±Øžv‚9P‘³+ê!`(Œâ7*ïÈÞøªRþXuþ¥Ãã&úÎ%â*¿¹¥ý  xrÊz –Ñ, RQgûñ"´SûØÑ(Ƽúpwe=Ë7ê&ñŒ¬D§×øÐýø”ÿn%N-®—츇ƒŠû3W 7ê5söâPÔõÍÊCýø‹0˜Ü?àØù£øà€ÿOõ#ɲ_sõ³~¢wvœ w«!¼†9Ë)P÷~F÷ÅD­uF2„Q¡Xq¯*”Q+FsQ‰a ¸ÉÖ€ç*‘yŒq ™£R)+Fs˜`€© ×%x#­Î"ŒJÀ‹za„ ^qW€œbˆÅ+ìÒ„jB3ˆ£’´'?ÓP4èF¬#2׉d DH ˆÅ•«Å¡‚=.¼Ë^%“T„IF%`A‰„4@@±hŽj‡»ò7¾/äè{¿"qo Ö ¬X.°]`ºÁu‚ëÖ ¬X.°]`ºÁu‚ëÖ ¬X.°]`ºÁu‚ëÖ ¬X.°]`ºÁu‚ëÖ ¬X.°]`ºÁu‚ëÖ ¬X.°]`ºÁu‚ëÖ ¬@®áþ6ÿÿÄ)!2 01@AQpPaB`qÿÚ?ÿ´É(”J%‰D¢Q(”J%‰D¢Q(”J%‰D¢Q(”J%‰D¢Q(”J%‰D¢Q(”J%w×Ëü|¼ˆ‚ÒÒ‡Iii¥¤APAihþ:ùyn$¸ ’áÔ\Iq$Ë%—I$ü•PÛ“1313131313131313131313131313131313131313131?óUz$ÜÜ’t$’|Õñ$ÜßI7$’J}|zÓð~ôÛM´‚¯?SŽ”ûíÛZ}|z-¨¶¢Ú‹j"¢Ú‹j-¨¶¢Ú‹*óWº-¨¶¢Ú‹j-¨¶¢Ú‹j-¨§×Í$¢Q(”J%‰D¢Q(”J%‰D¢Q(”J%‰D¢~šù}TrúkåáH‚A j<4rúkåáL”JD¢M‰öɆŽ_M|„D–ˆ´‚Ñ¡"ÒÂ7- JKH#i-þ D†¶ ´gO—Ó_-$’K‰$l’âI$‘2I$’âXÙ%ÚQË鯈 „B?ˆE(„5°‘øZ‡è¢õ¤BzQË鯖³àžÙÒ{§J9}5Òä¶¢Ú‹j-¨¶¢Ú‹j-¨¶¢Ú‹j-¨²¢Ú‹j-¨¶¢Ú‹j-¨¶¢Ú‹j-¨¶¢Š\ÿXu8üÔrûzœ{ h†AÈÞ!÷QËíêqîL”J.%‘ø6]¹qwu¾Þ§i="£DŒ´´d"ÒÝhåÙ_"I$ßMõ’Ióu8öI,’æI-’\ô–Iì–K.zÑ˲¾Z¯zFÆÄ|=N=›F†/FÚm¢ô1i°¹.Êù}=N?5»!¢ÔZ‹Qj-E¨µ¢ÔZ¼Õ)Pbf&bf&bf&bf&bf&bf&bf&bf&bf&bf&be=8sý ÜL¦S)”Êe2™L¦S)”Êe2™L¦S)”Êe2”ÕwÕW¯$?/Kê«×gàý³ýŸ£q§éø£ØÈZmÙÒúªõ¢‚ÒÒk †C!nA26 i@ÔiÒúªõ¢$¸’âFä©’\\NòI"pHÙ;\7§Kê«×m¢KH-%£ô[ø4FŤ†‘hû:_U^»d–I,¸’Y$½%’7$²I}½/ª¯^¢6ÓþH^µüŸKê«×ÓÒúñÒc¤ÇIŽ“&:Lt˜é1Òc¤ÇIŽ“&:Lt˜é1Òc¤ÇIŽ“&:Lt˜é)rÕÔi™‘™‘™‘™‘™‘™’£#23#23%FFdfFdfFdfFdfFRå}rð¢$ÿ£ÿHGà‘ùâéñú*åÛn±Ý:-#ÃÓãôW˶w'b¦6]¹* ݉’NÄîI(‘½„ÉC}½>?E\´´T:KF ‚ÖZ@©Ü‚Ò7‚ÒÒÒ- ´´:|~й Áqq%ÅÃd—n\Ip™$ï$’\I%ÅÃeÄí§OÑj-E¨µ¢ÔZ‹Qj-E¨µ¢ÔZ‹Qj-E¨µ¢ÔZ‹Qj-E«ú.ºÚfFdfFdfFdfFdfFdfFdfFdfFdfFdfFdfFdfFdfFRå}=O~KJWò[±i5·†Ž?OSßd>Û‹‹‹™q$’O†Ž?OSße"²c D~B²°ýöQÇéê{ ‚ ‡¤ÈAÈ ‚d2ÒŽ?OSÙ(»qú%‘$îJ$¸¸~‰?$“¤’„Ñq#(ãô×KlÇQŽ£F:Œuê1Ôc¨ÇQŽ£F:Œuê1Ôc¨ÇQŽ£F:Œuê1Ôc¨ÇQJ…ý=ÿÄ+!2Q@ 01Aapq"BPð`ÿÚ?ÿêaJ©U*¥Tª•RªUJ©U*¥Tª•RªUJ©U*¥Tª•RªUJ©U*¥Tª•RªUJ©U*¥Tª•RªUJ©U*¥W×ÓÛÿO§·Ü_‚T±r¨,\·ÑbžÄY,¥¹ÒIbÃ|>žßv¨U ¡È©%PF•B ¡T jBB¨AT*…HðÙÔDH34ÌÓ3LÍ34ÌÓ3LÍ34ÌÓ3LÍ34ÌÓ3LÍ34ÌÓ3LÍ34ÌÓ3LÍ34ÌÓ3LÍ34ÌÓ3LÍ34ÌÓ3LÍ34ÌÓ3LÍ34ÌÓ3LÍÿ´ÍÉÛCNúvÓ¼{Ý=Ý´44í§¡Û—ÀfäíþÂ|iÛX×´÷ú[»;àþÍ{jJ÷~åð¸»y.ÞK·’íä–o%ÛÉvò]¼—o%ÛϽÓXqvò]¼—o%ÛÉfò]¼–o%ÛÉvò;çÆ…*¥Tª•RªUJ©U*¥Tª•Rª•RªUJ©U*¥Tª•RªUH_'§·Êêmòz{}•X,J ¤’J‚,û=M¾OOo²ä’ªB© U~ HÑTOg©·ÉéíLK,"È®,\$±a]‹j[X-Éa\"êX°ŸSo“ÓÚ*IH*T¨ˆT©R4*…El•**IR¥PD ¯n¦ß'§´_‚u%K)*N¨*’£”•V`U>Ë(Ÿ$ê"¯%”•ò§Òÿï²V`±*º›|žžÞñì"zc´z£·So’Ç%K·’íä»y.ÞK·’íä»y.ÞK·’íä»y.ÞK·’íä»y.ÞK·’íä»y.ÞK·’íä»y.ÞK·‘îEoñ‡KwÔÛæô·z•DrB©<’…EÒIBÉêêmóz[½J’B¥T…Hÿ!¨¥t‚¥WÕÔÛæô·wp«…T±ed’â)bÊ"üÉe-—¿So£§´‚;iÛNðA÷Kw¢B ¡B ‰!TíBˆCHB©ß©·ÑÓÛÝ~;N¤©#~ü–ãSèÔÔQ~MG ,ˆ;äÔûÐײüˆ)©¨»WÑÓÛäô·{Ñìu6ú,¨]Ü—w%ÝÉwr]Ü—w%ÝÉwr]Ü—w%ÝϼŪə ÈfC2̆d3!™ ÈfC2̆d3!™ ÈfC2wU#øV ?¦Óé‡ôÃúaý0þ˜L?¦Óé‡ôÃúaý0þ˜L?¦Óé‡ôÃúaý0þ˜G²¾S7'¢}3=잉ú'Øë}yLÜžöD×ÿgÜ‹©¯Áò‚$Ÿ N‡Ùú| ©*}šú:ß^S7'eU-ÉdDqd,„’‚*Bt“üT°ªˆY jHŠ…°‹+Û­õå3rvT UH°5 •*F+u’£›$ÒºÉ] ª•‘f{u¾¼¦nOM…UTGQYDùRÚHŠ[RÊIeT°žŽ·×”ÍÉé„*„B¤!"Ai%P ¡T*žž·×”ÍÉì/Çe5?³ýT_“SSî=Ž·×”ÍÉí¢Gª=Ž·×”‹W\eq•ÆW\eq•ÆW\eq•ÆW\eq•ÆW\eq•ÆW\eq•Þ®ùþeoMª’bi‰¦&˜šbi‰¦&˜šbi‰¦&˜šbi‰¦&˜šbi‰¦&˜šbi‰¦&˜šbi‰£Ò<†mOeËÀ‹¨‹?'ôY`ûDùöº»¼†mOM»¢É¢šw„ø4S´û=]ÞC6§¦4RºH èBɈ9 © $hB© UDn¢¦¤(‰ž®ï!›PU,+¸Dv…E’Åбa_¦‚©bt’Å‹'D,X±rÚöêîòµI¥EB¥Dl)¡R¥A*i~ʈҤ*#`¡]g·Ww‘e.îK»’î仹.îK»’î仹.îK»’î仹.îK»’î仹.îK»’î仹.îK»’î仹.îK»’gø+¦ÄrJ˜šbi‰¦&˜šbi‰¦&˜šbi‰¦&˜šbi‰¦&˜šbi‰¦&˜šbi‰¦&˜š=!cÉémölXrð[R¸±".¾ÏSw“ÒÛè”B}*Tª*T‚5öz›¼ž–ßC‡|¨ª;àUQVY$¬’¤ŠátRy%DU‚D•ñèênòz[IBPE’~‰BSµ”$H$’P”% % BK!(I)Û©»Éém!d®‚|ÉUª¥T ©•R¢"É "| ’ªAD)•Y*¢¢•Ъ:›¼ž›ÑS#L24ÈÓ#L24ÈÓ#L24ÈÓ#L24ÈÓ#L24ÈÓ#L24ÈÓ#G¬¯ð÷ÿÄF 1’!23s "@AQq“±²04CaÁÑá#BPRr‘Ò‚`¡b$S¢cpðÿÚ?ÿà–ö¶½em£Ä¶Ñâ[hñ-´x–Ú¶#“Ö²‹.ä7©g s–ƒ«r€Í!¡n ûÊ!$®­CºTåúi) ª<Ÿ¹o÷¯9wg¥‹±ßrö ËHY.‘öCJ’hÜÎU43žàe‘´÷˜'MšUÞøÀ§ÝéP2­¬nþÉáç“EiÚÏÒˆ7™lŒÍõ›Â¶€’3PBnuí nš3¥Nb-¨¦‡tèO|¤9ïÐip 7Ùc ºð¡`}KK”viÉxv”çÀæQ÷µÊc#ƒ³‹7Ùc ºð¡`}KK”viÉxv”çÀYGÞ×'iÏÒä÷Ö¢¶[ÙÁ4†”}(£m $a¨!4NæX´gJe’/ìQ¼dk¾ ô%¶ˆ¡¸©‹Ü ’6΋‚Ìèµbʉñ¹–ØË$”s=íäô-iÊypBfêÙ ó—vzX»ðügZqœð9N¿ÑÙx¨A­ðwvzX»ðÿŒ»³Ò‹b´»JÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÕ8ÊÔ8ÿ¶ EÝ«i&2¶’c+i&2¶’c+i&2¶’c+i&2¶’c+i&2¶’c+i&2¶’c+i&2¶’c+i&2¶’c+i&2¶’c+i&2¶’c+i&2‰ÎÉŒóȨç î4ê[I1•´“[I1•´“[I1•´“[I1•´“[I1•´“[I1•´“[I1•´“[I1•´“[I1•´“M©$ÔßÛø í<-µ^S¬èNe—rzz 6´=|v°žS®â5„òwÝœò.Ç|8µ^S¬èNe—rzz 6´=h½æ€qj¼§YÑèÚ|=£Ç† èS°žKiD,HÑw&µLk@9Ö{m;:Ã~ŠQL¶Z×9*LéåFM¥ëË{úºd’@öW”,ÒŠKJÖš.Фf}±Y4 "ô npš{–påÊ:Z ³--V΋´)ØO%´¢ÊÅ­›jßv„%Î ÓVÍé²uð;±6)ÿx²¨×›ÿ‚m¬ªÓMd Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À˜rL¤ØÓdÔ*e×ÞÅ ãµJfÓ«‰ô)ØO%´¢$ h»“Z¢âl–š=½e3'kêò*^GB²óm”Ö¥¼èoúÞ¡.pœ¨×㦹Ҥƒ:×›kÂÏzS÷M¶jêiâ7´øþ{G 6A4” (q†Í tª¶k ys›Ú›b71ƒX¼)ꬤ„ÝYõ¿e›ó‚ˆD!{yEÊ Cæ¶µ²„ù1åsЬÓH}¦´õu Øò Ööh æ¶µ²’fÞæH¨YkÞÂÛLÑü&°@òë<“ЙW»™×ü‚¬EÑvšÞ¡OI”îáèÛ,’85­¥–¯³…µüÇIQv;áĆÈ&’ƒ¡e ÐÙ¡AŽ‚CÕ@¤m+#¢fTØßJYsi¥VÙxi%™{¿)jŠ­«ÌÖÝN„],.•”äÐVŠÞg6ÂÊ 3ìígx­í>?€žÑãèL½× &i¥—‡z2ëB‰¬­lŠp»³Óå;§xzX»ðôB:Ö<7Ñ9Î}·»§ŠÞÓãø ci]¯g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹èˆû<_OO”îáéXYgEo+Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹èƒJé»·þ ”îáÿ å½­¯Y[hñ-´x–Úû`TŽ…’Øy`’·&ƒ”–ÇÒ\îRc#™ò1Õ­¥=©¤ l„ (ÕÑž”Ûd—&©5Å‚–œEê^ç7M-_r2ºWµµä†)ÃͧEÓÖ­Œ±æ[éСsÜøásjK:Ó©6u¼)¾ÉYìü–Ã-_¡Cu‹L¶âhç±æÉÒ-ú–¯÷ÝØb–º*‰cÝ(ê:Ieå¶Æšv(›{›%t8ÕKöcl€ÓE”‡šžN•VVý$tÜÖR^>ó^VP-¹­äÖÏbÊZ\_›¥’ïz·þD™ÚWܲi-.E ’EeBË$é©ÏϼºÏ(”_ !ds[›©§j0çö–Z‘•Ò½­¯$0ÑeHój.‘Ò™¤š€tž¹¹<’òF§îˆe!ëÔΙҽÅÃM—=jÏÜ?äµgîòZ³÷ù-Yû‡ü–¬ýÃþKV~áÿ%«?pÿ’ÕŸ¸ÉjÏÜ?äµgîòZ³÷ù-Yû‡ü–¬ýÃþKV~áÿ%«?pÿ’ÕŸ¸ÉjÏÜ?äµgîòZ³÷ù-Yû‡ü:*i¦‡1‡tÿñóÓh{ÛdüܾÆ&³Þ•c¾0<KkTö0UÅ9Œv„$§'7f¾ôc|-›©ä¦FMHYÊr3t¯î²–ÙÒù*Ý>õ™,hè2UdÖG":Õ2f°H¥’T2¹€5µÐ ÊkB–¤$&4]&¸ìàlñ\ zŠW°5­®ŠÜ‹‘•«yT¢›:E¹o§BÍæÛjìå¤Òßµmš9§Gî3˜#¨¥¤h¼´…›§/7J~ÊqŒ²æž”ÇHÁkJÖ¥ ZËM-²tܞƚŒBÇ¢•´²3gf(ïv…Àä¶µO1°HÇšÒ´¡S>P9t¹}‰£»­FçB"²jMjJär]J,¦Ö†È Íæ›ZRÝ¥qëFm ô¨«hkÁ"ÒÊmhl€P£lV”µjõMá ,å9ºW÷YÊr3t¯î‹‘•«yT¢žÙÉé5²2Éh¥ü/ý#â¾Ú»ßÒž".£ÍtóVïcóŽcéþ-ã»{'œðEØï‡¤Ð*‹½Š‹Ç }\ç—FhA¦ƒèjâë;´­Q{® 8rc›ëµ¥2JZ!4I `y 5R4¶Ë˜hŸ£@uëU ’t:SDИôZ­ŸÜ¦·EoYCcˆ¼çI¾ˆÊA4-÷ e€±‡ïVª6صnª¯eƒÕZ¡Œ¸–ÔP¬Ô‘æßJÒµªòzM«•¨òw9u¥S¥³mŸ–î”#Ž2÷Ò´­ÉÌ{sonšddt_š«'1¶¬/ßîB¢‡©e¤Š€Ñ£¯Bɤ³FÛi MÎÂX×h©ð²No½G s›­Ê¥¤°µñÞÕm¹?&•ÖYþ‹5Mq¨­8_úGÇ›·{œswOñoÛÙ<ç‚.Ç|8dkoFŽ-¥•“9Ïsb ´ÓÒ£iepÓ­Páä ¤ö,¡Ñi–j:t«G+”ŠjÛY¦kîY/û)Ù#ƒIu¡^²—6âBk©[)Á¯.(Úo!ºø§½¢¤"]•9î#U¥d©ž èFFûFÓ÷LgPPJut¡n{ˆ¥“JÅ£ùYFô©È¯'(©¢õ™¤µ÷C«U’ÕáÀÂóA›¥ulÔF ¢‘yMxi`¡LêRÛíå:ܯŒ=¢ÉŠA’HüÙ‰¨BÓ€,-éY4Ž~Ð= ¡eÿ x,”õ9¨Gƒœò)E”ÿ¯‚”?(Í .²IowN‚¢ý!‹î™-¯ÿ¤|y»w±ùÇ1‡tÿñݽ“Îx"ìwÈNmµ7èVl‹=K’ÐÞÀ§sØ JUP jÃmuÑ@¨¸ HÊhwhD†€Mü h=tV¨-]Uj‚ÕÕà4¢¾ä†Ð\)råi§Jh{‰†µ®·%o`@¹ ‘uB4WIF€ ÞªÐzÀ@*.<ËknÏýª5 r£@¨*–4žº,ӡ׺·*9 z£Z÷+Eµ×EGG½P îHå_¢ô‘Av‹•Zƃî¸SyUsO¼#Ét®Hºà<­ u,[¸ý#ãÍÛ½Î9Œ;§ø·ŽíìžsÁc¾Š¿ô7nö?8æ0îŸâÞ;·²yÏ]Žø~*ÿÒ><Ý»Øüã˜Ãº‹xîÞÉç< ,³¢·•ìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}å6(Æ—;轞/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‹Ùâú/g‹è½ž/¢öx¾‰ÖìéãÛÍÛ½Î9Œ;§ø·ŽíìžsÏ2Ó¼?nö?8æ0îŸâÞ;·²yÏ<ÊwNðüI»Øüã˜Ãº‹xîcÙ5s:!qûÇܵgîòZ³÷ù-Yû‡ü–¬ýÃþKV~áÿ%«?pÿ’ÕŸ¸ÉjÏÜ?äµgîòZ³÷ù-Yû‡ü–¬ýÃþKV~áÿ%«?pÿ’ÕŸ¸ÉjÏÜ?äµgîòZ³÷ù-Yû‡ü–¬ýÃþJÀ¶Jò£s|xùNéÞ‰7{œswOño<‡tÿñÜÇ µÂ…kO߿浧ïßóZÓ÷ïù­iû÷üÖ´ýûþkZ~ýÿ5­?~ÿšÖŸ¿ÍkO߿浧ïßóZÓ÷ïù­iû÷üÖ´ýûþkZ~ýÿ5­?~ÿšÖŸ¿ÍkO߿浧ïßóZÓ÷ïù­iû÷üÖ´ýûþkZ~ýÿ5­?~ÿšÖŸ¿ÍkO߿浧ïßóZÓ÷ïù­iû÷üÖ´ýûþkZ~ýÿ5­?~ÿšÖŸ¿ÍkO߿沆Zq “E§÷[×̽Î9Œ;§ø·žCº‹ Ê÷£ÈÞ`Ýì~qÌaÝ?żòÓü[øNW½FóïcóŽcéþ-ãEQÐï‚ÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕÂÕ–ƒ |yžW½FóïcóŽcéþ-ãEØï‡á’v3Ê÷£ÈÞ`Ýì~qÌaÝ?żh»ðü2NÁñæy^ôy̽Î9Œ;§ø·c¾Ž_ÐVGhvy'öYECœMšrqhu[{i¥UÐL½©±ÑÁÅ–ô¬Î›Vm,ªGV‚Sr2:´I5Ŷ…§Ô«Y'Cª˜é¯: ”Öäm«‹‚c4Õ÷'42G9¦„ŒŒu:Ò…«UüÇ¥ZyA…¯a7[ªÌЇR½©äVË>÷B­™,~{:=$ƒãÌò½èò7˜7{œswOño.Ç|=¿ ¬ƒôŸ”½AE+ëÉk9GÞ³®Ø·PuûÓ}ñ|VŽˆ¾+,ÞüQÓ­J(¥v©mŠõ"÷ 's›f²7B´ÝfA:ºÑe«){8VTæê“¡Eš±Ó[]«&/sXm‘¤—)ûÜ‘›LŽ=µãÜ„b”#«­Z9SsVöÓj)£“°|y•±|F¿²ò³–yƒw±ùÇ1‡tÿñ¢ìwÃÑ–›Ž…'g«îNs™RëÑŠÇ ô-OþÅ5®eCnVšÊQ<èy«½èŒÝþõe£©TF´+CP¹1¹äõ&³§¥MÚt+-–6•½Yp¨V˜Í)Ï”ëÊs€ÒëÕ¬Ðô’v2ss… ï«v?Ž`Ýì~qÌaÝ?żAåk^t€O]ŽøqHk¬žº(¢ÿ'^ºl#óÖ¢œ‘¡Y¶Û]U[AK:Ÿd½ õWƒ7^Fn´ýÔÏlÁÎÑA«¦åfÛmuUç^µjÛlõÕr×v¦Fu^ªÒë ’AìU&U®ì*†FƒÕT*à+r²Òz«ÁÊ{GiVª)Ö‡Ú7MÚU\@õXðXêÖœm¶×US_!Ó¦¥r^×vW8ïUi{•›mµÕ^4ƒãÇŠŽpÐn4ê[Y1•µ“[Y1•µ“[Y1•µ“[Y1•µ“[Y1•µ“[Y1•´“[Y1•µ“[Y1•µ“[Y1•µ“[Y1•µ“[Y1•µ“Gíd»óž+w±ùÇ1‡tÿñâÐÐhÓ[œBâgKúÿÞ…ùb êOÛ“·‚“öñUk@siCÒ†çâœÙr|ëO´mé– -¦Š¡ºø¬³{ñD†€æŠ‡t¬ŠßÞŸáFÜÙs¯´híPýˆŠ ÜoYCœÐNtÞ²ˆÿ&–~éŒêTq¿K-SÞŒ€Ø6n ‘ä¥íüï ªÉAé’ž*1¡§8Žæòs5N—º‹)P»GV…[ÖnÕVLÉ4´Ej‡¤¨ @ìOp¼4” h.p©wJÉ":Ž.ªÆÐ×´ŠQ?ìs¶ ­Éô‹2DzšÂþµb|›’=£ Ôq_šc VÓé×î[;ãýVÂøÿU°ƒ¾?ÕG-)m¡Ôዱß=Mɼ¡Ê»Mè´QxU7*ƒP¹D èÒ‹A…WYà $TÜ8îìâ·{œswOño9$M{Ä’\+÷Ï]Žøq£–º•Ði^”b­+Ò„µû–h‹#œ¶>«(1·ž¯Ü³E4vöµZ\ƒ;Œ_–ŸëLÝt!#$°ð)ZU2gJ\öû”škmö”v lŠºœ pqcÛs‚.•æGfêhY¿ò›ê§ÅG½GÚ¹3M,¼;‚Ìs–ÇÕE,AÚ_Ùfk÷,ÕGG–¾1@à™3å.s}ÜÂ/ËOŠdEƬÒLÓtJ,ãXû«Öœé\ds…+îY¯òšê³ñA¢áÅ“°|x™6é¾ ‘º+MskPV‰C]Ôý .ÃðãËú ÈÚX st­ ( Œ½ÆÎÙNÒÒǵ†­)„@ã[¥ÕY;›q•«*{ ðN–Hy?”›ÓZÖZ{®hY8|eŽ´~Üwv*Í+YÚU c¤=g@MwXànö?8æ0îŸâÞ#·²yÏ]Žøp:Íy.³§Ð23Z¾´ô x©kÝdQrZz‡¡|t5eüG0-½Z¤ÆÙqµÒ:é^K¬ž+[eÆ×HèâIØ><@Ö™€3þiŸãµÅ¶4¹òâ«”LO¹Š&BÛ-£º{8òþ‚²Ò|öȦ“ز™¥‚ÚûЫ…CieduùÀ²š:Žm’;hžnp p÷ÕE#ô0²Í}ê ¤vqÝØ‹…¨ÞzAUˆ¶QîÐTÌ%Ü—Ê5§!¼ ÞÇçÆÓü[ÄvöO9à‹±ßddŒ¯$Y­T¯ ¶e#÷YÔG(éj±Ë­ê1#ÄŒy¥iJ\Ü¡‘6º‘à# *|Èée”Èb *]Ô ‘Á×ÑÔ§B.7U†VæÙLstIœ°à£/=¯u’,ÒœìFÊѼšÕK6efŠ€ 6«ö¢Ëz¯Q—È׺ÉiDblŽÈÒâŒ/{dÑPà›#¥Ñ[¬Þ¤p¼4”%Î ÓVÍêbÐ^àYœ’CÉÑJ ÷È$ehîM(²€ãÈŒ?…œÿ&6Væ(³`g$4ìM´ìë ú)E=e­)kF²“öñY;亵Y@cÜ:iU8u3±¤!)}®N¥/VÝ”²Ðû” &Í›9Ñ¥A¥µhººÚÙ™Xi¦ò¦Õ{ãé×2vKù›JQIØ>ö­ŒxVÆ<+c± ØÇ…lc¶1á[ð­ŒxVÆ<+c± ØÇ…lc¶1á[ð­ŒxVÆ<+c± ØÇ…rÖרs<¯z<ôÙ^ôyÀÝì~qÌaÝ?żGodóžqéþ-ü'+Þ#}6W½Fð7{œswOñoÛÙ<çœCº‹ Ê÷£ÈßM•ïG‘¼ ÞÇçÆÓü[ÄvöO9ç s­U·¼·ÁkO߿浧ïßóZÓ÷ïù­iû÷üÖ´ýûþkZ~ýÿ53ž[›aå<»¥Ýe{Ñäo¦Ê÷£ÈÞïcóŽcéþ-â;{'œóéGÞo(~Ê(º ÓÙøW½Fúl¯z<ànö?8æ0îŸâÞ#·²yÏ?ÊÜF† ñù~•ïG‘¾›+Þ#x½Î9Œ;§ø·ˆíìžsÆ4$iv­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ­¤˜ÊÚIŒ£ö’c>‹+Þ#}6W½Fð7{œswOñoÛÙ<çŒ{Gâ.ìôY^ôyé²½èò7»Øüã˜Ãº‹xŽÞÉç•¥iDâæ–{U¨òw9u¥V{î e€±‡ïV¨ÇVÜ/ÓDy%¤S¤¥iЃÝ„GïWà„la‘÷ÑfÞÂÉ/§ZšÔtº¼­T^ä.NZλUBq-¨¡F'ÇaàV•ªvjö·A5R¸tÊS@m§ºà³rDXêVú¬¡±Ä^s¤ßDep"É¡õjXÖuÖ´Q2•ÎWJŠ:k×ORÊ^ë³¥$%–®5¯Ýž‹+Þ#}6W½Fð7{œswOñoÛÙ<çŒ{Gî¾*èPoBË*- ²ÎäùIoÿŒš¦— 4…”ÿ¯‚ÉÏT¿4#ÁÎy¢¯ŠtFlÓZ?”ë/sÆoXŸzgîŽE÷L–¿×‚Lá  $©„f¿bESCžX(AVè@ÎÛÑÔ½fi-}ÐêÕmðÈåV–”s톚õ©?oÿÛÅ?8h$h²J6j#Ñ )é6iü*·EM+Ô½eÒ»ªºÝ|PÝ|QŽG¹„ÖªS×!Q¶[B§CÇÝM‰³g˜FŸüVQ½*gR¡™E¢œðâá@È‹ôè'öY8i­+r™×†eŠ£^OWÝž‹+Þ#}6W½Fð7{œswOñoÛÙ<çŒ{GÕ«ª¹@iÒ¹@iÒ‹€7•k6Û]tà.TÞPA¤ *µÜª WUr˜×v„ ‘QîTc@ê:yZêY·pQÍ{ÕC@4¥Ê¥'®œ h=`.[ZîШ£€#¨«.Ž¢¨æ‚=êhÜ­Yºè¨Q6ÐÞ(­Y¥*­PZºª®cI÷…ÉWN…BõÈho`F€ é(Ð]%T1 õÑQÀïBŒn‹´\½›f›ôqÙè²½èò7Óe{Ñäow±ùÇ1‡tÿñ½“ÎxÇ´xúW´Rý7*´‚=ÊͶÚêª.µÐ «H#¬.Sƒ{J¤Õ­¥’öƒÕUÊ WF•F½¤õ¹N í* Ô sŒ¡»J­t(sO²šiàå=­í*Ñp ëVm¶×Ux*çÚª×ØÎ2†í( B¦à…H»‚…íª©ÏÑî¯JÉhñGƒn‹’ö»°®Sƒ{JµQg­P=¤õWÐ;³Ñe{Ñäo¦Ê÷£ÈÞïcóŽcéþ-â;{'œñhñô9Ap­,ߨ²Ñ€,ÒžõfÀ»Y»Kºÿu@(ï‘¡Ä>ȯRËl}ÑQÿhèíÚ½Ö†•%Ðs€^„‘´5Ì"”S;ü|ígI•ŽÃÚÖˆ0êÞ²HªçþË'sZs€hà2ÈÐ縚Õeq F–ÑZk@siÊéàÙºiÕè Ã7›¬u² ̺·¨gé‰ßô«÷boý”÷ ÃIM.`qx©%L×r¬Õd-¦‚4ûô“ØhmªƒE3¿ÇÎÑÖt‘¡eUŽÃ ­i¡FàÑj—úvz,¯z<ôÙ^ôyÀÝì~qÌaÝ?żGodóž1í>†Ik¯M g8ÔH¢ÍÿìßU4ÿ+29-@=Ö](Œ‘Jc.ÖÑZ© »VúÕˆò‡6>ª("n®pÜìÅín(Œ‘Jc.¿EjœK‹žëÜP޵§JlVÍZj$åÅŽ®¯Œ3ô‘J§Äjý%Å«Jôðb–Áuú+UÎ(j„u­:VjGŠPþèWYÚO˜ò‡5T­„j‘E t¶³U§%E%u+£­"”Æ]~ŠÕJ É|ƒKŠk+["žÝž‹+Þ#}6W½Fð7{œswOñoÛÙ<çŒ{G1åi§OñÐÕ—ñÀt¶ôduh:“eÆ×HèO¥y.²xœ¦ƒÚ9‹»=W½Fúl¯z<ànö?8æ0îŸâÞ#·²yÏöa#…ᤡ.pVš¶oY6hÙÎV©‘Û·+΂E(ƒß ‘•£¹4¢Êmil`P,çù1~mEšÖ–êô&Úvu†ý¢ž²Ö”µ£YIûx¬€ò]Z¬ 1áÎ4ªœ:™ØÒ”¾×'R—«nÊYh}Ê“fÍœèÒ˜É%¶×û©¥9€òÝ=¾Ýž‹+Þ#}6W½Fð7{œswOñoÛÙ<çŒ{G0—ôÖ]g’zFÚfÕJŽV NŒÝÖ„M‰ímyEâ‹,¬5Yÿí@¢‚F´E{Z›b71ƒX¼)ªÇRJQÔО :4Õ’ kîSÚ†B×HH YLŽm(4oìƒQ%€‹"ÉKÜÕò]Éi®‹´"á¬ÎPVÝ­!´};»=W½Fúl¯z<ànö?8æ0îŸâÞ#·²yÏö`æ]hQ5•­‘N#ÜçÛ{ï4§¤8C:[×ÌÙè²½èò7Óe{Ñäow±ùÇ1‡tÿñ½“ÎxÇ´xþ"îÏE•ïG‘¾›+Þ#x½Î9Œ;§ø·ˆíìžsÆ,m+¢õìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_Eìñ}³Åô^ÏÑ{<_DGÙâúz,¯z<ôÙ^ôyÀÝì~qÌaÝ?żGodóŸøW½Fúl¯z<ànö?8æ0îŸâÞ#·²yÏü+Þ#}6W½Fð7{œswOñoÛÙ<çþ•ïG‘¾›+Þ#x½Î9Œ;§ø·ˆíìžsÿÊ÷£ÈßM•ïG‘¼ ÞÇçÆÓü[Ä{”D× dÐ^ß+Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À½jð/Zƒ¼ Ö ïõ¨;À½jð/Zƒ¼ Ö ï9©Xú_eÕü+Þ#}6W½Fð7{œswOñoÛÙ<çŸMºg‹¿Ê÷£ÈßM•ïG‘¼ ÞÇçÆÓü[ÄvöO9çÓn™âïÀò½èò7Óe{Ñäow±ùÇ1‡tÿñ½“ÎyôÛ¦x»ð<¯z<ôÙ^ôyÀÝì~qÌaÝ?żGodóž}6éž.ü+Þ#}6W½Fð7{œswOñoÛÙ<ç†ËÉ­+r½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ½ØJ‘ü«&6É=nù«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„«Ý„£`ïA•ïG‘¾›+Þ#x½Î9Œ;§ø·ˆíìžsÃþƒãͬÔZ¾œ424ªú 7Z¨¼s9{ñô^ôyé²½èò7»Øüã˜Ãº‹xŽÞÉç<ÌÙ‚ÓzíÑI1‹Ctk^Œ´­:ÜüTš)aöS×g3@«9¶Ÿy¶Õ[^O¹[fOQÓÊYþ‹5PÖ3Y:B9b1—jé­TÖ£¥ÕåjðæªÈÞÛ¥3C-¥]×ÌåìoÇÐe{Ñäo¦Ê÷£ÈÞïcóŽcéþ-â;{'œðÿ øó?ñÚðÖûGWþ“Ù4 ‘ x%Ô¹7sñYC^àÓœ'J™ìDÖÀV³¥9äQ•äv&~èä_tÉkýVJç\ P27ëFeM´ãJ @é­Õ¤fˆZp‚…½+#qmšÚвŸõðærö7ãè2½èò7Óe{Ñäow±ùÇ1‡tÿñ½“ÎxÐ|yLL¯éFÃÚõFm”7èV¨-]UW1¤õÒULm'®œc@ê:yZêY·(ZÚÚ\–†öjȵ×N Eµ×D ¢â‹€7žg/c~>ƒ+Þ#}6W½Fð7{œswOñoÛÙ<ç‡ýÇÐÑ’X=tªÌÿ“÷-VÀQý­¢é@­ž…@ö“ÕTÿ´häþUfÛmuW‚v½à1´¥UZAäÛs5õ4µÖ¬‡´žªª¹ÀvªµÀö*çY‰VºA¨÷*¹ÀzµhY몵hY몵hYë\—vG=£´¡W[—(]TqÚm mTܹok{J{Øá¡¤‚vÞÛe£¥@Ày.­W)Á½¥TŽ 5í'ÜW-íoiV­ =h}£tݧÑKØß Ê÷£ÈßM•ïG‘¼ ÞÇçÅ’Å#ZZÒÞSk}=þå·ƒ¹?ÙmàîOö[x;“ý“©4;Gû#ùþKor²ÛÁÜŸì¾ÕÍq²5[N¿¢;¯Š‰½r…˜ÐÓœBË4¨eb|›’=£ Ô)ËÅiM±I40²Õ=ë'rüÔcCNp fé¤W ' Þn±ÖÈ*®`%ÕÒŽOí-fh¸ 'ýŽvÀ¹™ÍÆæémBÿߨZÿø(ãÍg[5¢cÛ“æ…Îå (É#CœòkUë@Lвz´iµ]å%˜]3úkJ—6ÍŽN¯V„*ÑRÚÕd%×ò”Îÿ;GYÒF…%c°Ã¤6µ¢kzðÒštGdè#B’Ì.™ý5¥Ë›fÇ'W«B­k7jª2(ô2fžÆè´ÊõûÖÞäÿe·ƒ¹?ÙmàîOö[x;“ý–Þäÿe·ƒ¹?ÙmàîOöR¼9Ïu­ §@M•ïG‘¼ ÞÇçÕÛÙ<ç‡ýÇÑg«÷,Ñ3M,¼93M,¼9Lâj%¢Íì×UŸŠ ù™)kîNqq{Ý{ŠŠ;zµZ&i¥—‡#,RØ.¿Ej³¹ÂâE PauiÒ+ ZÑ¿ƒ8Ç–>êõ§<ËjR)h‹–fºoµïëL9ÊJϾK&qÂí¢vfbÆ»IªE m{Ó “—ºº©kì=—U9ÑLXjEš©¾Ðœè¦•šC³}"ŠÓAt#$R˜Ë¯ÑZ§âçº÷Xë“s³µºiJ':)‹H³U7ÚÒ³5û–jšÊÖȧ¡—±¿m•ïG‘¼ ÞÇçÕÛÙ<ç‡ýÇŽÊ×”ë#…ÖkÉu<|ΛVmq¨Ö€=ÜGVƒ«Ñ9Ç U5ââ+Â\n8\t¬Î›Vm,óšð:ˆÓÆw%†šxÒö7ãͲ½èò7»Øüãš»{'œðÿ øð»í Æú¬¤[tcCÇJÏç@£kfÍêÝ-Ë×вp÷‡·84ÒœFHÊòEšÕJë<·M@=ë:e¥í³Eb9³RâŒ/{dÑPàœDícë¢*!hQÝ(ìYs©Tá!ˆï:Qsr†DÚè G‚Œ4¨Yòöž“ˆälbÈ%Å^öÉ¢¡ÁL¡¡¯ 5N¨PüßiFÜí7òiN¶7ˆØÃJÒµ)ÐKBà*:B· ÿ[Ó^o*DG.·¨Ä1æ•¥(T¿ke¬y¨½’ÙZ7“Z©Ã¨%ˆ!BËmkÞËN{“ct­”>â:‚7ˆØÃJÒµ*Q!²[]#ïËNµ SEÈn¾)Ïy«¾«<^ÓM&:&2'Ùk£µr δ 2zt.‘²rj¿ke¬yªbt‘-†ÕgQ£¥©‘‰mp­²ƒÜߺñÓÃ/c~<Û+Þ#x½Î9«·²yÏú †lòÔòHYeb³iœ¹Y¡µš¥?e“HÖÕÑ -PY†@ÖÈ ¨à0˜^ñ^Ij&’ ­€zQ‰Hí¸h ч:ÂÐ.©EÍÉÛ)¢­¡DO’9Òþf6ôÆÉ¬t¡Ž{4Ù¼'HèÜÖæè*‹$Ésšy. ­T¥Ñ²:Vz̈^E 7+Fìe ]R(‹†NØ™Mm§¨"²’Ôo(OmµéE‚A×QÁ'Ù¹ìy´ t§ÎöØÑe Þš:tÐàAÓ ¬˜´Z<­ ?³{Ãh— )ꬤ„btOskÉ,YT² .ZO6k:ÜÝ—6‰¥™(‚òæP©~ÍïcÍ X*¦¶)h-M®ih§( ê9ªW÷E–kªšoYœËÃÈ¡&äÍËa³T],.•”äÐVŠÞg6ÂÊ z‚+)!OÉÓž¶éA±ä@?­ìЇ9 :SÞÈÝDj»¯†^Æüy¶W½Fð7{œsWodóžôfèëJôúH¤®¥tuñ,¶Kߢô.œÊ^Æüy¶W½Fð7{œsWodóžOn›¯!jœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœejœe•¿My¶W½Fð7{œsWodóŸø~W½Fð7{œsWodóŸÅYQµÅÍ.å>—SÝï[;ãýVÂøÿU°ƒ¾?Õl ïõ[;ãýVÂøÿU°ƒ¾?Õl ïõ[;ãýVÂøÿU°ƒ¾?Õl ïõ[;ãýVÂøÿU°ƒ¾?Õl ïõ[;ãýVÂøÿU°ƒ¾?Õl ïõ[;ãýVÂøÿU°ƒ¾?Õl ïõ[;ãýTΔ4j5èáÀÝì~qÍ]½“·tÿóÆïcóŽjíìžsø¬;§ø·ž7{œsWodóŸÅaÝ?żñ»Øüãš»{'œó»n¹^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%^ì%FþU‘äž¶ü•îÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂUîÂQ°Nww±ùÇ5vöO9çg´xþ(ÿÒ>< ÞÇçÕÛÙ<çžÑãÍD”¥z8f‡}êÜ‹ÁY³CKøÎ³÷]g‡3O¹jª¯eƒÕ^bÿÒ>< ÞÇçÕÛÙ<çžÑãÌH©êB¦˜Èoåê„Øí8´EÒ}è6¦Îj´ýÕZH=cµ=Í$B-éÌhþT@_-Íeoé ¿ò$ÎÒ¾å“H it€(l’+(ìν¬¸©òw=Ä6çtéR¹Ò¡o)Úåa¢lïÎûÏ% ÏÅ4¸’té<Åÿ¤|x½Î9«·²yÏ;=£Ç˜»6*þ€þ˜¹îÖu°™”1•6l¹•YÙ±KîY‡r_õF<ÐízS“›¥S‹¶m­Ýe ~‹o$,Þiµ¥-ÚQÇ´fЯJб†¼-)ÞG%Ô¢är]J)$AÑ——‡èšCº‚ÍX 7g- ÿº#³TÖ‡&ÿo'íâ„®c3}#¤!›ªŒ‘6;#î›Ð$R½ ¹¶‚ã4ö¬ÌÁ¶ˆ¨-¸¬¡ômc}„®c3}#¥5±2¤ô›‚lSr®-R5úT§:J0äðz“b ÈLÊÕsT” ënï&Zh3>àDíe—U ̬£/s”1Ù‘†šn)Ò6•j 6ilR½h1ŒmiW8Ü ¡¶€µV¡šk(?7JÔ¡ÏGRÍB\IuÁeh¥E.)ÏuÁgLL³ùF²±Õ´û“¡”6ЪÕmŒ÷éM’”¯ éïcóŽj\ìšMä°/Uƒ» Õ`îÂõX;°½Vì/Uƒ» Õ`îÂõX;°½Vì/Uƒ» Õ`îÂõX;°½Vì/Uƒ» Õ`îÂõX;°½Vì/Uƒ» Õ`îÂõX;°½Vì/Uƒ» Õ`îÂõX;°½Vì/Uƒ» Õ`î´̞&¸¤0uú›ý¼Ÿ·Ší⛹ø¢^×C?SS3ºôÒšâ 3z}ÚS$fÎ0y]k,ÞüSÿo‘Îl6ooZ€ÄÓgO(ôèYFô§DÛ²Š}Pà™,&;6M:s1’¤¾§B9T~ÏP~e öK˜5€LD^k§IЦÔ:Ó]E5£îõ”ZÊ“¢º.P?¡²WÛ=ÂÐYKŠ6ZÓŠô Ù*:´^¢./Ê-Q9ó´æÞ48WB.†#d rJ{z&oÉDFRç5”lÜQ°ÂÖ˜ôW¥3÷Lýý³±1ôh¥¦×¤¯Uƒ»9¹4 ‹ˆ`ü@öm™Í4ÐÐÞ|ÿÒ>?‰ÑãÁËuÙº´@ç/÷+v…ž´üÔ¼¯vŽ =ô+(åÕœšiVs¡Z{€ ê«.~•i¦ «OuÉórU¼ªÙQï¡F@ê°t¡öƒJ´÷!ÕNkŸBÛÕ¦:¡H/*É¢Œ›ì…öŽ¢û7UÉq¥ÊÓ Bæ•4V %¹ô"ô->ý!ZcªqšÛ;•–>¥}£¨ŒõhZM^/в` ¡µP²’Éâ-_÷JŒ>^U‘T-º–®VíònTcêz‘kŸB/RÈâh*ÓpVs‚ªÓÝ@¹¯ÿHøþ${G„1H)Î7'[³k7÷PÑ­Z¨AÕÎr»*»Ž ¤ktý–_›÷+4»+&¥’Df–ûTOÂÓî:J•Ù9ŽF¹ÚAë\†X¡¡o½FpeGj€ôj²‚ÁmÓ•zÊí:=,ÒÖ´ 4Y-Ò²jY¨ŒÒßj‰òZ}ÇIYAé¾ .³ÔÔF‹!º_ )m^,¨¬ÞZm,¥Ý9Ò§R¢»8*ÁÂÊÊMಇ{tý”·Tö¬ :ÇZê¨Ì†ÑÚ JšÕá¢Ê’ÎÐŽR÷ñY/û,»õ=¢Én•ZÿÉ02;rÒ¢¦à ÎX­ªÊMà²êu5Y¦N#³ïY=%fuº½NMÄ„hsMüý#ãø‘í<ËOcºÚoYÆÚµJ7¡kAÖ³7³Þ¬¹òÑW]Ál9ìwIa¥SìÖ¼fÜ–?%­ ¢”³ª[ЭÕÏ[Qs_# ¯°oVX4!j ‹ˆ¼&Ëiå㤛հç±Ýl4SYéi©=*>Sè@%¶´ÐtYÕ-èVêç¿­Æ©ò Õôª‘÷ç/ Í©,þ[ZkÀQik‡ÞiÒ‹´¹Çï8éO¥yN´Sé^S­7B.{¬ê‡“ä«éUl1Ýl4EƺoqÒJc$o½¹Ïy[5¢«šá÷šQ¥I7“yD5ΧQ7(ä5«.R¶§í '÷VmIgòÚÐTn»7p:®k‡ÞiM’¯/oI7§È+WÒªGßœ¼KrXü–´&ƒ¢Î©oB·iïw[xúGÇñ#Ú<éÄ‹+E®ÌæµÙ€üÖ»0š×fóZìÀ~k]˜Ík³ù­v`?5®ÌæµÙ€üÖ»0š×fóZìÀ~k]˜Ík³ù­v`?5®ÌæµÙ€üÖ»0š×fóZìÀ~k]˜Ík³ù­v`?5®ÌæµÙ€üÖ»0š×fóZìÀ~k]˜Ík³ù­v`?5®ÌæµÙ€üÖ»0š×fóZìÀ~k]˜Ík³ù­v`?5®ÌæµÙ€üÖ»0š×fóZìÀ~k]˜Ík³ù­v`?5®ÌæµÙ€üÖ»0šq.´¸Sÿ†ïÿÄ.!1ðAQÁaqñ¡ 0@P‘`±Ñá€pÿÚ?!ÿð6ÐPsÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃÿ“1îŸÉ˜÷OÃ0µAú;RÕÔ/Qô €ðÅ—#èM z £²öƒÑ™j$>‚%ò&ÿû‹î}ÓðÌgv˜Í6D'›tÑì^Õ:ä)ªÚWâ@Wva&)mÌ6•IJ¡”­YûÑrÿA{X0HÓ5@A2¨€°‘D¦±ÃØèÒ">‚€mÄ:£ •;ǰ÷@&±ˆf€“( #è(Ü@#ª1ØÐ¹S¼wopZÂ9Ê¡p9UßЭïðUa¯jÍ^(Ä ¢jAÖ+ŸÛ -^ðön5NúÀ—•(P#Vb±k mÞ&:‘°0Wø$%šés0€ÑÀþF¤ ]à²{ž·Üû§á˜Z‰¨è+½ fѦ°„¡M­!¸”:sÿÄÖ9!D& Ö¨'k!¦D9Ñ E[mû*Âæ²åÍ}aC   øPv2XPb¨Ò"Êph@Ó K·©î¥mêÿ¸ÉaAŠ£H@‹)Á¡Nd7SÜ(QI Ó°š¶E;OÀ¢hkÐFvúð¼ ÁÝÂãB}J"´ÇÁ%¿ÀÄÞS€Uµ-P ´}À¸Ò ©Œ +rÙº}Ϻ~5€‚±X€ùW1.î­ôï´à0€‡÷OäÌ{§Õ g«A ö™o3-æe¼Ì·™–ó2Þf[ÌËy™o3-æe¼Ì·™–ó2Þf[ÌËy™o3-æe¼Ì·™–ó2Þf[ÌËy™o3-æe¼Ì·™–ó2Þf[ÌËy™o3-æe¼Ì·™–ó2Þf[ÌËy™o3-æe¼Ì·™–ó2Þf[ÌËy™o3-æe¼Ì·™–ó2Þf[ÌËy™o3-æe¼Ì·™–ó2Þf[ÌËy™o3-æe¼Ì·™–ó2Þf[ÌËy™o3-æe¼Ì·™–ó2Þf[ÌËy™o3-æe¼Ì·™–ó2Þf[ÌËy„>¿ýh¶u,‘²gÌ㙜s3ŽfqÌÎ9™Ç38ægÌ㙜s3ŽfqÌÎ9™Ç38ægÌ㙜s3Žfq̘Áýà˜iöôL㙜s3ŽfqÌÎ9™Ç38ægÌ㙜s3ŽfqÌÎ9™Ç38ægÌ㙜s ‹ &nüogÄ) :Œ§E ›@‚ êùÕ«ºù«ºù½Óð 0$Q”袡shASR? S@u¡™ßøÞÏŽo¬}@­YŠÆ#…7ÀVbnÄ.` 7%9i í0’jW¼J%Íê!çhá—nw»¸¨¥ÒOU` ”ÖíàX …€)Ò ƒ%;ÝÜ}@­YŠÁ‚ 4UA$uB¿sÖ 0Kn¿t‚€´0{×Ú3Ù¯ìÍ:»ƒ]æSÌÊy™O3)æe<̧™”ó2žfSÌÊy™O3)æe<̧™”ó2žfSÌÊy™O3)æe<̧™e÷öoAõkØÿ°Q´÷/éòfúÇÔ Õ˜¬b8Sq¬¢Tࣲƒ´m œ9˜(ÙAz+ƒëÚ`f7—1"vP*’(v:B=ƒ=°DT“õù3;ÿ›Ùñ¨ÈHЭ`Œ„À¡¤/9“ÍÚ)H}@~ Ö¦)}¸x@˜Þi(Ô¯´¤aêŒ>ÀtoX0ÔB_îñÿ½~ö·=ãƒF [X£´$â °ê*î”6cBã°²5ïð÷IÓŒ²2êØ?ì©Mõ3;¾+H•5&þ±)[åÊÅFBF…kd& !yÌžnÐ#;Θ¤sf’‚Ô@T€¨ÙAƒ]vŽ@ÂO¨ŠfêB†!E•ÕXÂÞ ο.gàs{>ŠË*¨‘éËkO¡Tª[f&…ƒ+ü}Óëæw}»ݬZüD”C´1ÞøÂ¦ËåÌïü  !¢…ÌåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎPîVß]™ÝõIå.]:LåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9FrŒåÊ(ê’-J‘çø6gwðÄÛAAÏž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ï‚ß+TðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáñ¶ðQ_ɘÆïüšÆ7äÖ1»ÿ°S[˜ ëàÄI æÄÄYö‡N/q,¨ÞÓ¶ùBåAËS¥ Æ•ˆ‰ð"¨Ò-°¢?¨lu”VNßåô¨R $È!Fˆƒï?Oﱚ}ž7à¶™b0Dè^“j—Ó¹•7Tk’V¿p¿±3º>`jb.„WØÒ:¡â!WrªU=}_ê(H}ƒÇÙÖ7à–*M»ÚŠš™ºÞoHÖ;abV‚‡Ò!‹´)êxôÃ%SE«¼"žÊGt¨©ÒE)8Ë$Ô“òauàK˜SõHè¶h#<_¡"@´Ô£öxÝÿ'ahk^zÁLª©§¤ÛJµ´€g«>¶ËâP5îú¤¢íS 6ŸH ý ÞYô·ŸÐM|Ö3¼Ô>6¼»å°ÝåØsRÁå¡M˜ù,®´Á@úüq»þ"Àb$”‚vÇÏF4hšŠ´‚Øpª€vþŸòg¢ŸGÇÛâ,D5³eU.háy#)ÛÒuÁ¬ejh%!øêkÜ( ‹h„NMqÐ5ëRÑÐÄ‘¼ËÍJ¡¤,Ü[Ã'¡¬„CÔnaª°àq ` ÷ŒØÀk8€È¨Üì”áÄ%pÞݬûÐÎiHb@€×xHúwu°”‹ÜX0`Þ/J­é§‘ì­¢s¥f‘ ˆ@€ÒñˆEÉŠsê¡”b¤ ΡÉ^Õ‰íU•E•Aîžè öQäIÝúRTd&LVÃ…‡ºP“«ˆ¬kM&whÖUCªÝcV¢FAjðàq ` ÷†aªä¨§;ÿä¨(:|NÓÑPVÿ×g/ö2ÙX4_kF4hÑ£F4hÑ£F4Ñ0‘L”*Rç¤­]uˆ”epîn~FP/vb’…ƒZˆß€@ú‰±›Áªj!ÔE50­Þ-`c® *.T‹¨#´tx‚M$׋¨ršø­,.aãX+ƒ{Lv ühT+Ô€& “F±ï²"h\1=´¶ ,uxê1I×;õ* –0:¨ª-`À¬ï)T-t4oL7‘ÐÇŽÜ‚û Ú£@Fê+ݘ›—е | %M`A֥޷}"êîèVÁ'¬û?£'Ý^AܘhÞÁ%ÚþÃ(uJýX&QÀê¡[¼ZÁ[¼ZÃßdD&иø†ZµH´Zøãw‘µ.•û Á*‘ ¯ÉÅK‚ RN€`~¬†£â;Rl>ኣ·Ñ'܈|Ë!\ÿd" ˆ˜`’= Vö†×YìázmDnÌ3ÐtŒê&+h@ÿ@¾Lnÿ•ÅKŽ˜BZÂgÐ*)8ô¡´áhm€ G—ÕtWAQÓ­R_øt¡t9b«iÐ劭¥æÜ¡CY©ÅØH¦¨Dhïáz„´íð !ƒ`Ý_Æ)xb€Lï/Œ4 ™Ò>a®‚£à™êM_B(:ÐBu‡¡&!b¦%ÛN“ˆè„FšÜêЀ@€ #ÉWÙ 9XYÙ ÌW ÀVSÅZ€˜âuÅšb:(PC’'“¿òlT±XÆïü›,V1»þG,RyD …×N“9FrŒåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9@Í1ÆrŒåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9FrŒå›@8Øôuþ,\ÎïäÑRÅÌîþ(Ƙ‘0¨Kö´hÑ£F4hÑ£F4hÑ£Wt„8;ãçÌîþM*W&î ÿF4hÑ£F4hÑ£F4hÑ£F4hÑ£ET :äMÉÿîqR¥*P1R€@F§Û¥)JR”¥)JR”¥)U¶)JR”¥)JR”¥)JR„À#¯ò`©XËïüš*V2ûÿŠ•ŒîÐD« š˜™ oAè¡ðßPfˆ",6ï)Q•4MApO…× ¢U.¬ãP:-H¨ýf¤`jƒÞ†I0³cGITÁg4×´bƒH=¢bÝ—&Ò–¡¹; cŸÿI¥Dƒ¤¦+»J@ÄZ¢!‚Áúy}ÿ‚ÀÅJÆwiŒÙ!7²F•_äAjëÝ 1J¬D ÐÀ>ïúKIGr Ã#íq±:ƹ]«Ã[Ó‚cý†Xj£ÙĬ,J¬°Ïzwm-„1¥â %H*'ÐÅYÔ@Väm>ó `ñ²ª-µà……Lvúy}þÊäT¿ÔßH¦Cö{¯ÉEJÀcaÒ¬À¤ÌéýDˆà_YÕåÖ° ²Ç¬uAÒðp«Àjê°B°Kª:d•ûƒÆ“­b%ø¨XãÎÀû¡íæ[ò †;:Z±0È3܈FòI_¹Ö %~þþ“xU_«}L¾ÿeÌÑt2ÿ¨{]ïý~*P–ÚöùØx>Õ”¯Ú8Kª¢êÂÇÓgú´C¿ªu¡·hµŠ¾„ ±Ó?Ô4 $à[0l(æuÅ$Yö‚櫈-…i“‡RTVVì{ AƒA&)˜x¸?þÁ¢WU®j£XnÔ”9ÑG CÏ Ïõ4ö˜xƒè3ª%:˜¢pgè_Í—ßç…†–½½æbœÌS™Šs1Nf)ÌÅ9˜§3æbœÌS˜aa¼Å9˜§3æbœÌS™Šs1Nf)ÌÅ9˜§0Æ ÷QRªÈ%`ÀÒ–ëØ^B!`W?·üù½¼0:!à¹ce€¤P`¹HŠèe{ßô‰d«w™ z F)€z‚ ZZ@4j¢íä#U›¦^…žóu?cX06Å”Xf P¨TZ©:á ‹z„úðª|¶"z¤px¢†}øËqiÞh„é,VTÚéiT~£YêÝÁÕì;¢i3`§Òé„Aªë/¸¡CÚ™=ãwùRo}-vÈ >­øi†¾“D$é2iÓx Ðj!É:@ ‰PF±MPŒ™Ú´ˆN+¹ø¼ŸŸÝ>ê*Szy@°CçbÃv—aM‘ö=\Øíc±s°ìú· O;Ev2Óú ;>­¹þѨ~‹g´ÏHµh.Ä;í0í*ò ÐB°FJñjOH_¹*PÐ~þEÊF—¨Ø@ò ÑD´hS®ô¿X€ôåµ§À16L‘ØÀ–M1#P^°'龉¨Ð¬Ä •j 6„5hö˜@®¡2 ·ò >»Ã vÀ¢Udò l_©&¶€¢€€ùrûüœÎÈtÏhR8ˆA×[þBeùÖwhP¬nÐH¨ j2±æG¤d¥ÐÖ¦pÜ®éFìVÆ/J@™Ëø½àR+bºÏî‘\^±ôð¢ÖÅÝÅK€¦Âê@o]Ôú!¦ kþFz˜ÐD 1/o‘л8 l]uxî‡AÌÜ|º®(›ü™}þH°2@L‚gR'õí!û06š }ß>wiŒÙ)k@AF¡;¢­´#R{A`›G«0Žlz™¬m†¶B•s¬.­¨.ùýÒ_® @žÆ6êØ?ì;H UW©?u,V Ä4Fð˜C4 X …€)ÒtÁ% «7'hEˆORàdêƒQQBˆÛ#Ö23 ~„´T¼â(°ºàº˜ºkOêíu#o‚ßd$Ô¸ æ³€õF uX êëöº´|RYÐ6?^…APx|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáðj¾b„HÿS<>x|ðùáóÃç‡Ïž<>x|ðùáóÃç‡Ïž<>x|ðùáóÃãmà ÿðà1RÅJ T±R,T¤S¸l>z4hÑ£E;PB¢YqØ%*X¨ÁëÿÔ-·Ú©öþJ T±HaOëÑü{¿†,RÙÔ²FÉœs3ŽfqÌÎ9™Ç38ægÌ㙜s3ŽfqÌÎ9™Ç38ægÌ㙜s3ŽfqÌÎ9™Ç38ægÌ㘇©$Î9™Ç38ægÌ㙜s3ŽfqÌÎ9™Ç38ægÌ㙜s3ŽfqÌÎ9™Ç38ægÌ㙜s3ŽaÌ8ƒü¨1RÅÏìüº~T©bçö|áL Ôe:(¨\ÚgWÈÖ%ÒðÝI€€|fåÔ€Œ~¦#OÜ©éD°L¥FTÑ5òj¸P¢oð„¶.ºŽw­x½˜Ûƒì=Óò @ÅK?³çÍõ¨«1XÄp¦ãX2]æC¼&­P8Ò À@5¤5€:"•]N¢­]¥/@—Eb)1 d‰U5”¬…Ö”N:ˆ°TÁ$uB¿sÖ<Ö©6Xפ€è:µè Zow¬2‡AXÐ@1ú„•d #Ó¼N¢­]¬vŠF¶ •uŽÜU Ø÷I@ïhyð•°0Lª úö#2=„j É-­&åâ­H¾%h)bÿ¨”.¢€fñ7¸Ò©RŸ7º~T©bçö|õ ¬˜4…ç2y»AÔÃ0vƒ«f¦w0¼rÐ+¾ÑLÅ„»o ×P 4šºŽµµÚUï¾Ñk\sÐCØ0QèŸè’ %«î ¹CaV4.& †¥³ ž4t|`ÁG¢ŽZwÚ‰¸–.- ‡P½†ðE@PR\< Lo ˆ,Á* æX°:‚I‚‹Â$á½¶t‹hEZAFÀ \EZR¤" ü^fI= 0¢N°( ß’b¢)A"°‡H _'º~T©bçö|XªÚ)ª;Å5B#Gx Ð*gõÉVSÅw@@ï ÌW ·,UmÒ,£E7$ÁD„9 ²wøtÀâÕ§Xz~#é)¢u À@°Bs]ÀÄ2%è1:. btB@¡g ^° ܦÐ(À Е[N‡,UmÄV $G5C"gxø†€àÒ”¼1@&w—Æ(ÌéB 75hQëh?I|a ¹šB°µù=Óò @ÅK?³è—ÁûN§¨œþ.5òð×b1×­B[:uf'Q2ÕÉ¡¨†à Ð_t ±[ˆ-a\âJ3ÈPtøÁ²ëœ“úñ?‚"÷%¹8­Ä±ZÒeL& 7øu¡€(I¶‚Ü DÀÒ9¤]A ¾éN‰TP,Ðd}tü¨1RÅÏìú#´Ä¨áK÷=QÑW»…@ôA€  Q-Šzd™\Úï*ꬪ•UþÊ‚'§Xgbe €z9+5´\, WHd”•-ôáÃN¿­Ø-t‚ßV™„ ¹a00F6/×X Q`­é ƒUÒ$fL?º"\ºL6–Gê+’OY ƒ*¨!“‹äPí L(gbe €J8V]hÛ0šk^¿CÝ?* T±sû>Æí,‚€ìœ-SÐ-:6ƒë@h¢`÷¼ôšuB|©´îÿ¸”¶ÉŒoC»UÀpl¡ŠõÞiôTD”W¬›Ý¬ZÃʆäApb‡N~ø M¡®¡3$·6;Xì\!DLšJ¯þMîÖ-c{)Zz7/oh@!ƒ {eØc‹ÖºÄ (¡+ô–3´Ô&ŸE@ô@è­4,_è{§å@Š–.gØ©ª;ü€ýˆ¡{|Ž€¥ÙÀhKbë¨+ÀЧt8fãäEK¨¨¾ÇÝ?* T±sû>ÀÌ¡ƒÕA$uB¿sÖ2ŠÌC·ùX‚µ ì#ß`&Ô(c&•jGû(Ȇ@»;ÄL~±¬ä§.!¶¢Â»)ÑªŽ®„ 4sTK´(¸P 0``"JÃ"f›¶ð&ôÓˆµÈSÑ)RÊ®_óëû§å@Š–.gØgv”6cBàÈ(P#ÇéÂÀiÓxAÅ{§46Õkwpøâ ÔÔÅ/ €Éº& ja6ºÍáU`)@¼ çõ·XYÞª ¬%¬zˆ])J‹×XI­ Ú‡¼ÐnЪ=k{}tü¨1RÅÏìû ¥RÛ14,_âÄ€(èa:%©õ “K‡÷€×÷OÊ,\þÏÈû§å@Š–)$$4Pƒ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9FrŒåÊ3”g(ÎQœ£9FrŒåÊÊ»ÿc€Š–(1RÅ*X @ÅK©X‰ƒÑ™O3)æe<̧™”ó2žfSÌÊy™O3)æe<̧™”ó2žfSÌÊy™O3)æe<̧™”ó2žfSÌÊy™O3)æe<̧™”ó;Jé?_ûŒ©b¥*X©@Š–*P b¥Š”©b„ˆ´iéÚg\Lë‰q3®&uÄθ™×:âg\Lë‰q3®&uÄθ™×:âg\Lë‰q3®&uÄθ™×:âg\Lëˆ[–[X3N‰q3®&uÄθ™×:âg\Lë‰q3®&uÄθ™×:âg\Lë‰q3®&uÄθ™×:âg\Lë‰q3®%w °H_¿äŠ–.g_¶t9r«^ê~ˆ®†¦´àl,\οf0oHzÉ@\+Fªlv¹\¨ÙàÈ^/mk5ŽýgvCúÂ~øFÑóÙªVQ «ö‡)dš‚,‡[Íb€¡o¬+¼$$ "± ‘¸Ð7‡èNªRŽ?° T±s:ý˜)Žêz RTÐb" &EEà‘F\&¨a½÷RÅP‚= ]“B§t÷Ú Ð)@‡=-¨f6ˆï?º«XX5j•µ()‡HSá1ô žßøÀ1RÅÌëöb¢dY$+:ø #a¬éÅVÐTC` ðÅ™Þu~¡I0Q!Hlçê¦#ÚõèB4μ=~ 5¸ªè* +@©þÀ1RÅÌëôBUVöÍÈzAYl*Ò nL4M¨ :5ï~…ü4QÀ˜Þ 5'qd[x¸1{’ˆ‹Üœ 6)Xå… º(:1,I‰Õ €èœ4Ñ:*z_¹ÒÓ®[» ai°ƒA&71MPŒ™Ú!¨ì)Úk!´"—U+ºÂ}"ujèA ¾é@ b>b­LÖCh@–PªJáVª5ü›@Å"Ž@âAòƒZ ×5kþß`ÉlØœSÜ_HJ +}à'×ÁR¨ l„=©“Þ1Ðx+Z‚È0X2'`Šw€O¯ ¤#Ñ‹õÖTXëzAÂ!ˆWh«×_Ô²º¦«¬Jªºw’ºÞ¸C”@ÚÖ ÅT ;Ëý®ÞÃY-^“Ö2ŠÔ»ª'¤~‚²”°Åý¡Š¾ðÿ:,ô¤3±2 ˆÀ=•šÚ(ɱ€„"™v†Ié ‡¬€e,1GÆ[ˆ«NðÇŒ—O£¾.§ôÐ 0`Á}ñTX&.g_¤Zö}[qéËkH€ô嵤Œ¶AKõ"¤ÖÐP¤T8UÞaÊM½ÛÛÒýbÓ–Ö¢€¦ Í%Wÿ ’%X€ÂÆßëàa®ØÔCM¥‚jʺ²2H \z@ÍCVžˆO ”:ºm)”®¨‚§Neeã¨KL‰*ÜEÑAF¾ðD$YÝ%Ÿ0-ØSO¢ z Œ¢½dp-¨¸‹d[»Ã@‘5]"‚hƒ £_xôßDÔаḛ,\ο8à )ŸˆSaužµSD×Ê@!‰Ñ)øGWÒÑ ÄºAB@oñ*( ˜CX@’•SDÔ1ÝK• ,?•ûM>£§å˜.g_ˆ÷I@ïhXÈ´ ÿebQÔÁÈÖŠ0©ÑÅP/à8V!¢7‹H™¡eצt0^ Ýl3`õèT  ûºÂ"$P7ƒr¨° MH•Š38ž¥ÀÈ9Õ¢¢) ûÀz$šØfÀ'ëШ¬v„u-¶ä`8q§ÂµB×AÔF…è@A2ªƒëÚð×xÉšMÉÅZ IA$mû !&¥Ê²`Ò†¡mã¯Ò@ê¦æâ­KÁ,!^Òû£XD) §à JR•@Ð@ïP;*·€68#-–P–¶*@‰($£®Y³`‚§ItÞaô¬'¡Jú~M€1bæuøˆ“†öÙÒ Û%ÔfáŠz!„m WÖ À³úÛ¯ÀzØ ï´w·PSþÀÑjrºÁíP ÐㄟòÌPl¬+²°AÑ2‘ʺQ~°aÔ"]a‚!>²Œ&ªw.UVT$´8˜¡‡ü—Ê–¼æ±[‹¨"¨¤ÜÁFÁFÄŸIuP8zÌâ \< Lo'®ßhÐ"éP€•¸U Cô„³€ ¸"*â\¬ÝE„=ƒˆ5áÖý0ÜTÕNåÅÁ„£F IõLÝHPÄ(²º«pð1¼!™…B\5zÚÂia´:á¢;—äØ.g_³l±êàôìgi¨|šV é´²úàL‹ì¨Rzžó3Þf{ÌÏy™ï3=æg¼Ì÷™žó3Þf{ÌÏy™ï3=æg¼Ì÷™žó3Þf{ÌÏy™ï3=æg¼Ì÷™žó3Þf{ÌÏy™ï3=æg¼Ì÷™žó3Þf{ÌÏy™ï3=æg¼Ì÷™žó3Þf{ÌÏy™ï3=æg¼Ì÷™žó3Þf{ÌÏy™ï0œ–£³¿þ,P1b“G¢aƒBû¨0`Áƒ 0`Áƒ 0`Áƒ 5äà±\@ÿ̈±RÅŠ–,T±b™”Vg\Lë‰q3®&uÄθ™×:âg\Lë‰q3®&uÄθ™×:âg\Lë‰q3®&uÄθ™×:âg\@ܲÚÅuLë‰q3®&uÄθ™×:âg\Lë‰q3®&uÄθ™×:âg\Lë‰q3®&uÄθ™×:âg\Lë‰Q 1~ý¿%.gå1»þK.gÚïv¹ëð ÁV–?Õ_5òD'¸ø” {¾©(.ãzËìq»þK.gØÙL‘ îšÜ0ô7®ð÷ z¡¸¬ÐˆÈ˜±PÄÞÓwT#Õ\«L¨-ß 'ºý”yRw~”• “¤ Aš­m6–öŽ4€Þ-Ø TZ½âðÔaá‰!PH¬è¥kÞå>C7ûnÿ’Å‹ŸÙö&Áª¡P¼I+@k@‚5¼m­@5Ö‡€w=‡ÑÐoÓh4—}«B±Wê€NoM þŒŸuxHpa¢B@Oxº{º‹¨»¡X]ò"½'AÎUÞ%Ãîð%É­N®/K ëö8Ýÿ%‹?³è5x§+§Ã¤Š‹ÚvÒ ‡=´Ú|}´Ú| cJÄ}uÊbƒ7?æ  ó¤é\Ÿ°Æïù,X¹ýŸGÛâ[>¤•i®E¥[P†F(…Ô)´Á’¸€„$ÔTÄ–¨or®4 !Yiº’Th)µµýiOjKúw€õ­¨ÿaÆ‚°P÷ ÀÙ¤$uPÜÁ+‘5(­+*&ýe$ÅDü–8é]\m€O` k@7D DªYR#ÏÕcÿ™OÄY×°ƒTJë y©šÞꑪ°Ð4­ j¥Ä$ ’CVGgx0åD¡±Su~a7o¡ßíñJ™'õ2ž&SÄÊx™O)âeN°±jÕ•NŒ]tR›B•E}>£DÏ´y&¼ ¦ð´ê¿vjÌ\XÃqÀÜJý@@,ˆˆË­†%#Ô  DÑ3íHh¢ˆZ(pN·¬ë˜¸±ƒB’#¯÷ ÃÎÐ/¯Š­ 3„‘‰:Ò ½·0à…o¸”ì Œ3bð°ùXN¨ØáuÞÃZ ‹ð·«üõ"£†Ô4im -dÄ¥MB£Î€3•ÞéB@šÂ2}aÇŠ0£NÏ[ó£Ægv‚ ª©ÐkE¨ÒR@Á} „è  Ü»t 'Bô…'@³]Á¢¥Dêÿ"Æ@ÓÜQÂMFDzZ: ­ ÖPÀ€ÛIÕ=Ïô´s 8Búº[ˆhLˆÒ®³¢öFîH½~аˆõS o(ÏÛBkððÓáßò\þÏ‚pÈE?T& nã 3ªPS[®wÃÓðo„/ØšˆÅ<ÊPÙZÁØÃXƒÀ%O‰J }@÷•à,õ ü-ÕAV7­ww$²™$o DcWh ްG¶0Ö ðw¬ƒjBYkP(NFm>ÁÂ@úB0Ò‚Qb“™¹‡ÉÌÜÁœÀ‘û›Ò1ŽØw¬ƒjF»B.x `xD/-CB+CðÌý $* ß>à4”ìàì…¦‹V )¬mÑÀw¾á+~¦’¡Cn“ (X{¡Þ² ©f@¥”¥‘Äu‚=‘–…€tøcwü—?³ò˜Ýÿ%Ô@‚Ó±”ãÇ?÷nôç÷ß}÷ß}÷ßkóÏ<óÅ=÷ß}÷ß}÷ß^¸ÌzÛ­yó•¹ï¾¹ÿ½÷ß}÷ß}÷ÚüóÏ<ñóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÎ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ-0Ì0£ 0Æ<óÏ<óÏ<óÏ< ÂÁÁÌ0Ç|óÏ<óÏ<óÏ<óϽ2åÏ:LβóÏ<óÏ<óÏ8ö絞}÷ß<óÏ<óÏ<óÏ<óŸ}÷ß}÷Ûß§Ï<óÏ<óÏ<óÊý÷ß~ôï}ßÏ<óÏ<óÏ<óÏ<óÏ<óÏ~ûï¾ûï¾ûï´ûï¾ûï¾ûï¾÷Ï<óÏ<óÏ<óÏ<óÏ<óÏ<ñO}÷ß}÷ß}÷ß}÷ß}÷ß}÷ßóÏ<óÏ<óÏ<óÏ<óÏ<óÏTßLp]¢îßßüóÏ<óÏ<óÏ<óÏ<óÏ<óÏ÷Ïm7ÛMtß´Ç~0ßMtß.÷ÿ<óÏ<óÏ<óÏ<óÏ<óÏ<óÅ=÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}ãÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<àóÏ<óÏ<óß<óÏ<óÏ<ö<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ(÷ß}÷?½Ëù÷_}×ß}öŸ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÊ=÷ß}OÓr›"Dü÷ß}§Ï<óÏ<ò…<óÏ<óÏ<óÏ<óÏ<¢}¥ø A£ “½Xó]x?_móÏ7ûï»é-¶ûê<óÏ<óÏ<óÏ,#Ÿ~x§ŽµíÝûî=¤Ù®çÚ|ò =ö eÈEýöµ4óÏ<óÏ<óÏ(j’ÿY¹ùùpS„GÂÑLì<ñO}÷Ï wß}¯Ï<óÏ<óÏ<óÊ=ûß}÷ß}÷Ó½»ß}÷ß}§Ï<8ÓM4ÓM4Ó]óÏ<óÏ<óÏ<òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿîóÏ<óÏ<ñÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ó<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ó<óÏ<óÏ<ó¼óÏ<óÏ<óÏÿ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ+÷ßr×Ý|ûÞu×ÝzÛß}÷ß}[Ï<óÏ<óÏ<óÏ<óÏ<óÏ<óÊý÷Ó:"UÜEˉüµñl’÷ßVóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ò¿FÅ({ϯ¦k¾‹ÛŸdåÿj[Õ¼óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<¯Ú@ÒžÃs´o"€ÏBvÞõo<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ+÷ß}€¶äjýïéûTÂ$×ß}[Ï<óÏ<óÏ<óÏ<óÏ<óÏ<óÊý÷ßmüçµ6oeäþε×Ý÷ßVóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ò¿}÷ß}÷¨}À6v Æ=÷ß}÷Õ¼óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<¯ß}÷ß}µß^÷ß}öï}÷ß}õo<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ/óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<{Ï<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏÿÿÿÿÿÿÿßßÿÿüÿÿÿÿÿÿÿ[Ï<óÏ<óÏ<óÏ<óÏ<óÏ<÷ß}÷ß}÷ï°8K?}÷ß}÷ßTóÏ<óÏ<óÏ<óÏ<óÏ<óÏ=÷ßyÇí~—ªŽé¯µž}Çß}÷Õ<óÏ<óÏ<óÏ<óÏ<óÏ<óÇ}÷ß\ºBæDòæ‡ÎI0ίß}÷O<óÏ<óÏ<óÏ<óÏ<óÏ<óß»¿—8êýýVÎ4ï 3ô4åì½SÏ<óÏ<óÏ<óÏ<óÏ<óÏ<÷ßOöóLp¿Þrׯø¡Ìõó|òÏTóÏ<óÏ<óÏ<óÏ<óÏ<óÏ÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷×üóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ–{mÒ1ŒF"¼ÁˆÄb´«yR1ŒF"”AˆHQ#‰öÍÙÈd2 †C!Èd2 †C!Èd2 †C!Hìû›ÝÕ®æ÷³ Þ$Ö3%a¢Ôl®Hw³k¹½ì©Lýª-=¤P!‰ 9ø"ª±úÐ)= I7³ò2qÍ®æñF„ˆ´¨¤"¬#î 5.ÈDë±++’ rï§MÈŠNn)ƒ—úY’¯»¡ KrÙœŠ¨‘!´‹Íá8(Á=‰K{’ØN7j ¡-é8›‘91©A9’qt‰Ì’ÐÚ_nJ¢ þ Ü¹-w7„–“5 E_Á ÓCÉ¡ù"‹À¦•&GcШ(ÜB–ÿX†•.6´hº’‹h!7 Ìóxª¥%ªn%Uøø!ѶÂa­¾Zîot–&RK$–I$²XäI,—ѳ%’„‰}%’Éb‚}-w,»HÄb1ŒF#ˆÄb1Œ#ˆÄb1ŒF#ˆÄ"­¯ã µ®öç©IHÔ5Ví ™* Z 6Z½V»Ûž¤¥l|P9©a"¶?DJba@œ}þE&ãXðB¨ š{ <ËŸM®öçV¬r$‘N¬Jî%ZyP÷ðˆÐhªÈTŒ‘$šGú!£°ª‘ö¢‰¥¿ö$uVoÖס܉nKr[’%îH—¹/r[’Ü–þõÂ5è›V(h¿A2, !l'J:â „èmÜJ4:ô/Ò×¢÷[^š?’‹6ø„7Jü¢:­Ív7›PIJ¦ûxQ[þ?ð¹,ÿE”Ù–ÒåÉ+TµÅÆI´¾ÑpÝêA'ò-ËsBYÿ„(­ÿê—þ†žÄ!9ø Ýqàƒœ·>H‡úÛÿE_O‹Þ‰d²Idö7:&Õ½©qiG±kÐÜå£ 0£ 0£ 0£ 0£ 0£ ÷¥Èd2 †C!Èd2 †C!Èd2 ƒÏød6!± ˆlCb؆Ä6!± ˆlCb؆Ä6!± ˆlCb؆ÂåNêÿ¢HÔ8}"’$ÝÓWér”ÀÔt‚HÓWö5wWý ?”$µ¯A&T|ª¾ØˆQ¬y‹ìÊ4·I;þ„2qQ©Q„$ ”gôQKíÇ eÿ?èÚ«H)kHÒ¤({SÁ·ÆFç®®êÿDk•©Dô”ð6Ó=a²¸˜¥è9«Ò”À’Ѭè'v)I4Í’‰, ‰Ú’}5wWú4H£ ‘£sY®Ä(à’‚[ëDå.ˆZ¥ °.<`KO"ZßUD$VB!%ÓWuÓDëA¦¹N^ƒVçJ|¢›ˆJãIi; ¡Fꔢ5 %¤ð8BÜ1Š,ù!¸‰8^]ÕÿLºI“’´’ˆ&Ô lîUH¬`¥Õ$HÜ7nzMÍ}»«þÅÈ„›”µòAÆÚ‰|6Ø…É2Î ‹ÿÑÆ‘+¼í°áÿ£ïãØÕÝ_öæ½mËõ6ÚcWtÒjsUUUUUUmþedKÜÿÿý;ßÿ¿ÿ÷-¾â÷²²Ä¬¡j9/Âò+J>¬:KIbš7’©§‘7ý<ûV;‹Þ„]A6D5b]Ê¢²T”ÉQ°“dæ †G¦ÇqsÒ‘#û¨–çöP†"/ ÓU*XNŸpTÇkŠMÈ–o÷r4djš )Ü¥}¼ kY¿À—Gß!)‚•öðHŸ>›Åá)%«$uªT„J$mÂ¥··JZ¬²‰1H–¬N¦„†Â­&ÈK[HþFl’¹9¥=,wºÌZ PPÇ'- š©*‚Û`RFÊ(ç%òÑæ UÛ#¦69â¥ÍîpÖDÓ$¤Í.–;†Ê´a0˜L& „Âa0˜L& „Âa0˜L& „Âa0‰$¡@—uÿÿÿÿÿÿ¹ ÿ‚Ý"’æ?r%ÖÊŠ¦ÿQU˜¦¦H¤ÿ¦[ \yömwºeÓW n99‚_pJ"ÐoLN®6jö-w½ß‡ðFk_èFÛ RäI5[|‰(8ÜD”ÇÙ%+Q¢§?ÐÓE_º mS_èJR›Ž ÂÛÉ¡ÏP™º¡LmäXd½»®Q06WCt¥‰âI- ‘9º„&hJ$’­ Ò–J$lªÑ&¦ ‰LA8“OÝ`jq¤‰d­MQ–»®‡à„žFPI‰Uãõ¤¼‘·‚f–<™×ÀÑÔHœáxPž¤/ˆçð&“H:a ž> ¨k,%öòDÞdA~‰Î‚:|›¡k¹œ#€À`0 €À`0 €À`0 ä§ü=ÿÄ,!1aQqA‘¡±ð@Á 0ÑáñpP`ÿÚ?ÿêSª‘…òfɘ_&a|™…òfɘ_&a|™…òfɘ_&a|™…òfɘ_&a|™…òfɘ_&a|™…òfɘ_&a|™…òfɘ_&a|™…òfɘ_&a|™…òfɘ_&a|™…òfɘ_&a|™…òfɘ_&a|ŸçgÎ?ùŠÿŸ8þÊT£_¡3qŽ„¦¨Äá"‚œyaqµKLyÈ”ÑQ:U½{“¼RID ‡/=Ò(pžx(ݧ •%UÀNèÍÌëûÿ;>qýJƒË§©U0•a ¯%(·$JA¢*¨‚^ƒbiñ&ÚâT‰È‘L~ÅÍ=¤Ü7 ÃpÜ7 ÃpÜ7 ÃpÜ7 ÃpÜ7 ÃpÜ7 ÃpÜ7 ÃpÜ7 ÃpÜ7 ÃpÜ7 ÃpÜ7 ÁdÿÚêZG…%(…¡ A¤!h4„-Z &ߺ٠AÁK.;a Bè!hBÐ…¡Ö{£ÑÏGfI%V©v’n+ØnLyØINñM~Iª3¯›@ÓkÔm—ö<µuÿuŸžÞ—üÐâªãÜ¡ËÇßô6¥)q_¡4UÇØ¹¯àJ§Qì$oSÀ0 ”J0 m¤•Ö~ä!³À0 ¼ÀÀÜÀÀ0MÚ×Û'U# äÌ/“0¾LÂù3 äÌ/“0¾LÂù3 äÌ/“0¾LÂù3äÌ/“0¾LÂù3 äÌ/“0¾LÂù3 äÌ/“0¾LÂù3 äÆªµîlùÇÝ_÷6|ãúh“ ­!‰‘;Š\N³+D‰”~›þæÏœK!Q—]!È”79kNŒ’Õê+S®"ßI4%Å} Ôο¦ÿ¹³çJ©è7wÅ$5CQªΪ>ÙИáªDnÕŠAšQ%ÇÒßjS©&‘aÀy‡ ¢'Y±®-E ¢8Àé”¶´l¿îlùÄW9CMHÂZ×ÏÒÂD䉶ø™Ép71*€Ù5ÒB#nŸà‘4æÂZ¬ƒPü’$ÿæ~{Éd²Y,–K%’Éd²Y,–K%’Éd²Y,w?{gç·å /)#Dùô‰+ NS"e˜– ÜLŸ•ÿ{gç·äö•åd]iU½Æå\õDÎ^:šc—„§„ý“¬É´Óâ>” BÆÿ½³óÛÕi;wî,—ò6S ‹Ôj&µD¦ÖŸl•_1Â^D“£™6ÜYÓÊ m§ÀO<ú¥^xh44ÞŸÀÚ†ª8­ßÖÿàŠ4!¡ ZâZâZ´!¡ “oÝgç±*cѤî4sE¿/uÔ~†¦‚P£Ñ òHœþ‹~^錚6¹\®F×#k‘µÈÚämr6¹\®F×#k‘µÈÚämr6¹\®F×#k‘µÈÚämr ?줖š›Æñ¼oÆñ¼oÆñ¿Ìi¿sxÞ7ãÎMãxÞ7ãxÞ7á/OqÐ~˜£—Ãù ù>ÈSO›‰Ì&…QÔLD/™¨Ûi[?¡“«ëõ]øíî:ÁÑ·% §ap‹ ˆPP¥VMHŒI*Ä¢Pšvünüv÷âÝ«Wü ¬Tþ˜î>͸·"yJ¬"ò8ãý) öÒHlVóO’igé:"£ãNƒs¶ºgäP(Qnèb«ëý'7;k¦~IÊœ?¾ã  #Á¯ ¦'8hêIkйЇ €â ŒÄTƒކÒI¬ –$ƒ˜D\B ‘Áz]øíî:˜Jâ:a=:9LQP˜•:&K¯ÆGKAέÔPŒ†“¹$=';õÀ äê8*V,B. ¡jZ¨O„ b3"8µêCSQéwã·¸KP›2 ƒ È2 ƒ È2 ƒ È2 ƒ È2 ƒ È2 ƒ È2 ³Kÿ…´Þ7ãxÞ7ãxÞ7ãxÞ7ãxÞ7ãxÞ7ãxÞô÷=ïÒª†°8½§¤TºŸÀéiR8]8‚M¯žƒ®‘®?_¦ÿ¹ï~ñ‰™27ÐQQ${õ#2ÞªoÔ$™’ú[¥ª[ýú/ûž÷ábÝw$˜—ò7^/èiVõBJ^Ã$§AÅöœ>v ñòRuÛi¿›‰øºZÁuáN£I]&¥¯ÑÄÛ³$]î5J’ó^±)×èfÕ¿Âÿ¹ï"j'Y‰hCYA:©”¦IQ"d½«²Q’‰‰[„Bbj&8LhpÙ˜Bf…d¦åíiüH˜¦N‘˜LNS"i©EÿsÞ/2N ØW&Qa²õÞJ… â}ø†Ñ\QÄÌô(GÜJ¦ÜFíF_Y+ EdjÙ#\`š‡—ÔnÞª¾¨W³¨š5ïÚ •hÈÙÃ/¬”*ºˆÒ©ÜÁØÌf3ŒÆc1˜Ìf3ŒÆc1˜Ìf3ŒÆc1˜Ì)­Ç¿ÿÄ.!1AQaÁðq‘¡ 0@Pñ`±áÑp€ÿÚ?ÿø Õîé×2»äúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}WÞ»ÿŒýë³ú¾õßügï]ŸÕ÷®ÿ¹‹(HiQ/`‰È0<í¸-b€Öæî}ÐB9Í?ÒBJ½Ð6 5e»ñÒ~‚O’[ÇG^qHñBš#ªöüÂÊTKãXK .¯ä… ߈'ÍýϽvWÞ»þçï]ÿƒdØ¡Óß×x ¸q·íîš#T4e’ùZ hq¤FÏ5¸©J6o ]ïïŒXiþCå±Tw£é“JL (Ñ&qM2-Ì7»¿r¥+Wg|]´AÁ´7¯8Š òº!w.6G©Ù£!ÓX.QÛÓÅë'Ï/ëƒ`]ºûç‘&Þø/•˜ ×PùeÆÈõ;4d:kÊ;zx½dùåýpl ³·_|òäàÛ‡$WlîÙ/ÓØCðhüTù~ °d/›7|廢%eKpA&6 W{çp ‡Åf4YEå9öƒ4ìÎßܹ Æ$˜kÂå´»ÃÛ5U‚°™Zñ£mXe áBë[ÿ¸jâ‘´`Mºúc Ѻ=ÿó÷>õÙý_zïûš²–…øÞ;c>¶Há½f"ÁCHš—®©ku•«íIõB éJcµ[þ†è:°ÈèUØáφ%Á9ùcþ¬æ$è_ž$ÔH™«ˆÜ¯D۵Ȟm5R4D¸!›YC<1w¶d‘ÔØ“ï‘e¹ˆ&íÏ. ¯(k¤4Η³m‡dç{Ñ÷ÇS[’Ò„ïÁCaÞm¾§°3E´. “G.±yC]!¦t¸Õ›l;';Þ¾:šÜ–” ïy% L;Í·ÛÑRN2@Á7[•¿oÁXÙņëÏKŠ1…SD¸mQaGàx17)r\(AÞ¾ø:´aH;ø~ BãX7a2yÊ@  ¾Z¸åo7;·Yeñ‰ÐV¡:ˆQ·¦ w—Nª»m0UÖUœCx·ŒM<æ:üsï]ŸÕ÷®ÿÀG D~Nþx À€ËhTèšXk·é¸(œlG&À þÞ»?«ï]ÿÆ~õÙýUÆA.iyƒéþ3F4hÑ£F4hÑ£F4hÑ£F4hÑ£F4hÑ£F4hÑ£F4hÑ£F4hÑ£F4hÑ£F4hÑ£F4hÑ¢±";¿ú×yk9;7Çí¯^½zõëׯ^½zõëׯ^½zð’¤Hµ5¯ãÞ÷¾Øµ´Ärv•ß|u!X'J§‚³]²5…ËÓnºFyë•›EÓ4‘Ù÷Âb xm¨vï",îCa[5òȽvÀEpëFÜùÃÊ– ¥fØ÷þ”¢k{žNxºÅЈOwci ÜÖ'¡ ü2´þ˜ØÕ/\6È„Ði~ç-m1¥wß$з˜iã{Þîo€ò ]@¦M¯`b}Gð÷®ÎtZy3…iÚÑŸ6o’`".¶Õ¿·©R¥J•*T©R¥J•*T©R¥J•&8on²ÉæL‹‡[Z?F0YÏüñ‰ñ$üž÷Û¶˜ŽNһ+éTðVk¶È@D]“wÁn’R^Ÿ/9.\ô®AßÄÃ-ĬCÏtÑtç€xÜŸgíHૌmBä™hm„Ü=ÎÎtœâ7£_Ä=¼ ½ ÊpyÊ‘ÐHËÊejº½íÕ8pµBê€ûâͤ3DÞ½qPû©äóŽÐŠÉ+gÆDõ‚’t¤¨®ÔéýkÛzM{ã6®­Ð-«ç€¸ÖÐpθ~¬wÍÛÿ‡üÃ\ü>?ó:wJƒ¦ètáBYÃê —¨J=±6³ŠUž*þõÙÅo)>Œ­ƒwçgÐe¦šD°—öþŠHd¢ìè“ç‘¡Ä»”Ÿ)žõßòD¡`ÙN9R: cÃ3¹L­WW½º§u(¶Î+Æ(E-¨hßW¯±(Î ½„‹>‚`è‚#áöõsªv ¾sý¹wÞCÆqîÁg^sà°–„³§ãï]ŸÞz÷®ÿ¥êï]UOïø¨å-wÈþ€ý\Áü3Ô”-SFã¶y°¼Ø^l/6› Í…æÂóay°¼Ø^l/6› Í…æÂóay°¼Ø^l/6› -\4ýãÑVÊØ©‘wg› Í…æÂóay°¼Ø^l/6› Í…æÂóay°¼Ø^l/6› Í„–*ÄèAã³ÿ‰zê÷të™]ò}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¸Œk}IÜ÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×=ÓëžéõÏtúçº}sÝ>¹îŸ\÷O®{§×:=ÝzâÇ\?Oä}ë¿ù4¿½wÿ&—÷®ÿäÒþõßöu馭ã×G9DLT^­•¸y†è~aùd#t$ ›Âcùg`Ý4ißl––52 h/)‹Wi@§Yç-¹Ž¨Ù¿‰¬•h¥óºÖðJ_»*üp8ª‚ÔïˆÌEJ)°£‡œ(UK£[~˜Xl]š×ypàõ\à |0fÐP4eq.þ¯ðBþõßö~ïÉá°;­öÍ4]£¾K¯r}OKÝwySªÃkjynÿGàÑÖ“æa´^H¦ƒäaâ 5ÇËŒ? •î¼ÿã‹`ANæß#—¥úÛéì|3²ëD¾ `„ åf¿ þóÜøÿ‚÷®ÿ³­â¶˜õ¸7‹bÉNl™Rê²îˆÿÛO M-ŽPíàÃ|a2/@N~ÆâŒ†‰±Òà¹ëÑP&nìÏü+ÿ&Mò‡0†¸×[N¶Íï#>X’}É+Î,k!UÀ¬»W7•Eí€ì˜´Da„AÁÊE <š  è#Kþ_Þ»þÁ!vªü°ÿÅб]ðÖpcHó šJtÞjÉAÄk¬5s½ÆïãíHM;qÒs´ VÏ«%ô:mŸŒ›¿ô©1”Ù¤9w¯Ûóu_ž]§‰©<þ=6ÏŸÆMO‹ùzmŸ?ŒšŸ> hYzgœãÝ^¼þGý°+ƒàë/×ø²öF¼¥ uœŸœ0`Áƒ—Žh@¤J'"b¢lë»gÜàÅb™«|ªyCò¥aˆäÙ‰¼š6ó 8³Wy;}?ÿ¸ÚL:ÖrxsÝùà©íN)‹Áã3$l'Dë‚ÚbÝŸŽ^eÂÍXG>ÀQK€ vé–­7£|^t oͦQ¶¯~–SŒ£°oˆBc%ª"¨N›9Ä’Ü¡¨zŽ2{W)R©·¿ p‰°uïíÇý€CÞ˜1ݦJäïþ™#U*Ù±O¥Æ>¹E#ÑÍ.䘠¤6¯.+`*t­ß´–³?!òöÒ:žÜ ¥vˆÝßoˆX7’ ø²»-ª¯B•—‡6ꔨÍrk㊊[§(Mï¦W/Œ‰"§y2Õg• ~>¸‹áB)¤ ˆóÓ zFKˆì9ã¢p4.±O¾|†3Åxdéî`Gq±êxb‚ô-)ÉãSñD_šcB *ƒB8 ¶{×nRÑÀ²ÌwÕΟ^ý²{W)R©·¿…ƺì ÉÜë¬ü儇â®6¡cÍÚE ©>Nõ>”#Aö—/X៵ 0`Áƒ 0`Áƒ 0cŽ3wÄ”P6œþáû‰¾cÉ˵8Âï¶_¸ç½wür¶˜Ž–»íóª3µ!Å‘3µœ$¤tU“ž:ÉŒÞÀ„(ž?î 6@âªÃÁgË}W‡Y’Þ:É”­ÏSKl4:c“øD=E9Ôù`ïƒmB׎˜†1@im´½>XÙH)¡«ÁdÈYkçJ:uðw€WLu?_,ãÓ¶¼Øt#½âÑeJ2®µN,˜qªÃ–úŸÑA ›ÑNñ÷׆ÆÈôãÛߌpTûfMöÓ´Ñ[K®ŸÞÍÒAR¾q+æêv¥³ž¶aÛ!AãÕÐy§4ÐüâÞt<ë¡…Þ 0Ò1ðÉóÂ(' Å]\¶ór»©Òå$–#P4µÙÓ $úòºGß‘VU º¡¾q®ÝŒ·¥ï{ ÀôGŸîVÓÁÒÓ}óz¹±¼©nÌϧ¶ÖN=½øÎþJü*²½]´Öˆ6·ÆkR6o*[ s2„`,ãxnÍ›¤†%<ãOªðë2[ÇY1§Õxu™-㬘qªÃ–úŸÒ˜dX[Åç$%“V/oÈ]5Y8O¥÷cÞ =A Á›ë4ü×½wü“x*pÕãú’ xG©ú;ÒZñN—ÏâS/“ÚøÒ¥—x¨}áÅÊœ>?F=‚V|à‰Fâ¡Ëø*£BË{ ½à¡²Àê½'óeÍ?5ï]ÿRÏlÊ\Z„C°Ó~pnBÀ j®‡œ|Å$Œæ§l;(ä’‡[p®6…უÕ`ïrŸ<7–öZv:“4@ÉRœ3%͇x+Ë㨠˜ãz%¡QÐwK@<#³<¢4Û僣E rƒÎ0\+ ×…=w»×Yšˆ¨¬8ÈœÆì¸“ñͨ>>§yg?ÉïDÑõÀ˜rëx ç k‚0¨(àaÞtwyË#,°Û—N²ýyE&ÝÙ‰N¤ñ-ŒQ\DÝFé9Ä[Õ§z`ÊdÁDU DµòÀ1cÄ9øb÷lz.ÐJ=;b>d•v˜˜M½«¥ˆïåŠø’%N0 ±È{F“ F. r¦¬ î±F¸6ñòÈÝÔ¸-—¬zçå8 WÇŒ×M›¨âëI1ªà'VŽX$ ªjP ߺÒRÂäx0À†[Âtc¹›tŠrˆ²pæª.’®÷Y8ºÁe‡úþP¹§æ½ë¿ãMJG#!Í{- ŽDçå…]Q&A·ŒÓã‘Ót¼kÆB‚XP¡^÷í–ß—€Ò.°F½qld;ÇüÍgwP F©ø&& p"é˜šÝ ø2üðÇÕmuóÈ ´ƒM“Îm{ár\÷>x&(„¡P¯Âß–;^ÝÔ¬u½·‘Õ“û³Þûaºc‚ßèÏ“‡¤Šû½¯ªäÇE&ð&%‹`j§2ìò”PÀ¼ºu‡w_\ÉEgát§’Ë€¥'Àó´êuÉçðG#zq>xý{(&PÕëšújòA iÛoŒ41$½|±`™¢HKw<ùÍ4¤j¡ ÝÞµÎË à’·YŠýÖÞšÞQ;Ž{÷~)!Pª 0XBU8ë„·\KlÁ uìoŒ|^WÈ^G§‰„&C  !ÚËú‰ñÀ?”.iù¯zïù*)EØ È³w"fC‚q3h8@/Ó þë‹‹Õ#ÜÎøÀøyÉzÏ{.TïIkÌz_S½%¯1é|gtr)øS#Sa©!S˜qø/zçê€\°Óq|×neé–n/ší̽1ˆ#¤qc!äa¼U¨ip‰¤ñ†Æ, Ãç4ì€tö]ßÁÉ(™ÉÞ¿c@š}ÅãO¼:¹S—ÎråÕÊÎ_8ý럨r§zK^cÒøü#Qa³K|x™¿ÍgC*W Âø0q×Tå XÐ@ùNá‡Ø1UZ¦IÜMo –8GDé3ïˆ57“°Hè¯,ÎTQóLY^”,'C—¦m ´™+UUþT¹§æ½ë¿ù4¹§æ½ë¿ù4¹§æŠ¶VÅL‹»<Ø^l/6› Í…æÂóay°¼Ø^l/6› Í…æÂóay°¼Ø^l/6› Í…æÂóay°¼ØVÕ % ±ažl/6› Í…æÂóay°¼Ø^l/6› Í…æÂóay°¼Ø^l/6› Í…æÂóay°¼Ø^l/6Õ¬ù­~?ûÙ§æ½~kѧû5Ð2°¤(¢óûPÁƒ 0`Áƒ 0`Áƒt#(!3.çùo£Oßíâ‘ ¦Ê/Á 0`Áƒ 0`Áƒ 0`Áƒ 0`ÁƒzeR¤„Rõû™§ïå~þQ§÷`ˆ/\ÿTÏê™ýS?ªgõLþ©ŸÕ3ú¦TÏê™ýS?ªgõLþ©ŸÕ3ú¦TÏê™ýS?ªgõLÔÓc?ªgõLþ©ŸÕ3ú¦TÏê™ýS?ªgõLþ©ŸÕ3ú¦TÏê™ýS?ªgõLþ©ŸÕ3ú¦-t¿Í2?÷®ÿäÞ’?÷®ÿäÞ’?÷®ÿ§÷®üª_®Ó¨“£‡`E¶×cŒà”§VkyÈ$ ˜#+t®Ÿ|K´Ìv‹m¾29Ó¨%N® ØHÀ9C¯|{LZ¡:WW#=í7²–\º|ƒÚkOýÅÜ!n Þý°9°ÀUk£4ì÷#£ÕÅߌåx‚°Se¯Œ±"äk¹#ÄÆÌˆ«€9rñ  ÕߌX§Yº®çˇ "CÁ µvæEA¢óyžf(ü¤£Oýë¿éýë¿ðl¬³”$>ßL¯†› ÷‹U3pô‰ˆ­sDÞ~òaçõ—h¼æƒË”\á žL"6—ßµÍÞÛû ÿ†EQ!Õ´ù[õÄ”p *ÏšcøJlà‘ñ·Æ¤Cªo# óÃpÊqÈ`yãx‰ô«¤”öxÄB?*ü𡣈Ù"ré9¸kÒuÃMlÔýïMŒ‘†ëOÃf'.Ž“þÓü9§þõßôöÍ5%DJxÈðBq»Ðsq8RTBG£´ÁU¡!B"†»¸†€Ä& `ô:äµL޽Ž]åà‚È#yíÆ§‡&QÓnÁÄÁIÑ&P3±«À“!-¹ ¨éß.¸ÀÀõDMxžr`7«Ûôã匊ÑSbE_L-Ó[b2ð,9xÎ/Òèà2â GŠgË%˜ÒC€®ÍâÅ×i|Ìã1·çÿLC÷½<™š³“°‘Nª#¿…~"-›9s±Ñ¿ÃÞ»þZš˜ºtÒŸ< Œ›¹² ^*h£×¶:•å~kŽ£ïæ^çGNÙã¬çÑoàSî¼:ŲñÒÌÙÂlP^w¼Ó(ÝžW "P ÁæãÅDKµ³>F~މT<­òvÎ"„ ðLzR@œšëœ­ðÀù¸ eˆÔÎÿìÂà‚Ûnò½³€øƒo|(~®"Ü)ÊíâyÄžbBð›ÞsbæáôÝñu:¤{?„cCìò¸/J ¤ pwƒ§Æ9¾Í'W¼pPüÌÛˆ’—Ú[ú½¾¢ÀbÑe~¿©›6lÙ³fÍ›6aàJ°=»M›6lÙ³fÍ›0W =yû¡§÷¤.&ðŠVÁÒo'1PD½‡è㾑[«rêüIú Y¿¡¢W’íÁ-ËO׎L³X¼£±>$ÉwT,’O–{¿?ÁÙê÷6ÿ¼ƒe ÒÔ'kÓ&[›¥PéËi)¦„g³ "…À­^9ûÛÒ_¿ïþ8hñÝïî\6À;*lu‹¢³ˆÛ«“¹‹ÍÀ¼ßBŒêáØACZ’—hÎxëçð·Ûáu@ðf¤A°ÃÔÊÌ”rîÖ‰Û®P`\ I°Ù-ûgÜj&>©C/rúËŒ˜^…q)¨–*rG¢1بÑWWÆæ€Á5ò1ƒbWÒy¼Ÿùg#™(þZ.]i›}{|ÿ!B…>Ÿ>ÈYe‡ãï]ÿ=©(•z2Jj~l˜‚×e9.!õ%r¯C à‰Ðwœ1Ž1hà^_1;®Êr\`€…_8"Q£—°Hí‡,üþõÙýѧâp(l:Z»— 3Þ»þoM±çó—SàçÙ¬Pp§nùÓêzhp§nùÙZçÜ_”˜ÈÅ %äV˜c&À«Õ_*®{RgÊLâe<†ƒ—E×8Ý$ˆá ¦ MQ°‘-Ôœ[’E±^p,t3ˆŠ÷ç=ý•+~:Ä´šˆ£yÛ_§ÈŽ“ÆL¶ˆr@8^øŠ|Ãr4Û8úVœ<¾ÙþÜ‚;‰o?ƒ è7nÅã鋌—®o„;g]vøž¡ó—8ÁvHŠÒ=®– @¯[€Ð Ø[R9 a‹”ÛoA ÷˜(JÇ `‡¹iNp Xl§AÆaìÜŸ,‰‡í€ú]=[¾ ‘ùŒù‡†v®ÏÁp q;üÿzïÀ3‹ašëÇ'¤€ªqɃ$ \Däó‡…DÄD»wã<ïa„ÁKzŸaÝÆ ¦r©ÑlføÂšMj´|PÂD9áüþõÙÍ2ê|OÈÈ[4}gb¾†‚hp(?¹4ü×½wü&ÆŸ…Hºßè+X 5»¿gó¨ °0.#«ˆ­MU¼åxÓS»9DÁI£J»ú~@6vy?Öiî€**us¢,S wº·Xîéè^D‹¯Êm1‚™.ý-×èt06+"¨a’¡Ç*èÉ®î7OSþõ)ò1PRVïSùýë¿ðm8‹fÀjºý° t£ÖÍ;,œ›Ïϳ¢’d Á¡¡0W¢}%}}ð :˓ҚÉÄK6:)¥=?½vqôZ—¼5û&B‹Á£ø“è°´¦üF-B‰auû“OÍ{×|½ð°Š•»+Ûû/yÖ+“ØÛòÊÐúccT½sk° :!j®¹Æ#™¸CHûò±$oÆmjö0ÕÁÃ¥²‘$k³Kõ½¢pUï€!4T©;â6Á\d(×ö”ÞüÌÕkT@VÖÌa°G pQ´#ÏoÀbT§ ô?±'ÑÀvà'ß9a iµñ„©)ÁFÐ=°K±èØ!8ÚâÌx‹Pzë¦- Ðw_£GLѺH`HÇÎo€ò ]@¦;"TƒaÇPÞ©‰Œ+‡E9þÏ`€Nà½é6%‘«È•ùàÓTÄazÎ1‚úsªšOŽVmLÒGgß:á¼é>Ç= !dˆTÚSoLŽõ¾ƒ úå„ Ö߇?¾g evðtËÍ $õ-§ýã[‡2Wï‘Ò^¹Õ‘Cˆ@Ôoò†ˆ&ûõ¾2 zr˜Ä'(§gô:{×ÏCê äN¦ ÒŒ¤OÛ'‚-ÌhØÜéq2 @Œy'‰°€f¦G°p/œ˜‚GEyfLCBÆœ7ø‘OI“äåðE™­:½gç÷®Ïï%~kÞ»äðN•”Ú½½”Ç ¥P<8î ›·ÿù‚‘ìŒ ‡mY™#êøûA·@¥ ‰Æó‹èÎ0ŽQ~Y20¥#:7ÓÏǢ莻錘ÁàWQÐè/8ƒÅ¯`'®h<©s—ÀœÿÌ,xxnÛ:¯ ½ Êpyü'—b•fÛ{øŒàÔH¾ò£í®ÒBr¯ÁèX6SƒÎ¨5¥\ˆtËŸ´Ë®#ßkáa_G=ë¿!Ô/P”{cWXqʵмåÅqdv¬@¶ ·¿ƒO{õÇâ% uzÜ)ÒšGD÷Å›H&f‰½záF¢½ìm™·ð"0™îŸL÷O¦{§Ó=ÓéžéôÏtúgº}3Ý>™îŸL÷O¦{§Ó=ÓéžéôÏtúgº}3Ý>˜1ä›B—¾{§Ó=ÓéžéôÏtúgº}3Ý>™îŸL÷O¦{§Ó=ÓéžéôÏtúgº}3Ý>™îŸL÷O¦{§Ó=ÓéžéôÏtúgº}3¡ÝÓ®,7Ëõÿðä©FŸš*Q§æŸÊ”iù©"M ¬Ehö?8`Áƒ 2pN¥ qv?ÉeJ4ü×`s·ÈÏ,>xŒB‡¹ÑÀòIR?4 ˆ ކZ'1¯ûŸá²¥~kqã916iýÍëׯ^½zõëׯ^½zõëׯ^½zðĪ6²oä?qzõëׯ^½zõëׯ^½zõëׯ^ô‡òd©FŸšmï]Ÿç%J4üÓccO†R-Mk ƆÏ߬ëŽ'€ÑN‹Ûò(hm³Î°’‚]ÏÂ1ÍPáÓã‡à-ĨþP"j…ðq…î<–“¨y>øô—‚øQw‰v™ŽÑm·Çä6˜ÁL—~–ëðÓÝUTêä‹(Œ^¦3 €q,[l;u?aï]Ÿç%J4üÓo{í‹[LG'i]÷ÇR‚tªx+5Û!É6 D@#xà†×g–BË_PÑ¿‹¼”¾*ÃFþ.òO¸6”ÛÓ!$±:‰´¦Þ˜BbÑçDÃ鄆BˆƒÉ¼ÙOˆr‹Ë ‹7üg²0A󸮥Ão´›Üñ›ßç`<ƒP)‰Xj*VÊ9ÂБJY­|±²Óš¤îüòZøÒ†ü]àü `ђͽò‰©"óÐ:lë’XDÚSoL»7d¨Ñ«VåI˜8=¹óÆ,Ù¾%Pð'ß 5Û¼…?BüðƒF41µ¨>øN!ô5IÓÍNù ðš:\l›a;ãŒ*. äq{áSD‰\# =øzX `(Ž»¼j˜ƒ Ì/YÆWI@#£µÒ†ÍÌŒÍ'xN~›Þ»?ÎJ”iù¦Â аl§œ©Œ±á™Ü¦V««ÞÝS‡-ø˜¯VäŸ>ÙÎ+è£~NÅxyÂ6ü=„ç8PäPL]IÆ•`» ±À^wŒÉ§A÷äÌ\GBÝ÷ÇhnO˜íÅ0λÏ,}SÃí¼­}Î4C¨6^¡(öË&ù·FùpÎà”‘íÒÍü?hnO˜íÅ0Q‡äìW‡œBæ9üᘆ5è×/aäÀSµð¯®h`ð+ERo–)Ê8…eÖ#½4!‹yc¶{AUZYÑéôÐëã,pŒ²Ãn]:À Ô‰§wf"–€xGf MQƒdݽÌê¿<:OvøÍ& „;¹¥¨ P0 þOzìÿ3*Q§æ›{¿Þ=<{ßl p婿[Œ%“gÂö?^þsÉ"P>Oà’Š…PI€r©À\áõð6™ÔES€8Ö8¾K)\!Ƶ§ÅÏû8UÖ_ÔOŽ!‰²¤Ê:½rމ\G©Y|dZC¶Ûã+÷äFêŸ~ø¬í)>œï!®²$xûabx¢ÍšÓ5¿?…€ àÁoÍ"4†\m¢”¸^¿Ö(ßB ¥‡Yrn "ŠÎ³×!D(p Àí^S%\ó>¼÷>xC,! ¼ˆôÇ$®f@‘1ëÑ~^3U_Ć”óXo¾Ý}sx.ªÛ×Ï 0ZÒ 6O9UÖÀ+ñ¦P~suM]}Ìp°¢«oýàUHªtí¾ÿ“Þ»?ÌÊ”iù¦Ò[n/ší̽0Â8Ńx|á„q‹ðùɉØ$tW–`½g½—ð˜‚GEyf Ì#Ä„ƒ·~sïˆ57–n/ší̽3äÈáLŽðvÐñ„RdyšÑ\i2Vª4«ønñYÅø8&XL%ÝŽ—sqõA.BI¬~õÏÔ¸€õ3‚¾0>‘ì4£ç&(RlÓ®™áÊß çXÍ8úW® KÇ#@Q<™Ç×ñI !ŽpóûÕX í/ë†*hüUJ¢ÊXÆïØ{•jSkÕ?ßáÁÞ¿ âÀ@S’èÛ®¦ÒÛøt‘q«’M²1õ1U*‹)c¼]ÄTœ¡ÔÉý0Åö//à ë¢ psÖ$EAÝg1Ó¡Û ÅøâAŽ/ž£‚ÐBþ¹¿¬Np9oÎ]õ¶‚л&ïè{×gùéR?4ØIü¬¸êëîà¹Ä`g/¡ŸggŠ÷­ßüÂ<蛯;÷Îø`uàÂQ  ÇuRùqòÀs¿Ù§OL½E«"J¢h~Ø×ü „÷^¸.”Y¬ï7ÎPW£Â´<ãæ@Dxï®®]¢•s{üìçbê1(4D÷Úµ,Þ5‰–y'¯Ë`€Nà½ëZ±±8V]£›u¦TJšÛ× FÅîJ§º\¬Ú.™¤ŽÏ¾u‡CyÒ}ŽzþBÉ:©´¦Þ™ë}@õˬ1¿2|Î:Êíàé—šIê[OûÆ·d®;ß#¤½rú—æö|ƹë“S <,ºìëúþõÙÿ•(ÓóM½ë¿!Ô/P”{`]Zô÷¡V\¸£."€ó¬ŽÕˆÁv÷ð!U׈"üÃh¾Óìξî2&1 ü´bͤ3DÞ½p£Q^ö6ÌÛø‘3pëB+¥ó–`K†óR¢A®r=(t€³ªñT"ÔÉÃ).¢¸7ÓÒwÉF¥rèÖÇœrmÑÝû\u'Ž«O†Ÿ_×÷®Ïø,©FŸšmã8÷`³¯9ðXKBYÓñÞ$,{ÌUŒ0@?QzðÒß# ° ëû×güšT£OÍ6÷®Ïò²¥~jÔ‚©Ôˆ/lóay°¼Ø^l/6› Í…æÂóay°¼Ø^l/6› Í…æÂóay°¼Ø^l/6› Í…æÂóay°¼Ø^l/6› Í…æÂóay°¼Ø^l/6› Í…æÂóay°¼Ø^l/6› Í…æÂKW ?ýŽ•(ÓóR¥~jT£OÍJ”iù©R?Ø‹;$*iD~¾©R¥J•*T©R¥J•*T©R¥J•*T©R¥J6®«Ùi–<öýÇ*Q§æŸÊ”iù§ò¥~iü©FŸš*Q§æ”Œ–Phz¯ÝÎ:téÓ§N:téÓ§N:téÓ§NœC<ÉmW÷s§N:téÓ§N:téÓ§N:téÓ§**Шè^§ò¥~k‹öß!¶âù¦œË×ñè¾È.‚4-,»üjw¤‘ægŒ˜‚×e9/ìýë¿òR?5Åû?•|è ]FŸ,3í„C S{¹Óêúèr~ÙÂ%¯¿=ý•!>Æñ®-o‰5~ðê*B—ÕVî#S`mø«¼@_¢A7949fÕEÒCuÞëxe„f“eÕ”áñ†b×¢C\¼I†X^ F. r¦H_‡ XÈS‘.ºåýŸ½wþC*Q§æ¸¿gïž: :£×£ÿÔ#nxääyR€AÇ}\ûoûdE¾Ü%çúÆp¤#“¼]ad]žW D ÝUëÓç€âçýœ*€‡k/ê'Ç ÝJh!¿ß– F94\¼-à.Š3 )+ Ñ~žpÆXW•ºÌ*+R¡ü¿h—½wþC*Q§æ¸¿gë{IjyVmÂÀÑ:WåúàN„¥¥&÷¼Ñ×JqWneéŸmêˆ)ЧÞ\©Ëç7û-o©0¤È ó5¢¸2Òd­TiWŠl¤]Ýñ‚•…zâ¼r?@Û?9r§zK^cÒøÉ‰Ø$tW–~ÏÞ»ÿ!•(Óó\_£ïÀJŠêiÙ¾0y¦>ÌI-Ó›!9-çyÁŸ |A¸£8„umêÞmÄIKí-ü¦ï‹«ÑkÝÎ&¨@üÌHÈAÒÈ2ô‡làÆ> Üé"ãW$›dcê`©5aÆ7{ÀT\H¨¶ö˜hþˆŸÍöi8ú¸T©P$9oOƒC^ýØõ¼LZbÄDúg<1ø ƒL`Üå{aŒq‹GòøË)ð£6òSžp!†×êá-+`#Ôw›S%Ÿø2K¨›Jmé‚ÐBþ¸`‚¦ÁÅ…xÎTTQò@áµú¸Á`D¤9oyˆ Âo¥ï]ÿ‰Ê”i :R =^_ÈP¡D ýå(tÒ++ø(|¹À\$¥·tø~—»ñÅe&Lb j—hÎxëç%—s­‘ùcį¤óy>+òÏG2QÊðù6;#ÌŸ|3ÚDÐéMãˆUCY jJ]£9㯜G T54^ùã:tAB €í×þá@4xùwÏ¿!¯ƒså€tø¢1بÑWWÆiLɲè&©®07ñçsòW§®çmšSÁÇœY¨Öi§#¾1˜J€¼tÃÐ/È;vÅ£®cQt#®žSÎBfPshyÆ´®4W]3V bQiÈž˜·ND_`ºQf°;¼ß9A^ Ðó”E0‰kþ³}ܨJl|ó™…ÔÚq­+Ä×CŒ¬É@g.íh±ä(NV?FÄܺ&Ÿ^ÿ/Ð(P¡B… ýº˜¡?·¯ñâý/ö¤&Ï”™þÜ‚;‰o9þÜ‚;‰o8Þ•Š·w~Ãl=›“å‘0ý°0±@^PzLsF (8ÐxÎAü4«NUã?ÛGq-ç Ï[ƒŒÙõ¨Ò tÁ‹|Æ+²^ø1©-x‰ÑŸwàC܇´§9!Saá,óÏ­úu~n®~|jä\`ãb5¨kŽ7rƒ¯Ÿù‹pÁr·!4ݾîÜáÒê{$<ºÚÉÆññ³RDE:c\U@¾Qâüð8;mݦCX—°êë|äÔW!ÊêO7AÖ8k‡ÎÖ pÀvÁëE!±æW!ÂÍáu9¾Tñp8;mݦC:ë·Äõœ¹ðXKBYÓô}ë¿òFq~wtôgÔ×âliðXT‹­þq»LÇh¶Ûãò¢‰DÍò{8¿ðq<ŽÈuNÿ¤ PVyÖ)—~†ã¸—5VR•ûb]¦c´[mñˆvÀ§‘œ·ž0 p—òˆK!á~¢èþozïü†Q£\_hƆ6µß ¼’ØÃ6Qø3ñÜW  °¦¨£u—#­c/„4ˆý¿¾R·e{k*¦p´øúc!f¼wCzóÿ00“)MA8E}¨{1â,AAë®™FЧB[=ÌRìÝCª=±KtÏ \náÒÀ…@GGiòʼn#~3kW±†®-”ˆ¹&<êCœ,,Z& œ"¾Ô=˜ñ  õ×L»7d¨Ñ«Vã2¼Éf‘õúc‰ŠA8E”›ïøp@ëÀ:ß‚ŠTA™^„}÷5;ä/À:hép<(Š|eÂt „.¬*뙌G2-p†‘÷åçUÎîë·x1ªS†úÞºŽ-1ï8þ°sA.š n¼a0`1K‘é…µgpšïÀ% WNïMe ÛB™kÌîï=ßžBT!  "Í:çC(Šmh<²fñÅof·…ÀPÞ€h!¥Þ<ê¹ÃÝÀvïÆ<š"h+]뜭?¦65K×3c`8÷ÜÈ'è(D3_½wþC(Ñ®/Çõšr˜YpÙâipDìuÁ$|‡Ì4æÞ˜…¨D%ðã.óÕ­Ÿà+(+µzÿwì ‘àñš†(]åð/ó5AȬº qýצð~]qáì"püB’Ó§7Ól†ÔÚ…ë|°Ø>Jp{‰ï»¼´O\Km–ÌÝ–‚v'ÃTXßEtá™T 'A{'LAXt@ãû¹û@|ºâ=öT>êAy<àñ1¶¢ò"ÇŒìS+DÔïn¡Áø1§lÏÈ|ýÒý=j6qí¸ÞôrãxXWÑÆ†PNzË™#êøûU°ê^O9<»«6Û߯3 ºˆ ßyÆAIE¥Ã)ÏF°&϶¡‡¾øû5Âà ºý1]—– )ÜóŽÐÜŸ1Û‹:awÉ—¢ñ¼.ä{×NpÔªW°Þ,ÜÅ¥µ êõö%À°‘gðê^O8­uï#Æôˆ»ãÁsvÿáÿ1î99"z;qþÃ)RÝ–Ÿ?ÇÞ»ÿ!”h×ìÿìÖ(8S·|Ý–ú}Wï—HæêO?‘@À5#³¯ŽPm¡Ì~ËÞ»ÿ!”hЂcÁ…CGUúÿ,$H‘"D‰$H‘"D‰$H‘"D‰$H‘"D‰$H‘"D‰$H‘"D‰$H‘"G’TäÎ__þ‘(Ñ©F@ UªŽ‡îŠ(P¡B… (P¡B… (P¡B… Z…ªk[ÇSÿ̆?4iù£OÍYjP4o”ýÔéÓ§N:téÓ§N:téÓ§N:tæâHè›lú?º:téÓ§N:téÓ§N:téÓ§N2ÁE° t/.;òÓF›4i·Wxè¢9‡oÁ¬j!³´w;õÆN-»\U,×Û¡¼ÿ1,ZbP,ñ¿ÇÚš>vâ«sQÍ­ÍÿŠ4i·#œ£Ñó‘þÎd:ö?å‹iT!"Îá¶7'Ì4âι¿0)ž2daHRvo®8uóÉp1öã|·ò£ç—™8ù ™òÏá“§¹aÆÄk©áŠ Ð´l§'Œâí t›¬çX¥:v!~cQ﹌U.sÛ7Á Yä3%›Py‰£8Š–øËáiWüP¹£MŽ»‚¨ZÃE~Yuµ}¹Ðg3»<81~Þrª7ÊòЛ˜ Á ›Iy†V^Æp»zLy\5vKxëÆSK±ÒÒo¾mZZlGCÜ4Ç>žÛY8ö÷ã8gú+ðªÊõvÐ[Z tÚß+i‰àéi¾ù+i‰àéi¾ù}Ú#@±—?ítTAÎÃéš`)CÉ2w5·v[fì™iuŠ*MŠpÿ…—4i²š *yLL#^|rd¶MwÛ„¦"èÓ®['=-üQti×-“ž–þ‚ÜÇTlßÄ×ëˆÆ=E—ñµº•Tc¤L„¶äv¡£\;ãü4¹£M’°ÑùE êÙ¬`“9±l“Æ ÊŸÁ¡z ^òoQÍÄŽFñ†á0ŠRì$ØL‡ý:…›m‹ÄÃKKDà õlלΩî^†%:õn3ŠS¾ =•tlÀà¢îʯ+qÎI|ªîo物Àù†ùÔ1MÊ…Q°ÌNÐÄ@ò…_o¶Si­MUÐç =°ð‡¹’Ø Ó´Û]ý­PC*j‘zᕆèëß¡j!–>>qmåïGnüñ…F+·Ã†¹-íi"dq̯\j ÍQ„Àg@¼Ú¸z–™®RìG¦Y«Ðrö‹¬kCì»âa«j^ÿL*1]¾l5À¡ScÁjyÍom¡Gî~ü¹¥÷f’j«J½wR¥J•*T©R¥J•*T©R¥J•*T©R¦óÔ[M/ê%cÑ…ø±ëÜÃF˜*ëzõÍŠ< É—Ì—ÎCk£`7,úàB‘H9³˜oñvÅž(°×`“-yžZ´;²Ÿ\÷¾æ B:@¿Ùøàò†®dmT+¹ìÁø 䕾øp“­ë½ÏG+¾æÌAØéþ±V2“n¥sã<­8 vvÄòÃ!`1˜®9ÌIÌ5ßì}LíYŠÉÀ®!mèâC^€y]N= …\‚[I­;˜Ô‘÷É¡L ›°»ÿÜø¤³´vN¿ó ª4÷|äÅÛ‚ð¼ îOrÈTæì£CÆ$5è•ÔèóÐÏhïýD$¹i!Ÿ…Br2h‰B;¿àÍ­Èm^£_âEÛx¯+ð\M[¢~ AÅ|Å`Ê’›:Ì=–|K€¶”4ËòüP¨w@ÃãÊJBYì<çшÛòÿ¶nA9{/ËÝÜP;Ä›ñçÍT3ç‡/*è™vó’öoË€…(¤ùS P¨wfPZÀ­9¡Óœ]É@À•“æ˜MCB}“Ÿ–3»¸ wˆ3°ŠMtv¸á"+ÈìùäʽB/ÁÆ>¹U&«Õ›¸ü«…6pøƒ #‰¡Üלâ3m‚ R¤]†píÖ^ƒt'ÌIòcœY"’×k:ãpÄ.ù˜>Ÿ+ÃÙ9Ž'³«4ò×â)F”î¿,ë©°ü«†… ‚–´égЭMGGKç*7‰"e:Ï8MÐÞ„“ë—:Ðì„‹wŠ.ÂOL'n° 9Wž†Pª…ÞÇ8"²E$7®Öuİ’-6ýð¤W¶¿í–/°ò^Àmùa+ûð þX»g#YØçLˆMQÐâ·k:ö˜ë¿"w¶ù‰[ÉÖÃ|Y—CL7ù]xü¡)/!>Ùþ°3ˆ,~ø|’ðNO›­ÀDöH]?&H˜G¬Ùç9‘3®]zñÛjද8 / Öyƒ óTå ¿Ó ¡Px‘ÐaF4'TD%7ç( ì†ØÓä~“6Û Béù2DÂ=fÈ79ÃÚ ‚,ú„7DÓ@¿£,«y_÷žõÛ?¸›7ïÈ?°›?3í…Ü£†Ï»ˆ„¸Ñ€S;«öÍÝ£¾Nž1  À‹þŒ94ðMNÄ>Ø 5EóKóË­[ ‹}YçÇg.¦í{xÀ(îä•7ï›N$;ê'ïøØ›Ú{ór*ÈE>Gé0ÛRò´Âbn1]Õ'lEuN[ãçˆ`¨N_ôc*œWp>ÅÅÆ5Œ•8Jsswƒ¢‘S« lÎQ¾° r|ÿ–.Ù±uÍ©ËsmQ*ÐëÓO!c²½¾QV!U¼×ŒL,½ &î¿ E 7 ‚‚@'kºµsÏ »äœÏž1#å ±Ççåbäh i‰ Îéü2é2µªyW«‡¼¨YáÎð»þNd˜ ¨ƒDpBëf’XÁ®€UòðãQ¼CMŽ8Ç?+#@bµˆA «÷sDQë::œÕÆSDzW¨NN–ã²––Ð|ë ýéÑÚõ>8gïnŽ×¡ðÇw_Fr c»¯£9³È8X@˜ ÕQwqÿ·¬B˜M_»ˆ´x“ÐÑ7!SÐUåÿX ‚‰©Z#¾oº%Ü!¼×¡Àû/S㉉Û^t®)£¼³]&¹ÁCfQR ׎“EÑð׋p”È…:€åë&¬L„„$蓇1éc¬*sá"N'9Åk‚&Wîæ€£Ætu9«‹–£~Rs>xì¦=ƒìqÁôÉü¦F€ñ¢í‹é›ÈGb–ÉÉÏòœ8páÇ8páÇ8páÇ8páÇ8páÇ8páÇ8p‰D>¶·ÛÿßÿÙzuluCrypt-6.2.0/docs/library dependency flow chart.odg000066400000000000000000000353351425361753700227660ustar00rootroot00000000000000PK|7rCŸ.Ä++mimetypeapplication/vnd.oasis.opendocument.graphicsPK|7rCmeta.xmlSË’Ó0¼ó)ÃÕÖïXåxoœ–‚*ÂyK–&A`K.IÞ„¿Ç8ë°)*Giº§[3­òéÜ6›W°N½ H„ƒ ha¤ÒÇ]ðcÿ9ÜOÕ‡ÒJ“Fô-h¶àùf jÇæÒ.è­f†;å˜æ-8æ3è…ÂÖh6 Í7çFéß»à§÷Cèt:E§82öˆHQhª.P)®¸®·Í„’A£‚C$"hÁŽ55b×–: n¨r? å±kκ—1æjz¤Í˜¬SŒ4Ÿ´kUó¨âˆ …i»A³nnfʵjm3bß¹>Z)›{K<Çh˜:÷<|UpúÜÄàÿ¯-®¯½Ä`<TKÊÆuTå´aaò‚PQLâ§!M÷”2š2BJtWJÁÞ„„d»Ç„¥K“(ÁŽqFó-°Y ¤òCìCÙÛ©Wõm“/$ÿ~ÑxW¿¥‰?¢W‘ìøå~AÃÀ6¶zVµ…¯ÓƒQ‘(Žè§g¥ûóËy›mV՗Κ_ <Êñê\EN³Î¼N2œò-¯· )‘æü"ÿ¦4+_¿®3ê¼›éÞÔcó!G½ö»€ÒU%ºYº÷ù«¿PKîó¿sÊ:PK|7rC settings.xmlÝZMs"7½çW¸¦ö0àà P†-ŒÍšZl³o²¹‰™kÔS’ƘI€Ã€±¥RñÁ3Ò{O­–ú_|z‰ÙÉ3I‘7‚òi)8bDù¤<;…jð©ùÓŽÇ4„z„aW Jé!òDOç²¾xÝRÁëH$•uNbuÖ1¾šV_]·d‹'/Œò§F0U*©‹³Ùìtöë)ŠI±\«ÕŠöíjh"@j(¢¬àÃ×ç¬Ó†ÈÇtr(Êbôú|D|m&,f…Ÿ•J•ââïÕhSv(—[1N´æûÁV„ÓøP3vkÕ Uûµ×^µ/7kÍE΂æÊVnмXgñ£@ÄÆGN–ÆF )ëÏf¯ÞdÍûqÎ7*ZÈ“`õRÍý’r4 •Jù¢¸ó.ìŒU&x¹Zª–rÃÿN#5ÍÂ?¯ž̯þèdš©ÿ¬V®TÅ/Ä$)PÁ D›\0ËÞ-;G;œ˜¢fÝhC¦TB»BÐ4Žáh‰Ï‚F]¹´Çü‘áAsL˜„<ø|ÓÆÇ@ïÊ'É Ë.x%Òœè}2["&”K$æ{rØIq3Ýþ‚Pu„~è¥úùYLŸ¥ò†ðˆl±™{t_ãºú—+A&}ÔØîíq÷€kFcʉ‚>²¹5[O?P-C—u/•ÏKŽ·jWnsùØ¢å~ôÈ\G¾M|"ácåR‹ó Y<ø«ÚpÓÒ×W¤"ÿ5= Ÿ z[Jñm¨;l)}ÿ|là¶‘á¶ÄüÎþ2ow|sWÑqx3RNQè£ãxnÀô‘?*pWZW¸Åȃ)ºò Smä6£áÓ^ÔuDwá<4– =%|¸¨<øä€ÑdÄβ7¡âxÿj³˜(SˆØt{ç:îï úÕVä8®‰‚˜ff¯ù3ãÿkÍpæ¹f¨¹gÊm$BÂNõå³ßmóøníùÐ;:wÝ'<ò^ÕîÐ&aµ¢ÿ¸Ó¥¿ …GŽ+àh³¯,Gàøþ/¬ã»Ÿut¥Íx Í57 ÛΊ.OÑèë?ã{ž‘_3®7v½^ö²HP‡·•Ra÷{úK­$aóG âŠ(rüÄâ’*½Ð¡q…LJގÖLJŸS-à—%AQ.cø©Ä‘«ÎcÑÉžhclzŸ¦s7Ô”GÍûlví¼²ÐôŠÈ©3gäÈ c’2¥i*;p:×ñ¢ú)a? Q} 6qã½!*tߥ©ëÕûoIJx?å¡J}åð]iËñKÄ'~‚ë—$|òQð¬sìmmæ&Ñ7«Ÿ¶–EïPµ/få'¸¡Q6.zéœZƒ~ç«£i†”_; ©ý¦Ÿ|Í#çëÄ•Iô$BÎæVu D¦ùV7c”“\ëH©*¢ƒ"&™Õ†c‹¡¯sЉ ÉtƱ¯ËÕzÒ×”0ª6Íž§×`aAtu¾i>$Õ1±GæÛM‡•71œtÚ„,5ËÌE™qª—,´G—PéfÞñÞNë€<÷Åg¸÷¼ÍPú8«ƒ0ðSYYèý…¡ðcéø¤#`<„8a{bÕûÊ[¾·>'/îúOŠæßPKeôAÈ‹!PK|7rC content.xmlí[Ýn㸾ïS.Ú;ýP”(ÉdÑv±@Éb°™ŠÞÑmqGI¶ãy‰^öýú$=ÔŸ)[ŠåOv“î‘ç‡ßù§•wß=¥‰¶cEÉEv·@†µÐXŠˆg›»ÅÏÐýÅw÷x'Ök²e$ÂmʲJEVÁ·ÜY¹lfïÛ"[ Zòr™Ñ”•Ë*\Šœe×R¥^Ö{5#euHf³×Ä*wÅžª¹Ì’vÀKWów®‰Uû¹Ì’@UÙ×b.óS™èk¨§9­ø‰O Ï>Ý-âªÊ—¦¹ßï=6D±1Qf=Û ötù¶Hjª(4YÂäf¥‰ dv´)«è\ù$­*R¶MW¬˜ ­è™Vó‚•@Ç•†9o!•g`_»ÍlëÚm&`cZ̶³šxh*8šo*8RySZÅúõ͘¬?ÞíªHçî%iP…Ïg³¡Vù…½¨’¡qöZ\Û²³yV¨÷Ï’ï ^±B!Ÿ%iöˆ‹t 4 C&Pèl'M¾w" D9Á`›ÍtO\F“Kÿóáýc³”‰ùebgeE³#2eÊ“ÙZÚ £¥Ÿm ’öÌu i “ˆ»fÁrQT½‚Öó“ìb÷ÅUšL‡09Û‘nŠ(%q° á ‚‰¾ãlÿÇÅ ;=o˜Á‰aÖ¡þKM¤æ‚geJš>œ€©W±ésëZl³¨ÑC {ÊYÁåMj¶å`…AFá,éÂL¿ÿØ2 ©ž–`uà]"_*ÜÃU¤Oó–“%¢õéŠ'Ñ%,K\)ïãO¦œÓe~† Ôî¤Ô%öâ¾+Bš SšýÀŠ}MC¦G,LÊûwM2釵æYÊ}·økÁ)Äù޼çpWY匾aâN!Rš (r^…™wx¥)˜Ïoýà*µÙ^û©]êTˆ?Ó\”9¡k¿­hß‚GÚ#ÍJíš$+~šo„v†ˆå¡¬Xú52¾ß†<¢õÆ“²)4/"Ó#Û¦ýüI:‚‘æ#…Lö‡3Ã1i-}–~D=ÍZÔBtû†Lf¤ó}ëN0áe‹Û0Ò …J@©˜´ð®¶IÂ*­™”ãœÍc3¥ËÒÿnñßÿü»SYD‘³æIy¦'t3=¸Àí¿>ÉðpÇ~°éJô©k[2X Ê­½^S†" OUlAE{É?Ã1÷O5.Ïô ì¯À¡Ìe,Y1(XÂÛCß !(ˆÞ$BÎ òß$BîͲ çM"Dn†~“øx·ÃçÆiÿf9o4N7DèmÆidÝ "÷ujeº­µÍÉî°X‰èÐ?´màý»º¡Í`ÓZ4µ¹|Fm³¡vd¸¶Ó >Égì£îùP—s®œoí+o­`¸õ}ÂW-ZÄä}*˃¶NÄ^«lhaÏÛ3²,–×É4ø"epÉ­ä½èß`i–f#bµŸÝ9lU@çH³MßÁöKåõïšd~ß²–ÑŽß–ö/íÇÚXÎ ¿…žÒdÉ¡Så‘Ý’ ŸžQ2GN„ lÙŠ‚0hQUkXd–‚>o“íß‹C®èã9Ž1/µ^¯6•F³H+¡sO¢úqÞRUh"öƒ&ª˜yÐíðÿj#h`#—80l›ò܉ØVL$0¼ë,DgOì ¬$¤Ym ÒZ®µŒ1«àê2¯Å.D–ÁN¢3 ûKÂ÷‚œÞï5Šz•6öiT€bxÈí/ÃJÈ­U#§jgÍð&Ù2=<S²zt¢#¹­ ªÄ¸ÙL7õ@>-ðk§ß‹uǵüncìÇ®…çj‚@ƒÈFz³<¢ÚAx[WÃW×ñe8È9÷5âcÅ×Õ÷d¾„ºÚò¯ò¶ÉvóšAYPÜ(8Ï[F2çyÌÍdiÞ¿úPþ2.‹l#@®ê´ÔZ¶ê´½ñ\éµö˜×žz'²aûqHŒ×?¼·„)WR:/æ–ÎÀ-9U’sVÅÚàªxB¯´-Ãr/:å1ÿ… ¿ÂW<“~I3ÜÖ¿¼ËL8¿K—Šþž‡ºoÆxÆôòÛK]»î± ®s!RZtÔ¶’Õ‚È®ÛÞ”£9×¥Gt9= ¡&ßJüˆ,Dbàþö<˃ix" Í÷ì—óDwà‰îœØö¹+â)®èÄV=>™å‰b›ý%Oì†ëØs tô0érúÒÀ›]‘º“.‡Æ\ŽL¸œut9€Œší‚\²¿óχÊ4pÈX=8ž&I‚ó7àoþEsŒÀ¹¿±Uoƒ ÂÞß ÃÂxN=ºJ>ñèõYømtá táÍÐ ‚s] G­BA°Úà¶J¹¨ŠP!%«¶ù-ô‘ò¢…òÒH÷¢Ç`º{+b8ùJ¢ÕQ‘d Hr! ƒR‚ÔƱÑJÜV¢´½žF`…5V~khFø¹LÁ¦ày˜ Ü[ŠRwçØ£D Œ$l¾s ¤™õ•§ÔQòÖÀ…Íeå[±Ž¡ûÁ†‰ßÍg-Ë1ü€ R¤¼I'Ó"PÉL ZDláëËÒÑéOäHÕ‹!$}H1cvIˆ­ÁÜœbô›ÿºe¸ÞIõbœ¾É%œ»¤x¥yŽz÷ÎÖ‰Ùú ÖÎ#vìYŽ¿C5f¸0h6!þ¯f¸Ð^}»¾·è{¥Ða‘Ñ 2_qq•á*ý”´XGC‹=×ßaÁw0f¹.ò5ìØ¿žƒög´R¾²9®”ñ˜3šSŸØV[(ë®o[±OÈD_êúPï7 'PcÁðÚg4è^wQ>rGÁžqQŽAÂ6âêÈ©ï¬w"À0‘—r/oÀ§hË„¦b}бµ?Ɖ¬3?NL›öh]0'šà,yñÖ @û~»Ž‹riŒÝ«Á€B‹ îðb êÎwò8Ý€ã>&Oö¶úƒò5 Hæ°éëk¿I?«0úâ¶7ô!Зêßà:;G§•†µc(Æ.ðeíp¡‰häK(Ç÷_äPýf‹9xïÅœøïêûÿPKÿmHz( ž=PK|7rCmZQQThumbnails/thumbnail.png‰PNG  IHDRÆg?žIDATxœí{pÇÇG È ¡!d$Àˆ—ÅTã \Ð ì\Ž‹9×¹ŽªØI®*öÅuwvÝq%UáL$Øç‹)ßñÈQ¶ƒCHŒ°@`ŒÐK¬VÒêý~ÀµÔè§ÞžÙÙÙÙÞ™žÙß§(jw¶§gvö«™ùÍô|¿cîß¿¯ ˆ8ÆØ½ˆÛ@I!‚AI!‚AI!‚AI!‚AI!‚AI!‚AI!‚AI!‚AI!‚1*©åßûmD×q ŸýÇVý!쥊Vf‡µ.ˆóùäÓ¯‚¶Á"”"”"§JêÜÑ7ÿËç+¯~R[q¼iÞó¿ý÷Ƕ>¡ö§ßûÙìÅkª®ÿÙÈZùŸ_¬Þ¾Wó£’ÿ¹lÓ__Iypª¤(DOmµ—>zglüoÙ•™ó–ÇOHlõy›j*7|ç''¼L¦4Ü)[»óųGö­Ú¶÷ó÷uw¶6Ö\üà×ãÆ'ÄžkŽÁþ«·ÂÄš[—³æ¶7×O˜4™k_PT|â—ÿH?4%µ·«}p ¯³ÕGñèßnòÞ^´n;Y·ëgw·7OHœòȪoéä,ZU^úqjfnæÜewþï3:c{SÝå“ïö÷tnÙ]~étÍÉôôìG<7/ç>‘˜”n÷6gKŠ09u:ù!ÏþÅÄ)©äÇ«úâü˜±ñmMuä#:å«/>½ôûÿJ›5Li®¯^³ã…óÿû¦çÆ¥9Kב_419}þÊoŸœ| 'NN™ÿøf2±§³•k?Ôíȧ¾Î¶¢ßïïíª)»B1!1)%3wJÚÌ¡eÕU­Úö÷´çø„DÏ­Òqñ ¤‡‡¦føj*èŒ>~`é†ghòWA×<-+Ɇ§»Ú›œ¨'Å’êhn ûƒäŒŸ·’¼­­ü"á¡äØØØ¾^E‰!S²yì³ßzêÅýäõÔŒ²W ¿ëŒ¼%÷î &$&“ýÜåßÿ&iZù&¶7ÕÓÎÕí‡'ÇÐO‰zJOêëé(ܼLN˼tâÉ©3†ÖaÁcWN½—™¿´»£…ºò[ó~²æJo7eÒ´YÞ~âqª¤è™Šú|åk±‡ü¿píSäzšRvùs 7ÅÆ }ÓEüe:¢ž¥¿E_“£ûQ ³:ý´ìÒ)XέXÚ¬¹Ÿ}Þ’œºCvÍ kŸþA€¯.;N•”qrýºÎ§t#pцû%…X J  J L’2rËAŒJ*è¡à J  J  J Lh’’aºä…‚Å›H­ò^ÊÞ莸aÙ&’skà J LX’:wôŒÙ9‹Šè°]#³ÿêÜq±FPo¨@ß×ø–”–p÷Rµ×È–‚ѺqcÆÑ!°¾š vng«oæ¼=­tüëó¿?>!1¹¥Á3n|Âàà™Þè)ß´ûŸépì~õ ŒßU/4&fhäš<.£FÖ‡ÝP¤%ÝÕ×/ÐÍÕTûý¾¤%Œ;>†8[ôMD æÀ£uï ÂXvn£§ŒŽÇM™›˜”ž’9Ç[þù„Ä$:·«½™Lélè‡aÇï²”(Ž9ðà5ý!å®Ï²=ÇtÚÀ†¢ÛF öá[ôûÆÆÅÁˆáGŸø+âì ÄH Fë’×ìX¤[QzšŽÇ%»¢æºª¦ÚÛ'O%²0·åîîöæ+§Þëjk&3¶6xaü. ùÁ"Q65ˆÚçé_D€ u·úÙ0b¾okC ŒÎÌ[ª,?aI Žúì(X¤;)) Æãömýž¹öNG½¡èXaZNöOÜ÷]¸ö)vü±ƒˆìêÂÚPÇã ¿ë 4¿¯CÇ;ì/‘Ÿ%%ç[©ˆòMš¤$¼£$¸‰ðÀ‡%…ÆRIÉ06&Ò®›ãޤVï¥ätg,ZYj÷*hãÄ3}<ð!‚AI!‚AI!‚AI!‚AI!‚q­¤ŒŒ8å>ª­¼VYzzìø„±ñ KÖïÔœÅÝ£O…àZI)ª§ ×n»qáÄW×ÎÕßþr×kGèx7ª*:”ôú™ãëw½Dfl÷ÕqֱܨT‡ºhZƒ›%E”äõ´‡! KLž6ü ;æÎoü]GKgËJµpõ‡û%ÅŽ8=ñËŸä/ßXuý<>:))5.n, %¥>Áã&LŸ ?*Õ‰®¬–áZIiŽ8Ýùãƒäÿ%žÖœeúœEä;%ШTD×JJ¦G¥F3()D0öHª³¥ñ‹3Ç*??›³pÕ‚ÕÅ—O¾Kw•W?!5Û’^ ° (0r™@ݹN {©Bg­\sy"â’Ò|lrâ””Â-{ºÛ[ÈÿÊŸýƒ(•þ^_M%}j4oÅFÚ˜ ŠY¸v-ï!+fp /PPŒÂ¹t¶úhLOG+Û?CZÆ— àÍ¡8š‘f*Cל¼ÓÞà+³.ºÄ–»zy"6.Ž´d×J¹Æ7£œ˜”T¨eê?6™˜œN£TÈÖ‡§FÙì….+&-+?PPŒÂ¹4Tߤ!09lÿÓÜÓE[ÂexD“m©2tvX[ø °Dª$¸<Á®•þrYØGaMlv±´ù½”‘p\æ6º¥à©QöcöBmÌ%®hÅ(L ÙEÑgPUý?X4´$ èeu ×¹ÿÚòýtµúàR…zFå²_…ÒL\ SPT¬¿:‹VÇѨ›‘}§º7M¸øå:—T|}ŠÒ•H!©ˆÆxêCë,zMŸŠÒÓ³—¬ÑìS /ÚÔ¹Ø,)Ó1žtv(èîÜ(¡ 7WaütûaúLJ^‡ªÎuÔk1±±£é Ã¥%9÷g"Ï2…œW@¨·üªÏ[Ag‰ëíjïîh!å'[»…mjÛ!›%e:ÆóÁì#å4 ÓÙN˜ž]°r´*™‘ÖYP¯Aa¨Œ”– ãLD§œ=¼â@Ù•èí¡Î>?8ÈÕn!E›:›%e:Æ“¾…r©µ¡†í–«)lUÈÕYPi¦ƒ‚SOs]µâÊÎ2.u"uöQ~†mêtl–T˜1ž\A ¸zPª9#×?¼åîü¾š RZs+Éb.ÚÔéH÷"WW›® ­ÒÔ³É0Œ5ÅM«t’BœJ  J  J  J ŒÕ’’ÓŠ¤ä@±¾_9bK%%É8 51ä]7Ç>D0()D0()D0()D0=!cŽx¤ÄeDVRöþ¢!©Y¶(6Hò÷ƒ¾!$ù1ÂAž? ”"”"”"˜JJ† {×!:oòDv/eo¼‡½1rÞ ·<ð!‚AI!‚AI!‚AI!‚‘ZRF\YÛB#ñ Š‹, åDjI)*WE2E'a¡·«âÈÿ¬ƒÅÏž]ºiÏ«÷ûó–o C°ñ((*¾øÁÁ¤ô¬?¼ýêc[ÿ–N±ù›;Ù%¥ø»**Æ:Z§Nc,’3²©UƸñSgæÞ¾rFa2Èë%ëw¼ýòöäé9±±c¯: ÏÝ=Š$å直—°P°¦âÈ“u°H™îý½Ýdï•4mVwG ˜j½Ô–ç_ÿÍ?=“¿bãˆÍ†3¸ÿ¾Tª’ZRš§PAà5ë`Ñr×VkŸþ}Á:dÐe½pPÒc!µ¤„à&‹@Hµ£r¿¤äGÈÈe{Ž é'üû’®Mg0ç*ÐT{o†BîK –”Áˆ¦3sùÞ®v2=)}–:^¡pówÄ.€‰hÐ|„#"{)ý,5bÓ|5Ô3Ó[vU¯ ‹]Ñ ùà‚ JÖG¼¤`“…rh™Î’™K=3ÉŠ¨ã-«LEå o3f/ –ï f°B˜'ÑêÀfö…2R·²ç–»¦3½Û^¯`$vAm"* \`3¼ Ÿ’¿¥ôìy´ „d.©øt¥@½£2agð"&6®¥þNGóÝÅ_ßqûÚ9E„dî`mîm…¤"¾N¶‚f°‚⟭Àe4QW©:hþH&Š8ðܼD_4×WMIŸ™·l=ÙiÑ6ª ¤à°kÓÇèÈJJ'|¡«­i4!@Ù(|!h¶BÍÍK4X4”­ÐT[E$+¦™­Àe¸lZl¶Üõ6ÐÔƒŠ’'|{ª›¹£D0()D0()D0()D0.—”ÁÒZ’ëÎîÀÍ’2(y®è¸7Kʨ'áD»¤¤ºîì¢]RˆpPRˆ`l” û,¢ *âèûHöì¥$q•§ðÄ"”"”"y%eäùqî##¾çôùô÷ßøajV^kƒwFÞâ–»uÿÜcé‡úÜ‚¢­s 7y˯~ztÿ¶…`4mÈ+)EõüøÂµÛtLÏWoß{ýÌqð=gMÏÏÙ×Ùê›9oEOg+}æ}RRZá–=ÍuUçŽü[RF6t2%-³·»£¡úÖC)dÑðd=ÑŸçF ‘YzZö<0=ì§ ¦f< 6h×N¥L‘£~ ÞõH-) ëWfÄô\ö=gMÏÓfÍkô”ÑÇØé3ï¤ÁÅvµù ·ì¾Uò脈¬hÇ÷Ác}p>%sNõ—È”6_˜ž¥eåÓ¬ tOµ³Ô»HŠõ+Ó1=W†='À÷œ5=êÅý¥§écìžrò“Oš’ºâß¡ýIA'3r—ž<ÔÞTÿPÊôáGïÕÌ_¹åÐk»v¾ôÖÅ÷­~†µAKÎx˜v¢ù@½ë‘WRšÏ5=g}ÏÆÊŒ{ŒÜÒW´òË"*™ž»xѺíŠêÑø]¯fßÂ3ìÜ”ñ“&³DòJJ`efðÁyrœ ¡B:q..—b=öKŠõ@o®¯Þ´û_èt®Œ§E™hÂÝ´ª‘˜5®s}K>¸êa½+«eØ/)ÖýÃ7LýìH!F¤£ïÎyÒ ™˜û_8Xµm¯Ú¾œT^jÇ:Ò?kŒÎ¹ì‘ Q}Õ€4cýUI@»K>ò`¡ôÒ½êa—+«eØ/)ð³£oõ=Ð9O:eÄõ@WÛ—+ëØëœËžÂX¥ÃUÅß_V•ý ÐQÒðºßWL¹²: ¹$ÅíJ0tÞ“nÄÄœõ@WÛ—+šŽuþ‹æ\ö’¦ÍÒt¾c=û˜®4úéjõÁU®¬ÎBIѪž-Ú¹&úV}¥61g=Ð5-P5ïØE«#C9ç;ÚŒíœì8Õ½Egô¨,’ˆƒ<Ð]‰S%ÅÕb‘³V7¸2¤¼°Þ3RN )ýZLm­N7àuîê5·.‡d­®™†EZ²yZtÆÜeëÉÊôu·C¡kUw‹HJ¿S[«+Œ×ù¨zˆÖêšiXÙ+GkÉ‘iþö½Á(ô¢ón1àIé×bjku…ñ:wu¸qkÐZ]3 ‹­%aFe8»Í7Z–FçÝbÀ’Ò¯Å4k:î&1×K kuÍ4¬²K§ –dg„ümÚRÇK=p€¤L¡3e¬%àNI!6E’ÒLKc£ÒLß–FXÜ&)¸|°`õÖ^&gÍ9‹ŠèÝboùUŸ·B'*M ý¶´½_VNÜ&)¸|  ßEž””¾ìÉ]B¢Ò­ÛÒˆ·I . ¿‹aK}%̨4­ÛÒˆ·Iн|ÀÖ}¾šŠ˜˜˜ Qi¡Þ–FÔ¸m»º| 0- /%èã6I!¶ƒ’Bƒ’Bc¤œîÊ…è`ƒ¤íˆ|ˆ`PRˆ`PRˆ`PRˆ`PRˆ`PRˆ`PRˆ`PRˆ`ÄKÊYYd˜*ñ’rÐä,õ;<ð!‚AI!‚AI!‚AI!‚AI!‚AI!‚AI!‚AI!‚‰¸¤d 7ç|õœ8¨Úн”´yëE+Kí^=úЇË|¦“jÕýÐTÜ®«[p›¤ÔIµÊˆ°ÈÛÞ®vƒIµÔÎåúÙãd–Á>e$×ÞoçÜ&©ÀIµ~oƒ&Õ~þ§¡4Ç–»wÀ3ÈÂ/álÜ&)uR-™9³kŠ &Õ.\·|úå¹÷©gÍßÊQ¸MRšIµ_ûæ÷àµÁ¤ZÊüÇ7GlM]‹Û$*¡&Õ"A‰vI!‘NRl.í‚ÕÅ—O¾K÷\.­Â\ P$ î‚,‘»6°H')6—–¼…\×þ^¢È{Í[±¬Û›êÉG45ãᡱ}j`È "‹HJÏjóyúY›a2W_OQÌ©wþ•ôœ_øD}åuÚá@]"]U6I¹âpóÂGy…¹<#u%˜—T Ûêéá\¤†\Wz…‰¦ëߘء <ˆ Uƒ©ðò'w½ýòö¿yíÈñ}/ªm†IK"zA¡)¾’v˜‘³€]"„¤ Û’Ù§NëjkâòŒÌ}÷’Å1Lo9Û0)©@Ï,=q…}-`4-Xÿ6×W±-¹ÐXÎL…‰n¶<ÿú…÷¥¶†‹ñ “šëª Ã–ú;ìÙ $eHî¹döOþûçë¾õ\ž‘9–í9†÷ø„AsiÿL"Å?ïu㳯°³p-!4–3æL…Ó³ƒÛ—s)´×½â@¯_pyFAá&$•”@ÐØbd‘— RP¬e)´š)4Š ½»¬_F®D•«%¯ƒƒýšÉ°, I¯äj«žŽV¨øØÆÐ`8øE;‚–”]О.+P -Ñxn”š‘œÑfMµUDR°,Í zw9P -B[îz=åP-²e¬Å?G$°ZRl9¦ ;, I¯ S[eä@ŧh¥ÐêDвíÌ …:¡·–ÏÞk¢„DC‹P²c«E¶ŒuVKŠ+ÇU2,¼Í˜½â_ ¶b+>¶14 ;‰@´êeJ¡… šæºju³°‚hF¾5[-r_ÊéX-)®zRWCšÁ²²_Ô‰€t"h¹öRh¹[È´™¯¦¢­Ñ«³2 AÃU£Ü·æN³Ø2ÖÈrz. !»f'ShÜÛ$…ØŽ’rè°|Ä—”o) á€>D0()D0()ûq™¿#JJ dp”"”"”"”"”"”"”"˜è’”´6Šr®˜¹û³Ñ%)EJ—G9ýM‰:I!‘%q¸°ÿô¹E[çnò–_ýôèþm?z3ÐŒu EI‰Gí f¡«·ïMÍÊóÜ(!’"mXm:[²æ6ÕV6ÖT:Ñ5%%žÀ~¡^§dΩþòÂÄÉ)ÝíÍËžÜåïÃqžs¨k(JJ|^iž¾<BËWš§WgDèuæéÀ?D­Dm‘›ŠÍ+¼Žö`m¨v¶h°®"š¢4DTW)ý±¶@i†UW ¥Z>ðýïÕ¨BŽ©¾fÅtré¯y-qÁ¶N³HJ™ ^oS·ù<³àÅPë iÕîoç9:¸{›\6]=f´y³¾ÒÜ”j¶¶ŠP€B·]l{Ìt»u3_ TB%ëBa[¨FÍ`ûÄt$†Û¶4Ü_ß¾53Œ5 ½Ãq¤ï¢µ‰*\j ¤# ý.L¿G|`NËwz·¸“¡å‡¡e¢¥C1¢<ŽæeJ´ëÄŽ £É€›òÛ!/bhº q«1õ@CŠo~§‘Ü1 ©_÷€ûR¦#JDûŽ„{Ðxlëj\Œt¯|õo ;Õ¶®ôµÞïké@mk-t–=M|žÎ&»Ý²Š)—~’NÔWXg öóžÆô‡|C÷U¤LVý¥úo¡ÿª¿ Ž?q.ü ZuƒoƆ˜UeFî]{šÎ1+ø ¥g ŠÛBOY:A|5˜SþZnx|ÿ’š¿Æ6W”7pœl6µFG?x>ëÆ®»ú³³~ þd3õöÛ5ò„;}ÿJn ‰p0™½hb˜âÈËåIŽŒ&/aÓèJ¾>ÊžùØœEú"2u;ÂÓ·#|ò³¸½-ùÝ'e½=H’(Z­¾­=˜äz•ýÒ}Œï-a`O«ßû›¾8é0I)‰_úÊ1 úÍe8gLÇè´À0½Hªz9úÓéØð,>º'J+ß,tËž“äÑcÍ)©jññzX|Ÿ¥Äz÷cPnäkoMJ‡„^L6õùÔ= ‡r€·÷\óˆ/€á{Ê‘kç-u¡®ƒB¶·Kÿ}ï;.eó½'hq±œ[š[o%7Ûµá"Æ“ñÁbÐݲ†“J*·¼ï^s£pÛýݳýÖ£¶W¦wúNáÑjœ5?<;ÂÑäL®ŠËÛ·CƒÒ‹÷_Öï uù¢óÑ΃M>è’ˆÚ\ëÒ=,½áoH]ÿ PK”bÄ­±a5PK|7rCMETA-INF/manifest.xml­SÁnà ½÷+"î­§ %íaÒ¾ ûFœ S5?©m¦©S£õfcû½g=ÓìÏÎV'ˆÉxlÙ+a öÁ¡eŸ‡úíw›Æ)4=$’— *s˜®iËrDéU2I¢r$ié`çuv€$öË™éš-lÙnSÝøzc¡.óq¼u÷ÙÚ:(:¶Lܹ=;茪i Ð2‚5ZQi'ìø,˜/uò!ªp4:1±F‡R¼¬x‡—àLb*¯M@T|HOÖiÚõÙ¸‡cv_¨ŒM‚.!8Ü!1N ¦ú*–w½rœmL[¡´ %õQèãß›ýëÁ»J' <®—+ý§Ñ£î7â×Ý}PKªåÇÞPK|7rCŸ.Ä++mimetypePK|7rCîó¿sÊ:Qmeta.xmlPK|7rCeôAÈ‹! Qsettings.xmlPK|7rCÿmHz( ž= Scontent.xmlPK|7rCmZQQ´Thumbnails/thumbnail.pngPK|7rC;*Configurations2/images/Bitmaps/PK|7rCx*Configurations2/popupmenu/PK|7rC°*Configurations2/toolpanel/PK|7rCè*Configurations2/statusbar/PK|7rC +Configurations2/progressbar/PK|7rCZ+Configurations2/toolbar/PK|7rC+Configurations2/menubar/PK|7rC'Æ+Configurations2/accelerator/current.xmlPK|7rC,Configurations2/floater/PK|7rC”bÄ­±a5 S,styles.xmlPK|7rCªåÇÞ<5META-INF/manifest.xmlPK6‘6zuluCrypt-6.2.0/docs/zuluCrypt-cli flow chart.jpg000066400000000000000000001041471425361753700220160ustar00rootroot00000000000000ÿØÿàJFIFÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿ 0"ÿÄÿÄÿÚ ïÀ öPMYI4RM“E$ÑI4RM“E$ÑI4RM“E$ÑI4RM“E$ÑI4RM“E$ÑI4RM“E$ÑI4RM“E$ÑI4RM“E$ÑI4RM“E$ÑI4RM“E$ÑI4RM“vM‘ã»;·/ÑÀ¢Úç»CËéÇv„úŸBy@O¡>€'КROÅñA;·/ÑÀcr·®{•‚Þ*ÐÇcÉ£¯kÊsõöñ“¶·1Ô¿9Ö´þk9²ö›~OO!~ƒž '¨ êz€ž '¨ êšSÊO¡< ŸXÞ9^Þy^9^9^9^9^9^9^9^9—o:¼‡ ëÇ ëÇ ëÇ ëÇ ëÇ ëÇ ëÇ ëÇ ëÄk'.(ŸBy@ ô'”?#ýry? O¡< úÊèO(èO(>„ò€úÊúÊO¡< >†©´ž('Š â‚x ž('Š â€úÊO¡< O¡< >„ò€èO(èO(O¡< úÊúÊèO(CñÝø£²öŸBy@} åI5$z¼ÞÞÏ·íà{xÄl1z=± ¬>ŒŒ ¯ÛÀöð=¼ vbÚòú¾Æ­œÃÃÙåöð=¼l_ Ì^oÛÇ“+ÇÃ'œ9OoÛÀöð=¼oÛÀöð=¼ ޳ì8v=@>„ò€æ¶¹-ÒìÍ?_˜7€sÝ-Ï{ÛÚ^×Sg¾nö} ÖmOd.¼À u¤y==-Þ/¤Æè'Š â†®{!o&dÇãžõiè|—6ìÿVoJÏ:[úxsY›ïŒu›6·Ó½fmzzöPhãZ8õqGDóë¯0Éžõçîì?2ïxõ ž('ÐèO( ô'Ð!H¯#׿ ಌ}Œ}ÇÌ„ó1A V¢ÚòzC®Ö­œ¨öùÏÏc¬‰u²äÖaËôb÷èhn{K. xûéf?¾Ç9J;?°ó÷=@ŸB}>„ò€ŸB}_^‚Éê '¨ êz€ž '¨ êz€ž '¨ êz€×Ø3A@çО Ög¨ êz€ž '¨ êz€Ÿ¥vxPÔõ=@OPÔõ=@hï„ O¡>€ŸBy@O¡>€ ô'”èO 'ОPèO } åúè ô'”úèŸBy@>„ú} å>„ú ´§…=@OPÔõ=@OPÔõ=@OPÔü›€ŸB}>„ò€ŸB}úÊ'П@O¡< 'П@>„ò€ ô'ÐèO( ô'ÐÃø÷ìÿœæÐèO 'ОPèO Îg§?'£ŽëHn´†ëHn´†ëHn´†ëHn´†ëHnãÖ­!ºÒ­!ºÒ­!ºÒ­!ºÒ­!ºÒ¹'d—°OHúè ô'”úèæzng¯=éó´÷&K»ƒ[WèôìéÕŸw–«›Ÿ_í+>ýŠ-&O/OÔÃQ̓å•Òô¬èqF-ì2q›øµðfô¨øu›È¾åiõÍY³pk,˜òKج} ôúÊ} ôs=73מˆôùÚ{‰tul%‘ö°›öˆö¸Òת4¼P×1Éè±ÚÕÃKudÜ~Ko>ôºX©.e{¤Y¿)-;"7ºÚÑ3c{1*§Ö XÉ$½€ñzÀ'П@O¡< 'П@/Ô5ž!Ûºóâ¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â¸â2ö@8vŸB}>„ò€ŸB}'П@O¡< 'П@ ô'ÐèO( ô'Ð} ôúÊ} ôŸB}>„ò€ŸB}'П@O¡< 'П@ X¦Hí˪r­gªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£ªr£¯ËסO¡>€ŸBy@O¡>€¤W‘ëóð«‚Z,¢ÃµPJÏ.ònÝ™ÓÑAͲÙinØjÔ[^OHc`èO 'ОP}PÔõ=@OPÔõÌèבëóðï™}ãZ8(æ—KFϳϛ:“´®ÎÍÛ&s[c&ƤzYeÒ©‹.²Fž­¯'¦zƒž '¨ êz€ž '¨ êz€×ØúÊ…#¡éá=A¼OPÔõ=@OPÔõ=@OPÛY‰êz€ž '¨ êz€ž '¨ êz€Úµ6—›ÐÐ ô'”O¡` ž('Š â‚x ž('Š â‚x ž('Š â‚x ž('Š â‚x ž('Š â‚x ž(Oy)ÿÄ13@P 025`4!1E"#$€ÿÚÿæŽf…®¼x ðà+ÀW€¯^¼x ðà+ÀW€¯^¼x ðà+ÀW€¯^¼x ðà+ÀW€¯^¼x ðà+ÀW€¯^¼x ðà+ÀW€¯^¼x ðà+ÀW€¯^¼x ðà+ÀW€¯^¼x ðà+ÀW€¯^¼x ðà+ÀW€¯^¼x ðà+ÀW€¯ì7¬ýß«Á÷z¯Ýú¼wªýÞ¿šëˆ„h‡®[°ó™äaµ›À¥s$c™Ì#ùbdƒëós]sÄåŒnæ ¬ƒîõ_»ÖKdv¢GäpÙß¡þÊùw±aÍÎaÅ¢`ÎÇ8xÛÀ‡.ØœÁEi£“lþüÆ5ñXƱì%¬Ë3(™.qÿtéDÈ¢Òo,£æñ3ŸœÏÕœð³DbÄcY¬ƒîõ_»Ö8-8E8KQÉu¼â(¢~†KnCb‹ áÜNc\é8 HVˆŒ—œjÆ%ƒ­œ™'õ|²?Y¾áa¿É·ûq |YšÃsÄËý¤jn#Hçs\ú²¢—Êè2%D‘ÂfÇ\!²‹Ñ1h˜´LZ&-(8ô%ÈxstêéÕÓ«§WN®]:ºutêéÕÓ«§WN®]:ºutêéÕÓ«§WN®]:Ìóã–Oêù^Ü=•ÙùtF8¢†D،ð{c1£tV8TÙ•#D£ù¡~¯žfÇ¡Ä=ý;ý–OêôпWÏ3cÐâÿ¹Ø——caÀˆV ¢8̯GüknGdXÀäÙ·‹Î–¹ÏkX9!+­âóÒ,Èlü_ìì¤g0T2¨ePÊ¡•C*†U ªT2¨ePÊ¡•C*†U ªT2¨ePÊ¡•C*†PÉžfÇ¡Ä=þ2?t®øø¿ò.p+<=¸¥«8%Œ³+ûý£QŽæ4Ì;þҹߤv8?œ‡ÁþÏ¢LØô8‡¿ÅâkˈíÃ(I#°v‰Âc„:O2[0ICŒÖ=àkÍI‰ÑÆá6+÷¯3¢3$’!ÈÿgÑ&lzCßÓ¿ÙôI›£´ù¢ÅEŠ‹*,TX¨±Qb¢ÅEŠ‹î\2Ñb¢ÅEŠ‹*,TX¨±Qb¢ÅE‹0œ}fÇIÇ$s¸” `ý>fÇI+‚Ån"C!}>fÇI3cê6:I›P™±ÒLØú„ÍŽ’fÇÔ<“6>¡3c¤™±õ ›$ͨLØé&l}BfÇI3cê±ù\ª¹UrªåUÊ«•W*®U\ª¹UrªåUÊ«•W*®U\ª¹UrªåYŠç}FfÇÙfl}–fÇÙfl}–fÇÙfl}–fÇÙfl}–fÇÙfl}–fÇÔ]0üË’É ä…rB¹!\®HW$+’É ä…rB¹!\®HW$+’É ä„I+nHW$+’É ä…rB¹!\®HW$+’É ä…rB¹!\®HW$+’É !È\÷ÇîúœÆ~57òjn¯ ”mÏEÝß»ê5í%¿D†Èw5æ;&g!9¹+ý¤ssÂùN$&Å XÆf(.’Sà`$¬ŒÂ‘—3Ë™¾¤S *GõQ®Ä Ä;«€q 0ÕjŒ5F£ iÃê?ôå? w´Çy[,ÓÞL³ ùÿi ÃA±Ïám–3šóDŽÜ:u<¥#GÄõ`ÓÁœb©0d©Ó€záœ"º£ Q†¨ÃTaª0ÕjŒ5F£ Q†¨ÃTaª0ÕjŒ5FƒŒ67cgÈy_»êrÙøËœµŒb®±­åÒÝ\¶jkZÌdCÎsŒgü°qÆìeÂ˧5­f47.õ {º({Ÿ!åxßÌå½rÞ¹o\·®[×-ë–õËzå½rÞ¹o\·®[×-ë–õËzå½rÞ¹oYÆZ¹o\·®[×-ë–õËzå½rÞ¹o\·®[×-ë–õËzå½rÞ¹o\·®[×-ê ]‡tPö;>C©ãÓ2)~ >Íc±³ä:ž" g›Á¹ØÙ¡ìv6|‡S3c³ÃØìlù¦fÇg‡±ØÙòLÍŽÏc±³ä:™›žÇcgÈu36;<=ŽÆÏêflvx{Ÿ!ÔÈL-‰‹DÅ¢bÑ1h˜´LZ&-‰‹DÅ¢bÑ1æ±ÔÃØìlùÎÏêaìv6|‡ggÈu0ö;>C³³ä:˜{Ÿ!ÙÙòL=ŽÆÏììù¦ÇcgÈvv|‡Sc±M˜AM!ÃÙ™òL=ŽÇ‡òøÿggÈu0ö:iîv­ë[Ö·­oZÞµ½kzÖõ­ë[Ö·­oZžµ½kzÖõ­ë[Ö·­oZÞµ½kzÖõ­ê]œú3œFÖõ­ë[Ö·­oZÞµ½kzÖõ­ë[Ö·­oZÞµ½kzÖõùv­oZÞµ½kzÖõ­ë[Ö·­oZÞµ½kzÖõ­ë[Ö·¡½üßBÇMÄ=þ‡1ŸMÔšæ¿vMÕœãÆqœeÍo£ÝèIý_3†ãSuaÍw•®kð³ŸÆA¿¢fç¡c¤ŸÅ±T~/ BâÿB;ÚÈ&&Gć#.$#e¦á¿œ7ˆàüÀXhã¯q=YÃTŽ7 †ñä1æ“ú¾n!ú8{m€¯i|O–aå†ÖvY⛓æä§bÄÒÄcÚi™!ù?;ÿHæ¼Ì1ùbeÙŒSròÉÉq'#dÿç´öyÙ¹"|Xɼxf—懱ÒLáògHý6Ü)…ÑgèÕƒO€q2#±ŸâÎsK—CÏü(Ãy}ÂÕ#úo+„pÒ´Ä©‰S¦%LJ˜”ˆƒÄo7ýöQL6fhÔl·SÑñÏÁ&·ûpéfòìךymk ù·3†Dÿ’€q2(ñŸãÅ‚¦SZ+R›™Fû‹€rñý±åÃp÷HþžŽD> (i‰S¦%õü!ìtö÷ú¶~2Æ;-kYŽH“›‡7KurÙœéÆœxô`û½ ?«æspìin¬ˆyYÚàN°Öã8cpÞPñŒãÃF6,µ¹ÌœøcpÆE¦2kÅœaØkÄÖµ‹ kV6çÌÍÏ,={$=…Ä=ýLw¡'õ{7<°öC¦‡±ác¤‡±Ý™ò4={$=ŽìÏé¡ìxCØé!ìwf|‡McÂÇIc»3ä:h{ö:H{a¹Ž•\ª¹UrªåUÊ«•W*®U\ª¹UrªåUÊ«•W*®U\ª¹UrªåUÊ«•W*®U\¨@哦‡±ác¤‡±Ö?ä;„={$=ޱÿ!Ü!ìxCØé!ìuùácÂÇIc¬Èw{ö:H{cþC¸CØð‡±ÒCØêÌ×89âS¹±šFÆíðöIÕCØð‡±ÒCØóLý¾ÖÍΪÇ„=Ž’ÇšgíøÊ.CþÎdr¸¹òE+ùkÜcŸ!Ëä<’‚×<ßó< ì°0ä:@äJp¤z¬Üê¡ìxCØé!ìy¦~ßýöQã°ÅpåX'ßï³ô&ÿ|‹³Œ6SpI."Iý³aEabîðý<¤K'a[¢P|„ÈŠXŒdBþ¦ÓOÆ9xÿYIÿ5'•“Åü6`#°ÏMÊ`ÜÜI˜ò¸“Ãáùñ¡äfçUcÂÇIcÍ3öüe &Éu¶@Ÿ˜ÅÀ9B‚VÈ3b©¼ “.{‚s¢.<Ý5b—dUll6+#›R(œù ["¾„lž@âFœÙ9Žì¼‘žè„œ…Á+d l¨âp³˜oË 2öæÐ0ÿäp‡/Š÷CÇøñfçUcÂÇIcÍ3öýw€dzÚ&yÎ1>é2˜,y™¹ÕCØð‡±ÒCØóMÎ1/[V¶­mZÚµµkjÖÕ­«[V¶­mZÚµµkjÖÕ­«[V¶­mZÚµµkjÖÕ­«[V¶­mZÚµµkjÖÕ­«[V¶­mZÚµµkjÖÕ­«[V¶­mCsr^ªÇ„=Ž’ÇÓaìxCØé!ì}6Ç„=Ž’ÇÓaìxCØé!ì}6Ç„=Ž’ÇÓaìxCØé!ì}6Ç„=Ž’ÇÓaìxCØé!ì}6Ç„=Ž’ÇÓaìxCØé!ì}6Ç„=Ž’ÇÓaìxCØé!ìz¯#¬Y²d È+ V@¬Y²d È+ V@¬Y²d È+ V@¬Y²d È+ V@¬Y²d È+ V@¬Y²Â0$={$=Wˆ{û\wGcÂÇIcÕâþ×ÝÑÃØð‡±ÒCØõx‡¿Õ!¹nlƹs[È#ðI-+\RÊk0È#2 רEi‡px e³/ç»ùélÃ¥=¥äw}X>îŽÇ„=Ž“\Õ\ª¹UrªåUÊ«•W*®U\ª¹UrªåUÊ¥Ì'«$ùbÈpZÛŽßp¾AíçiB3óMÜWd˜ÖŠ4üã1ÿÚ2θŒG3†ðÿ´õbÏ}rªåUÊ«•W*®U\ª¹UrªåUÊ«•W*®U\ª¹UrªåUÊ‚,~ö;÷ú¯ˆîšÇbâþ×ÝÓCØìRã¼Ù¤uHê‘Õ#ªGTŽ©R:¤uHê‘Õ#ªGTŽ©R:¤uHê‘Õ#ªGXŒlš‘Õ#ªGTŽ©R:¤uHê‘Õ#ªGTŽ©R:¤uHê‘Õ#ªGTŽ©EÅžšÇxgÈvÈ{áÇx…èjô5z½ ^†¯CW¡«ÐÕèjô5z½ ^†¯CW¡«ÐÕèjô5z½ ^†¯CW¡«ÐÕèjô5z½ ^†¯CW¡«ÐÕèjô5z½ ^†¯CW¡«ÐÕèjô5z½ AÎÿßÿÄ* !120@APp€BQ`aÿÚ?ýœn "Ȳ,‹"Ȳ,‹"Ȳ,‹"Ȳ,‹"Ȳ,‹"Ȳ,‹"Ȳ,‹"Ȳ,‹"Ȳ,‹"Ȳ,‹"Ȳ,ºø¿¦pýºø¿:BBÇ¿*5ýˆDw*@’*T7Û¯‹óرfI$’X’IdþI$ŸŸ‡í×ÄM•È®Er+‘\ŠäW"¹È®Er+‘\ŠäW"¹È®Er+‘\ŠäW"¹È®Er+‘\ŠäW"¹È®Er+‘\ŠäW"¹È®Er0ÅÏù§´Y–e™fY–e™fY–g ¶ÿHâùæ¼ !¤B kŸ ÏÂóHÙ‰³f&ÌM˜›16blÄÙ‰³f"É?§ÅóÎId²Ic|ø^~ý¹A2dÈçÂúoÊbS˜”Ħ%1)‰LJbSb—ß·)%Øü’Y&¤|¸_£åƒlÖÍlÖÍlÖÍlÖÍlÖÍlÖÌ1kþ$å”±±±±±±±±±± ÏÞâõÔ‚G’duáë÷¸½v%‰’IîO^¿{,lj5F£Q¨Ôj5#Q¨Ôj5F£Q¨J+sö$’Nü»Îä’I&:‚I$ïÊyIÜ’I$’I$á} ýº1åýD táëÐüt/Døû?Gr;ˆèá} ý¾\=zŠF篅ô!EQTUEQTUEQTUuUEQTUEQTUEQTUEQTUÇ~#„Y–e™fY–e™fY–e™fY–e™fY–e™fY‹'÷xž9/$@ñîx .U © Jö*T¨Ôr_w‰ãœ–$³$L±<¬<‰,É%–Dò_w,eF£Q¨Ôj5F£Q¨Ôj5F£Q¨Õü ˉ ¬ÚͬÚͬÚͬÚͬÚͬÚͬÚͬÚͬÚͬÚͬÅÊû¹ûuà ‚d1¨#àÃ×îçí×(”Xì'Ü’IS#ëÃ×îç‹’¹È®Er+‘\ŠäW"¹ȦEr+‘\ŠäW"¹È®Er+‘‡ÝßÿÄ*Q !a12@0AP€"`pÿÚ?ÿŽ"*ûuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu ÕN¾ßñœŸ¾ßçW ½Åwc‰ë2¸3ØERfbª’%B{~nO_ïóÄŠCH÷0E B(c¶‘"ŸŸ“ã×ĨžäÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛdÛg#‘[þéĈ©Ü‹h‹h‹h‹h‹h‹h‹h‹h‹h‹håj"ÃíêïqDUÁ•$"þ½y¾?…8ÕS&§œjq©Æ§œjq©Æ§œjpæ+}þŸ·® !¨EO^oáãøúdÊC$ÊC&}9¿_M©ìlq±ÆÇlq±ÆÇlq±Â½Wßðñü}"¹"¦;äýR*aEEÀ‰éÍúþœˆ‰ƒkM­6´ÚÓkM­6´ÚÓkM­6´äz;ÛÿZÕw±¥Æ—\iq¥Æ—\iq¥Æ—\iq¥Æ—\iq¥Æ—\ip©…ÇÞáýõÈ’AÎ}‰Y$%×ÉòûÜ?¾¸‘QZ¤Dj¡ƒ ‚=|Ÿ/¼ÇÄܦå7)¹MÊnSr›”ܦå7)¹MÊnSr›”ܦå7)¹G.W?ÚÞ?‰ƒÞŽÇc 9>] î`Áƒ·¦={0`Áƒ ßCãÐã=Ìÿ‰‘W·O'Ë¡=úä"ˆ¦b¨¾ ®p"ª¡žÆW¹z9¾‡Çòò|ºïÕŽŒ˜ëæúT&ë&ë&ë&ë&ë&ë&ë&ë&ë&ë&ë&ë=úfë&ë&ë&ë&ë&ë&ë&ë&ë&ë&ë&ë&ë&ë&ë&ë&ëU}ÿ®üI•"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú"Ú­¯»Ãòôw±•É"B;±îH®S¹"DŒ¬Iw$H˜ŽÏ¢ýÞ—¢÷"D‰"*"ž‘AdPŠ"‚´F˜ô_ºÇErnðnðnðnðnðnðnðnðnðnðnðnðnðnðnðnðnðnðnðnðnðnñý o*dÒ†”4¡¥ (iCJPÒ†”4¡¥ (iCJPÒ†”4¡¥ (90¸û¼¼ ªe ©”$‚.I'àäù}Þ?^$T‰ÜTíƒè"\`Dëäù}Ö9"M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶M¶=rïúïÿÄB ’1!234Cs²á"@PQ‘“±Ò 0A`aqrÑ#B¡ÁR‚ðb€ÿÚ?ÿóD‰œ1J½Ô•{©*÷RUÝIWº’¯u%^êJ½Ô•{©*÷RUÝIWº’¯u%^êJ½Ô•{©*÷RUÝIWº’¯u%^êJ½Ô•{©*÷RUÝIWº’¯u%^êJ½Ô•{©*÷RUÝIWº’¯u%^êJ½Ô•{©*÷RUÝIWº’¯u%^êJ½Ô•{©*÷RUÝIWº’¯u%^êJ½Ô•{©*÷RUÝIWº’¯u%^êJ½Ô•{©*÷RUÝIWº’¯u%^êJ½Ô•{©*÷RUÝIWº’¯u%^êJ½Ô•{©*÷RUÝIWº’¯u%àëÚ'Þï†öí¢}îñøaÿhñ>Ú'Þï€âpY±kÐ^ë‚´ £þ]z8,¸8uz±aË^˜0ĤùÍ:vl~Þ´çÿÈšlC”\8=~'›½G?¨M5ÿô'Ï_öí¢}îñç¦#áÚ{®j,ñÝ)ö§ÿ)ºŸõpiQ:¿ùX}4‰‹Ð/ÂpË È³Hü® ^&B˜u— Þ¸C¥!Rù`OâÝhµ¥ÈDyqŠá;s¹p0çZ<¬?Âá?øø'Ú˜\È”Á'±E1fZÇY š‹¤ÖñŒŸ¹C{4mãÿl6e=í½×8Eÿ¹¦µÄËŠÃ/~a3 ;RO·n;çûAÀ£ƒ>Kä'õ î³7ÙœÉ÷¦Y˜ó×ý£ÄûhŸ{¼yéúNÿ™“>kwY\[Ÿø÷¡ž.Êy„æYyŸ+ܢÊmºsVCá‘ÿFôpÚq3sºÐc¥1Ô‰’ÑhýW 2w*E5ñË95©ñm‡Ê}hƒq\S"2Ǹ›ÂàöO&ç5!”Ÿ)'°^D—3¤${ŸÍåÞ×'ÄŠàç» ‚Š×m`DCÈ.'ÜœÇ\W茱ÿBô" Yì®;›W ÐìO# Ð%Θ%9bH2%žNgž¿í'ÛDûÝãв*PÛ šò9M»¤_öí¢}îñøaÿhñ>ÙÄX‘q7­[–Ž­ËGV士rÑÕ¹hêÜ´unZ:·-[–Ž­ËGV士rÑÕ¹hêÜ´unZ:·-[–Ž­ËGV士rÑÕ¹hêÜ´unZ:·-[–Ž­ËGV士rÑÕ¹hêÜ´unZ:·-[–Ž­ËGV士rÑÕ¹hêÜ´unZ:·-[–Ž­ËGV士rÑÕ¹hêÜ´unZ:·-[–Ž­ËGV士rÑÕ¹hêÜ´unZ:·-[–Ž­ËGV士rÑÕ¹hêÜ´unZ:·-[–Ž­ËGV士rÑÕ¹hêÜ´unZ:·-[–Ž­ËGV士rÑÕ¹hêÜ´unZ:·-[–Ž­ËGV士rÑÕ¹hêÜ´unN·gúÿýf÷‹ÚÒUì¥^ÊUì¥^ÊUì¥^ÊUì¥^ÊUì¥^ÊUì¥^ÊUì¥^ÊUì¥^ÊUì¥^ÊUì¥^ÊUì¥^ÊP{¥<7|ì<Ý¿Sãð|o°úѾÉ\ÔGZ-»þ¾«„q‘$ÞL‡ðŒ@ù´+Ow(c+-ˆ&œ×>E·¨¯„ûšp… ñûF¬µøQ²g#"œgdÈúÍúŸú±šW½649ÙuÓø67Ø}h¿a\í> 97€$¢†ÜaÌýTûKù_I¦ñ˜8roIp«73?UÁGmçMp~4C¨%fõþ×¶Ðú„Ùã;”}aÅpÇÃ/*Èš´÷!Ó’Ÿýn|™Ni„¾A÷)1ó+‹µÉ”®ýÓVLA5l¸õ«,|Êâíre+¿tÓ¬™Ù2)NÀ¬q‚~£¾ öNV„–Q´oYFѽeFõ”mÖQ´oYFѽeFõ”mÖQ´oYFѽeFõ”mÖQ´oYFѽeFõ”mÖQ´oYFѽeFõ”mÖQ´oYFѽNwûëaíc èïóÔà¿ù.÷=‚ÉnÁ­û¡›=¨)Ò1§4x'ï·cø\‡ àÄc[—ðŽ«ýDCâãÀ3ú® Å4“€:å Ä0'`3(ê¿ÕÂ5¥pÍoúˆÁd7e«ì‰ú]ôøºØ{cØÂú;üõ!Ä3›.Q[3ú„“ü«6¢Yÿ›X hºÎ)o¹MÎqýÎ*È–õ§p†ŽH¬® ×\m+vž÷{‹Ìä›ÓšáÔoFËâ5¦öµØ…g’.ù ÷9ï"ëfrM‹iÍpê7¢ðç¶ÕöMê0däLÿ´&^[ÿàõôøºØ{cØÂú;üçú| Ýl=±ìZKˆ—RÊ?úü,£ÿ¯ÂÊ?úü,£ÿ¯ÂÊ?úü,£ÿ¯ÂÊ?úü,£ÿ¯ÂÊ?úü,£ÿ¯ÂÊ?úü.Þ1ߨù®ìYGÿ_…”õøYGÿ_…”õøYGÿ_…”õøYGÿ_…”õøYGÿ_…”õøYGÿ_….1ÿ×ãàVëaíŽjà.‡ÉP¢ûÈÃõøAºØ{cšñ“ˆ\ènëpÄ]fså„­‡¶9«u°öÇÂ-ÖÃÛÕºØ{cáëaíŽjÝl=±ð‹u°öÇ5n¶ØøEºØ{cš·[l|"Ýl=±Í[­‡¶>n¶Øæ­ÖÃÛ·[lsVëaí„[­‡¶9«u°öÇ LÔ‡„}ág‘ûåYä~ÆyVy±žUžGìg•g‘ûåYä~ÆyVy±žUžGìg•g‘ûåYä~ÆyVy±žUžGìg•g‘ûåYä~ÆyVy±žUžGìg•g‘ûåYä~ÆyVy±žUžGìg• |*3€ptˆo¸Ï«áëa퉛­‡¶>&n¶Øø™ºØ{câfëa퉛­‡¶>&n¶Øø™ºØ{câfëa퉛­‡¶>&n¶ØøIàH8ŒU{)W²•{)W²•{)W²•{)W²•{)W²•{)W²•{)W²•{)W²•{)W²•{)VK›Œ‹Ôf¯e*öR¯e*öR¯e*öR¯e*öR¯e*öR¯e*öR¯e*öR¯e*öR¯e*öR¯e*öRž,¸tìO½Þ>Ô›mÀpÜ€$LÝóõlÌZ¾^™ª|Î'н;ïwµánsÇy%pWH›ð!Å„a—bášwè #߯(q )[}‘‡ûLÁ;O CUþ¡RŸ¹5ì]ÖGÉYâÚ~d(œ«MlËBãG6%}¥Æãu´!qEÎ-ž¸¨ø·Êrœæ£Z‡+§ÊÅö±#X$1ÕJtSØböµ¡²+„ÇÊ%i³÷¹f°;°³XØY¬ì,Övk» íhõö¼3[þ® ç\& 2ƒˆu£/pV-·áÆPœÒ YN^å­pwê Wú¬½À9¤Ì{Ó p¹Ž´ò­qR¸CÈ“$l}6›‹>í $ÿ‰…æC‹”ÿ•‹3Á´Bá œ&Ì»=¬A_Éÿ*p":ê8BŠ8T(Q.²e5šÀîÂÍ`waf°;°³XØY¬ì,Övk» 5Ý…šÀîÂÍ`waf°;°³XØY¬ì,Övk» 5Ý„ZÐ"H¼ô$mS<]ëDûÝãíH°Ù'èÐerä´7èF*ËXÐ:€RâÛ|îV¤-]5jÃmuÉI ÔÌ6“×%"0/Ó`2¹·'Ĉ{ÍÝJÙláñvµ&´òV¬‹]rö±>ƒýænÖÄÛ= TÏzÏä?þÃÖ±AX ¬GÐV#è+ôˆú Ä}b>‚±AX ¬GÐV#è+ôˆú Ä}b>‚±AX ¬GÐP›\&d9b>‚±AX ¬GÐV#è+ôˆú Ä}b>‚±AX ¬GÐV#è+ôˆú Ä}b>‚±AX ¬GÐTIµÃ¼K¯™»[lô$mS<]θ;pÃe—ÜŸ2ËÀîO™eàw'̲ð;“æYxÉó,¼äù–^r|Ë/¹>eW1ÖZ×ÖÊùüþ\éÚØ›g¡#j™âg‹¹Óµ±6ÏBFÕ3ÅÝTÏs§kbmž„ªg‹º"6©ž.çNÖÄÛ= TÏtDmS<]έ‰¶z6©ž.èˆÚ¦x»;[lô$mS<]ѵLñw:v¶&Ùè8°}înªd!{$Ö6扇ªg‹¹Óµ±6ÏBG‰.CE¶ÿ?úz"6©ž.çNÖÄÛ<Þœá€ÜeÔ²±+++²²±+++²²±+++²²±+++²²±+++²²±+++²²‘+++²²±+++²²±+++²²±+++²²±+++²²±+++²²±+)ósŽyŸ_±ŠF`¬¬JÊÊĬ¬¬JÊÊĬ¬¬JÊÊĬ¬¬JÊÊĬ¬¬JÊÊĬ¬¬JÊÊĬ¬¬JÊÊĬ¬¬JÊÊĬ¬¬JÊ.¶ùœ¶VV%eebVVV%eebVVV%eebVVV%eebVVV%eebVVV%eebVVV%eebVVV%eebVS?R&0ýǯػ[lóx_GžÄm‘À Õ™‹WËÑ6GXSqu•fbÕòS7)ƒ0„ÈÀ=‹þÑâ}Œo°úóqu•fbÕòFD`>¬ÚAcÑ…r^Óô<ÉŸ{|}‹µ±6Ï5d7B´×6s`Šî§àP¾‡üö0-0:q%ôM“K‰‡ Õqqaòœ§9 !Á/³yœ“ÞÛ°x NÄÿª,N/ôÀ2ŸîPÜ+, ƒ¶$"ÃÆ|ýŒBã!d_õ*B'î¦(®âì™ >¼o°úñ?`Zâçip†Ã„^xÂo’s˜Î[L‹ ’hwÂë…µ±%…D…,IaPpNÓì¦`§†£ Ù8bLo8 ¶-—õ! $+‰ŽT×í™=JÔ>O_):$!9Œ8e$ËM³€K é­ /{®h\\HfØg5‘‹8o¼.9í²=ÃÞP1`0þéÏ×gÞßú±šW½Bƒ“ܧzîÖÄÛ<ÖÔ \&ð\ç`·)ðˆÄü˜¡2 l¶N÷ý=×~SKŒ‡)ÿ*f!ƒh…'<4޵Ò•·Ú¨0’?GÜ£C~RH+E8½pvµÁÇŒ±sc6rh”ÕOƒÆþ¢·„ˆŒ3Áf!ì+?~ÿÊÆß¿ò±£÷ïü¬hýûÿ+?~ÿÊÆß¿ò¢›Q±™ÿŸ^'ñ⛩ÿWkœxÂp®ÂN#&üÑ#8Ç\'Š{n ´¦¸K›w%@w¹±fTµÁߨ^ì ˆ/ê*Pˆ|CŠÁ-_ÊðMŒ/†gü(‘ΑØ>ŠNxij;¥iÁB⣆€À³<*¢EsAe›mÁ…C4X®q¦³ Å '¯ä™³®Ò÷,æ4K_´:s@zÍk®.*p^èG´($€øvÄÜÇ\±£÷ïü¬hýûÿ+?~ÿÊ‘$Ê#Æ?Ü}.ÖÄÛ<ÕÚØ›gÑ èïóØa²@’™h&R¹I­|ý6`»²àê*Ô…«¦‰-lÈ‘À¬ÈK©`†Ûçw±Ú—kbmžjílM³ÒñµLñw7v¶&Ùô»[lóWkbmž—ªg‹¹»µ±6Ï¥ÚØ›gš»[lô¼mS<]ÍÝ­‰¶}.ÖÄÛ<ÕÚØ›g¥ãj™âînílM³év¶&Ùæ®ÖÄÛ<ö&Åt0Xç {¬õšÏ#ö3ʳÈýŒò¬ò?c<«<ØÏ*Ï#ö3ʳÈýŒò¬ò?c<«<ØÏ*Ï#ö3ʳÈýŒò¬ò?c<«<ØÏ*Ï#ö3ʳÈýŒò¬ò?c<«<ØÏ*Ï#ö3ʳÈýŒò¬ò?c<«<ØÏ*Ï#ö3ʳÈýŒò¬ò?c<«<ØÏ*Ï#ö3Êœóñà*^éõŸ7v¶&Ùô»[lóWkbmž{Tÿô‹µ±6Ï¥ÚØ›gš»[lóØ:§ø·¤]­‰¶}.ÖÄÛ<ÕÚØ›gžÁÕ?Ž"ílM³év¶&Ùæ®ÖÄÛ<ö©þ-ékbmŸKµ±6Ï5v¶&Ùç°uOñoH»[lú]­‰¶y«µ±6Ï<{Xë.#êS1Ým³oþö(b+­D³Ê?>v¶&Ùô»[lóWkbmžz.Cÿ¿ÏH»[lú]­‰¶y«µ±6ϯa…²”ð…ŒÊV3)XÌ¥c2•ŒÊV3)XÌ¥c2•ŒÊV3)XÌ¥c2•ŒÊV3)XÌ¥c2•ŒÊV3)XÌ¥c2•ŒÊWȵ)NÊÆe+”¬fR±™JÆe+”¬fR±™JÆe+”¬fR±™JÆe+”¬fR±™JÆe+”¬fR±™JÆe) –H1yÛµ±6Ï¥ÚØ›gš»[lúçíϽ¾<íÚØ›gÒílM³Í]­‰¶}söQÑ)Ž´1x»?ÌÔYË’òÑê¶#¥3Õè¡¶ÔC‡è­Fk =åžïUÏê\C œQ>R¶ñ ÍÙœ× •˜“õfü3êô=âðÒQ/8u(pÚiûf}íñçnÖÄÛ>—kbmžjílM³ëŸ´z‘?ÝOú¸A‰28Âj?)Œ"SVa2Pٌá?øø.ÿ‚àºïÊ­ <ÿäIMÒ—ÍpQ<w(O`“Èr‰Ý?Ôg« Ê(‰Ê0‰ý0™2A2æA|Saƒyµ5ÀÚ.Òá?øø.öß&§<ÆYÂéÞ¸ÜÏÂçg“ƒø\6Äkp¬ ÷E‡/ä&Æÿ¾%ô õ\ç`Á ¡9ŒkØË²åÂ8ɑƜQ˜c5‘ m|—V¸~ü)ì~$09)ÍË‹Á?vbF…!'†£5áø&ØÃ)«CŒ&wúŒûÛãÎÝ­‰¶}.ÖÄÛ<ÕÚØ›g×?hõ ²™ëB. <]•Ìt>[‰““ƒ8؆oqAŒl ™N‹³”0‡(¯{ƒ­É6 Óh ½Ðù.A°Ýf ÁõVc9‚¼3Þ =²³iöŒ½á4c„ýPâœË'þ½ÉÐgŒ Êàå埥1ƒéèƒJLœÓ¢Á,å !Ë„:;ÁkÀµ,ay\ ÂÒf£D2“å%ÂLÇê¶C±C†ÒFJEAc%ún:,ÎP¸ç¼:m‘Qg.SË‚ˆ-L^1¨µï†>M÷«P^ÑÏ)®¸§—¸8ØÃ/rp€æX&r¹>iî3™õY÷·Ç»[lú]­‰¶y«µ±6Ï®~ÑÌÞÙ–Ýè°Á&úÒ*І=Ÿ-“Rceë³ïo;v¶&Ùô»[lóWkbmŸ\ÌË’0íXõcÕŒ;V0íXõcÕŒ;V0íXõcÕŒ;V0íXõcÕŒ;V0íXõcÕŒ;V0íXõcÕŒ;V0íXõcÕŒ;V0íXõcÕŒ;V0íXõcÕŒ;V0íXõcÕŒ;V0íXõcÔÌ#¾<íÚØ›gÒílM³Í]­‰¶~v¶&Ùô»[lóWkbmŸƒ­‰¶}.ÖÄÛ<ÕÚØ›gàçkbmŸKµ±6Ï5v¶&Ùø9ÚØ›gÒílM³Í]­‰¶~v¶&Ùô»[lóWkbmŸƒ­‰¶}.ÖÄÛ<ÕÚØ›gàçkbmŸKµ±6Ï5v¶&Ùø9ÚØ›gÒílM³Í]­‰¶~v¶&Ùô»[lóWkbmŸƒ­‰¶}.ÖÄÛ<ÕÚØ›gàçkbmŸKµ±6Ï5v¶&ÙöÜ·µ³ë+-¥–‡RËC©e¡Ô²ÐêYhu,´:–ZK-¥–‡RËC©e¡Ô²ÐêYhu,´:–ZK-¥–‡RËC©e¡Ô²ÐêYhu,´:–ZK-¥–‡RËC©e¡Ô²ÐêYhu,´:–ZK-¥–‡RËC©e¡Ô²ÐêYhu,´:–ZK-¥–‡RËC©r×K¨óGkbmŸKµ±6Ï5v¶&ÙöоŽÿ:1ÿhñ<ÑÚØ›gÒílM³Í]­‰¶}´/£¿ÎŒÚ‘ýGKô4‰(ÇŠ dŒ'{ìþ'Ÿ-ÁÓl½è‡jšÕÈ«A'OвŒtWäŠ9pMÔXXÏBøè¼bá^û *çÈÀj‡$¯àÙZ>ò?ê0­6V´Šœ²ÊÍb]êšâp²àe~» á"\5Šð,"T€dc–]{î4HWVwæ–አ'Úè–5y÷DB9™ª÷!R±GWwUEüràˆ-$ÅùóL¨PA=ÈjG¼œseÓª€šGUPÜL>5uSÖ}Ë¢¢ÓK±†ˆaN(ËI„Zþ"NÊ—­YBô„€X:¡jÞDÙÍOY÷ ƒÜÊËWKM?Ôû±˜+U,ˆÍ&@^?ˆÖKÖèµsµwtmR‰f:b³:â/N ®³îôN¹ ëåu`7y( 1DB¹Nêuïgóú°¿fªk=Kì§$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rCm xØðqÿÛ6]`?¥:©NªSª”ê¥:©NªSª”ê¥:©NªSª”ê¥:©NªSª”ê¥:©NªSª”ê¥:©Nª¡©Æ$côø¿géñ;xŒá`F”FÞ¢¨ 0*‰>€š:è€Kz&‰ªL†¥¾Iðb&1ÖÜÓ”6A“}ÅCÞˆ|rvþèyÖT™Š{‚Ácâ™Þœ[ÚKû¸Ò Æ„Œ~›·Šwe±$·1¢¸h}B‚íc¥DÉ@ –cDà³L ”D["PFû:Dê¢|[:ÅV¢¾î9z­°#Œßçˆ0`Áš)(º;²h‘xÙ¸ñS’NI9$ä“’NI9$ä“’NI9$ä“’NI9$ä“’NI9$ä“’NI9#\¤=ÞL‰ÛÄ뉸 "Y]èÕTø[*Q.{ó†ÝäN¯Žöœm2€ãØAê"l†ÐNàvi¢")ÁjÞ¾9þS”òh¿gâÅ` E`hh¬àHذAmx.jÚ•±K'TäÞ°± ŠÉÛ¤ƒGø¤YPdà#Ñ£~W³ûö&ˆµˆXаõTrUì±Õìþý‰¢,+ŠìêÕkp~vð|§“k¿g º—º—º—º—º—º—º—º—º—º—º—º—º—º—º—º—º—º—º—º—º—º—ErN\“ŸÅŠÇÉþ‚Ù<£špÕ‚»°È˜ž”ýš+)útSÞ¶àì»J»J»J»J»J»J»J»J»J»J»J=]ïõ»J»J»J»J»J»J»J»J»J»J»J‹ ’Óõª+–¦ž¿?Ä÷kÊ¡ý–-sÂXÓ‰Fi-qûÍ,X±bÅ‹,X±bÅ‹)Dq«_Å(P¡B… (P¡B… (P¡F[ ¤°›þ'âÅ‹,X±bÅŠ öÝJuRT§U)ÕJuRT§U)ÕJuRT§U)ÕJuRT§U)ÕJuRT§T* -@ x)NªSª”ê¥:©NªSª”ê¥:©NªSª”ê¥:©NªSª”ê¥:©NªSª”ê¥:¢"l X»ñáç°¾éî.±‹bˆY^O—*Ûýx÷Pƒøq{ùîwÝbõƒP¬ì¦á Zå QÂyúÀS{*Pè¶žDÀøòÌú¢«{µÏªÖÝÿ6C‚}SÝTMΟuV$#á“\Z¶«!†G·ýDdQ €àUÅë sû¦îcUuݱýDèâkßÍtêg5Jp¥8Rœ)N§…À`¾ïÍÿ {êv AÔ3°³ÚË·$I1eXŒ ¾»"©°L)¹öC˜F%@ãT0G¢j2[T°Õ‡è´­Ç-ÿH YaR%`2¨°AÈ(ßî,¨­§DámUïeÐo{Šh¥8Rœ)N§ S…)”áJp¥8Rœ)N§ S…)”áJpƒ åJX ßtœ÷XŹDÅ\"Éö½z ´Q¡àP€û®,U¶_Çû ÖƒÅú…Ñ„ƒlœ\bqˆ`°LÏRv¾†\2#LákÃ×îÅï縩w|zW‡áCð¡øPü(~? …‡áCð¡øPü(~? …‡áCð·åESµ”? …‡áCð¡øPü(~? …‡áCð¡øPü(~? …‡á„7_Vî¨ÅKNð>oÿ^è¶8ü£û,T àw³ü”÷N}! =ÃúÞŸæLT±b¥‹,X©bÅK*X±R±`YÃc¾ð0`Áƒ 0`Áƒ¨t‡xZ¥þPâ¥K*X©RÅJ–*T±R¥‹Nª= •o}ʃÃöT±s%¬Éb…†—_w¡E2¢™QL¨¦TS*)•ÊŠeE2¢™QL¨¦Ug­ TS*)•ÊŠeE2¢™QL¨¦TS*)•ÊŠe«½}[ù}’ @PF”QL¨¦TS*)•ÊŠeE2¢™QL¨¦TS*)•ÊŠeE2¢™QL Tµâ}ÔS*)•ÊŠeE2¢™QL¨¦TS*)•ÊŠeE2¢™QL¨¦UËSbm|¦+â½Ð——*ÛýOZŽ8®ä`¸D¹VÝIÑJ‚5W†*s·áU‰ÛÆN+¹..U·W†(c·„õ¨ãè J(Çvü)Í¿éŸl©L ëè‰Ê-öU•XúœÕ7ÚEÈÌÚa0 Ü&­7Oë Ř`$£¡];klÔ ÓCrtMµz€#ŸÙ,’`à@´_æÈÔâ|q;xàp/•ág²}«ÔÑYšÀæ„Qæ’~†ï.áÕ†ï.áÓ‡ŸÙœš¦Ç–gÕµ $Ý[µ2|çB¦¨n©ðt[Œª¨µ_Øš·A¹nˆA9MU·B¸ÆSœ‡ 9=§©:\-5 Äž}gˆ¸lj,æ4ñÎmN-í%ý,”ÌÎt™wH#€=¨b)ÚaîPm4~_gà?¨/D¬°© T Ø!ƒ¤’ 8d b+J½ÅPí~ #ªˆê¢:¨Žª#ªˆê¢:¨Žª#ªˆê¢:¨Žª#ªˆê¢:¨Žª#ªˆê¢:¨Žª#ª8¡ ¢ä øùÔX±gøùdæß:‹,ÿ<&ØYp%KÔv@B˜ØxF9Á£N}° ÊöpþôAp|(ˆæ¡wDsZàÃ=PÂÈdI»3-§û›ÑµÀ"ˆ*„8GhsLýé;u,Yþ>(`0ð÷E\ÖF†­ðƒ1*™5ì_ýI¾+˜{&Dʱ ;ù\0N¤©²á‹ÕK˜$V膻ˆÜ(~U@%šN=U¢-¤ ±|tXbÉÙÃ&ÍNsÎÿG ÂX$ôMI‹Ôk†©r:/A>° ¦@6ô÷,Œž<ÝîŒLaû¢€HØ«àÁzºtòÔæPJ àNÆQ œvv ‚`˜eN‰`r'ÀœÛçQbÅŸãà'€Û. +uwt^ë¤Í§ªÓ»!M‚ ›*uP¦´ZÝ@pO{n*ÿê5÷b: {¢Ås¹zd @æ4@VÀsŽˆ™‰Ev› ×¢\:“ª ¡¼š†ô(ššõ Té­ÁØÀT7È@YÐ/B `EjÊ T®‚½¬ªºE" ï¨ÝMºlÈæ‚áF®œ@ʘا¡.=V¸D±q)É…W1ºl‚Ý2qO„t“€ÚÈ©‡¥Á@À<›|ê,X³üo‡èÀ°wñA¡ 9áÉ#ÛíœD,l~ »kãœÛçQbÅi‡4矖)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JƒÃÿÅX±bÅ‹,X±bÅ‹,X±bÅ‹,X±bÅ‹,X±b³mƒ®Ï]ž»=vzìõÙë³×g®Ï]ž»=vzìõÙë³×g®Ï]ž»=vzìõÙë³×g®Ï]ž»=vzìõÙë³×g®Ï]ž»=vzìõÙë³×g®Ï]ž»=;o‹è¤X±X«,V*Å‹ƒŠ¾¬QðzfïkÝRÐ5ftH‘ ë Ú¨*D½‰6MÄîI/@Zéœ8'Š>'íªxÒàˆ@4ü¨¶teä¯äÀãÇé®î_ DϺ,µNÊ­çUbÅ*,2ŒB¹›“÷Š(P¡B… (P¥}fZ-è>ñ`´m›”éEg»8¾fe±\ìœ3‹ ©ì@Lt6(nÛtš²º®çL =mg“GÁ wtZîr2P¹uɇ½QûÔ]f¦&üÓñ (P¡B… (P¡B… )}ˆ¶ä¬¹óH¬±¸ZÊ60Îfž¨‚ƒS¯ñVPt`jä„5¢€[…‘s‚äÙô±V5®J÷,A‰0Œ À¥Wóvå²r– GÑ®Éܹì„!°E…ó¦ÓÿUŠÅX¤òˆ…Û‡9$ä“’NI9$ä“’NI9$ä“’NI9$ä“’NI9$ä“’NI9#&|‹™ˆ?¢œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œ’rIÉ'$œÛh6<ñ´T±t:êvË©NT§*S•)Ê”åJr¥9Rœ©NT§*S•)Ê”åJr¥9Rœ©NT§*S•)Ê”åJr¥9Rœ©NT§*S•)Ê”åJr¥9Rœ©NT§*S•)Ê”åJr¥9Rœ©NT§*S•)Ê.ˆpGøÞÿÿÚ óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ãï¾ûï¾ûï¾ûï¾ûï¾ûï¾ûï¾ûï¾ûï¾ûï¾ûï¾÷Ï<óÏ*÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷ßkóÏ<óʽ÷ß}÷ß}÷ß}÷½äoÎÓáGxïÌüÛß}÷ß}÷ß}÷ÚüóÏ<ò¯}÷ß}÷ß}÷ß}±çÕÛžùïzëÞ÷ß}÷ß}÷ß}ö¿<óÏ<¯ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}÷ß}³Ï<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<4ãŽ8ãŽ8ãœóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ?÷ÐrY÷ÞPóÏ<óÏ6óÏ<óÏ<óÏ6óÏ<óÏ<óÏ<óÏ<óÏýõï]ú×}÷ß<óÏ<óÅ=û\zÿoþÛÕ¼óÏ<óÏ<óÏ<óÏ<óß¾ûï¾ûï¾ûÏ<óÏ<ñOTRòTâæÄõo<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<[Ï<óÍ<óÏ÷ß]¹ëmµëöÏ}÷ï<óÏ<óÏ<óÏ<ðãM4ÓM4ÓM4×üóË 4ÓM4Ó]4ÓM4ÓMwÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ sÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ;ûï¾ûï¾ûë¾ûï¾ûï¾ûï<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÊ=õ®òï>÷»½ìÑŸúÓ}ûÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ò~øÇ9«^øÅ/ùï¿ß~óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<øãŽ8ãŽ8ãŽ8ãŽ8ãŽ8ã|óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÍ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ×Ï<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ñO}÷ß}Ç=~ç}vûß}÷ßWóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<Óß}÷ßkž»»Lï÷ß}÷ÝüóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ÷ß}÷ß}÷ß}÷ß}÷ß}õÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏÿÄ.a1!Qq @A0P±Áðp€‘Ñá`¡ñÿÚ?üFL¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼LpŸ^ á˜:ð^úZZäÐoŸ¡$ÓX¨LŽù5@¤‰Ü„¡YÂþÅ8ÔÉ-É]̈'«óü“qï`ëÁ{í´cÐnÔ 7嘤†Ì‘)’~“fÄÉànÆåϽƒ­b„TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"­¯óGŠyyyyyyyyyyoá=V~Û ~ÈQþâš8"-ëbŸqmܪª«ÙàõL°7(’á».$Imî9½<~üÀÝ8ƒÅ˜: —:t$4Ö}<»=E• %/g7¢XKï2f±¦„ö'~D1F¤‘Å r”Bôòø;ë^çÿÿó3þ’QŸkÿÿÿÿþ„•ß`ºò¼I9©ÀऀMàNÁ=gÇ^.û× ÇÜ@”%Ej mG% q£nâºñwÉE$7!¹ ÈnCr܆ä7,!¹ ÈnCr܆ä7!¹ ÿ5Ôw"[’Ü–ä‰{’$H–ä·%¹-Ì} nKr[’%îKr^ä·% nKr[’Ü–ä·%¹-Æm9ì3t$¯×ù”¥xÊ<O è·úôâèÉГûþ„é·ÐiªHIÿ&@¯QŽCKìÈÑa†A¼Ù3/•уì3tI,–K%ôâèÉÑ$²^ä²Y,z cK$–KèÁö ÎZ)E(¥¢”RŠQJ)E(¥¡$”.šQJ)E(¥¢”RŠQJ)E(¥¢”RŠP“ùwd¨¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼’µïõ”L„9Ù eË| ÇP%ŒêE)oa+9þ„“Îuù NºCo±µÓÿƒÈ4Âc†§!)«ôÉwúpå ÉD2qNDßhvLN0&6 çМ@”ä^A³Ï¦K½ÒŽG#‘Èär9ŽG#‘Èär9ŽG#‘Èä(9ŸÉˆ                     Ô{›­9H‰›§†5jÑPÈHµ#Q׋½Í×IbþBEªÎƒz CgàH’o:ô†˜ëÅÞ²í"¢¢¢¢¢¢¢¢¢¢‚¢¢¢¢¢¢¢¢¢¡TÿÿÄ.a1! AQq¡ñ@‘±Áð0Pp€Ñ`áÿÚ?ýœÂ$¸\. …Âáp¸\. …Âáp¸\. …Âáp¸\. …Âáp¸\. …Âáp¸\. ¥­¼ÿLfÛÏó˜›Óà•|É,È™<‹LµºIk+—ö¥rSjÌl¿üLpNQ{ˆ‚´ÞŒpM­§ßü´oófÛÏó’©±I?t>ÜÄ©Èð[‘‘±"Ó„Aôè`®„È‘¢ûöD¡GæÍ¶ñÊ @ P( @ P( @ P( @ P( @ P( €Ø“ÿš<4’¡P¨T* …B¡P’¥þ‘—ŸÇ‹G£ÜCÕü%$8›v½É$¢¾·Õãî~ðåzœ¯S•êr½NW©Êõ9^§+Ôåzœ¯S•ê@y6^-¬Jr‘@€Ù¸¶÷øûŸ‡ÝþµÃü‘9LšS#E–4Cœ‰˜cD9É È‘áøcý¼šøbòòòòòòòòòñ\7áÃ÷ƒc>~ÐIc¨›Qqø#[Ω.Ro­Q÷"Íkx¶­Ò:e駆?Ûôtvü€(_ô’œƒrAÈ9 äƒrAÈ9 äƒr@ùž{=¶3÷0hH˜¤•´LZ+ !¤oÛÏç³ÛN3ÃÞFÍùÈÄÜt$œ§Ç¬‚ÉËs ”œe™ß3ñ·ŸÏ1Ü,•+˜Š:àC}A „àC8¶1sD8àCPBàC €“cà‡p!À‡p!ÀDš!‡îý‡‡4ýЙ4=øh™Ñ‰“kv¾Ã§Ããg6Æ.kßa£ÑòD–¼¬Ñ·£t7ê÷DŽ7Jûê2S¿§¸‘«ØÊ&S&–+]©,ɸ=Õ÷Óc5ä0ýß±…’…³›c5ï±…À‡„-R!!°B!lf¼‚Je‚Á`°X, ‚Á`°6Ú^Í‚Á`°X, ‚Á`°X, ƒ(Ÿãº!jt* …B¡P¨T* …B¡P¨T* …B¡ èó¾Çƒ4íHâý†Ð¡ p;[Ü—QLœÀÙ7¦ˆ“p—ƒ˜Æžãi‰3ÌqR蘆MnùF8ô‘ÄS¯oôÝ òׂ›ˆÔä×^ƒðÁùßcÁCNQ “JŒÑio¥CÐMCeáBgûÅ’®D«?;„Iâ=Ä{ˆ÷î#ÜG¸qâ=Ä{ˆ÷î#ÜG¸qâ=Ä{ˆ÷î5ïá›2×еô-} _B×еô-} _B×еô-} _B×еô-} _B×еô-} _B×Ð[ÓÎáû¿m©ÃbR”È™„ç –‰”n9ÛÍçqíÈÍ’D×F7zQpVD](ÙÒáô¹ §D`™f¹R7r¬Ö£Jø(_”Á …!ÔD&˜öÐt-)òøÞ‚5 ó9ûCô±Ý Õ»¯/£}˯â÷®¿á³KÐ ùæ½ë¯ö>õÑÿܺÿÈzkÞºüFñ%&¬Þ¹ˆôÝ€t(6¯YyÖÃ6(|X1ÿ eòƒß¶Oˆb5ˆ©a¡L…aBª­˜ÝúBÄ `-rcjáÁë]PžfÐP65RëJ¼ú þcQ늋F”ïqÅ)cJu_”´ TºÒ¯>©tf7FLø˜”Nv”Ъ«r™,…Ùt‹£ ¼þzèÿÁ£o ºß_ëºtéÓ§N:téÓ§N:téÓ§JLUº!mVºD×½uøi½§®fEY Zlò>•M̨ Í} å* æÃœ[…:™yx_{½< Ñ õ‚¯P „ Õf>ùˆZÐ]_ fq¨‚Óc¹¼5Ý{hUBÖœ#ìå¹¼¯§Üñ‹öW™a@MÉÑ4¡c•¯–emp_ßù÷®Ñƽë¯Á6e¨7Ž6¨º.ˆ´)ÑŽ.á) nWz¨Ñþ «#H1òR8ì@EŒe­ñ/jæê¬_HÉ‹b)„MR.€ê`T8€b‚àSeÀ©…½qX¾\ÊjÑFˆë|Ìàwº…‡ PpÙs7f¿õR²ÊFáÃB·¸ë«_' ð{×Gèã^õ×ûzèýh@[/³%ð2½zõëׯ^½zö©´5= ò#ó+ׯ^½zõë×®žŽpý45ŸZ­Å2ülžIŠÓs‘|þ¥4²Ë»O*cšUÔ€5AŒ÷ÌhÑ£F4hÑ£F4hÑx’¸K5ÈGú´©R¥J•*T©R¥J•*T©R¤õW‰(-e:'þæ4hÑ£F,¦è´¢ßîùîùîùîùîùîùîùîùîùîùîùîùîùîùîùîùîùîùîù9v•¿&–o‰ÝóÝóÝóÝóÝóÝóÝóÝóÝóÝóÝóÝóÝóÝóÝóÝóÝóÝóÝóÝòÁ§kX£k§×è¡A|æeá´Ã.Õ¥i½qðÔ2Ú^µa­^ÿÎÁÛì‚ÁFÇá²êóô¿áW¹X¤]Ž‹zmª»DóHa.؜ԳG‰`pƒiÜ8c5 i¾W!ÅyÏËGCuZOwÎnï*F´tðê®J.èÙzè©E/uY¸Š‡Â“Öé­DÀæ² Þqus e…JzÀ°1yhÔP¾ ´ÇQ |!˜†1à¨cW_7Í”»EêðJxšýó0P²åÁÓý^VT½õF®:J•*T:ÏØ*09ÚkI…tFü ¿(@ÔZ`¸èKc ·ÛÊ=àôÓSÔ–¾µ2e4»û3Ýó„ê!Eb¥n±š Õ\=ÖAÑÕp[J ™nûyÂeÕøhþaUtÅÔý´%ZF…vÒ¼ãõì¨MXb÷Š7ЃT´oWólíÊûnÜò2öBò Š²Û‡h0fêcñý•*T©R¥J•*T©R¥Ct¯õߊH;ç0º+-†XJM[”Òéd_.•üj{·õã« á°)Ї„tju— 6—­ykW´X¶;¿rÒ½C à™ý—mêH¨¡Â'I\'„%l:‡ðÔ ªÍØ)ÅÃse8©ŸÍuÇ¡ õÒ¸Ô}øÓð;HÈH ˆ„D©¯^½zõëׯ^½zõëׯ^·KAD¼Popãêëׯ^½zõëׯ^½zõëׯZ @m‘P¡uO_¤M?ªá á4‘å‹í$ê}Ÿ©M?1ìƸ+w”»®ÖÛ!{ÿ¬ÓóFŸš4üѧæ?4iù£OíW’±‹W&¿8¡B… (P¡B… uÑ]´Eš£bjÿÕ §ïÍ?~iûóOßš~üÓ÷掠ä;~„CÉÙ¹¥|5ò”¡ÄØ(=©_š¾)q¬gàÇÈúeù¦ï¨¸ .ÅÕ¾¿76lÙ³fÍ›6lÙ«fÐ >ç׿æÍ›6lÙ³fÍ›0¸ê㔚³Xtù*|G¥ Ùþ–lÙ³fÍ›6lÙ³fÍ›6a‹)Z.Á«Å×ú9³fÍ›6lÙ³fÍ›6l° †"Hÿ×½uù5¹¢8‘º\8âT2Ú^µa­^ÿÅ¥z†•É)ìm¼ÌõUÚÕ†µ{Ä>¤¨ªìCx"v¢k­êñý-¾å×ñÓØ(Ú-y˜9ꫵ« j÷Š‡ÞŽ–ª´xøm+Ô4®Oà2µ©A›ê°ô~!ÆÏò°š&,»½ ”ù‰æÒÜŸ€°SˆáÏÉ¡&ÂÊΕ÷ÖXUè&WC˜Gu! Øká)jHASAÕI "u%ÆNT²Å¸pŠ‚¾¡¥·áLꆘ:ÔÒˆ¦æœ7,ÇÉV>ˆ Õœúëа [ŠÄ[Z:iñû—_Ȱ FMÊaÆ´¼ëå5¢+¹£-Úq)G‹–9[{Ô ›qG:M¶Ï_Œ¬W‹6Û=~2±^,öÄ# Õi?.A Õi.ëw1êhrÒY!Ü*ʼLG‘E(z½Xæ` 7dÀmlò/IfŠVW]fJ D™Õ4Ê]޵ž¨šÜ¢ì4*Õ‰‹é´;Èn†ª¸ÇÌRHÍhntbüp6LË­Å5…»x™Ü*ÈùA…ùœý¡Âêu£w®éáýÃWýŽÜº S\fnzŸÎ¥<ˆ‹,•¼í?*vÑãhWc|ÆúÙPš°Âï¢ATC~˜éR&RUþ.2¶µJ¯©h×¾:\žÞe@hÒ²¸\ ü@ëÓ’5W1M>c)±Ú³égÑ-ºu|Ølœ|aƒ 2 ±ê,N|‹>ÛùDDXAztæc­U‘êwáé)ÅijÚáëÞ}KKÏá•„#`³†±(ã]¿¹-}j$dÊiwöb×m³c7€“!k+«l-©ù˜Wâ²µSGÒ½#˜oY©û0i/B bôÇInŽò“Wëò m”èWƒ†5[ iÿ©‡Ç#«6 ^˜â<¹Š±rO^ëÄVÉc÷ŠÀNÒ•às+Ì%¸7ø²¾KK#ï öÔˆîT­ÕU¾Ž¿`Áž”ÁÏå•@etþÑ£^õ×䯿ˆâB¨r瘦ì&V÷“µæ¦5×àN­½ íã̦P¥6XãiƒŽªºZòÖ¯hØ\Q^©¬œA¤H§EiPt脃yþ–ßrëøéì M–<ÌuUÒ×–µ{EÓ¢Pº¬eæ4ƒ@(¡(ÂÏvþ§2«ádLÊ éVˆÂjµ«lÜ)­Xýë_PÿÇÂhѯzëþo¹uý„Ñ£KŒ¡.az‹ÐôþÕ4hÑ£F4hÑ£F4hÑ£FD;¢Èd×_“š<‚Z)1Çô¨Ñ£F4hÑ£F4hºž6­Ù=èÑ£F4hÑ£F4h”ÚÊ!i£×þÁM4üÑ£OÍ4üÑ£OÍ4üÑ£OÍ4üÑ£Lú†¨V˜mýªT©R¥J•*T©R¥J•*T©R¥J•*H~™‹HuÖ½¿é$Ñ£OÍ4üÑ£OÍ4üÑ£OÍ5¨á´Qô€ÀУKv­¨½<¾¥4hÖÛ& WÂ#éFd|Èj¹'zÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÇzÂVn»¢á°ÎõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõŽõƒ¢ÞJœ§C«ý£F{'_©¸M5ì~é ­—I³2½_¦w]R¥è-®~#Å `×§ðPG¿¥í*¼Jæ5i¨ð†X&‰ð+öÁ«EÔe¡©hêý¦…Øu¹21 ¢Ð3w¿ŠIÜzô<xþ”$0¨—Æ!1Ø$*&W\úBƸ-*%4,ÞßDa4hײuøv}·ò˜T9†¥¶¨òŒxK¤N¸cYoƒ”]:¿ü¿å$§{ßHû•ùÕçë[Üe^¾Q¤Ù1޳(êj<®çÚdù/Kzñ4Žë"„ÈnÛx‚È«6ÔxRz˜ºÇâgëÌzÐj_nDèøþ{¨n°-åw /G Ò%ý§°õD1q¢še¬ã™k;úɽ´ô?àäGð˜S#./TÚ F’s{ÜôÍJXÞ€”A¶” f‚[¡å.&£ ˜fíÉŽ±Üy”–jY¿­×ƒv­hÄ-ÎéI€¹«¿Y{À V‹Aù‹ÎòkjõIH9¦ *ÛZôÿ{ £F½“¯ÁËý!2èv µÚYêUUUÌEhÂmXY’&M3[ ‹FéØð]!¬J.ÅÝ]K.Æ&ÒÅá´{Ñ@£a²«hË‚:‰I¨:tKÇ$¶‹Ð2æ% dŸ5t½årÀlFét¸¤º+n%£µ·O¯9lÕ*êåoÂëÊ]µx°´Ã¥Ó¼bâ‘¶× KP¾ k†ôþ‘Mª ÇÔ»›K†Ð°Õ²Ñ— •®á·ÎÙ¯âê2@šLV…s¬Bbo÷`Æ’Uh[X-ÚàyejNjê—nvÈZQn¨r­Å‘è"…~SH+m9ØjÞ°U×*Ö€ØfTiÊàPçKó”öê‘æC\µÆúBìÓiCõ@ލÞt¶y–A”ê-GŒ¢G: p ÑFˆÆ ïa4hײuþ‡^͌ޗNzÿ[«j–Û•]_ˆð2ˆìÌ,Pðšû|³]ô*KCQ:úõÊåóú £FJÁEçLíIÚ“µ'jNÔ©;Rv¤íIÚ“µ'jNÔ©;Rv¤íIÚ“µ'jNÔ©;Rv¤íIÚ“µ'jNÔ©;Rv¤íIÚ“µ'jNÔ©;Rv¤íIÚ“µ"”¯þi£F4hÑ£F4hÑ£F4hÑ£F4hÑ£Fn÷mÖµnu=gºsÝ?¹îŸÜ÷Oî{§÷=ÓûžéýÏtþçºsÝ?¹îŸÜ÷Oî{§÷=ÓûžéýÏtþçºsÝ?¹îŸÜ÷Oî{§÷=ÓûžéýÏtþçºsÝ?¹îŸÜ÷Oî{§÷=ÓûžéýÏtþçºsÝ?¹îŸÜ÷Oî{§÷=ÓûžéýÏtþçºsÝ?¹îŸÜÙîß­.œhú´hѯzëõ7i£F½ë¯Ôݦ÷®¿:d¦ÐR•Ç܉S¦*÷24Ñ”–w‹]]s  ¤ÍAkÕ²³b u)*q½Rô‰iCa9 @ L1z•ÇLÊ´ ôUeuKuyÈw8D¶¥ë:õ3žzœñHé6mny¨;nk"ˆ˜^Ó—ÂzÕ_Ýų>h­³ÆZújûþ­o?ö¶š5ŽW‹(5›…ùÔ©R¥J•*T©R¥I¸ó³Ó½æôùÄcPÞð¿QQËP§k(‘o{§ãølîªSÍ”a¼*‡š%À€š²=3 Ce:‚¶ÎohElxþ°Ln;«Yçø‚¹“ME‹ã˜AIºÖŒžWžf<Ÿ®'BÊêÒÕYZÔB…¤»/•zCÒ‚P(ÈV¢ï=ß?œò!·¯ã×õ)R¥J•*T©R¥J•*T©R¤{êàw@ÿ×½uùÚx0w(4ƒÆ©¤›6ÒSEÖ¥Jx!4ˆùÀkpŒýƒ¥¢Ïfd[H+ £"9gó¥bæƒT:%ÐY™Ý9qàb5t2n*Æ58’JÙN™ÍÊ 7I}Bú!p’ lÑ,½ŸáöŸ0±~rä ô\¤ªêãH¨x©³}Õ]k½_ÑM{×_©»MmVâÕª]Sš4.h\й¡sBæ…Í š4.h\й¡sBæ…Í š4.h\й¡hj±»ÄœÐ¹¡sBæ…Í š4.h\й¡sBæ…Í š4.h\й¡sBæ…Í :Ä:ÈVÅië§üliù¥ÎŠ·¿!ue×SüÚ•*T©R¥J•*T©R¥J•*T©R¥J•*T©R¥J•*T©R¥J•*T0'A$0‰›ÿ¦ÿÿÙzuluCrypt-6.2.0/docs/zuluCrypt-cli flow chart.odg000066400000000000000000000276211425361753700220100ustar00rootroot00000000000000PK`8rCŸ.Ä++mimetypeapplication/vnd.oasis.opendocument.graphicsPK`8rCmeta.xmlSM›0¼÷W Ú+Øæ‹°·ž¶j¥¦ç•±_R·`#l6鿯%ݨŠÄ¿™7ã÷ÆÕÓ¹k½WŒÔjç“û(®…TÇÿcÿ9(ü§úC¥É ÍÇ” :°ÌsTeèRÚùã ¨fFªX†ZNuj¥Ð-šÎBËɹ•ê÷ÎÿimO:Ná)õpD¤,K4WW¨àW\?íŒA “‚A$$hÅN55a·–úŒ«2;å±[ζ—Öújz¢-˜­G'hù_Ѧ“í£Š6àºëfÓÞÌ”)Ù=Úf¾s}„hï-ÅyŽ‘›:³,x•púèßÄàÿ·-¯·½Ä`¼È¯×”M먫y)|€Ù[ࡎ0‰œQº"4M*tW Nß„¤Øãˆº/-Ã,Ï˸Ȓ´B+lÑ!­‹} ÆaîUÛò%)¿_4ÞÕoiüoÁÔ$ý~9_ÀGPàØz¨Ÿe3À×ùÂ( I‡Ñ§g©Æó˹ȼMõ¥ô/àåøM.Ê2²Î¬I2œ²‚5E‚yЧ9»È¿)-Ê×§k¦Œ+¹7Ÿëfjîr4*ëöû¨®ÐÍ"нÇ_ÿPKYžË:PK`8rC settings.xmlÝZMs"7½çW¸¦ö0àà P†-ŒÍšZl³o²¹‰™kÔS’ƘI€Ã€±¥RñÁ3Ò{O­–ú_|z‰ÙÉ3I‘7‚òi)8bDù¤<;…jð©ùÓŽÇ4„z„aW Jé!òDOç²¾xÝRÁëH$•uNbuÖ1¾šV_]·d‹'/Œò§F0U*©‹³Ùìtöë)ŠI±\«ÕŠöíjh"@j(¢¬àÃ×ç¬Ó†ÈÇtr(Êbôú|D|m&,f…Ÿ•J•ââïÕhSv(—[1N´æûÁV„ÓøP3vkÕ Uûµ×^µ/7kÍE΂æÊVnмXgñ£@ÄÆGN–ÆF )ëÏf¯ÞdÍûqÎ7*ZÈ“`õRÍý’r4 •Jù¢¸ó.ìŒU&x¹Zª–rÃÿN#5ÍÂ?¯ž̯þèdš©ÿ¬V®TÅ/Ä$)PÁ D›\0ËÞ-;G;œ˜¢fÝhC¦TB»BÐ4Žáh‰Ï‚F]¹´Çü‘áAsL˜„<ø|ÓÆÇ@ïÊ'É Ë.x%Òœè}2["&”K$æ{rØIq3Ýþ‚Pu„~è¥úùYLŸ¥ò†ðˆl±™{t_ãºú—+A&}ÔØîíq÷€kFcʉ‚>²¹5[O?P-C—u/•ÏKŽ·jWnsùØ¢å~ôÈ\G¾M|"ácåR‹ó Y<ø«ÚpÓÒ×W¤"ÿ5= Ÿ z[Jñm¨;l)}ÿ|là¶‘á¶ÄüÎþ2ow|sWÑqx3RNQè£ãxnÀô‘?*pWZW¸Åȃ)ºò Smä6£áÓ^ÔuDwá<4– =%|¸¨<øä€ÑdÄβ7¡âxÿj³˜(SˆØt{ç:îï úÕVä8®‰‚˜ff¯ù3ãÿkÍpæ¹f¨¹gÊm$BÂNõå³ßmóøníùÐ;:wÝ'<ò^ÕîÐ&aµ¢ÿ¸Ó¥¿ …GŽ+àh³¯,Gàøþ/¬ã»Ÿut¥Íx Í57 ÛΊ.OÑèë?ã{ž‘_3®7v½^ö²HP‡·•Ra÷{úK­$aóG âŠ(rüÄâ’*½Ð¡q…LJގÖLJŸS-à—%AQ.cø©Ä‘«ÎcÑÉžhclzŸ¦s7Ô”GÍûlví¼²ÐôŠÈ©3gäÈ c’2¥i*;p:×ñ¢ú)a? Q} 6qã½!*tߥ©ëÕûoIJx?å¡J}åð]iËñKÄ'~‚ë—$|òQð¬sìmmæ&Ñ7«Ÿ¶–EïPµ/få'¸¡Q6.zéœZƒ~ç«£i†”_; ©ý¦Ÿ|Í#çëÄ•Iô$BÎæVu D¦ùV7c”“\ëH©*¢ƒ"&™Õ†c‹¡¯sЉ ÉtƱ¯ËÕzÒ×”0ª6Íž§×`aAtu¾i>$Õ1±GæÛM‡•71œtÚ„,5ËÌE™qª—,´G—PéfÞñÞNë€<÷Åg¸÷¼ÍPú8«ƒ0ðSYYèý…¡ðcéø¤#`<„8a{bÕûÊ[¾·>'/îúOŠæßPKeôAÈ‹!PK`8rC content.xmlí[[ã¶~ï¯\´oºº»;´ Ø ™ ä–h‹YI$ù¶"ýý%=¤.¦li,wÝf6/öˆ<‡<üÎÇs±0o¾9d©¶£eÅxþ°@†µÐhñ˜å›‡Åï¿ÓƒÅ7zÃ×kÑeÌ£mFóZx^÷ÚyµlfÛ2_rR±j™“ŒVË:Zò‚æÖR•^ʽš‘ª>¦³Õ¥°ª]ÓC=WYÈtÉjþÎRXÕŽK²Ÿ«,dTU}Íç*ªT_s@=+HÍά8¤,ÿð°HêºXšæ~¿7ö¶ÁˉÂ04ålopÔËÛ2•RqdÒ”ŠÍ*Èìd3Z“¹ö YÕ¤|›­h9R“ ¯%­@Ž+ˆ9o!UgÀ¯Ýf6»v› ˜£„”³y&…‡T±ãùT±cU7#u2áßÀ|‚IùñôöÄ«2›»—@•¬˜}ÌFZÕçœ÷¦ …æ²Ks±e9fó¬Hï_ß—¬¦¥"½(‘4êçÙh ‡LÐéNP¾¿DˆjB›Ít/\Å“Kÿôôö9JhFNÂ캰Îòª&ù ™*cél/€ìiIÎfSAÈ^\Raq×,iÁ˺wÐz~€]pQRgét³è¦ŒãQQ0Ç6!œA0ÑwŒîÿ¼d§—‰žS†úk*RHÍ/* Ë2}8ªžW¹ésëšoó¸ñC =´dbФRm9XaQM»0Óï?¶ Xªg°n/–Šö0A•ÙaÞrâFñx}¾âYt‰ªÊ®Çœ÷þSÌé"?CjwRê¼xìŠ&èTf?°†bD_“ˆê1ÒêñM“Lúa­yv?,þ^2d‚8ß Àí9žÆUU1£oh…¸SòŒä‰‚ÕDæ]Aóå­ß\•ö=Ýk?´KñWRðêogrÍàokÚ·%g±öLòJûޤéŠD&Í‘abu¬jš}Šo·‹‰ÜxÒ6Eæ³ØôL7œj?þkÒ Nà³Xóž$\$ž [ú‰OÝÝœºrí8ÙÖ\$‘H—ëôwQ~l ÔoÖZÙ–ÈzA6ÊQ/U7å…ê¦$E¢n¸ ¥èRäƒÞ(‰ô“2^të¶*zኖ5ƒ+' -¨=á%ûÈE|ÓIÊ6†~ÙV5[g‚;¡Ä2)жR}Sò½žP¶I ú­IZ5`*|é´øöÓòÕ/4ª÷¬Nø¶^³4½z쌔h©C¢±ì]œë{‹BÔ2ì(kgÅÒ‹œçt&(³ýîÂÇpL"­ïÏÒ¨§YsiD·oDEFºÜWv‚)«Z܆‘-TJÅ´…wµMSZkͤ‡ä´h›)]”þ‹ÿüû×ÞLeÅN©“±\OÉ fzp=·'¿<Éðpƒ‹ý `?³ïS×¶¢°”[{]JF<å`O]nÁEzÅ>Â1÷/——Nzøp¨ KV Úðú²ï†D¯!环!÷naÃy•ywCÈ~•øø÷Ãç•Æéàn9¯4N‡wDèuÆidÝ "÷÷¨•é¶Ö6'»ÃvbÅãcÿжodC!šÁ¦µhjsñŒÚfCíxd?Ùv,ÐÉ–²‹lç¾¥k²MëE»dmÏô*!½\Hv—}/3èªÞu3)9Š×ðíUÓo·î@áy¡p—ìZ>dx.êâÙµ‚îù(çmž[~- †[?~ܦÛ–Ç|”2mò½&ß3´ˆíñhžˆ_’cèíyFëò(w?‰þƒÃÞ–fiyVûÙõXÀ.%4$ßôÍk¿T!_AXF;}[ÚÏÚ÷’'hßÇ,]2hRY܉ Ÿ¦}>v/]ƒÕ5žá×@©„W}“²UÕîÀîU„†—þ°C_ñÔž¯ø[F€ðMþx—n7,"9D„òkuŽ3pŽsÕ9¾a{Þ¥s°êdÁåqÔËâÙ79G§úµúÄøÄ›qa°®]×@!R/ŒcøÎõ6H._«CðÀ!øªC 2óF2¸$XÍý7Ý‘UúÅ¿?Wð<‡x9æü¿”Vtž–‘ÌËÛZ,œa' ±‚tg ÔJ©j½Ð oÒ-Õ ÎòZþLןÄq³.#óÀ !Ø>Ѷüƒ]gqé˜ 4˜s{WŸpë@º/ííüE£ü=•I"Êcȸ*ƒ#tgUD‘ˆ'­·Å,–,†„ºg,nªËžÅhh ,œk,pU%°Jl…ÃÈ ]`(‚Ýw:PÔNÇAòOæFñŒîŒÖ9}°k‡|ä$º µ‹øÓæ°f;¶õ¹1mÆXNõêÝËŸ·œž~lj.¬‚¡ süA ð ÷¼x³Þ$Ø£ÑÕQ@uNý?q ìÞ銪9öXE!Ößúò¨F™fŽïªÈ†Àbo,DXÇ;ON§˜+‘í˰Û¥ñTŒU¢A6jØ»v®e%!àñÕñ?Ñ¡ã2È@p‘àKˆaK6JÙa—ð ”½)ÌÚ'`]0±e²n[n©ìZcñì¹D¾Oeë*[ï¶²u °þJg‘÷2²®µ­Y¿,ÕQ[þQÓέiCêL•ÜÐAØþíÙhaæ_ƒb׳](ÌP€Çˆ öö‹ÄnÄ †Ó» 1$ßZ˜ƒwæÄÎ<þPKöìW—z3PK`8rC·ð`´••Thumbnails/thumbnail.png‰PNG  IHDRÆg?ž\IDATxœíÝkPSgÇñÃ]¢Qƒ†›€”r©"b½ N½0S]ëªÝnën·8élgZwöEÛißÔW»Óí¶³»t«Û›Ó©Ö.£*[]+èª\ZÇÊEÑH"·p3Š€ìÏzC ùçÜòûÌN'$'''ðÝ“œÄó<Á£££`¹7´I1$ÄCR@ I1$ÄCR@ I1$ÄCR@ I1’ÊÝõµï¶TáÜߟštÏöRù+§¸- ~ߟºêÎbxábH ˆ!) †¤€˜_$UõÕû+ù’ø£¹¥¾¥îDÈ4]H˜.k]±Ó»T—œSøÜÄõÄ<º()3Ÿ]>ñÅ;–æ E¯}äΜüòÝÕ;^vóQÔN›I]:S~µ¾êæ•‹;÷dÎÀ  ^ÿÓ6œ,[·óu¶X—¥¼ôøôÜŽëÅ»+¾w«·+>}Ù[½¦ŸjÓò6ê Ql±†Ê²A[ÿÈð]vÙÜ\Ï’ºÝoín»2ÃÉoe?†ëgw›[“2W5ÕýÇ—· gæœñŽýÝ–ÚŠÏ‡îØæÄ&õvµußhaWF%fØ?Šfh3©èG2ú:ÍúˆèñŸìÏ*{à ³žŽé³«¶\½pªæè§‘óÓ;M W<ÉÊ3Ƨ°¿ôùãØb=í×ó‹^´=²—ß1\o˜—ÂJe—­–ÖUÛÏî¦Ó›.×…†éX@¬'vS×f~Çÿ–•f¯ÿ[&$,<8$¬¯Û™–µþi[·Æz´šTù‡o¦ånhm8ýÃw_Øú¬3 Æ  ~™Ýºpå&ö× ŸÎþü‚À®IÌxüÜ7û¶íþ ¹îDíÑÏ Ñ ¦&ÖÊâµÛÙ­«×Uì¿{gÀécÍŠŒ«)ÿd–që˜=D\Zöí~Ëîþø5æ– º™ÃCƒìÇ¡ÁÛìQ Ñó%øHF›I¿6¶;a»§·Æ&g²ÿÙ_ÓX{lA^a`P0{-ËÞðŒÃò,Á‰+ß-Êß*^¹áù·\ÜQ¼Ëâ‚müBÁӘ쩨6“òTÊÒ'ø§o¢Á#H ˆ!) †¤€˜gI¹ù]4ø3’rçßÊà…ˆ!) †¤€’bH ˆ!) †¤€˜œI)áÄ@|ØFNæ½”¼'âË_À CR@LÑIñ3RÌÍõüü–‡Oâp ÈKÑI ãg¤ôušk¾ýdtt”ŸOr­á ?í¤Û|5>}Ù½‘!¾dSÍ1~òIÈ4?ÝeÕvüM(=)f–1véÆg+üÿ¬ñ´“sßìãg³ð3UÄ“O–nü5?ÝeÒ5W—n (õlc<ÅI Gµ|}«‚¤¬ •e1Ií×.Y-­âi'½mül–ÞŽ‚ÝÉ'q©Ùüt—IלSrˆý~ÆN_q§¾¤§5ܹŠNÊá?áD ¦£¥è¤\{ØÙ,âé. '¥j³îpzÀ«ÀQ”lăYv`±¸`»8€;þ‡ixçùìÂ’·ÙQmjîzvÀÛßef¯û:}DO‡)tšndd˜Ÿ?~€ø`ëëâGÁ­–í‹&™“òó¯DăYáÁÄa"bùQmè´éì€769³­é|¸Þ`ºT“œ½ÖÖoåGÁ÷×7ªˆâËËø¤äL _ÙŠ³Â„ø0 Æø4~T+Œ Ð\wbn\2Û·ÍKͺwodlwÕ~‹#>Ü—— ^øä1ñ-”à |˜†žv“xTëb…å[vñ GÁ²@R 5µãV%Œé€¤€’bHÊçüí¨IùÕQm@@€Z¾8BR@ I©†ZvTHJ5TÑ“€¤€’bH ˆ!) †¤€’bH ˆ!) †¤€’bH ˆ!) †¤€’bH ˆ!) †¤€’bHÊ3Sϯ )Ϩå€ËI1$ÄCR@ I1$ÄCR@ I1$ÄCR@ I1$ÄCR@ I1$ÄCR@ I1U&•»ëk{hMګʤ˜ü‰rø¸ýT-ì²pPr¶LRf>»púë¿>þÔ‹rm°S| ñ)Ì{)öÇ'o±ŸÅ…ßZW±?*1-3`m¿{ûVoç y·Ö)û§À·|â4NçŸaÿt š³G> ¦ [”¿õ쑽†¨„¾®¶‘á!ñJ™Ÿ¼3^%eÿ{O=µ•ˆ“·ØÏâÂôܼÎJZòDÑ•ú*ëÍkkŠ^=ý¯¿yºr‡ÙW<âþ‡-ø4Ì?£Ÿíb š+?œd‹™.Õ$g¯íïë/k]Ñ?ߨñ›=ËÞÛ-^éŽI ´Ùì¥øMùÈEœ¼ÅôS8‹ 3;*>5gû?»<'&©¶âs÷‰"qöOçˆòèéØÏ?#8›‚Æéü3ìÓÅ4lïeˆž{ çÞ½>‚-ÆöR›_úó™Ãÿ˜—š%^éþ/áa¿ò–½MjÊó·öoA®Üäp+cLHóbë~æ£ÏN¾…r:È~þ>Aˆ‹)hò6¿àðXìÀÔ6U²OqÄ'?MAƒ¤€’b”Iilª ž;›ò‘²b‘%%×TA>"ÍÓaÇöû½ xárH ˆ!) †¤€’bH ˆ!) †¤€’bH ˆ!) †¤€’bH ˆùKR F2þ’”€Ñ`¤âGI4CR@ I1$ÄCR@ I1$ÄÓ~RøvObÚO 3ˆHLûIÄü")쨤$QR’ÍŸñ0´“ˆLöÆýqJº½”§‘’ÆÆssÁ/^ø@JH ˆÉœ”ïæ`±4×R{;Úæ¥.éi79]¿8; wàO/>–ÿÔ‚¼Â¶¦O}õÁö?z<²'%øl– àà¼Í%VKkÕÁ¿b…ûi²•ÌŽŒ¼=Ðqíò̹1—ÏU$¤çõ[oæmúKÐt©š%Å=21½©æXoW[÷–‘‘!¾Ìœ˜Gø5ÑIñ5Ì™—$NçÂ7&cÕYò“?)Á7s°°˜ÎÙkëëÊÛüÂåêÛ¯„Ý”_ô ¸é³æ.\¹‰Ý…ß67.ùÚÅ3ìʾ. K<8$¬¯Û™Æ—¯ ÓéùìçxáãËß“:(")_ÌÁ24h[öäoù yRâJæ¥,©«Øßß}sæÜX¾Ñ›÷ïÙYüú¾³‡?2·\ÐÍŒ ䷊װÝ_Ãӹ࣯12'åë9Xìeù–]üǦÚ㬒ؔ%™kwدgMÑ«ì¿;ß> ØÍ½±¸`›ý2ü¶†k»ý­L×á=E쥼äé,ì¥ÊËGô~ ¦…¤@Q“.)ÿùFÂÏI””Ÿ|c ^ø€’bH ˆ!) †¤€’bH ˆ!) †¤€’bH ˆ!) †¤€’bH ˆ!) †¤€’bH ˆ!) †¤€’bŠKJö5e§öÔ—”àߣzjàZ%&ª†¤€˜ß%e?ò§àÞàŸÕåç>7q=1.²ê8í'åbäÏÕ;^n8Y&þébäÏ´¼zC[¬¡²lÐÖ?2|WeIMämR¾˜H#EáÚÜùSüÓÅÈŸ¬§óÇÇFÇëi¿ž_ôÊРí쑽„)ª.ÝPê‹KÇ«¤FGG'_ÈCä"¸ù“ÝÊÇu僺ùÓji]¼vl´ã‹U‡ë*öß½3@»‘¢œ’CøAé&ùÓ~ðOa²‘?Y‚>ÚNÍÐ~RžòtäOp€¤€’bH ˆ)1)¿çbÇðì˜K®G×Å%%ï!t@©êÿ!€ì—¨’bHÊæj÷’z€/¾bò7H ˆ!) †¤€’bH ˆ!) †¤€’bH ˆ!) ö?`ˆ†?dñòIEND®B`‚PK`8rCConfigurations2/images/Bitmaps/PK`8rCConfigurations2/popupmenu/PK`8rCConfigurations2/toolpanel/PK`8rCConfigurations2/statusbar/PK`8rCConfigurations2/progressbar/PK`8rCConfigurations2/toolbar/PK`8rCConfigurations2/menubar/PK`8rC'Configurations2/accelerator/current.xmlPKPK`8rCConfigurations2/floater/PK`8rC styles.xmlÝ[ÝrÛ¶¾?O¡a§çŽâäÄÒ‰Ý9?Ó™Î4é™:¹î@$(¢! Zv^¢—çýΓt HP"e*–íÔÉŒmbwÝ» ìŠz÷Ã]žÍn©¨/®œ`î;3ZD|^iž¾<BËWš§WgDèuæéÀ?D­Dm‘›ŠÍ+¼Žö`m¨v¶h°®"š¢4DTW)ý±¶@i†UW ¥Z>ðýïÕ¨BŽ©¾fÅtré¯y-qÁ¶N³HJ™ ^oS·ù<³àÅPë iÕîoç9:¸{›\6]=f´y³¾ÒÜ”j¶¶ŠP€B·]l{Ìt»u3_ TB%ëBa[¨FÍ`ûÄt$†Û¶4Ü_ß¾53Œ5 ½Ãq¤ï¢µ‰*\j ¤# ý.L¿G|`NËwz·¸“¡å‡¡e¢¥C1¢<ŽæeJ´ëÄŽ £É€›òÛ!/bhº q«1õ@CŠo~§‘Ü1 ©_÷€ûR¦#JDûŽ„{Ðxlëj\Œt¯|õo ;Õ¶®ôµÞïké@mk-t–=M|žÎ&»Ý²Š)—~’NÔWXg öóžÆô‡|C÷U¤LVý¥úo¡ÿª¿ Ž?q.ü ZuƒoƆ˜UeFî]{šÎ1+ø ¥g ŠÛBOY:A|5˜SþZnx|ÿ’š¿Æ6W”7pœl6µFG?x>ëÆ®»ú³³~ þd3õöÛ5ò„;}ÿJn ‰p0™½hb˜âÈËåIŽŒ&/aÓèJ¾>ÊžùØœEú"2u;ÂÓ·#|ò³¸½-ùÝ'e½=H’(Z­¾­=˜äz•ýÒ}Œï-a`O«ßû›¾8é0I)‰_úÊ1 úÍe8gLÇè´À0½Hªz9úÓéØð,>º'J+ß,tËž“äÑcÍ)©jññzX|Ÿ¥Äz÷cPnäkoMJ‡„^L6õùÔ= ‡r€·÷\óˆ/€á{Ê‘kç-u¡®ƒB¶·Kÿ}ï;.eó½'hq±œ[š[o%7Ûµá"Æ“ñÁbÐݲ†“J*·¼ï^s£pÛýݳýÖ£¶W¦wúNáÑjœ5?<;ÂÑäL®ŠËÛ·CƒÒ‹÷_Öï uù¢óÑ΃M>è’ˆÚ\ëÒ=,½áoH]ÿ PK”bÄ­±a5PK`8rCMETA-INF/manifest.xml­SÁnà ½÷+"î­§ %íaÒ¾ ûFœ S5?©m¦©S£õfcû½g=ÓìÏÎV'ˆÉxlÙ+a öÁ¡eŸ‡úíw›Æ)4=$’— *s˜®iËrDéU2I¢r$ié`çuv€$öË™éš-lÙnSÝøzc¡.óq¼u÷ÙÚ:(:¶Lܹ=;茪i Ð2‚5ZQi'ìø,˜/uò!ªp4:1±F‡R¼¬x‡—àLb*¯M@T|HOÖiÚõÙ¸‡cv_¨ŒM‚.!8Ü!1N ¦ú*–w½rœmL[¡´ %õQèãß›ýëÁ»J' <®—+ý§Ñ£î7â×Ý}PKªåÇÞPK`8rCŸ.Ä++mimetypePK`8rCYžË:Qmeta.xmlPK`8rCeôAÈ‹! Rsettings.xmlPK`8rCöìW—z3 Tcontent.xmlPK`8rC·ð`´••$Thumbnails/thumbnail.pngPK`8rCïConfigurations2/images/Bitmaps/PK`8rC,Configurations2/popupmenu/PK`8rCdConfigurations2/toolpanel/PK`8rCœConfigurations2/statusbar/PK`8rCÔConfigurations2/progressbar/PK`8rC Configurations2/toolbar/PK`8rCD Configurations2/menubar/PK`8rC'z Configurations2/accelerator/current.xmlPK`8rCÑ Configurations2/floater/PK`8rC”bÄ­±a5 !styles.xmlPK`8rCªåÇÞð)META-INF/manifest.xmlPK6E+zuluCrypt-6.2.0/docs/zuluCrypt.odt000066400000000000000000000630531425361753700172450ustar00rootroot00000000000000PKiJ«H^Æ2 ''mimetypeapplication/vnd.oasis.opendocument.textPKiJ«HÄÓir$r$Thumbnails/thumbnail.png‰PNG  IHDRÆ߃ùrQPLTE'''444GGGVVV\\\ccckkksss|||ƒƒƒ‹‹‹“““›››£££«««³³³»»»ÃÃÃËËËÓÓÓÛÛÛãããëëëóóóþþþÿÿÿW0Nò#ÜIDATxÚí}‹šÛ*ÒíügÒm (¨âþþOzÖBvw;í$v’Ù“ÌgwbëH%«îükþO|þõ$ãIÆ“Œ'O2žd<Éx’ñ$ãIÆ“Œ'O2žd<Éx’ñ$ãýÓ­~F>þÏþ©Àû¦]¾rýÓȨ*R̲ԙ¼j•¦Z†j*cI*©jN³æ”5̘,šÉl)U1H”8NµØ-^b÷9G7?)ˆ¤(¥B”‰=~fß?† Ý Þçtßœ/ÎEuÞñˆ;9¿ v’[ÝÜæÂyÄ¿¢Öø†x™ù;çì9S=Éx’ñç“Q-ÏR€j¶f1ûyö9~ãB¼¶ÎŸv>øösLxýØ ÿÛûéxÙŒ³}ºöUÁÞém„£EŸ§¤´G×3ЭÄ5†b0Lª\Œ^tú³O3î¢@Ñ(¦(ç>í˜ÄM%Z°b (‘Rˆ~Äàƒ˜ˆ œÂ11´˜"ÊLð¡Å‚"1éO’‘£zÜ«O5 ’f¾ß]wÆ#øvÁÍúFAº{ Ap“ÄIܳeÚ¤ ~pë8─Fä @÷¾„"5‹òÁ$Bi˜h_8¼ùÚOòT £÷ÑzÏÒÆ½M¼`ìöæ[›-c—;<2ÖqžF¥6=jNì»þÞ°éÀ7>?ÄÊ«?¼ÂsÂ}’ñ$ã÷À„™£qN¹¹/ßàtsa±>ç‡Ù&¹H†ÜÀlí½šÏRà*ZJ‹ÕÇßFÁûrNÃŒOÜ“èwˆK˜ýÅ /íâðP³)'§vD 3˜h²PröŠÿAܪ¿£´÷}ª/ذ:o^‹€Ú-$ ž"WÂeÐÄÌR*hÌüŠHvÙùáÌár ÷€U £„ÝüÜ)Ùe@4ð}a0.ïsý¿q“÷^KTàd4ÀÛçy+,QD[ àbèR„ß’ýØ!’Z°-Í&¡L¢–SfÉ1ŸjöRà1f‚‹® ¥É\šÃ8Øò—ú ‘öLßUvSƒ@– ’îyð[¨V|—‹îªw“a QS% mñRÏ1¤cJx £rªe÷è5)Kƒ ¤¸€‰£7çK âLNÓ—¦iÆû ŠG1%R4MñDÇ+ÕŸd4QÒØ@(AmÆN_›ãŽ+6œ¬¿þ¬¥kèå7âúTþ­(~¼ÆÜÿ6¯¢iLjH5•ŽQÕ2:@Šõ/#c·mÁ—±±ÿEw ý¯"£×Jt"¬Á؆Jbµ¿ŠŒ'£þ$ãIÆÿ45Ý”þÒbKÓ¡È:Læo’Ý­9¬Ô¯d¿œì"õïûˆÖr`îÐ"dzômÄb/ðvOɦ¨¯ÚÈ„z°EI«Æ=…ƪ$ß„(îUcŸLÀj‘´84òœÝ]ËpÍgA#DXƒXƪà¼LXŒŽU%D´'šT¢£ó™S½› 9K=AúÃeèÔ%géÏÒ_’­@.{¡TxãÓñ‡Ëæ6•œÁÑŃ¿uÙãò2¬Þ;*P7xô„sÍ6´çÈ(6sYÝ T@’ôÙïúÌb‹»“™\êØØï&£Á¯”%ý ˆ xÓš Dpº"wq2¯M¿óA3W¬H5? 3M+÷Ê€H‰2”X“‚#vpv´ÕÄÅ0*«²yŠ—¸™y‚—‡„3ʸ›ŒvtõüQ¾o‡Zãc#¸«QÏJ_J:—~O³ÿ'µðÙcúrùº™‚–Ð@O£]i¬_]‘,Tt×âÀ*»C7†9ü³â‚¹Quµ8_!ê 6ŠâÔ ¹àp„AÉrÉó ¢+ *SÜ@±îÚÌ>3Taâ4öˆþehw1­:ˆˆ¤ÝIF,ôj\qÒ\2FD‹[Šx^!' Èx/iLçÕõð2Ç2ÈòÑF_–éU¾ ’Y¢~yJš€ÃÔ03Í8ï5øÀ‘8À†–J™0Ò–69 ÖU‹¼ê@£NqÂãñ¶räÖ„KÑÎfQ¾ ËÕð¶-·DSLÍÚ}µ‰'@F–;øøbÃBÎÑñø =Úð´ä=êBÞ«uLjëiؘ´sÅÛœŠ’…­¼…Rø‚Ðm¯ÃÐ$v¼¶Š÷o½ï~Fí7¥²r[¡W‡ÿ.ŠÖ:ÄáµçãˆY¶^ÔíÀ%ñbç"_!¢R¼mcÚx¦]TŠí‚i£ÝÔa:ŸtßE_(’aûæEK.x·ÓGù´åMÜîÜ Á³3£§ûéò Î{ â~2lNqAè æÂ'Íàa÷²ïTа³ÿ[‡OÎ67=F {rHÎöÒ¨ ޵oæ7uÁí¸É@»2ƒ>L†Q #™š›<ÅÎÑáæ n.„áØênw·6¯ÙOV4t´Ì!Y#ŠeÀ4aÐsì‡Ù#Ðì=¥I yÑc7¿Ìê£#œŠ/‹Â2¼IøúÉNeí7™$/œQ¹_zÌÝÿ–±q5Œu¶•ï8”ß ~KP_o¥×sÍq­ ²¯‚ŒäÍ®|ë†îS~VªÅ8ëbÆÅ\  ¸ ÃÔ‡)ÐÀ 6íÀ6S°†À±fÄjÉÚÀ,K`+#Ñ\QLµf¦¥5t±ÊÞVcYÑ7WÜ£!¾¡[ ¯²6®¼cÎ/Äà`ÚT)¸ˆ½1¥Òs7°¸rÊSõûUË–*KËk}3ˆ£ŽxÕÀà˜÷ì‹Å]ûÄPKâ6 Ì–ÀâVÁpGSZ^¢¬x:Tpƒ]0P»ˆSŒ|àž€M;}W¿tÛ0ÀGއ‘Á¨è»—ãKxI³Qˆme K°XÛÐà¯iE1ÖØeh jf“Ô Þä †P¸ò€žl!-Ä#ðb”£vKOÍù.=,ý¹ÁÇ­8ÔÏf%0õ[½ýK9ò¯ñåÝ2Þ~Ñ©”X/G.Çcc Fä.¤µ°"1æqêø£éîŠf¼eˆûîw†cÇl/|ð˜ç}Ü! ªßÂ>x´u—N‚xºüÚ«ì~IQêzmü÷Èð`¤q/ GO¯B¸ªèåuOèÐÆ{™!‰_qÚ}Ž€(Ì1K•ÒwA{¤Óví¿EÆïè:þ™×ðÔS=Éx’ñd|wÿâ 0î83~R£,Ö?0™J‡Ò³+jÃV˜~¡Ûн`™J/oËëŒ ýTë:QÔè{ vò9ª-Í£.S§,Õ.«=V adÈGŽ ¶ô¸A ¯qܯ§Šåv¸%§xru€´ì<;Ç@Ÿ±î$¢_ÏûÖ¥‚°È«s —zJHuúèö¸ó ¤â+Î:1PŽÁ1¢ Iè†NÊïÔÅcdÑ•>…ápàSA׈‘Ћ÷Õbö*û NódÖCRœÚb è?8ÚžäÓ¡¾´Êþ+àÍè=‚ÎÜpýå³ë®ã¥ÞÊ3RC§†gŒ¥˜aèƒ/Âpj×Ðw_“9ßænšö¾@Ê‹ÿM~—^ÉWµ;›:Ú ë2 Ë h³ÜZè‰-´cÛ˜¼TJ cÛ-ͼ‡tž%Ä“)cʾc,> QïŒ~ã${D…·ÁÐonp{®_n`s¬ct0Z>GõØÆ‹;¶Xt°î*ÙçùЪ~D¤3*`µ<×7È郴¢èxݱZàmàj,{ÿØèõÜK¿é1u³2ŽoÑò-%à‡Z+Ö è`õv¨½«A(Z¶þ^¼üÌÔY”Üréq\;Dç2=}®)gZ^ò,™^{•²²µpP“1p`öR­ò(- ­RåL<·2Ô×àƒÈtÁEÊŽ‘^d¡„BUbHL—nU|êô0‚DlwŽºÛR‹À«¸Û—äÓ3ÉØqýü@øâÌþZøè  Ôrš]­F°(|žÅg›Œ'׌²xàx)ø¦éo€çXÁäøz/ÛšLC#£/,ù1HH•L;˜›BiÉZªF¹§P´­(/Es¤ 8åöKC|\SyÓ&žÇ÷Y‹³âcüB¶ÙRš©®h©1¯Ö!P]Ÿ][M/DÊù«_\rùÐÊWO%õ«FÞê¿©V‡Jyûº<:S5qÙ¼G°´”ñ¯GçéÎÎ;OÇ€dމ£3ÔrƒâæNáƒtseCc§èœK¾C–ª‰Úws…Ng3Òk CÎ;jNP² ï“Ç ðƒÆøLVÂÆ©hŒÌÚ…qÉH8aêåi¤èŸzB9‚´$4ûçBÕ°Kn9y£©©X®¢!-þ59 åÐÉJRÓoŽ~n_ýF‹wñËJ*ê3þ-±óä19 uÿ˜f„ÙK{ÐÊýÅ '‡±©ÏËæ²1Å•åä(}>?Væ“qÎεìNëìá‚Ѫ±ÌÑ/;ç¼+cH,—òý\áÜÔÛõGqý¬JüxìÐl,P}ùèðúɬñÙ©müLŠ·ÔmE{KL(ü OkŸEsgp]…þ†ÙEàG^ócV7šRŘÒrÿç_J¡Ô`”ôŸgFÆž.éRò8Ûê"/¸š eÌb»cxVù·öb n.YÉ_"ÉkhCÃJdž?ŒÑž5dt÷Šý¦@Î0ñ ^€ÁÝôÞ§6™ž¡ÜóúžŒç90_¬Ñ,ã<ª-½°êÉáŽD—ÖþF >å'O2î&‚^n˜^ÞMÞäJŠÊ´ g¬çôÓ£ôÙUób<`Ý<¾ÊáÐàKއ•‹á&_ª·™ÔÇȨ½ŠíY#¤5_Ó!&y†«AÎéÝÀ &é6 ô[2€z¥ï-m¦>1«ئÄ’€D&30`¡27¦l©Ýh ]rijbš£YK—«JŒ€½Ì€i»J…i½ò½d4É%€€Z=Ýÿw ¾KL~™p*à䯠i#ÄöªR•®!ÕõQ=ØS9C?$?Ôñ±{¯[Ž\«”,##ÁmöO9¸ÅO²¼îJ>AC‡–¿xè/5{FÑáP²;;Ufª”•¥­È6Då¾,@€ÅJskkžÑ™ØFœ]lu¤Ri°¥6[¬C\'Çl+ì¬èKƒ‚w룬”ì4×N^…y<àVÆÊ­ŒÁcì:ÃêVä\½‰¤ ñö½y1>´Ï¶ó[Æôöíݳ$u»D½—5¤ŽdðÙÔ¹ ] rPl¢TeæŠÖ£œÅcjŒ64c"Á» c™e„U| ÛA©U2머Bb¦AÉxg”Èi™©<ؘ:¿¶0ü²úÔQé÷ÔÚúÜIFpMºÉ2Z¥¡rª‡/4—ÑPA'ÒÆÀ‡—7xØðÂYµA±pžkúÁ”Ë*/- FòË›ÃÞ¶JÍýËèûŠð2M—°Ó éÖœöppž«ÝÛvÚÛéR0ÅìIkÄ}¤Á44U,a"büíŠså±Z‹äz ˜²8•Œ\W”/ ´†šf…œÇz«+çXï"G”x”½R')ÿ&ÝÊ0d—Á›yßOR ‰L±;š“öH•³ÉX‘E:Ÿg{-˜Õ¨f Ã* CÈUŽXñºp‰îDøÁÉÎ sÅó„aŠLeÚÄYŽ•fc™ÊkÆÄýeÕ$„Ž*” ‰o“-Ù²ÞÖuV¶1^©‰UÖB[ÿnûöþÁÿ} o·Œ‡ÚõÜpIvÎLÛ>l÷È‘73éÜSºèÉÀšëÀF P/Óã¨q«´h…©ÃJNLT?Mj¶È¬`DA>x¾˜ŽðÌ¥íL;ÞL`è|­LLnx\+FúW"Ù˜öS3•§ƒKú÷ óˆ¨ãr?gm?X³VJè¼T!7qg"°W) _·Ë@ïµø\ˆÊåö('mh&ùs;Sñ½K¨‡ { GèXiÄ‚cú¼£m~êO‘±<ñ"3Y¬Õ‰z£>±Î©jáâEybä3̯*‰ï+ñõÀ‹!ð“ƒüô¡*Øt‹d@’퀵Hï¬áD™Æå¤šJ‡ °\Ì œœ°ýxÑ£ý@¿YÁÄ\€¿ÚFÿ92V¬öÇa®¾á Žþ |U·x*†ÊÑŸñX¤m\Bƒl@,WÈbüz°s§ú§’Á püc˜k(®Á¤‰¸§A]¯ËçßïAœ—êUÚŸJÆ=ŸÿÒb‘O=Õ“Œ'O2ÞE¯œç`´Ûü¸ÌÇ‹ZÓ| Zq—©ëœAê0C®|+Kˆyïký*&Úg ‡™r;O+Ùèjgjò3 ªlßq:¿‰™ :ÔàúºªzfñºûmåHîDç–6HP`‰VN¡°–ÉëqÐö¶}-)+5Šó›såL†“æx×Ãáp ¿"dÇ­qã¹RVÝÎ$,2¸<¥ßÚƒ(NEKˆæûºeÂ!Ú+’p‰µȉ™`]¤ä7¢b¬.ó7E ee0\~Çvü CÏ÷j¾6¦ZÉž2XñÆ,1×ê\Z3sýF¡«‹òêLµ†%æA#wý“c£•ïÆÈ}ðDÑùu‚“a7CÆ?*Ù¯LݵJ¿·jõ÷êÔ¿“-ìê QµJÇë%ôÜli?ä­ò™­l‡V’šöú9³ÄÛµj‰iYFyPgJŸ1 Õùô“`Zd*Ô!;ÔÐ+/1Æ„etfð†h™™ÿWc-ôSªÜ¥[’AÒÓæœõ¬rLÚS6´Áäy†oí”K;ÌI¥n”CЕwYûÝd$:S0[J‰Òܾ1ºÓ'§%½Ð› BÑ𮾎±ÇrN¢®3¹HùO^ ë½Úd˜P‰b†êwt?ÈEC1ħ•zúKg;åÄvò[;”Ÿ|ié•fú:6êËýoƒ©KW-Ô"µv¼‘¢Ó†ÑZNç»Á0ô+æÿÂ롞Y½ sJÁ“\é׌ïˆéVÊÒo°Õ’3 ˜ÊÙ’õs6´¥ÑV;vn‡}ޝ°1Õ›­F3½Y|ˆS}~[ »|QÅð«Âázr-ߎâãÍ}¦ó¡à½Ì÷oÌ@#–t.wùwUï ¯c¤z>ÆÐÃïø–N¥N϶¤Ÿ› 7åðZCôh£×dÄȹæ¸ávOODÙi±­w“ÂÞ-k*žZêîu¶ŸÄUÿʵ¯\r[ö»ùµX#‘†qÑL1éã¾Ñ"à›zížZê1êVÀPlLhBicŸ‰Vüô¢þuO®Š »ÝÙ¾¡ âÒÖ&3 1KI>ªX' Ì‘òJé…ô/9¶ðJñ<;÷2<† 3}…J%N ]©ü˜S¥…°»=áš<É÷eáÈŒ± Ì*Ÿª›%¬Ç“ bÆJo9jˆ_Q†ÙÊÌPÔï‰éåSxll<–-ìÝ6œû"Ã?êæüT¢•ÿåÕP˜ÆRMgÚL(¢¹ ¬MV- )oùÕ–±mÙ †÷â­åo!£›0Ò˜þfÍ ¤ ÂÓ€eÆaý5Ò_ÿcã)‹?Éx’ñ-ÍÈTýˆ¸iÞüïI]›ýÁd07‰È¨` © šymEns¨4]\KÌàDf råÏ#£@VcÜCàÚªŒÖfü¹?"·Áó6.€®?tr#czR í#ã¼*õçŸcw´c±pbÓ«ÿH–² ݽøsˆ?Éx’ñ$ã7‰M>ù1ý PõÖJŒ…¼ñº½Î¶%±ýT³û?ç|“øâü«s{ú{ÞÆëøR}y š¶šÜ¿Ü¾Õ½¾Œ/4çë_CF¦oZ.* J=~©«zÝ5¦¿}ˆÙÇß4ÄŸ'wH1âèUø·“QR1‰ío'ãþ×ñqÕÇ7ûU¹Þ(N”­|ÕìûÙÃÐÍ+´y£Jû*ùïäqçnψmšÏPãòu­=ÍÕKZeæ’jVË”ÌeWüì\RI˜ü¤1Á_i$og>–¥V1©\^¤ÍàS.h7Z˜`A× ¢¶–Ûª+ËXbj”fÌP¶Έ¸LúÞš¢·W˜›± âÛ™’ë­V.…ì­í: Œ}Ûu®¬Ï!:.uçŧ8åK2ÙºãâW¾ÔÝ©ЉÃê}L‘2S9u‘ö2˜~PÀpÒò>[^Õ­=Ayø=ñ;9Òn‘‘ÊÄ*ÌG“­6…«²ho‘!ã+r_55:0dº„6GŠTb¾h®À¢I;65q¥@[1þ–¬Îeé©hLsÖÌ$Ei¼CZ¬1_‰­Æl­Ç…ëx|_%Šüuø»JÉw§¥¿6_ ;üEÚƒ™-j—l¼… ãô:–ŽŠ1t’ÚJ³k8”ÊÈå©T™«2tF«éf9¼ÄV÷¸*Õ­DéQz—øÇ’Qb‹Z…Îz’¶xÚ«†¹2ý§•1o‡1Ì7þ!0yÏØ°kókü¡ñ¦ óXáçvî¢s*ˆ7™\¿Žîþðzª]ÚxÏ™Â਷¸ƒ¯ãê>FÖFÿòóÞm·1ëH{*)ÖAÅ9æFL‡y¤Á˜`Ñ®’q&2ýdT®Óf©C~Ç\ÍL)ÜEm¯’*3’¬4Ç)2 c¶%'\ÂV|JL ˜CÑA\S‹~c‰^ý9ª¿kö›)¯û‚?}aüy$ü퀿ä]-{cÎ.ññ5…Áµ¶èÉÜð!&"púäšÑm$†]8‚”7BZZù*îOx$cqµ§Pã ò¾­|Ó‰°Ik| ?ù6šÖµ–“¯&Ñ©ô ÇPúŠi+Œ ØÆÉ4õ8ÂH¸–W‚•ì™`€ÁYŒ&o=p0(0€:ô*[…G?"ñ˜K¥×Ìf*³±ôž]Œ½LÅRíw ñÇ?å÷Uoó¿GÆS’ñ$ãIÆ“Œ'O2žd<Éx’ñ$ãIÆ“Œ'ÿÏÿYUv.ÃéIEND®B`‚PKiJ«H layout-cachecd`d(pg``àe`2â@N;˜h,q&Ú] d¤ÀD÷PKŸ$4£-KPKiJ«H content.xmlÝ=ÛrãÆ•ïû(mUÊÞ•Ä»$N2ÊŽíŒ3;žÊÐq*/©&Ð$‹8ô“ÿaŸ¶j÷çü%{.Ý@7Ah‰â¸òàñ Ñèsúô¹ŸÓßýþã:òeš…IüúbpÝ¿ðdì'A/__|?{{uwñûûû]²X„¾|$~±–q~å'qÿ÷àí8{ÅO__iü*Y˜½ŠÅZf¯rÿU²‘±~ë•9úÁâ_²|u~›oçòcÞõek½+æÝ!Ó`óí Û®/ãX ªùú"éúòÇ,ºZ$@õõFäá£0~x}±ÊóÍ«^o»Ý^oG×Iºì ¦Óiž–ûå¸M‘F4*ð{2’,ë ®==v-sÑ?k¢ë¹L;“F䢶«Ùã²3G<.Æ_‰´3oÐ`{{GA÷íæ»k‘¯ŽìÉ]ï[xH|ûMÅ éº+,k‘ÊOÃMçeòhóý$IJTñPBwØï{üocô¶qø6 s™ÃýÆá¾ˆü’âÉúÑ`Ü #®ä#²iÉøHˆìÈ Ã?.gÁÑ©ÿöí7ü•\‹jpØ>ø*Œ³\ÄeRÜ„£+ôR¹IÒ¼$Ì¢»Â„Ý–¸­òut\Üñ©ºLƒààP@gÔÑÁ»z åöß/,MÞÌÓ=† µØö 2õfã ƒ~Ç”b ,R)ùtYÚ¡ERݰ]Š€òãF¦!>½öÊšÁäú(y”Êv3X =”‘Öå’N“$Wë %Ù¼2Þ¶íCºþØm:Ž$Xìϸ§(ü,凸aö—>»Bó@A2Ü‚áŽöXd½ò‡øW áË«@úQvÿ;ÖååÏÿñ~}ñMá‡ð>ˆ8\x ¹õ¸uí^_üFl’ì·Æ þá³æÄ±WK@·dÛ0Ë.z-pC0H´­ÞxmqöÞÀ¤ÉZÄÖˆM˜û þEß; kî„› mžÚWòŸâ¯E3ZƘ.(í²\®ŸE®Š=NÅB§ÄÉû>Áƒ–]pÓcO†cï˜PªßE‘·æ¡Eó”ÒJZ+z?(a)ì7"ËTlVúü€ÁýãŠßú1ip¡'F•rµ$Ó<”™WZ˜W \@YöÁ2Ž}ra<)]íÁø6 ?ü!?ŽüéÈùѯùñM88 ?>ò·£›I¿…mxLwä'çB>¸“¢çyLwäo~EÈc‰¡ Ïßž ùÅp0½k¡<éŽüݯùÁh4í»ðüôLÈ+5xZU9èŸ {&ëiI?8—킽3×Îed`„în[hÏc°?—•Œ… æmØÓìÏef;a?' ìÏeg;aï,µç2´Š®'¦ý¹,íàVLæ'Çþ\¦¶ö<Æû³ÙÚ.ØßÝöïÆ.1ÕÙl-cvbìÏfk§bL[°ç1ØŸÍÖúr:mósxŒög³µ]°æó['Î9›­í‚ýbt;vñ‡g³µL×Óþl¶VŽ'‹6“Ç8`6[Ë\qbÎ9—­“‰ßŒ½ã€ý¹líðFÌç²{ã<—­ÞõÅMK2GqÀþ\¶ṽE‹Ÿ£Æ8`.[;Êéâ¦%‘Æc°i[{‚ñè\UavbìÏeQÇ·ý›¶Œ™ã€ý¹,j'ìïn§nzñe,ªñk2ÂXò ¯/²$ ƒ‹ÃC¶a€}>XU;2ÂO¢$}}Aõ8úûÅR½H lô2æû“êEò°£—ñ>5©^"}4~ÇäS“ê%2ã—ñ‚>5©^"½1~—ëS“ê%¢²ñËøwŸ˜T/Ž_ÆÍüÔ¤z‰xsü2>í§&ÕK·ãs9ÐÃéÝpÚb”ܱ?WJJ¹ö§uÿÇçJIçã¾h ±?WJJußœ¶Cgr®”Ô‹4GMΕ’šŒÅxÜ’ÔQc°?WJjr3µÑ^qÀþ_ÀeY$ÜS»•ár•¿¾˜'Qp0”ïμš&Õ´W" E¬'¯?ÆSN‘ü¨8lÀ¿€#ÔuäïŒð/à^u݇¬å7à\NÛd>Ý´ÔÕ˜ÎØÏj¶ ñpï•î°fnœÞÝ —Ö,„#@ׯÑYM#ºtÌ1ÎjÀ•¤ŽϬÆñ®+t쨜Õ" g€nM³Z0à Ð1ù9«ùï®oæcß!b˜ÕÛ›]!:&-gõ–dWˆŽ¹¿Y½Ø¢¸»ºˆb½õ×¢§5>[Ý8¶\Íê-¶®[ufõ¶XWˆŽí5³z+«+DÇäë¬Þ~êqØ¿Ý9›gõ–QWˆ£›¡ï¢Uëmž®Ç}±pYc½5Óâ$˜÷âéY½ÒânT}®ÎN!†.Ÿ«s†sp9\¤£Þjè у¡ÓŸ«s¢è;ñêsuÎhÐ_ܹøõ6;qÎsuΤ;š¸xÈõ:±3Ä;§׬^Ûu…8Ý-œöñ¹:g2\ ¦.k¬×P]!:Vgõº§+DÇj߬^«t…xLÒrõú¢+D1ÞÈ®èÛtê·æ¨ó$Ø•ÿ@8þñªÈäU–,ªXÊ«y*ÅCH¥…¤hD&,d\]ÏSÿ‘g Âl‰ÝURäT—‰ä£Œå ~ÌxEE–óÍP¸ˆgM6ÓW =oÜ€çNòß™Iûrœj~…vFÕmÞJ؇ž‚?uÿE”ø^ açðÊÓt·É¶×_š /î¼sï5Ž]Ü‹8°ÆÿTDÅ—èZý¼yúF%'ÞÍýß5< ‹0ó„—…XG»ôRäE*½4ôWàëm’­LEäeITÐUc‹$õV" ¼ A|±ðQ3¦÷ø.ìoññÚD¡ÃêGÍ«‹ó²bƒ+fÞ7ßÿéÃ¥71£—Þ_e*x .íý7oÞýÙ ÖW„¿^‡ ¼GXêZf]ve4nEl¶’™l& ¸e÷ ko’¦†”·;/• ¨àïaì…kP)Þ"-tim ®°Èæ Cÿž}ó×oË9DæmeáÿaŠuŠ0P¼ßiÕͼ8¥5 ø/ß&ÞC¨fØ›­ N¾9`+½-þ8ÒOÖë$ŽvÞCœlÏ_~þ_á­¤dúËÏÿG«Ë«WƒÄ‹“üÚÜëV^TÌ`ÉN‹\SR qÒp¯ÛçÜc)= £gMf‚íBòéIÎÐ4(Îãôo\ØfG*[”¢µÄÆŒ PÛÆ´Óg¨Õz æ—.XÞb³ÚE)3k)ŒàJÒš€dqrÈ M¿(x¹—Ìäȼ<ñÀV¥;4ý¼æ¦bú’n5'3xKQ*d‰nÆ´È\v75ÃÉÅ=ø7`·ÉI±^t³ od ¿Kÿäo.iUjRÂx.Acàå´Àf1?•iåuÉ0%zúþ°M†a1\Í@)ÐÛXÛÂV&'uhQËma‰‡¹–·»xÖ} .NJ¡ƒVªó#:÷%“åO&DÐ!˜ŠxY„Ù ]>o‘&k/…Ý„ÿÅI˜íql&šÙðæEDÐ[Fx;²7/@Ãç¤ZáQ,3žä*‰Àhm<±x™²E‘ÌOÁÿˆw¸Jä¶(|Q¸J’7{.Q¿ÍáÆ€åPxƒ~ÿë/È8ˆ@âÔ0–è’P NèÝ`-xɯ^+Þ‚Œ‚ûOð¡ÎaŽE² öÂÃkðsØlo‰¥p„®÷?„ùjßçñlmªvþ`A€ç~‡ˆsÔ +ñˆ6J!ªØk.ü‡bÓGÄ OSˆ(¬´g>ËE˜âÞ$^“·])ÊRõîßÓ´ zýÖaF¦K«úø\³rGŒÔbŠ¸Èˆ±}ÁÖ¸(ÉÈL¢øTû„ÛÚÅ(7;ƒ‹{Ò÷x+8hIäðb¾A÷ïy]„éOrç}y±§æÚ{—+o|#}xîóݾhÅA £æÎ°ïaŒ9ó³X‚Ë– ØFxŒ·BÃÛ”‡àb ÿ|ØG´‹BÛx'CÜf™ê‚+ŽÙ§'^°Ñè¼aÀ ŒÝ½uH ç9ékxܽ¥š‡¯¶ÍL¯ÁÒ®¥ ĘKX$ˆYÆ@“ÇAÁ!#«[)ò—ÀZ Ò[vœ¿ûð7tA7Ìš¹©fïxb†*>쀾KÎÊ•6°qs&à¾Llƒ¾ÛÈÃÎõe=jŽB¥S cM lRšƒø²´9¢«ºEl_(éðyè'™&˜§É¤e®½Î˜Å‚Ni—Qoˆ­A?T²fˆ†)Œ0xH!rþ|W…÷è Æ¨ry«3äfÚjËwQ8“6ÖzŸ&ÌÁ`Šˆ+PZ ½±±˜êt(.ºpªiÍ*&"¯ND“nóÜH‰ÌŒx­Ùó”öÅÄ»‹Ç9æPg… ,rˆäì~µ5‹y Á;Æ»¬Ðr0 š+)c³C>KÑ0¦!zoh<ÖȬ‘æ¸ÿa€ÃCt0¼ gt*Œ)XWê·/Ãm¢^QÅ·öe 8á‚ð«N"@_‚Ütä–$jåïö³$bïD¶ç°¯Ñ%U*Æ´qä%Ðÿ2~y‹¹²«¤zŒýØ‚ûÌj(¸ö¾  ‰]î—ýp\IPþ~x_Ê{ÊêFÖðlÉ«DÆÐvVl6‘òiHâ×[ʇHõ™‰R{eupõî ¶y\ËÔ4«ÈÁ¾-²öŒíR'´Z\ƒ°è—+÷[…:D¥ÙéI®8ò¡7A"ÙE„(›8†ŠãBvfÀ»ÚD§üãŽò2:; RëŠ{ÂJÕuCó^'&pœ:!ÅÐÈÙT<“À©W¥Tk6-°ñrGЏ¦s¼·ÈɧÏQ3™ ‘éØû›÷í*ùAÔÂ5'£p‘Ý^OeærÆ1Ò 0leÏ*bžTÔf ‰»Ú´-†—"VìŽF I¼Çy²…€ S:)ÐÛptÏ)ÌX‡1Yöbº^\²2Zl% ˜É"‚€E&E†¶ÇX§¯ˆÂ±—¶> ó]‰=Z1`àجÜF!ðw ‹]ÑU·ÃžK)ð* m±+šd«¤ˆ0N1¢9¶`;ß¾™ápy_2È9^iS7¶Vâ€cÉEDfÔÁ%9+¸ÎEû¬7˜¤¨ÝÉ->’›è¤®nš1Æýí8ÚØTåØbÙ‹¸ÔÑlÊc‰¯õhs‰ù†9²ç©€ðŸ¿›™²ð'bÞcòHtð%‹TVÜœöÁcÊSÌÁ ôÖRĘÛYx»¤Ð©œA¿_)Ä ŸmUºGÇžÞ¨cêzB‹á¡@ vú’' )y‚ax;AT· ÌØ ì“¥˜Ô"æÑL³@UºYŸ“©ŒÐB®Ô%Pµ"¯ö§ü ÑþÜ{­•Îüüåçÿ>€ágˆÞç§0ÃD•äéæ›ºÆ< Œ²£õœã!Êa‡¿’…ZʲÀµ›ÓÉÇSNÖToniÝ“DýÑcï±bµô…H7 –äjNµ]†Ã"nšå5Õ@ÌHª¶äs na |tpÕ(ñ¶7E¬æØ××פ3E×bîÃ÷ó(s@OY7 _оå\IÉå:Š d¦Œ¤¹l50|7¤•Nf‚`‚¡¡¸vƒ;iˆêêAîÎëÝ”4ócŠňsîû"¤A•ÅǾÈ÷2èF‚ü«wŽ8÷ï’“ãöpTF ÷")€·ÊœÌßÓÊ ˆs¦ ‘À#Ø¥•¯+§sôË8 Þ‘?ÇÜic3gÎI_#žjÍG•à~ùùìZ™Šuêi¦®¼µ?¤ŠÃ,Gÿ½ŠÉ [Šé ùŽèiøûI¶ªvƒ ¤I¼„ù倿F-g?;o ˜îkoå PUÈ6šN=7íÔ4‚Vò“P¨3)D1Â]®L1b¢¦‡w™D 3€Í%F‘s„/í—à)/ÁÙTâ­kZÿ`‚ç3ØTÜÞBn•éÈX%e€fë0†·N±èº`â¼–7V7ܶtki–Ø!gÓ|gf0,îÑSãúo»[™[sUUÝT…žfp\ÅÓeŠåF.ÚQuYÇG{D½Y˜RºŽ.ýð|™b)ÛóÃÔ/Öüa㬭rxGF0´s eŒan'j.ü•m&²ªcõ:‰êeG&*2t‚6Q± {IîÈ•kŽá £^â7Y“%ÍW¥yGošG^Rã€.y›‹ ÁiÁOƒ+û’ìŒüžw*Ìôœ}'cÐÒøÚ,ƒþ~¹5`o|¿lЉeÔï­zÝ_˜w7âÆKcŠ^ õ_íqK-'s²ÕýI‘fë›Oï§ô›‰ 2òW؈ ²’5lžƒÁÍþþ©Å’ªPÔö°yé1 0]Ô ‹ñ¨nfu³WC$Kb"„{øô´ÖÎ’¦,ë^ŠáÇš*Ádùú{í?˜ÿM2ÎæÒ¨Í©B¾mWe޲Ön¼ÁH%âìÔzÊ€!‚ÛãF¥ƒ–›¥Ö·Ùn½–yúf Õ¹»]ÔÞî!bïk,"Q8_**·Äú°ë¶v²‚{R/àö\{û@ª]hÌâ2æìÃÉ7ÝùæZ¶»þcïË/¾_6°¸žcø®Íð°@ØýÔcˆíkä“¶M²Æñ6«\ʽö\J)Ï‚ŰubŽAÿ²ßï#‹«Îá0WçXâ§!q®hAÖ]•ÉD÷¸ˆrÛük’ߪò’œ±ÆôUDÀ­Qæ}v3öþp޽ÿðâϽùû%¸Ès¯F\¬çXÜÑé9"æ%•_ ?[¢2 Ð+·:*'Þ[}pМîE”ÀGü€Kw<=2$oçkJ­ BZ˸ÐÙ#ðò¢l¸T?}yõ›eþÛJ"æ”Ó/ý›}%„"J–ª}ª+.#ð£X3ª×¹lü‘a³[±¹THµ6°€ß”›ÒÏÓ`dž8¬zMê»ÙÛÏ”ÎÚs.>oQ™ä+]«Ö;È…Ý 8¡¨n¨¸«»a‚~åäë‘-…µz!cà9‹¬ ª¢ðqItÈ„ÉÀ‡PùàF=¨ÙùŒ¦ê× ¹×b³¡Ó‹ÎV÷¶™w@A}!#¬Äª¢ I^kßÉ šaJ%ÇûgŸª×£2÷Á@7l;ô 0„5m©“a7ZÑðöùLHS7u›½À æ¶¡$¯­õ%[Ës½"êTr„­hÛ)ðe¾ÔQ¦+.©ãäèϼÉ1g ošL{8.S*DbAÓ§gVÕç°ÔI™ZWãkï}‘—±··)A¯ë:éäÚûbTÃ-Q7o+D 2ƒs=‹ o€bÉf§Šõœá©šÃ4Ÿ˜{Ñ 7”C—xkZÞ& ãü)XÞ^{ßÇëC$ê:Ãݵ÷•ÄúÖŽf8È]çšâ\İ{LÄq» ÓbªsЇí¦¤ÚÄÁS>”¢P5F‹$ÿAw›¹FZðîì ÷B>ìÞ»$“¶JÖ²ö®ÄNe~®—ÔÆuά|3¡3a•¿w"=J˜Ñžg (•²ŠýªÈËjÚkP$û¦(â¤&+ãBO¹¬‘½¬nHÞv@² ,ÖŠr™"][F$ò+ì’µú„Ó0Ïe¬N°Ÿ›C¥Öù—2?r#FØa0)é8"v!›€qý}„ÕlîÈ8+vúýÃÌd§|©sJcªR·ë¾¬š‹u°X³;âÛUBaB‘Æ<MÚ¦œ¯}!—^à¶¥‡þô¡S}åvp˜«¬`Úåê Ügªl¨xÁŽGth™ï6s‰Gyk'a”óRžÍáT^A€Ç˹ù ÉO§ ½²ê7᯦¢3*Š.TYµúÅ9M“J_Ñ¥9è…Û|I¯ ìÜpvû›µÞèóG>|(ålùè¼(æÆLñ“’røf™”ƒÍÅœ¥ßx fö¹¶ˆ21×ÌL|XDeîfêºî"Û–µCp(óZø£•²ó[Äܘc, RÐxœàÉéY¬nÓ]¡c¶?‰ƒœÒOæHÆ ¼ó/ki¶®s‚ýƒsuÆH¨§š‰µ8(ê ŠX«ô,;ÎevÅàÖ$Þ‘¥6£©¢ãäàV¨2ªtH¶Fá~ +¿t–Ʊ²ëaÖMÚäó–hÄŸ¾„Fu4pPGtØ%ìšlŒ‹|¢2(…Õje R±4ç¡ Ü*‡™–2Æ®I*X™7µ8ð½×xW…ÎÐû4нøþÑÄN“/Òʘ•½Uxc_Lïÿ²G¿²–‡¤1UjݦuvžZnX6HmŃ59«4ÝS¬9ó?¼}²€Ý>YÀÊBÊnۤ젫hª%×Ò€¦YÁ5uÅÆrŸ_ˆ#ŸÁ…C}Ï×MÕUͺ£…xg®Z¬ÕxΗڬE 3Q3É2¡ãûnuJÓßyly\)¬”Zï!½%¡Í‹èšknɶÅÍþ ˆÛKÅÎ kóM¼z­Ó)²ïuJÐO öÓÚ­S‘WÉÐ3`oê·›ÛçÀ¢£…˪툾…¥°z¯ªHåF¦~AØd—Z™p#PÅŠ¹>Ü®™°jÞÜE@ûáž©“-tÓGËúnTÐou§óݬ4#L“.y%ºRã]¤àƒ\ÒÅJÆå[a¦Eœ1ø^÷ôà΢l‘䫬ˆÀÍ^Ë>½±  ô½7ïßk÷¼ –MÒÅ–Ô;›þvQ{‡ü ’lú$,6GÏa¹à{ÁE@Ï-«(µí–Œ¨¯ÜÆ'ZFÁ~¿ôh{q¤B牻’HwO™L®¶Ðnƒ¸!×òÉ7¯ƒGÛ)Wâ1LÒòŠ9Õ(qˆ°T‹¤Â,\Æ´i$àê߯ Úš&°$A¬#ɲ½Ã´úBôŽÞy›A£ƒ¶[}¯’qºÊhÚ¤kµùÞ´jáöº)ŠÔW+ ´>8Ÿ÷žN›RO§J„aö—²ÄÈÈ?‘6(gw¾™²e{ñ⇷â1¹évv}Øœ§Åê:ÞîF½qˆ—à\²S)HÛwå!H‘…eK7 :7¸.[Âvì$a¢!¥UÙi20ðfe_¬¤ˆ1=9—ê t“¢aff˜Þ+ E!E¨Úf°9¹®ªÑè£Z‘4B>·‡×§ün¦ˆËìN“·„×S},½~ß¹ªtÔo'Â+"Ü(D—>XW’ý].C¥ï™˜7»Õ ¡£2ÇS¡| vïà3ú:Å»ãWZëz(a ñAú|í&a·Á+Ò8ã^Ÿ¤¢+gÎHfñ컩àTƒþÂW|ÀDD»,ÔœyDå†Õ”u¡¾ Ô¾4Áì°°SÓýËݚꋼH3›”°™µ® â—¶$Ö5³*×7ýYljõ=—2Å;øZ@N7èt”~?OÌá«öNSVåA~')ý‹ùu€h´Taö@—þ‚"àÐx¡iÙÿŒ‘Ñc_À©ºúnÆt¶R/#åª8 Án»íý3ÙÀ¬¶VîeZæÒ_Åáó?vLòòð®CŽÂ—¬7B}/À¸Ý]q²¾îØÚ5 t½§ªàÁ]c®&úƒº°“¾ÿk«èr“MË9ž>%$^1Ž~;ûYÈé)ÞÖ‹éïÒ¿61úÑ:RŠ+Ðg§oA( =ê5z†®‚)5r½‰’Ýá£w¹Ñå-{±:wê”èzD¦5ÞØSÓùr¹)ÁUõêòŽU"JÎßœQIlä™û½x(slǃÿè›Mù* Ñc¸ÿЛ‹¶š²Ãt‹]tFÿ/ÎÃÅŽú½(¹½ªžaµrºýD¬Þá5ÝU’ Ów:Wwö¤eÏKBA}¹óX #U$›ÞÔ¹šûzM*/DUÎ ;”]uz¼U“è[½õ–ÕöªÚÀ臷ÂnÌ,‰œ[WÇ I1Ëã-ùª›lîÍÚ]óËixihùá´Sˆñàâþ½®X•þ"ûZ+•ë¤Ì€—~ H™>0‘Ð.ÆõïåAø®­ Ô£Ù1‰eCí©_ʸÙ"¢=_£„ØÃ»æ [ˆ‹zø½Lé31]ock×3U5& ×ÔÌ*U-èOÌçšçKcWÄáGMø%ü´Q<¶)ÑÔÄSß¡ø‹ÆAÇ‘¶uþNýF%¯ŽÆ«Ãß-*_öY{…Z“* µEŽ¢ žb"¨SŸôõµ„ÕÂZR p.¯z-ÖÇNø²–ùÆÎ>ºx¥‡: %¥¬{„²ò.£¦®%Ó³77½doÐÉw‘äQ­z–?žDcñî0ÜRu«Nâ/wSs¡—˜òQÍ­­,{2$7"@5‹ú©FNiÀ¸U¿ó5íÚâïš`'Ô¼D7î°‰¼M‘bf‹—ÄÊVÚ¡¬ðV vüªzëkö§ OëiVë _2Ê*¾ãmXñA³©’ÅåI[<ʼnCÊÓfêãæ:$¶NÀE]«_d.+7'yFm·¼¶÷xê‹k&;~æî ûƒf±Ã‹W0ê¦{»2é[ˆU|à§/D¼ ¶ÖÚKo½J–ÉÚ_ñ²ø¯å\°kð+bôŒ/PWÿâSë‰$Œó+Œ'àÿ÷ÿPKhLøqÈ$üÍPKiJ«H styles.xmlí[ßÛ¸~ï_aèоѶlïúÇesW= ¹¢Ýä^´DÛ¼H¢@RëuþúI‘¢dÉÖzçºh60gHÎ|üf8¤¤w?=§Éà‰pAYö„Ãq0 YÄbšm‚ÏŸþÁOïÿòŽm64"«˜EEJ2‰„<$D  s&VFø<[1,¨Xe8%b%£ËIf;­|핞ʴèÁúv×Ê~oIžeßÎJ·Ö¯ûϬ•ýÞ1Çû¾•.`êwß°¾ŸE‚6 E,ͱ¤ +žš}yvRæ«Ñh¿ß÷Ó!ãÛQ¸\.GZê Žœ^^ðDkÅш$DM&Fá0YÝ”HÜ×>¥ë›”éšðÞÐ`‰VUx„n›î¹Š= à,ÅYM#§2‚dø„9Õ¬|qàs/Û^‚Í+Lû;ùÿVœ6ËÓécÒAH’¾ ®Š×¢Ð5m|Î(”“¤mV÷j6Žº‚²l7U¬õ%&\$emkG.mÝrœïhXÝò7Ê!Ÿ.)ÔÂÊ?!9ûB I”??Lg÷wx Tr…|“$N2Ÿ,7Ä݆­ö0b¹Ô¹$cHý.»ˆŽÙµ‚HôüŒ‡a¸iÖ*?Ë%”4*@‚DŽ#¨?ÑŽqú•©¬h´ÃÙ)í'å[Ô¢ ›fïqtÛF-áNÀ=•;dªú N„Ƕs¬‘¯á®EJáB25 PÆ„Uœä;l'Ðv¬9ÁP1ÃbÑHZ‰*[”q)ð!H8’ë½hU+¨Óï5ÒÚ;/0ˆåBñ¯Ûl§®ì>ò¦`ÈÔâêÉKÚH^šQ]éh¥å‚~y8É¥nKp¶-ðšH¦"Ø}%â|~t »$úBx¦½kA…³fB¬tÔ¼V'ïr³5ÁJ¿î¬¤´Å ~þõxVUå'ä¹™ôó:-ãwc^'ÝÑæÌNô˯Aµzµ´Ð'W¸åNòàßòÉôÊ¡Ç1à®mÑy ¡)uæ÷¤w^d‘,Ì€*€—à7¬ãyþ[Þ¢˜B"ÈÔ$ãál9¹«¢³"9 Y…æÿyüçä±O3bsU“{œ¤˜fH€-'GJy!v •W‰9 xI3!>}Ì]ËšqŠo°Yyœ Åæ×NŒ8Û7&‡–Ft~!$G’m‰Ü©Ë }ç&ö'4œ~„XŠ1ƒÎ$a/ÁB€yGUT÷O‚c/ž;‡ƒwO‡ÚMÉTÈú Ÿ á÷Éø÷5‹mfKg)æk²\ïì÷÷:wT‚5“RðÇÃñbªeæHåáÿ'ÍMÕ-ƒ® 2]àdâ\æéH+:ÐlVùöç‰f›UÜ;•³–Z/?dØž]%³•WFw%ÀVëÏæ²Ò§÷ò#IÕ·Ó§ÑíE•N•U Ÿ à¶ €-2OðÁ ›/~MP^o¡¶œOú†š®v„nwRí:ã¿ö‡éT —ø"ç$jÈQ^ãè¤/GÃoGR{Ó¹Ÿ±>û]‘<Ç/ÌÖ6#¿*[ëÇ+æò_Ÿ‘D]¢éeŸ Œ»3xGÕgÚT¨á  ÇñÞ40¨•Ò–Îß&ýª>Ï'/½èͳ_àìú|E–Q=ÞI–]‰o'ÖËêM%¼IûfRj &—¬T£8ìUàÙ:–R¯GBžT±íæWY¸6È*Ãéòµ©æ²ê¯~¨¼ÁUw3•-üT¶/7Ú5Kâc—$o¿J=]^r¥z½*qшJ㦷;û?XDv¸é´£½ÿ &5ùÄ3´~6Ù34²‘*§Ë鼜ܰ´Mtºò —÷½y:Œ©¾]-G4V«C7ª ]ü÷,ß©ôÖñçÒ÷h%ág¡7—z ÝB\D$ÓOÍM? !鿀Ôe̸g<>›ùê©fÒ/Õø‘;yaäÖ¢«÷…ñX¬åŸxéÅó,œ_ãªã[â(aLÚ-Éî’"Ç^íENx«Õí(rÂÆê§[®¾+8…ùËBÚt¹4¤»z_Ò/¦§y1ýμ˜¾žöÚ弇/æ…îr1/:zŸá…>óY¤éñ/# ŠzIJusjlÄ. ‘z%ƒÓn‘ô©ÅtmžG}T?Û€òIƒOìã_¼±ÎÄꢶa*åØºqÃ’„íIŒÖs‹%ñ:ð&wÚìüºº*ÙR+vPÕÞ¬Ó ¹B¸Õ]v!ÙãÉÃxÖñ¬ãÙ-0ž¾1Œï:0¾kÇøîÏÞÆ÷ß·c| ŒïÞÆóŒçíÏoñýÃxÑñ¢ãÅ-0ž¿1Œ—/Û1^ÞãÅ›Â8lE8lÃ7¼ºË·…î°ßa;ÂÛ`ŽßÈ“'í O^ r]ä#Ÿ1I%³ Ýå'@å|ØT¿Û!,}5¯3?á¤P¯2–¶£ðœ×/2ú}Ì#Iõ¦£Ï~©¢üío!Éâ.i»vx…HeAÛ4TÍ‹àþÝ{7<å( jiKÍ"®? Te÷½­z}^]ÎØ4BV`oH¶°ÜøË[;áÌÓ0hQj\mhÉžÆê º…;7èV÷nJØé\9:€'ãT}T.3ã’c*` ç‹yãX]ÖË\Éw$qJ¬ÈsòÕrÃG”âgçzþQ}`Q*’Ûá 4ãáx<÷p°ïí¢58t­4].Z”ðF½ÛªS…¤z9sƱº…6´0d1íº´irç.†ì—cýÏKí oýݬ^ùÔ?F>^ãñ@E9Y R,Ün¶²QTúÐx æÛìqÙ Æð£ö¦ßÿPKŽnªš p=PKiJ«H settings.xml½ZßsÚ8~¿¿"Ã{ B[&¡¤´´$0@›¹¾ {²Ö#Éþû[É&M \)¶î‰Ä–wåÝý¾ý!ß|ØDââ ”æ(oKÕ7•ÒÈC.·¥oÓÞå»Ò‡Ö_78Ÿóš!IÒ\j0†–è z\êfzû¶”(ÙD¦¹nJnš ‰1ÈÝcÍ—«›NYze#¸\Ý––ÆÄÍry½^¿Y×Þ Z”«ïß¿/»»»¥Ê9_œª*]ýR">+²¤›qÊ®*•z9ý¿t‘mò…i®J­v¯ßºÉ¤?—Ü@dms‘]¶[»-‘Êæ‡õ³ÕJ‡žûõ™ï´¾­€M1.íî˜mLwÊE©u]­T¯nʯŜ.zssPv%ŸÜGšåAÁµzýªžOøgà‹åámWëZí<é“%®ÇRœAwÉäôž†¢&K-£8OG_v®5ÜcǤϙÐ'‹¿ŒX|Ée_ëp¹gj{šÉûáÞVµQÜÛÆsŽø;{ÕëÚuã|¹ÇàR«¿«½=W¬æ3ţʼnõ‚o'y|(†ùdwÐŒ o\7êg¢ðb4%Qû!·Der±Ò€m11]I$÷‘]”ôâª0h¿¶KÕá½W+g' 0ö]8cë.¾¤˜c·3Ö:¼€²äéy5½(f(KÿI‚™‘B“<8ÍÉ·¤1b^Ò‰“ÿI±xÉ_âíÖ;,X-&r?¥¤‹+(|½C[J4.: 3ø|G³>}Üc›‡×àÌòpùdOÆ z £ ˜d?ãîSؘ‘`,Q„°ÏVE¨iDZ؎˜b ù÷L­z¨"f¦øD3p6ñôrc°½…AùS6’pz—ä$Ó„=ÂÙÑÍ!|’(GÖùä•IÄ„ð ç'Yÿ[{Ý)¶vl_¼²®àq áˆ&QÇ¡CCO 3†Q1õ€‘s¼-ß䌚¦•S³ˆ=.Â&[M7|ÅY’¹Àµ'¦Z3ù¢ñ Y^ÀœyÁ Å\—Åz* Ú‹ÒQ£á(iQl¶]ÂB±xƒÝ3³ì0 ¶o ¾v¢S¼šv˜Ö½Ãùœ G~é뛸ˆR¾R¨\Â01ÖÒJpâo"Ô>“i!QA+m¤µO­€4}éSå·8dlù3…(ô·'w¨øYy$@êêqýÀGç(<„ðŽQV"ðå ©ÔÉ´cÝ–!YE®4jÖß]&‚D¸‚܇§5 E˜âh¿Ç›£<1,)Q˯¨ÊÄ,ð¶öŸÎØ3WžBKÁzå ¦˜B²xˆŒ5߯žÉO¥V£R¯Wß]çiT³>~<øâX—òþ³ÏËÛÖPì* >OÜô™º¥­Ò}¼@èªrGQ Úfb˜òF=›¢Ú‰Á”Ö‹W’ˆÏ„tÀ\Å¿FwI*âÁ.F151ö«ðñªå¨ïéÙPvjPû&Ƨdz„a‰Ïž!Z¦uCÝ#‡K¾X^’EQ$6[~%Ûš39J$õ™s¢’€Îþ!Ž¡æV“§œ•ÌŒºžØRê(¶ l»ÿ¼ÔïE€¦èàd»?º>n(D$`¡À&JQèí 0û;ÁDç—amAݲ nj<»Lpt2“<¿›Åäbã4|w¦ØS“ 7¤'€ \ý/ç+¶Úîd ­³Héó@S÷å€k :;ݦBÉü¿Âv_ Å\£Þá’©íiƒeŒmEŸáo²T¶:}n켌$•?#a(‰ÒˆÏ|Ø‹÷]áêÕZýmíì/ ÌV€~À;˜³Døð´íÒµÞ+˜¾Ñjë“û(¡e£ê­ÿ²û¤þSñ!ׇC#€K-†(œÀ–ž³ªžÏ£­?ÅuÙ7=Wå znרÕÂoi>ÍʹmÔï­´¶ããŽ,Ô¦F$Ë24MWTŠ+× ¦()´pIè ZÙKÃÿ-uao+i­¯A|.=ÅQŒ#4ÿ^éÚHÙ>ZÀ± ¹†¥-ƒ×ƾ·¬sàÔ/ÖÓ½Ô(ò©Œ0PZGÎ Å$ 0 ÙQÊcÌã,LY†Iœ¥›=päRðÕš8ÙÊIÆq&i–RBi’£›SA6Ö]| 3ýWñ}}aÉW–ýXRFñG´Ð {‡/ú × À¹µ)ž›ÊÀ·iy‡î,Búé¹QÃyÿ3MöIäÝûÎè_ ,’¬: ¢ÚDì °¤pXÄ©(Yœ1L Úàø°Tø—6§_Ÿpoݽm„7鶬Z„”Ýúî%Lbs*ë;QW—ïÕî†Ü\5SÖ¦ìŽë€ÐtÚÈUe$ÊYEX0WGê.p*w»ã±±Ðw¥pawl䞃нyPèÑÇ[üPK‘×ßÃêúPKiJ«H manifest.rdfÍ“Ínƒ0„ï<…eÎØ@/r(ʹjŸÀ5†X/òšÞ¾Ž“VQ¤ªêŸÔã®F3ߎ´›íaÈ‹²¨ÁT4c)%ÊHhµé+:».¹¥Û:ÚØ¶+šñjƒ¥Ÿ*ºwn*9_–…-7 lϳ¢(xšó7õ›X¯ž–Èv˜XŸŒªôQ:»È‘t€d“&ð˜4¤6˜ì‘Xÿ¬×G¦³w%`!VOÕ…¯³ëÒÇKu—«à]#Ô-KØck¡æqÀFÀ08k€K™ÚS+‚åµNÉx`¡æhØì²ßX—ŸL9PCƒõУšò³XŒ!smÀìðŽÓm-AçQ˜@< ¬êÃ45¥gá&¦ÇÃ"s¹¦öÈðxÐmwÇþJÕólŽ÷@ís> stream xœÅZÉŽ$Ç ½÷WÔÙ@·b©Ü€BµðMR>>i»X¬‹~ß\‚Œ%#³{Ææ0]YY™äã#ùæÍþxùïÁ„£u‡iq‡ß~ùçßÿ¡«æðû¯/×÷—a|›“5oþðþÓá›§=„Ûßùád¬qgw2ÞϯãÉ f4Óy>™>.ñÏËùu8…ï-_ÃÿáïÝÌÝ<Ì3>ïôá›Ñ¸åü:ð£µáŠupÅ­¡¿­WO°Çó¿Þÿñòxù6ìÀÂìA­þÇß^ÌÛtøƒv÷Ýß_ÌáÕ;üv°‹}ñÿßÃ*Œ³ ¿ÎM`‡øâþºÂ–aov<Çý‡Íðã%þ~‚­?ð h';Ã3G»€½Ð"°Kͦ¼å&¶—–탽 Ü M ›å;\ˆ=˧KôíV£Ý²ÐM7ôÉßu;¿Îé]SXþdIH/xu]ψ®iÇÑz#Yv%»Æ7ç~®Ý4 Á‹Ÿqx„îzD«…oŸÚswøéãüÿ{ž‡“ ¾ fŸM0átröì´=\—a”Ü ·‡•8ÇqqcòÍäwj9Ôyxë=|펰7„/›9Þ…˜rSnìhÊU7à:¦p¸Nã!<͉3ÇM¸ém(\Œ}Ѩ) +ÛãK#: ^ié`2Z;ºmI«_S€©×ް#4í]‚¨V÷ ò¦Æ€×+ýφ'¹YÈ/ ƒlÇ‘Íá&‡×¤ÐÉ—Z³!¢7~í0^\˜ŽW"dz!@wñq€LÀ`×…ÖWd·Ç¬b2”& Ç€–1É$“˜ã°#³ìæ07TÀT@`ã ã‚‘icž€3àrÒ>¦„#qYÃízÌ CU—¨ÆEº÷„ˆ}YbüŠÒ qˆ«ïÃM0 ‰ më à“&ipä·~Mù%÷­»Âxþ¨#—6åw7±¸SZ¾©ÕaruiòÌí36Ì»FFœÄøcÜÕ Z§49Ý %§Ç̨y=åõŒ²‡ƒ3@€ImÑ0¶dYdQXuJ&1ô²I€Ž;U Þ\¬<ˆÜwè0Wé#zE'E—§]6k‡Á›·å/à‡€ÔYbE/ºˆ]ª†âÌ6ŸM‰_L.=MrIA<í_c× yàÐ:¢24ô]l§*´(³â„„>0SŒuâ…&)T+ÞÁ±h…î–1«òm§)‰ø[€Îø»ÃNÊ8š‘”âOOE•; d!æ½nùÏøší¿_y²ºqU6ùÎ12 ;>”eªHñš©‰#´TIë¹;E¨°N®Q[ÉKB­Ù‰uÛhGíl «ë´ã¼ÔŒ¾VMÚ:xÔyíXnTU¼[´!mxOp‰c¨¢]µ GÅq‰Ô¡û‚*ãcñ–]”wîõî~·_©Ôv7§í¬/S6#¨ÆÇ¥Ÿ*?äOi$Õ@ÇRa¥ï¶i¨›€GjXµnPª6wo­²-Ͻƒ">’ŠVIËb‰âÂFö?çÝA3ßm†O·@)Ú§ÔgîÒ À\I5{êÌLõ’Þ‘ª9•ÕýÉ•j…¦áºEh׉þXç‡O–¬ÛÛSºyÛUë2JrÍgºƒç/ÜCÖ¦xF£h!©ß=r­ÔÏœžT©à£Ì›ôÎT9K3>µúÎààBz¬¡²ÁHÎÔÊÒŒö6ºÀ͸%i™býLÒë/ðª«ãöÎS»ÈÑÍHJÆÈ²~€¸‡â]+WáD%F2pC‰)d†¾¹—‘T—NdõA®ËUZ/×Ìb:…Ê ©ÝH©G«³`ìEh®Ù%ìñ®«|ãîéžÞÀ.-éj¬%1ò)N B †ñÎÜœ‘2`–<Áaò‘-¥sªxN=t*Dn¥dãZ• ¾”)ÈYæmÒ§Úh·4û9úÈVè:È/®ê[›+IDňáŒoENzRø ù©l’ïÕžê9ć*Ø.M— ˜¬Ûà†Tœ ×r1Š/,¥ôM7U^ò’:±’ÃùMLR`Ç„×2ìé:Q;«G ;«u¡`.žÌjy/“éäCòžö;[Õ!1‘¤R1Ô÷äV­r¾šµò@}¶Ê=zRpÍÆœi‘ªJböÖÚr{J{î=Šø VHáÁ¶…løI†³g³E×Ñ­Wè s¬Æ†A"VâîìÚ˜Ñd±9I¶¡$:¶T¬m½B±’½ê¬ëH?íŸmX²¦bçVñ…óW“¦Ôëz]á'PÇT.(ƒUý¼ÍpÖ¬eáªú­·¦š®0‘8¥ª+éšÜ¶) Ðà¾2Î ÷?àqWä â{ mèJlq3í0Ñ Ž  ‡¢‡)¥ÖbAF«Hƒ4NpÅ<œ`W5Ø 2]Ê~¢Í8[°ôè“k‹Œ¨ïf×^lýâwa–Ryè²”š~ÝúŽœ‡ZØò"œe9¤È‚Å ¼ëS‡&í0Wìa#KÍ[¤2=-çØ*g§Þ&•~é™Ïà9'įñ±¨©º¨Dsˆ£Ñæ°0õ0q×kºñmÝK<Ö?Ïm¯Ç}Éà¾?fš—ÚYì:‹Se•ºrn¦B‘"6Æn%,à~)Õ³òQÛ€EŠJWª6¥ì‘ïÐécÉvÓ3õá,çûVz Õ£ÝöâÒ´Ñ;’ßwTuÓP'bÅb¥ ¥FÏL¢2!Ñʘñ§"ë2;§©-ªÈÀ§«m•sü܇^ÃÇk'èþOkJÀ)Ñ&©¬†¤œÑ ú”éj_ú¶óCó’òÜ«øçÛÃÿOÙüN endstream endobj 3 0 obj 2588 endobj 5 0 obj <> stream xœÅ[I«ì6Þß_Që@Ýh°e Cì’\È"ôª;éM¿†Î&?:ƒ¤£ÁrÕÍ#̓[UF–ÎøIO½ëÃoÿ;(ÿÏis˜søý×·Ÿ¿9ü—ŸªÃïÿ~»|¼î}>Lfð/|üëðíCüòß~9©a=º“ºª›º«ÇªÕIÙõ8̼ÎþñzœOZ­ú¤îú¬Î«áè™ßøçï(§Ýê7³Ú¨ >˜”SWXë·å'°­ÕÓzýz5ÑFøI_ïžá©üo<à§[“û:5ÃÛOžNìøeózÔŸëÔ¢,¬ “oéaýÇÇ÷o÷·Zbs‹{ ±ië7“‘e;õw˜ÍûTì`Fâ„€2J]dÎsb‰¯X>øÀEÄ;|œù-ü‰û̬O!íÿ¸žÅËfÚEѳ›?´¬T-=Óg¿ ^!šxÁNÔ'!‹øBdÈE²Õ‚¬òæž<æmbM…åŸDÆÓ±wÏ™õZ$k ç‡n›Ã™øc£ékÍÍïKé.Ì7»ŠÜ-j.Š+¶g粎Q5‚ho†B<.<ÂÛI®5g™ Ù”MÚ’v€Óƒ:†âÜ@Z| äèEb •Ünõ–ã/£;è:h¤2˜èž¨B<êÖ6bÒªRœ…úªÏÙÔ'Ø‚œúÊÇûö•)˜iÁ%¡cÏÐ?‹Fɨ(—ú€õßdš…•6K20d ,øÃ-‚Q1¨{Ž¾È² )Äâ*ˆ¦£–Â<ž¤£¯´A¿ÛRi¯ áJ´G{ÉØÁCÊ”Þé’+e.dGr/£b-µø¢mˆ&r©1´‚ isÿwd|™ØÎfú™Ø&ûð"Ò<ü×i ϼ‰Ñ§%È'z-½jc-"Ò¨GÀbWÜ1 ÈbœF.ôApðÏ/oÊüÁþøÝ›:µ÷º/íCèD?þsø©-†qv•‡dž“ÊÈö ÅFŠX­ $u«NÒù(ÆÄÍC8RÉ´&DT]Q@\ŠmÂhnÁE­Üüzƒj6 |㢮QðfªÐDÊàù¤fç*©!<ƒÉÅÆœ2¿Ž^rD`Q¿¢1’Ì™â‡ÐW:’9d¹äuª ;Ž]”6wD’•½yQDI`XqcÊX,2% -„$æ¶#-IQ„YNÙM²W ໆ*ÉäèÌ®Í9I& BU®aT¥c IÄ*Œ: ”—†·È&WH4e­È»ámC¨K™J7´ò‚~‚„[&&bÅÓà¢+n«ªìêž<Á–uUû·…¬Ÿˆ±–"¿ aVƒ‡…ˆ¦v±_göï.aèh*ËbÚ¢9ôì%” Îr42güÔÁ®ìKP{£x(ù©éùgTÓ>·¢X ‘p¡ÙW¥žªÈ“¥ï…Õ ˆ¡DhºøuŠØ4û'`£U½)>‚} ~7|l‡x?—mÉ¥„°¨³0¶¨e5˜ˆç<¹‡õæJØECÞ@Ú—Ð1Ã2<»ÄWgùž¢•­óI‘5NÈÖ|ÚS™HùB²±‹ò"je¹ô™BjÖ(¡ZTFÌ÷S×É0ª´(Oþ*L÷U9ÌKÝ”I‚ý’è#¦̹•ÝÙÃ’š¾§¯¢}Uè#IÈðòVHP{ª®i ·íÚ£Ù“èœå9öD"–+òSù "„rñŒÒNzWk“ù½K³¤CòÖ×ü4ÖÍ´%J"ï¨å3ëõ.F`mK§wFœØîÚ„„2à‘KŸƒ}yaÄN•dBée„e†ÛhmˆûþeŸÌ _²c€v íÚXÓœËmÄ·O†Rb¯_[ ÃüU+¹hÕë+Âu°Ÿæ ûô6Àð³*&0o ´p , ^»F\ :“V*  $ÓBv×펵D49%)ëÒ-Ò*“IÛNs(óz{Mz™dœ½½àÔ!jtÕ:꺣ÉãeK``…™|UÁŸåHR¢FÈ0>¢¤é GP\ :8œÅ„2j?¯Wúšop3nn’[¬îkÍNUJÂl¥j}ArËy‰hçu(e]a ž•¡Á&£šlu—U&nb'cåŠ;ÉEO+ö&]ÉÞ½I<Ötw`»-‘+ŠWÚÅTÞµXœ¹Aí›s_¥ÆÖsó.¾nP fߢq'КÅ|ó4_N’ÕG_švÎgg›S.Ú·3åÂsÈefSƒ†:˜¤ì\#1n®+ß;k O²þmL¯öû2R¸á¸u¯d*ׇmå8'ïE‹™voرՒ¦ÚàB}AŽhô&D´ªïû­‡rS>Oï}…ŽCí)_c~PZ_CJVG¬“7r¢ÈPô”’‡8² þÂe3ÙŠeeëÂÈ„,ÉÈ&_<{öÞÙ¦˜©Ê팮w£û2ÏÖ ÙˆÖÛLjíû‡Ö·3–Žª“Ðæü&SJæZñŽ636.çˆÆÅæÏõ“\¡PÈ#Ó`0u«®Òøú*Ó¶‚Ú~¿ ë,ЈŸÍ{âÛ‘D¡,éÅò%–Ie×ô%´ñJ³m§_3Í´á‰ÍW‹»yýñ=U0fldÞ$ÞS/ýVñ¥¬÷{šÑËRDZ¿Ø§óþ;cƒÊ›ZÝ¡âìîy¤õ¶B¸ˆ•Ô^UÂùÅ‹m)G¤Vu­ëzès®½qvûZ[5Ry¦‰ÁcÕ@_‘óXÏÀùcHF55Z¤©m•–ø$ß,ܸk÷ª \çÖé¾Ö5Ê&5<ê®7ý¸­n÷—ç*8¼vAXCþß3»ìnJ†–ck I7 À\÷Gš[ª}>Gįs ýš¥êÌïJdg Gå,ïƒõkU]Þ6æ¸a´ÿé £BËxÁäf¥ñ-ém»aȧŠk&zB&¶ÂÌ.[a+ßï{WÏ4ÅÛÛÒOJ1YA}(º®F@Ô2AH-4&_«iÓ^%y}¿œ— 3ŠnXL‡«à$}±ú_G¾%œ¿œHgÑó„Ñ• 2ðÀ3%b°µy÷2X‘te‘Œ’óA£Â㽦üžf ›75w/ãÖ©É«×"SA_]|½é¹d½«*ÉÞ‡?‹c,a endstream endobj 6 0 obj 2660 endobj 8 0 obj <> stream xœíZKä4¾Ï¯è3Ò ~ÄN"µ"Mwg¸-ŒÄqâu$ö²»ªì*Û‰Ó,‚ZíLOwÛ±ëñÕWŸ­žôéÃÃï'þymNãlNï|øæ³Óoô®:½ÿùáòúàüÓtͼþpúüEŸÂ×_úölV=(oœzYÝYyu]¦³š–G¶6¼ÔF=Ã'W|SûŇ¯…_æ…0Â.ãY]âO3-z¤9Â0OçŸðSÙðŒóø G†å«‹2ð†}VNù81‹6&O·<†5©ð¹ŽóÜÔš>ó2ÂV_ëqÁ:>"ŽÃ5ª‘¯Ÿã°°E=ä½qFü²ËÖ ËQøþˆÏÇY°“F ù´ê¸Ÿ°?2a˜Ãâj³‰–ï^¿|X_ÞmºM«'[»M/6:%ÌŠ«`kÀ"£™£1µ¡õ±óôÐ}šŸÌÓX?m€½j$c9rý3îLŠú°œô.Ùt&×@°l9¶p*|•¶‚ã*{…Pêšàh“~zšÿK™¬‘† Ѻi¸íl 8ÈÆ†LP°Hþ¯¦ÀÆMÒæÐÁ—° L¾ôŠ,@ëàäI³¤Háœr8sÞ}?áâÂ8œã`¡8Ÿ;È!ï\}µMߎ2•]!~n`«£mUaÄòSTLhœG>~=å“É?Èšh˜l¹‘SaE°!HK.©×8?Ã(¥÷ÄbÓÀ ‚}n] ±h OVÈÊÓ¸Áä5Ê GKd½EcâËhá÷ ºÀFÁK”s…‚ï †!«f,ÖgÚDm±"ýpKÔIø&г£5Ã]8«mÂY“¶¤Œ¾Æë[´ü*Çk¯Obì÷¿>¨ðëÍýÕêô¨C˜ÿz²Ãáõ/§¯·Ÿïæ¹…À`ð‡µcwñnò;Lbq*– FºA^!ôËÒLÁŽà &ÆQH©YÔÍ=’# ?A“ID±ëÉ9+C\òó`R.Å!št„æŒåc¨RÞîñ°sÓ“«ƒ¶,ŒGf†¶¿ÁÌ’¦(6×#ØyUÇ­PŒT“ИB‚mð—jâ„ù0SA><Á@ÌD#ˆ°mבƒ€‘E«c¨¹0WùBL™‘›ŠaÞ+šªÝlßqV5É¥æ’fbvHM]®…bé7BëKØÚÔ´â*¥9îŒØ ßå"šJD*­U€¿'t:×#œí’>§ÉãHd»D¾³[ÒH•¶IÓ ¸„ ‡ ËmAFÖh¹¯Ff:¬®¡.ú,}™k.EM˜9…MßÕzl °ïê„R9ô§T[ÝÙØ°‰œÍ¦)Að[¥ß¶8žÖÙ7E“TuCš3;  7%E™œ²^ð#Êϔ甒™ L%–§Œ4WzÆÊ†­ɦ‰Ž0YÙ†HØ©$þaͼ¥´fŠ‘]{/nÊ!_cËÄ4š©^Óœ¾a[6 ~Ì‘-Ò´(bñx­‡.ØF¿$ï s.Æ63%StݺåjBèNy{]7ÓÜ”^¢~TÙ®Ì_7÷Ö+ª»ö¥Y¡ô2—~3®Yæ5Òùµ<ÑõÆ=Ð}àÒ>x:8©Š{a²~P)¿€ë¤y(Nú~]C€0? « iŸiíÏø€¹\xª("—rë™–Íaf&¤3̽ÆolµFÝv?®9ºf°CÛþ8xПò‘WKÝ5%«1“H¤ïBˆ\È(—/ž-@NÂŒw=‹žf—šI1j°ñaæš´æÕæTBe*å›ä43 `Ì_Ž‚Ø¨Œî1cwV;›†bÚg6h;̽ï†ÝvÕi7GÐlZïþÎÞÚNnÿ]«ˆ‚*f¼èQ¤º)ü<æJQ*ed2%uS·jZR%2ÝB±b@ Ãaèœ ÆªQ‚—–´(j”ÕùÉ úpC8™´´,Î¥ ×M§ï xsfæ»ÇF8Àè–Ë®šI•fƒáTN*R+h%Øë´e—{G¨ššG¢”h”REÍ×ÎöKõêY’ önË v&+âu3^}çÛ±-٢Э.ê !͉Lò)I!„Â^~ZTsμÜ,•Ù¨µ*±–Ï.U¿ÕæÈád$ß’êô¶MÁþ¸+šÔ áµ¥qq652µäFcW”.¡f-¾ÆÿÖ­Z5mî_)7u„¼ ‹z |m¤0»ËÌøÞ¸°ÿ„’-¾fyZ’yW€n“¦$2˜¹ §WŽÛ)Âçzd¥² )m ÆNÖC’}d‡Ùu¤™}{šÍê r&ótòòtøŸÎ7+¨.w=ŠV<‡ßf,–Jr©õnªÿ²síjÅS/›ñèÛk}‚U”[_ÚÃm ÔÐÑöÃŽqV¦d!è˜Õ¼èɼÄwÀ¦™L[3¯ÐшKµk·“ÅEKíZà -¨Y²“ ¹Gqw¶0²”Hý|€½Û!ħ¬QÁL¬‡åÚ?­ZìpéDq—»IY9ÓÁaס~jëàö£¹ Šú\UØñXNx–N‘éLºSæ»5P^v1¨VfmD §+¨û¢BmÍ8Ì‹+hgmr¦=µF…ârñbÖ™âN™Osp‘JNF:ñœð¶]4¹¶Ã¿ˆÓ¿|ïdKõ+ÖÅ6·I3]}a÷&ÆbyZ>^nˆšXö:n­b°AêÀ$h^öá®à»w°tIZòùKâ”’RÄÁîgIM‡¸=«Š):X»æË¥ôï¶‚ƒ’¡GÓ%ÝãÇÝâÕó™¤J÷ƒ…ÚÌIrËMóž~дHÛçÌÝ”câ§§‡_òZ®mS¿–ý¢Ï2'^ð‘JAZ]q†º¡ŸŒoB´›®½/„ôÍ])w@lÊâ,d†x×ç~¹ aÞ?Žî¶´²–wg˜S3rJ%ýP—ع %î†tö%È_qÐnkX‰kß½ÃЖî©ìX˜:ÙJ§›cº˜oÎU”h‡ÊïÁR –‰JìIûо½¤?áS_8=‡Ã£÷qWψ7â-Ù’#‹¡ë=÷g´²{ž?&·šæ3浊]Á˜™PG”ý8ܪYÿ¿]“½ÿÓ«O˜^yÝt<Ÿ»êeDRq§±¸·»Åž„tý!O‰¯-2s­ÜflP­]üÙ©ÍìÛw§?>%ï$ endstream endobj 9 0 obj 2543 endobj 11 0 obj <> stream xœÅZÉnä6½÷Wô9@;\DQ ´Úí¹%1CS¶K&@æ2¿²²¸Hj{ø`[ U¬åÕ«*ª'}ütø÷¨ÂϨÍÑÏæøñÃÏßÿ¡«êøñ¯ÃòzpãÓtôf/¼þ~üöEÃã¯þrÖ³º^Nî¬ÌE«³š.§ñ¬F­.ú¬–ËÉŸ•¿LáŠz¹˜³¾†ÒQ ð4¾‰« ñ¶S£Yâxÿ€…qÙ¸¬cnùk VÕcû=x¯NbQõ¬î¼ÔI齟ºéñ2²TV-Ꭰ{­×…훸’)\ r˜sÒ ßÍœö‘¶¾²µx˳áZ³Ÿ{¾©¯¨N3ÅÕð»â[KütØíxùõõûÃýõðC×¶Z=ÙʶÁ'V( :ð3‹ô`“m “¥H]ÞàêzØ”mœÌ“¯dS_·¤I—mÿ³*À¥Xmè~xM¸@2s)‰IôQHñÛ‡ƒ ¿>‘”?~wPÇ“añ!HUÿü}üie+Î5!d†‹sQ9WTYÐÕöÇ ÝZ“_-ƒû›„ø×ÀDÁÞcø#ºáK\¤)þŽX섞kAOÑÜñ xV{XàÎ~ž|¢"|pÓhu¼—ßÖCpJ7%„­ÂÍàÈ:ìöëJ½Ô!Çá¤é©¶Î¡7íJ"ÌX{lûä ›xÙØ²!| :‰ `9zk+FHJÖäÙso¶ˆ :°dËÎ7)¤r-¹ÑýÑÅ1ŒÁlƆÿ®º.‹®±£&]‡] 5nIàæùi®±¢ÖyØ8èf .r“¦ @£÷¤—(´ÉèQ.Òæ“ }!×¼E˯Â*úÕ…9 ÞN®4)^ÇG+­¢9!ÁIIz½‡*ºÀw™ã3b"¿ ÀG…8V|аjÁ•Dh¾ ÉH¢>¬XtÇmkOc“p·6+—…º¢("èΆuë€Ã˜£¶-6cè ²†÷G½Lñ ¨gv†uȱC¼ŒŽk¯á’}λj=®Ã¨úV­(‡½‘ß›/nËVf\²àÛæò¦ÁÆŽ`w¾\ ;*òE0gÏdmÇÑÉ€ðk œl؉E‰ hÜA:S溄}1ãC8èB É §eaJ½jƒE8ª"÷9gSÅ*«rNúhfýÛ¦vS“ ¶s9o!iìwc­ƒë?'_ ¯»-»É’AT(¾‡åæ2d(\ûi‰ÓÓ¶R¬j’Sà䜹ɉJÀ•±Å3E5‰ü§ ´UÂID–w¹òÉym£àʺ7S&„wó~®ðQ½^:¤¸%¤ dI¨J¢’2‰S2¾ŸÍ­• G+Ò¢•¼½e¶-¨}›p¤|2uá/ èÄ2fša >‘Ê#«îP!Ý’‹@°Ž~Ïцin¢ÏÜ#Ðk›€o•ÕWFl’ËÞǽk*O;aÝ¢bÝÂô2ÙœA§È²’ÉØ†n¯T P‡urcÕlÙÛÁ¨›8µË#êKþ3¸Ë üT¦äº–Md 1Œ/d3qŒ°Ë‰œÔÁÐ1é] îéd˜Ïz :16n/¸)Õj•“=·¨D6Ùl·ñ›YÓ],—÷vg‡†™XÜݲOØNg© G`˜¼WžV)æ-{0ª úa ¯öí¬@É;åP·=ð"°lÄö#cL/0Œ‰D[<%",°°§~§U+Ý¿ÖîÛ¨ÆH,½¶ò=“nʉðæŽÔØâß ìpG²¿òµ/´ûñìlp`<¨ 2œÊbÒÅs_íðvë箩–¡•2«H ¦-ÖßÚÖÃdu 5÷!aoC£k›É!2=2gá7”u˜45Û[-îë¾¥zG²n*¨è>¢+ó²uŸç–(j/?™O•9‹èÈ{%ýŽr­ob’˜•AXàiÑêÖ§ŒZý[‹Ewä.cEx¬7HVź;ÀBl†¸te.p2J’™Ùˆ†z%Ù!&1K h¹ ö Ÿ*'^Ö ø†K`´g­š¨µæb]aä6˜Pb¡Õ¡¦ò®X¿)†™Ç6Öà–\*rá·uà¸Û™4u Ó|\.lãmir˜ía z¥ÎÞÂJUVÂøTUE¤MÁÂNI­P ;5I’½{­0]Û¯tez0O+¦Î°â]lÝŒSÛ=cÚ ±ŽkÎÚýoÜ„}ŠF!™Å/¥õé\Oùd Or#ꉌ#V¾Våx1v´Üfg£j¸›!Úã5D3bØ3Ý ÛÉ^×t‹ìð¸¹è¾}ÎöÞXiî{;¶¬’Ãd…  T¶ÚŒø*sÄýÄÕ/ /Lm¼Â iˆ¸N _ýH ÛÍÎíΈ1¾íí"DÞD¾f]”輯ë†êi£.?’=d'üÓŒÏdõ=̨ê‘FMî—+k V=‹& È8é›úìÝÞok&õ@#?°¢îœ/:&òѺ´{(ŠîÔì¸oü/p QãŠÞ©Ç®©¨ 2£bþVtx|ŸíÿÏ«§–é¯l-ØÅuOÖšmZÏs{Šä³õ³åäç˜q«æo9‰…¡ÙJØ–=ëܘ~.äæ®ÁWMù`ÂíVc=ÛÚ™Ðm›rrMÝÿH¤ÊX*+ŒÊ;Åøð&õ¤ˆÆ¬ÕQí<ªSyå-ÅX:C*‘³ýjêIíÄÙ[e[, ÅÙE…k<^–‹™û¶9½iÏ®âNYŠI؇Ðb¢ºÕÛ‹¹â֯맲£ ‘ëk/°L®ÂŽÍ«åÓ•&qò›щ9ñ})¤„/¡R1ž­øÜJcwÛšnZ9…¢Ü¤À½“ƒù´S/¤s!<]|7;)"/5!èC’H/¹ëº]h«Úòí9æ¬< -šÄ’Ò²Ÿ¬£}ï2a|5ƒ¬WgB^*ýy·Xœ“D%lœ“4£zwÎIjeÛj ¦~¢¦*.t;^]VÆÏ¶§¹À¸š["?”t55ëÑDÔ¦<@wï°¯ñ5z“A¾¤•ûEybÍeîËÇÔØáò3G±ÈL6 ¢‰™Q¢çÞâ½kH8N)—ד±qkóÐÂGÄàGžÙÞFÔc¢ô´‘e¨8Æ’jäµ4RIøFÓU¯££õ%oöÎçoÞwàZ70†óÑÇ­!Ïàêö0ÇWÓÌŠít-M'õóÃñ?Xü£ endstream endobj 12 0 obj 2478 endobj 14 0 obj <> stream xœí[K‹ä6¾÷¯ð9ÐK²eC¿&Û&9„œòºdÙËþýHª’TRÉ’'3Ã’³3ݶTªÇW_U)ýItŸu½ùO ÙM‹ì>ýzøá«îOü´ï>ý~¸>F}š»Iæ…ç_º¯ŸDgþídzÒbèµP½\广ØÃzÔç~ìµ¼®Âÿy[çs?Û_Eo?}²OÎæ7ysëOÏßχÅERÙÎÃ`w^ÅtVrüº—õ8âêZ,vSµ'Ü_»/Ä1öÕ_Ý#î;³HïW¹:û›] ?’îkÿºÛÖ×r 'ô ßÒã›b8÷““¾€Í'·‰²›¡t9ûU°brr8Áô¦nãÌáÌsn¿‹ÛsÑ…>Ë9êÆŸFèU£ J íÓÆCúGÃPzѧ1w‘›5Ô0Ú彦£oÜ*'£á(íO+ôÕþîMi•…kåû—†¬èø'{°f]pâAAÿÒ+»¡ŠYž¦Üg¥]ʼh.{£W¿3u¬!“Ç}zïáe¼&Ó,$`ŸÉ™yän•h\§Mtõèû]U"´½À× Ý²à»ì¿u ÓÃ…· 68Ù[Ìà°KCýz>-¹ú/Û`µã´_ΕÁàOÞ׃SæÑÛ¹úw¬s‘CO%B¢î`‘ø™[Ʊùî)Ø/ǦôàÂ\täÐ?<ô&Œ>£R¾ûæÐwGaÒÐÇNÚXØýñG÷ý†æ„bA(Ö 0ú⑬˜Î‡…ˆЦr¾ªˆv—…9Ÿší¶ªwfCÕ§ fÓ%Å÷+l,-z‹}¯å£r‚çæhß77«¸x}ÙE& ºŒÎÂþÅà©§La Ÿž¼3ËÙãn²iß9ÿ86m1kÎZ®[@0(w’ P ô¿di ˆ wª´ é6ü†Â`Í;Ù°ŽÐV3ûÀ¹ôÜ"İ”†0†rZYðy”Kà'Z ’±ûÒŠŠçƒ7=ÈHÁtÝ’“d0hƒŽE ˜ñ[E}7Çâ.`4»¥%ñeТqÐA”ÅaÍh—^Öc‰ƒî@IŸ¾Á1,8¡g¤^>â9ˆhn•™Zî5 0Åd§tšÐæ=…›Ö-9ÎŒ&"åÌøfS”'¬í 怬̉CBŒOƒæ]PUÂb°‡þÈS(ö»Â¾’Qøµb®È`c4±"²ö¼¦JBÐ툑ç(:-p®-ÐS=K@UÆ §^ç/ŒÞ{€"Ê"æ¸øÂHLçB˜4s•˜Ä ‘qþø¸Ë‘¯ˆ‹7ª·¶/‰%ôE žƒóÄBF†b“$6?Avu ¾|ó«›V †©/)òœ{‡lU>VÅ‚´³Õ¦Öäq×&糜É`ï9RHàB‘B"=6woÝW=Å›RV'hÈJDðÂt ¸ïÎé2.¦¹Q(—[  m’ û=ÌÛ$ÕúOiCÄSŠušò¼$²ç-jäR^kµ‰H:ÅŽ>9"qæâœk—)7'yǶQÇå½ëÊyé ¥Øî“+e¢ãèáǯVJ9±l"Æ@âk=௄ʵ&5B²ÝÈ Å–{’ï}æ‚@zMéèÓCq¢‚ÔUZt1ä@,t™Ü11yú†”{Æ(Cÿ%ÆU4$5÷®UZn*Ký£«á¤’µ±™Õ,añ³‹k49èkÎKGÐJÚ± 40Ù #x±ÐöaN²Ò[¹g Évßü¾ÏqC6Ìbñ(B”o"÷ŽbgKÓ+ýÌ®†pàŒäBé½2ƒ¢6ì,–¥”cÞE½Y\£7Uº¸’„D< õêÄßIsÃÆlúŒÕÞ=ð®èR<7\°pX÷£‰C…‚]Ä$„H4R,ÜZ&GžaöÀJ}Õqæ“@±jÇTcŠ‚P¹w|”È[ùÄ% ´S$ôñC ÜgL Y_˜ŽA#1 Èâ+æ!Š˜‰žBí¦’y<ö™1G!ç0íÛ]#RÚ—¾Tî’bë6êe@î·¯,ÉÔvY¼q ”–dz‡Ælø¢ÐübÀ._¤vIçIjÒ6NÙðv›¬µ¡!óßÍž@A÷ž§•nõÈÅ·œv݆"¶Ž#gHžÃ¥WŠ]ñPy ½×ÅëÖí뻡Ñ̼kÈ(!™ÇæÉu‹c)‚œ7œO߯pF:ú{çöÛ£zÖ¾ô­±1EØ( 9O‰Wòá&“Ú:ûä±tÌLx+ÓVYÕÊóÂk„òÿ +ùÖ cÁç@û2!³´Gúïž¼fµb=YðKíõÞ"ÁƒÍÒ6Ów!!€‹z{#2…z?q.*K’ŽåË1àC÷7'E endstream endobj 15 0 obj 2391 endobj 17 0 obj <> stream xœµ[ËŽ+·ÝÏWh@>ú 4-M€ìœ …á•{cˆ7þý¬b=HvSãÌ…ñ©›,ÖãÔ©*Žyµ§?^þ{2á¿ÉºÓ¼ºÓïÿyù×_N¿á§æôûÏ/o/ãôºœf7„>þ}úë»=…Ç?~úþbf3Ëõ<]ìtM?Îîb&ó~u{».øÒLnµîzž/é›ðÚ‹ñ郷ð¸O?á¥ü†qð}Kk§[ø|‹ËÞ®g;\Üþ^y¿žGØ–× [Ò£áË·øazÞL(Ê~1j¿ô4ž#ɤ³kzÌ^Ì ÿƒ%]”7þîÖ´,ÅÀ÷Ž÷½Åå’YOñmƒŸ™¹¡· –¤Xü5®þ$Òï|îBÝI£éÁÉÜÜ™®?|üýåññò]Ó¶Ö¼ú¶QñA:%#hÄ¢f½wH¢feN𦅘÷:B¸ T¿f›‚FqW<Þˆ[ÞaŸ‰lÇ®€.š4 FˆïE×á#¢rQÃç,ñb&o®Ñ`­°·«·ÎŽæÈÏ’ 6Ú•Çþ‘^_àÍ•­‡ð1:ê&ËÚ̇\ô3Qw¥ ˆÒl°xkÜÀNñm;«HAe‚Ÿ)q%¶:6è´¼®¥W% 䊀òs Þ{ø™>ô¥fu˜¿EE —x؛ûÃmO>ð=8¥çtszŽE“¦Qš5éì…3fÉ:&'{'·ÙJ³>~7š÷ ¸–>‚a/¶ öM¨¼–=+îä¶$O'Ü[ż ¶°Ù½’k¦A4LÑ#P?ÇH6}ê*ì²JŠðªpÃÅÞ {yöc„­´ß#æ,¶bL`7¶û»ÂpiI}(9ê‚éЂ9NÂß æ¬‚ÙNæ›ÉÞÒ.ô+¬XoulW7¿ŽeÔUÀ’ âÜc^M>$B1L(QBv©xËG@‹[ V]¼®R É5Qdu ™QÇÆÕ“5í Dßó>ïœè‚\è2H`0WÞ¸5FÁ a«Rౕ­¯’%iý “£hpKQ%¢018›¢èFçÍ'bt•èˆKÐH£2e Ç(.)xv”{e­å¼´0ü°æªÀ<$Q ¯(m©Eð)R*Y²ì°ü]¢Rwá,‰ ¸~æ@²LÙ¢ ÙSpßC{ëZåRi»„ô¤Âƒ` D(%n#狈ECëèñ•]ÄLÄ«ŒKXèa]Èù…JƒNFsqCHÎ.zÄÅ¢ L’ëAp.qŽXDVO2¨(y‘AD’éäÖqvun9rÕÁyÿhßÌpÐ_[ Vrpv‚}VYp#ù÷ÄÓ V}þE)YבïLžÑÉÖ« ¯¯c(ûô Ìsd2åŽãò§Rn<©Ïn/ÕU¸l“tØfÁ@Éó‹*¦$1É#x·µ´=v÷­á6CkøOáÌ¡‡¡J§-xmñ•Ì„Eˆ2µ –Ri>âÀe}£¡"ý\îÛHe»HºD$ Ë (J$íÃè×£FKí\õ$S!dà…YpEµ£dÙÝRS¸,¶qƒV-ü×a§l- °90PíœD=!k+8ºÆÅ&«í¯”°”·FÄÁEUáž'–”}Œ5+¸å¡y¯[OI¹ˆÙu–¹LV 1™A¼–$x¬{‚y|@žœ§8:È0! <(;Îþh¨açÏûØ3Î7±tlY¿ºª;ô<¤ȱڷX(‚ö-º€lcÌ•xî‚™¯šè”óâd–çƒ4EÉrß.×ï@¸ŸÆŠ¥†ˆt”a5‘ŒÊ …Z6Å„D*m•Žš8Å>äƒ4oÍü:u0ßû¹·ŽÔ T$;åJëÔéðjüØhÖÔ·l¾(.THªTý46€/£èQÔ|m`þl+š…F3ú=¤–‹âYN˜˜éHðÏB©¦˜ &êÇQp[%ƒ—2áð‹$÷ЖnêÖ†jpÚUý¼KSA(r!(*·zJÇÍœç®öÌM„pêø8hJÜŠø&Þõ[u¿§`œœA«2¢“ÁÝ´TéÎ;ÙF¤sï'ªÆ#ߣÛD£"ªÙ¢Þ•à ‚2£w3ý) ®ºÜ¥.YªLÕ1*Ö[$r‹¶åÚzCàRŠžÉì¾Upë{)ñØ¢ãPç·fîß)Av‰—nô© [+§h´òú•*Ö.[„ƒðs.anEiE·Ø—𳑬d3&³ë®¤ä¶;+v‘÷g¢#®3F°xâîUv³¢«Ú3í`ë,ØJ!:ÝX µyø³L­Q¡ïKýIïç*êߤ’ÌÆÑWR5.§ ô= Í™åžáŽì\ÁÑ0‹ËJ2Ÿ<Èa³w›ÏÍUâ+[ =+µs6|† ]]ìÔ[]ìið?-eº²•ïùRˆ½3Q6±bà ©5s•Ïë ‚­ÂVÚ ¤—CT;6¦õuçž»Vu·Ô +z7ALlst=í_«ä[Þâ¦ö‰auîMæºF‡§ *‡1!’‹Ñ0LÍ—tÊéD66FÁ4ã§U,Z[yíù:ÑõÕv)°æ3sÇêv]ëÆ>”4ú EʃÇi ·»Öt‰3'Ç£Ã>y_ÕήžÃ}Õ£û åÀê Ñ­{•e—–žû=yõ¨A3®Ý¦¼†*ðBôN dL¸ªž(ïÜ™ì‚)Š[ ÌG‹ÎŸhÄOÔo}k—;—úè‰Z;äZ’Æ0Ï¥ÆmÏvy_FÒ½-¾W¶ ÊOÜß Ìü“ƒ³ö_ÖÜÅ|T—\ p7À×4 ƒ&7áÓÅ›ºë+Š+´VªÐkDZÕ÷ä†nËŠ rD ÷þØáÉÍR†<´™ñ5 ×çûŸ£ÝÍ‚öƦ¸[±ê*ñ<‰Vm§^}H'¹²«¥*B¹ÍœØš!P§¸K—µ¾.™\)$ý§ |Œó®A±ó„æL—‡7|Üñ"tøX’à‡l`ÉeÞzËô#.ÈOvÆïÃýÈ€œ|šÓBšƒð_¥I¸cŽ‹]¡â6¾w/ BEãð¾%ÀãÝŽÿül¬¦jVŠ>5‹>4^åR0<ì›E¼0õ£Æ~ ™&6È?l©ÚtòænI퉑Æ ÝÍ’íÅF©ªnÈDÍBp6ÓWq-ªÍã)?cË}wúÿzS endstream endobj 18 0 obj 2962 endobj 20 0 obj <> stream xœÝYË®ã6 Ýç+¼.T[¶À€ã8º›ö]]µÙt t6óû¥HJ¢,ÅÎàvU ææaI¤ÈÃÃGÔE7_Oÿ4 þ9mš~4Í—?O¿|×üÍߪæË§ÓííÔ¹ËÐô¦… o4ß?tËß>þz5íÔuWåÔMYøï´›Îæªîüú˜´ºªa:»«î§3®§áªìtî¯ÊøÇÚø÷ðØðJX3Ã8¿׊¿ËöÁc“oyøïfX­½X¥Gú8ãG“tQ=Ëð*óÎpn1BØO´—Ðú¸%ª‹ÊÑÁ½_K»— ß\éül¹ã¿/9â nrxo®x{MZ¢x­\Ô]\búííÇÓúvúPuœV»uÜÍKi­0 Ûò× šNÞa‹ãU,Š^q9ï'µø®ítO@/iF@{ßõ$îÕ-> ÃH(™×´Ê™NØ1‚{ðÏ}r é€"rÃiºM¨w‘˜9a‰›V¹Ü  Ìªf$ šLt?ò ‘7noYxµôÇ;Âj–ãUâ½¾â´Gž_’mÙ<7ò{MÝ8€ûvœ:¯ßZ'(j<Þ`ÕÙ²Ï$L9îáÈ>aõÓ`‰„Ÿ‹K¸Ý÷e« òÿ/³5qÈ‚)òg…(¦.Ü%3ñl}ù/ãùœ2´’0J笄Å9EÇC°5×3KŠÖ#úÓöÒWé´\Hc‘Ì8 !JÌ%i”¤!å÷Ï'/_Y‹Ÿ~8©æ¬!X?Ãz÷Wós]ÏnpeTw1±ïDu Æ€GAå!iŠè™¡¨Á!#ä›”|—:ç08d ¦˜SS #Sta%6ˆ?$eL-ñÔ¶½¦³× DoüšÈLx+ ³Å3Ãg'…ÃÓçþv9¯Ä¼P/’bºëMÓ™…É?·xÑ`¼èË,¢V‚ß ™²$|¶o‚Õcäe%"ÿÙ)~LJšnÿÆm[ÆXç]H 'µ 1Ô 3•î"/áó ›ëó9DÏxŽ gpÓè‘Vz`°S>G{쉼éá‘Ç1„µÏn˜‰ØŒUé°±’Ú²úZBT‰ˆ}ÇYUÖ†Ø{Tú 2H ¯*O´¡(×&ßöMrE#øî4³CDº( q·" Û†)¦üÐhˆjQP‰lèaj±PQ–ΡQå>ËeQæñyàRÝ—y4ò¦“.âÜ‘Õ`ÉkìÐ,\žuû;S®)ô±²âDøb~Õ"1eÆSœhÔlHæÀ첆4öRÃaRÛ*Ú™”$RIOéµ "‘»y "© xà_eËŠQòHÌÓ$»¬EcOï’¶êÆ÷šr:ıË6!ÜÒBÛwÿû´Pq±™'W±1e÷0í ³·M¸›‰S,I¨Æ S¥H eU]¯åŒ9m1œ7Ï‚Köët‘6dÓáßšQH·èôJaƒÅH=ÝÃ$dÇœS²v)êhâyÎ&BB ÙæÍæü=Ð;ÛV3v¬É$X–Œ‚²+-¡f«øVœ™åé†Ð¾àæv(SIáFi½=Os‘d©#Ö0ª˜Ž=i„j‘¶Ó¤ÑÉ;MZ×Ãý6ÍŽ¦„þëڕѦc#ºðlXM$€¬8Ù”´'ÏzŒ˜'LHÿÅ\%UhÜ™o¸ö¥Ô†jÆJtÅZxSÝÅúOoË?ѹe%”?Z&ø],Ù~,œMð) ‡Í„:Ïa ³£m­X­ÏÎ÷õíô{°¿už˜¼Ó}mJçÑy —meÙ×&ŽË¦ëš]½ÂeYI~˜G³_SB—ZUò ýD¶ ÝÑ‘}g¿fgzF›æ"D2O¼ôkÇÁµÌèÊɃEr¾‡+x´"îbïäb‹Aîì`fµÎôô®…6Ä¢–paBDVRè,‡ÞÙÇXì¥æƒ*¦>–,6ÑSGS/‰ƒ*#è‹ÌÑ®“åÏqò*K*蘸¾í“>4ÿð9E² endstream endobj 21 0 obj 1655 endobj 23 0 obj <> stream xœÕ¼y`TÕõ8~Ï[fÉloö™Lfæ%“„%„„LD–h­¦»Y+¶hk­5­XÛo]RK­!/ßóî›™Lm¿ßÏï÷ÏwàÍ»÷Üs·sÏ=÷,wÒÓµ£…I/a‰´ikSgö…¿ˆ„Ÿ¶M;{ÄyËs0=DóËÖÎÍ[þ¯«Ï ¢ؼåúVûoÜBˆ±ºú¶–¦f²hp&!W=mÌlCÀ}òõZÌc’Û¶µçºë=‘BB<ØæÜ-›š,Î,‹ÖcyÿÖ¦ë:+¹½ æ|q[ÓÖ–@SKÈZ!†Ý=Í$w”–»”òή–Î¥o|óÇ aûøOù1©Qò Ëñ­NŸa0šÌÁj³;œ.·Ç›éËò‚bvN(7/Òä)S ¦N/*žQ.-›9kvùsæÎ›_!-¨\XU]³¨vñ’º¥W.#ÿï}øƒÄIjùyÄB:é÷¸{œxÉC„Œ~¨äƾ奣_üÿ9 úz%ä y‹¬OÔi';’þùy¡Ê'BÖ’'ÈþÑìqr ËU¼9¤Ì䲟y€å†sœyK|Z¨ª:^ ´Z·2ÕOÝX—çó„¸ÿ§úèÃñ¦D“'üƒ(É8³0+²•¯i½MH¬ÙÛßtj´wcHBûOû;«‘Ü$Ò€Mœ}î€/^sW4.ÄÚàŠhbê5+ëâöëâL^ØÖ„ü_Êží˶¦p"ÿª˜ Y8Háìl… NId#fâ½+Ô¼H6úž"RQA4ÎÄ”’Ád‰sµRÒ›,IU…pmëV5ìsy‹›CÕHñMñÞÈ]×( âæÏ|Ù¡ý6«X^¥¸"Žjqs»çó‘HX+½òRe¿@3æÏÔ×G>ì ßjËCØŒÒNu¨:–ø¿³Íƒ ˆHèÚ•êâR&¤¦ÄŠUŸ(.ÂM1\°ö*º˜ñ¢PgܪL­®2¬êöU ´J¢Zܱ0Nb›µâEÕt_‰ÕûcUê”¶B+ž%áÑ¡¥¢ïé0)%Ñ*Ùµ¹,¿zCsk<ó5ã¾k|Ùq)Š+ 5´D¶C MòQæˆR^©o¨[ª[±¶avb jÒ—W=¡™PƒOm0®ËÓ‰ Œ"¢€±¡Ê¹ø׿éðàª0nå\±|$‰ÃˆO«[ªxJ~\£¼ÂN k“­i”,¶³°Ö—ÍV?…Ó,c BÔÚdŠ),Ð!.¬¥ …–…éņPK(jãR¤A™›BJå1(ÍkU?.—F,$ÉÆâdF!f¼¦À—NÜø"šOek'/N‹ûu¡ºUû•ÆC‰ Ž|qœ(,,Ͷú¨,P6te¯(à–¦zÿ IR6sÛJ#¡ÅÍûC«æRl”'7ùnPú²‘:¨«¯,œ†¢­òDîXqB‚;V­mxV@½ðŽú†§`Æ*£'r±¬áY e¨T2¢’QZZ‰Å÷=+ÒKK9  ùM§€P˜. ²é£Âµ£|Ú‘D,áÔ)‰Í!L§Âz)Œ~N…dR/é$½ddLŒï( §òê±z OÁ¾Xk%Ÿ‚Þzɧbô"†¤ŽðŽÕc]¯^Ûð´OgýÆŽ*•²‹§ •j±Ya”/EÛöÇ¢Êf#.\üqÍÇe ÍÇhŒñŒPKeܪTà ¼B…k¸Y\€Õ{qí#qP8`]C6nI1ó§¾ýÂGÊJEQ¨ìÞ/DûbÎèܧ¨ƒêˆä“w¤{õ9$‹7›Î`V7yRž‹æÙ‚¼‘7Æ¢ ,Ï{ìWcÔÃÅ¢ÖîlŒÚmý“¡o2ôN†ÎÉ› Òdš Qf#"N†w'à …Ó,™ W¼F‹…É0L› ´æ™ÉÐOÛRk®§ŸíÛ·wuumHe¶«üŠâ©((°ÚH¹§¨qÃz5U/p—[Ãê¿ÅPš_ÖpÉL;M¸0ŗͲN*Ë]N‡F§ƒËÎc_xø;¯½ýøC-Ï¿6¼ÿÑo?qÑsü8Ó‚*øÝ·=ó#ù£D®g?¿±Sæ{e×ÁÛF~®¹ûý2÷Õ̲Žì<šeÿÎ?ø1µrÈÔ¯Ôõõäq©“GG‰¢fƳ|$Ê:Ïà´ pć °Ç=h6@®à P~žbô€é4@ÌH4@Üý4+€`˜f/m}:¡*5ŽQ~jVV©T>£8ÏíÌV‰_“½ýýPSã-,ôòŒ§™xÙè‡ìSì˨ù¹ÈsÒ-VÞ@xâöèÌ‘¨N`‘(ã=@<0䈊= x`˜fÏx`Ðqô{ Ï½èô@Ì’Ô*s£ S¨@ Òë÷Óšj5üNr@‚ÆOMvŠ1” –'X@ÈÎÉ/+.qiKóC9§Caö)¹öìo~ó»7;póí·íØuËž^x[¶Êûøâ?ÿþ›>7ôÞ÷Oº¦ –!\$&ÍE*¸x4\u–HÔ¨\Ö±"ʺpäóÓg2Lç NáOz '°>5ü ©µ§5Ï !ѪŒÕm MÊÇ´2ÖYì²Ç×ʳþòÖ¾þY«zäó_ÿö=[Ês§Àßþ:”¿8Z$·}&[ë$‚BùÏKNKWšµZ…‚4&Nãd3}’/æcú}@|"¦#¾AßO3OðÅ}Œà+F@ÌwÆ7ìÓLvúú>ˆ­Žõ|:º¾–¾¯\­¾ËÊé[Ê)˜QëuE¢^"˜tN»3µ³–c v§X@Ö·¤¦ks—+©°Â†P€ܼۻ”ÇjÛ¹a[¹B= s:µz œ ZëÇ6À-aéù<4´Ê»×ÈòÍòî]`¼ ù ÝòÇ#»‘›á¾}ò§)¶F¾^‚ëùÒÈNü¤WZîà Äë8!´ ‘¨Ýi1*ã×fE¢ZÁ‹÷ du„E‘ HA(‚Ì¡—BÔDŒÂÇäÖØ*[•ÉÏÖTW\£,¸ <ž2Ye†@ÝŠËÏüjûòîßžÝÒ¡ù*TõÈŸËÁÞ=Û×F»ä‹5káÿpgï=ï)üâYo!¼úÂ÷&1X³DpŽ5ȳN’EJk½–LÓâô¼gç z#ëõm6\6›`äWD®ÁÄЀ¾ô 3±D@0_RŠ @À0ÅC¤±©¦ ušc’™N8)‘Žàþ›åD^ÏÉW˜]´:·evi>póvožy¸¸økÞ~å/B»ü@[Üs5¼eÛÿPÄf˜œþ!ðŸ}*·®„Gyú!…çQLsŠÅ Ò¨–Ñ›³E0뵨9D¢΢ÕIGÀÕ#@³õT P*@®8Î pN€³œ`@€#`ÿèÿ¿üÿcý—Ã/@@ ø§i›½ˆÇÌíÅæåÅç¿©@*Âá ëI¥ìÛ4qŇ’û“¾˜Â%òM18yØ@s\½ÖÁÞ€Ï7²‹9€o'òe2§_J È™_‘Z‰Ñ¨±ZÝ.V¿*JXXÖ)9m‘(îA«ÅŠŒêt¸s# ÝÐçÆù¹!憈$7 º!î†~šÝ ¸¸a˜B5süôㆴãdz„_$Y5±1Á¡ %Ï vLìÜ(N“¤i…R†rbî…î]5/]¸B2¬è-Dž,"„ýî¿,2(ÝDìvÁhÔz´þ@–7ͲØ1ãòD¢.§ 1Yae”Žà\N7€rÌ@OšP€ª” 7>ZŒ;•Iß§¸;Ï µ…SðôÉ7nŸ°úÛÇäS8%•S œØ°óq»ºœ Ñ«œ éb¸êÊï^q׺äkoZ±zím»åk¶o#›Vþå}#÷+aV5úGìi´Qt¤‘6²B*´jµ`4:]+± VÆÌ[YÆ!¦HT°h(Š3œ.º@rz¾'Ö ‡ã¢Y)GÚÊKTéš”£I GÏ×HerT;J®VÏz¯\Ã~޲$ Þ“F­F»Çè x˜8›Áï±[f‘ӌǞú$ §5kp)ð)]¾³øQNàNºtª­ @ ]:\YMÚ> À›øaž ®ú=ØC±[éB×PìœØèBŸÀŸ(>rÆ@Ž&ñ»°1+“Œ‘W?5ŽñíOÀWG3û3ŠÍádëÒUéãÉ¥ãQΔýC”ÙÔN¶ÞL窶~ž"0*;¦Øty,Ð%Oãx‘CÕÕÿ‰|º<¾‚A*J(£$$å—ð˜ü²çL* »ñ°³TæS_`f~¼liQvpViÃâYòÃ18,v/lØ(ß½ Ö#ר^‰¹çî|í¤ò­ƒ¹W‘o×}£o u»’ly)Gw“l²WZ°p6›Û“áÎÈ ¹m”pŸIŒDM.¿Oë[å´K5I AoHÊ‹C0‚Aš…@JKW„ EeÖ ¥7<¶3è¦ÛÆae®‰Í€[ÙÁ„r&¹ü ¥JÝÑH„¯3õàâ—ýÊöVÍYÚÅ4ß´{Dzè5ÙVoá¬Üi_ü¯Oä/\µSdOQ‘‡]6ø½ì«UÙ7ŽÑ™BîÔ‘I“2Ìf­eÝÎhÀí¢×,B¬+¢Äõµ *”fkʆ)›4ž4ÕTˆèô©¥–cÛ,¬© Ô<“G?üç‡]?›“·@ó;l Ö¦°üöw Šä_Ê/É¿“>kúOä—+”1î}®'o ç‘ D£1šXý#ëX;©HèOhÕ¤)Op}uiiuM8\sõŒÚÚášlc#Ú©Ýü’SQ†§2?J½ò1“.¥)'NÒ²Ò"˜ÎЕw;õ·¸,ó«ß©ùVqጺë~øP´åê’oõm~¤hjY׊ÕW.»w-žiº»úü¶n«:zC©?»jSÍ—_ÝZ©*_–Y2}áº?Ð~Ðxq>3à)E?Ódee“É“ ³l¸dÆôHt†erv–ÕXXP‰-N¯F£×;VFõÂ$EÑÎSíaX†™aÈ ƒ+ š0|†sa8†…áHîÃÆ0@$ Ua(¦xŽ0pahN"„¡' RJi1–ÃÛa Cœ¶±' ÍáD*ŽD;†Óaøvú(Úµa˜1ÙÇlµƒþ0ÄÂPŸìÃAkž£5‡¡»— ÒÊ}´î9:&N:i÷Ø«%œ’×ãU®ËiN—װƪ§!¥97’FDBÓJÚc1K‚*!^H˜¡3£ý—ÖEMÝ1©z‡ÿÊת†¯—WßÕŸY]]á´”+¬^ÝpÛAy *ôv6VpEiyA¥üפÅq\—aâf.H Qÿˆ7e€¨>=ùeØM~E2MòhP VË}%jf­Ó˜ÏØ fCÞ'Eá‚t£åš¶l&è“’Âm÷c÷ÄyUUeÒòw>;õÊÙÑ’f–_MûAÉ<Á?N|0SúÍåb}>·=ƒóg¹|^_$êu‡ÝŠŸÝ¢5G¢-øüÀùá¼¾ç‡=~èñC³ ü øµçüpÖ§ý0à‡Ã‹ëÒê|›Â×Ñ: % ǶêýP•„_ñWÚÐ?ô¥uUê‡\ŠAü(Aý0ä‡3~è÷C¯:ý€‡ŽèÁqš(Þ8¶IWâ7LdªË•ŒINi®î$Åí¡²Y㤉u²Èü÷]Y9£0§¸¢ô‹/^‘¹lÃŒI•g†ì¯Þèì|øÑú‹Ÿe£lPôSÜüïó‰Ÿ<']O¯ÉlÖ{õ ?3õfÜh™ÝN;Ãð¼ue”úƒ0D}{õö•c¦/ÔÑ—î Òâ>êTK±è ­B<ÿKÜ¡o‹OØ,ÚÚÿªPmñ£ÐoÞu”°ŸµMŸ27eŒo8ž°Å©33ú!ÿêTòw)Á[¼ÃébpûÔ2&“Ã’ÁkùHÔªµ˜ †S£ŸK·a¹ê]På‚\.à\pÞ.èwÁaìqA--¦G(°ÙX…¸ QÏÑ ô ¢ˆ´ ,éuAÌZ ÂϸàEÚ*uº ‘DZT2Ê‘`¨ñ‚Kñ[))œ$)jJãÜí|È¡¤áNØ~œoÙŸß_"¯^|ôÝ÷êÿøÆÃÐÚæ`¶ŒNx³ö2-#0·P–²ÇÎHC9+µh 6“‘Ï´;¼œÏçu²vÞª52²ü~©©¹–ó;üL®¿Ô_åoöïññŸöŸõŸóëx.ÐÏùÏû3Ê9„)h‡ªÉ¥ØJïW|ïþìZå-Mµ¸kqW2Ä_ìgô¬×a3YL‘(oÌ´sz—ÅâÓp=žñŒÞIÆXkÌ ¨86®/(P}ðéNøDLBa0ƒ*¯õã¬d=°ÈknzK¾EþîV(“‡;à‰›ž9s ¬Ü"e………n¸R>á,,àA¸[!žü) áä'äé íæ èmSîÃÁlé·Œ¥°F³±å°Þ€Z.Zâ¬V«×³±¨Þ6`…#V8l…=Vè±B«ÖX¡Æ ùVpYAc…óVø“ÎZáGV8i…£VØIÑê“hoZá´ÒÛI!TY¡Ä ZÁabE>µÂ9Ú"6[¡4YÀ [aÈ g¬0h…N+HV(¶*õ„4xÜ ý´4B.9\Ó7òTpüŽSU=_QòÓÌ{k¹"´Ö쪪r€ÙõèÞhž¿ÀváýãÇ™¹¼.óB›Üòn5d©êQ¸ïEº{ȽRÌnôhŒo¦'È;QÆÂêHp;— Í™PŸ U™Pš ¹™àÈ„L8’ ‡3aO&ô$áB& öùLÊæL&Ä3¡?:3!’ —hÉ©§TãüÊ*{Y\HÌ-³ª•ß2nßüô¸üÏ‹ò?äg<ÇaÓà«ÜÇ™ee™ßýÛðßÞaKiúmùÞ“O'ø‹ çé%ŸKßredXÜ Ï°: Ÿés;Á&4Fõ.Ë™¼66ƒ³˜,Q­ÉvÄ}>ØãƒfÔû`Ž8 ûàœ|ðˆzhQ•J}pƧ}€U'ñU¸è­XŽ’rCÖñÁ}÷A¯:iA1Å¢-õû â»ô@½œ‚6Þn·§Ó4/Å%ªÆÏÒ£gHO¤1¿øy&3ïnùÔÈߟùr‹÷8së^~^Y¦,äøÊ˜£wËs|e*ã”eŽÜÁ\§0;Ñ?vj¡bW¸u“Ä:ÉZ4= sLÊ7FaªÝákŒzÜp Á™",‚aú]\b‘:ÅÄðÿ…]a»i¤¨¬tº¦l,&ª|¨Ñq`A(»¾2oÓÍ{oÞ4oøÇ_Xj½ÿöæmÚ½w÷¦ymùíjh¦¨öÐ͵NŸ½f÷úþ“ò_Ž,Ù[°fÞ´¢9ën‹ýðülº/òPýùÅs¥wlŒÑ±N—‘èÐøÖéôh+‚ˆµ1„Aád«pÅCô”:„º =¢*è)…ðk‡]ð=¾Ñãk9ucc »à1ZÔA«©‡^ž„ïÒÒ^ /¦9£´µÚ!Z°œ– Sx<ÙGcòè$´¤Ý¨(­(ÙÇ¿4U'^¸¸¬¡TþSª¿"š’|7£Xa³„ÕjUü€¼sÞ¬÷-ä­ò~vÝŒ7­p¼sä—_×.\ë+Sus÷èø8®™ü\:`d8ÖÁó†,Æ <´¬µ7 àž`·Ë¨À"À¨ï  SI"ÀœAšï§Á±… ÐGcf¢Ã4Þv&‰£Â;Ó0EÚÊ8~Œ(ã¨E:M¢¹Ç"½¸!-^ÆÇïy?<òîL`î‡ûâÊ®ûâ) °<ömÜh =³é]”z‰“Gæ´dzõdD½ÉfC†T¤Š/*½L¶C™°;:2¡(,™ðn&¼˜ QÈr”ç>Já¯Q`#E›­â½H+«5Ÿ¤ÕvÓ:A Ñ¥Íõ²÷rRL‘ÿŒw%/ãðc’H´âFf×>|rcÛ·¾&/{cä•ÇŽÃðáÿ…ãË#{>/W&¼ão"MP—çOñµÄBlÐ(}j5[,œÍ$Z­À±v‡Él5#Q¬x"kxΨå,€„É[º§(Ý­Ôs9·7Þ³ô‚_þo*¤csgІú%n))Í¥º¡& ,w\ªMloœ ù±“t]Pqh£žžbX]³òò„òaUûc³Y`³áUyуðÓàí'F~:°wdxøüªLY¤Ï/è”Å‚Û䛸¶‘ê~^‚6ðFäa¤ïó&£A£Ó4Fu¬r+ª1ÊÚúLÐk‚N4› ÞU&M ˜€3Á° †LpÖ§M0,-5A® Î¥Á˜àp²‘X­˜¢9h;sRØ{LÐC{RâhgLÀ š n‚~Ú@„ÖVGej6ŸNÈÆËY³ÿJ¢v“–._¡\8y|äÏÇ}&2vØ’¤þò ÒÎN®’ŠíZM¯7kÌNO,VdjƒG’ÙhnŒÚµFqB…êçrB¿S¹oD•¬p8=È2.0”ÒµBfIr·)jVÓÅ—äYÇÃýÌSªŽuÁƼðprˆƒêú.E„SDXò°´W•òlž/æ!—çy8ÇÃYx8ÂÃzx¨âá0½<0<Äxˆð ñ€ÕDåÃ< ò0ÄÚˆóÐOÑ;)Þn>ýBØeBŠI²+³Eeg¹”qÀý=„æikØ·8™DJ‰_•F§¹šÌùþÙd²ÉDòC¼ÏŸéÐ/¨dË"QwAAïËql›!ZÅ9‘¨(XKÐ2Ψ„þJ8\ ½•ÐS Í•P_ U•PZ ¹•ਮ†*ál% V"¡È{Æ#«˜¤ÎWÂ9Š|zêjJzŽú’·Ê.Ã,Åø)J&}±ÎÜr!‚’D‰M9´3“1àüIŒÜ{ûœžÌúû¿4ràN(Ò4?8øêÞXóÚ2>5à4ޏ…ßpÓ=…r|fß²¿|8"ÿw~0)—4 öã-’ÍìvÛ€˜Œ,êÈ&›é5)¾¢™zS­É ñXõ=ªlŒóŒuÛXF‡Ú3€ScCkÅÁ¤½X‘0©Ð²ŽPIÉUžÎ ‰)f§Ë.=(ÒLͲB²3!Â`~½Ç p·\x-%Ã8ö"ʵ4?CÝodkØY|=H6Ĥÿæ4–8ÝY¬•XsBçW¢¸|î`PcfÍÇÖ)>c–›‚Ü8Bð×¼‚×BÁ‘Áž¬ AU|!0„àš !8‚³!AOšC0‡–q!8‚WBðmZ á¥´Ñ ÉFOÓ*XtmêÓZ¼â,-KuUG[L çZ ÇrcZMmWǷ鵂ÔP B %ÌeÝ—Ýçÿ¡Œ(ú ¡Þ7k8©ºÃø_áÏ™³œ4DäRMº¼‰Fóè}ñ@þªR)"_=–f?Ø÷lá²ÙN¿#´`æìu5ã³êZ®a«Ø~¥²–d¹4Uƒ²ßà¶ZY†¬œ.¢9±žc®‰Ñ©\°P4$Õë¢î¬ôkŒI±4>À_Ø—ŒÌ[ GÆ"\|\¨àªº ‘õÜ?€ûËGž”¶e¸\V½×ËX–Þ‹Zôúåz4ôz ˳¨øó¬×e¥†©ƒØRn|ÅÑšzöSŽÿó~8G³*ÒÕÅß釈êÍoLóQoP÷cÉØfL7ã¯w&N8åaÈN¼ÕͨDÅ稆]Ц£h<#wO¹þÆX¨ŠA·"S6ò šƒ@pÁö¢®ŸAê¤B-A;ÐH´‚VÔ¢%®•24ŠÙe=’ˆ†ŒÐo„˜0;ÞJÍ|U¹)¦rP÷âqHyV¾,/Ìtƒm¤ìòß`_©ª}Õ4•ýž$ï¿#ï(÷ß%)ìþ{wT§eÝQÆ+%ï¿÷'¯¤º½Ì-t5oc”½ÉtâúÙߺáö[»zz÷|‰92R ÍPWB“üuùI¨„,ù¼ü]ù¸üW©1]~¿”ˆhîFÅH4$;Gôù}Q¿™ÂÚÕs¬ukûÎhÍšÈÏÏrà—9ƒ90GràpìÉHTå@iäæ—åøœÏs9pšâN+r€ÊΈåj bNµ7&Òv~cò VÚuà´;c÷ݬã.*$˜ˆçz¾è£·š`õù÷úªpí(ùèü'õ§ŠÃ'·Õä—B â³~®EhÿÌrÁ›.xÖ·º@ñ\5Ó ÑY|Û¸à€+TÃH¥4Ðä §i$êʼn¤‚LJàIu»½è‚¾dÄé uÅicu¤¥ Ë“®²ô#.EûñqðäÊ4^ö`¼ljbJ?æ '‚,ü†2ùˆüH™\µƒ!/C´ÂÕPü:<¿#È>z±9á)ZÎ>~q{‚ZŒ Y"/eßfßB{1@®“;Ì™v­–13AÑêDÁ*dfdnå¶?£åµ‘(ï“DèˆP¡Ÿfb" t0™ŔΙÔ7Ó]é?aQY/œ PÎJýºþ¦a&ýQ[XÓ&o¿%ãگɻßz½³C.ؽwN·_ùQûÖÏ)W oªYü À-ç½8è01©¿kPd_7ÝË.2S £Æj´º=<v³¢gr(+Ôßmß¾aýå$±"x­T³B¶*~Dy¿ùÓû¿}ëOüúuæTÁR9.Ê?ãL¿ü}ù÷ƒRføä÷å™ãò7ä'å'äÇa=î Üüãô¬>"máY~»Ù¨Õk£>Ãı‚žÍtª¾kkôCПøáI?ìöÃr?TøÁâ‡Q?¼›ŒªK4ª>G¢‘ù^qWÃðƒÉc:–Š»«ër'䥑¾„%œ—É›ð˜wT^r~"ßø3å pÁ¬£ð_‡å}ðêƒ#¿~Bî§$³‘v“7=ºåŒ‘ שþ€]xn*þÛé’ªýÞʲ>=ÝNâìF‹'H#«\äñfíŒz5/tz!æ…ml‚ù}9›;ãÇn­¤Žkúͼ{«ÃÊͼ’šš’pMui¸:qC¯š9®© cFYϵ¨ƒÂ=—EbÒ,ŸÀdiŒÓÐÚ|Ä,˜=k6ÛlÝQ›†ñog<ýÍÐý!‚úÓ„ñÚX*˜‰Jä¸Ï´èç3ªÝ®DTSÕ Z6›=tñ•çž>¶xçíe¡Ê“»÷ÎUg¢ÍÌS÷~ë+?üÅÞ[ïð{ŽSð_ßìüñË'–®£ë6gô"¿yQë¶T*âÄä0y¼ngcÔÍÅ¢nVp4Fm,*Øä]€!JùNJmÕƒVüµiš!Ù!Ū¶*AòBTñåŽÈ¯Ë \÷Ïþ2ò9tC«üMù[rÎqÔ|r.ܨƒöeùyÌQ.-&«øú§àXÝä¼tÔe³9¬ÃÀz=V‹6Z;¬L¡XúC =oµjôz!U$ž §iŒr6•‹§ñGYéœÎRxå¦Kïp×Ö'WLgÜsI<Ì"›Æ½üEÉ¿púLt~Ží[<@/ù©î˜¯Äù Àš=+Œ)8öîÈ;Î~\)vž}õ®yó‚ÌÚ‘ÏRQß2¼Þ/7?®Ü+¥²g)™JîVL¶åå¹Ý¶ «1›QG.˜6Ùn³Ûº£Ev°ÛC, äÞ@ Ê쎆´¬å¶WËX´ Õ²^ii04 ú§Al`öR94ÆÇEê…ð$‹ØŽô¤÷jLå)LcL>ÂJD6þù{/<²iÒ¡ù_¹ÿ݇mß²£·¬gZ¨rSß"øîCw<[Ÿù¹"¤\bß±=wju+õšÞ[÷ÝHy?Ó*Ÿ<ð ‡ó›”Ÿöá¾}™ÆŽV çk4 eÕgðŽÑ1ºÑCÊoçð?£‘2€dÀPôg@,0;n¦êO«3S˜i§÷QCýÓJvþÈ·0u#Osæ]yAàŽ(2C^Ê´ñ‰•dIF¢7szÎf7ÞG**ÆŸÅ.·s:à–·Ñ_2ૹûÞmoûýOnè[ËåWÎ.¨oÿoXñÉǰüókêkÞ–GçW‰}D’} %l&f›=ƒ }ØËæƒrÜçO* €Íé`4•Ûï¯YØwÃO~ßÖö{yiý‚7  pAîÛ5õ×þS>ññÇò“Ÿ«þƒV8ÆÙc„%Z´s5 @že¾£˜x°i%­æ;Ñ ¦‘ŒB­–¬ß>^'OÎù[y¸àÅEì³1æÖVx¸µ•Àè§ðgfìÇ…ÔçŽež‹²ßWv¤êræ çAÁ'l¼OýOJ×k°šÁ`³¦91D|bƒ36´Á!z™‘Ø ­Ó6¤9¼kƒ¸ vÛ ’†QD‹oök6è´Á° ^´AÅ R¼ôpàøx`ZXTu£Œû]Ý'ÉûcN’‰Žå¥ìpÉ!ÓÉfiŽŠ5„f+gpk š¢bÖ<-sîáiÓD‡#¿;êÐêÅî¨Þ+)†¡bè/†X1`v‚yžˆQŽÝòs¨û¤üU^á}˜$¿“ö²^ì:Ä–Œ¬WõùVò äö¢î›'Yõ¨“0ŒÑD8žûNTÏ?MÆ~ “Üá´“lì1ÛÉìØ,7À±Íð³C^O´ÂòšVµÝffûU\7+äIù‚‘ãL¬ÎÀ›«†èñü%¬ÍnÉô³UÇðZ¢³Q¹ðxLo¬5rl®\v`ìpÞçìð¦~d‡#v¸ß·Ûa§Zí Ù¡Ä9vpسÃgvø£ÎÚá´NÚá(EÛhˆPÔR;`£‚ˆõÚêm²×=vh¶ÃSÔR¦Ó1;ˆv´CÜý4›†_®Ò_!#?/p—'øÌ–¸ É>‹gÃlžÛÚ<{ÈÎOÊk–`NÁ£E0O’`©$¿Tôhü²µÜ”C?„Eò³/ÜØtðyù{PûÒ¡M ÍÛÈs\6w?Jƒ’ãŸh´: Ï‘",LÓÁ¼ÆŒ2ûÜfØû6Ë% ßV¢Ì9Ž2ǃ2eŽÏ@Pcã¡\‡(\ž(q .”9.—â D+Ð4™Pæ˜LÊœPæh¥\ ¹0” ý¹ËÌþŸÊœD(Û®Hh<ê‰êìRô-›]1w Gýý ÀTþñï¿!üù×ïX·Ìê?®ð+'^§¾¸îæ[n»ž=ò³ßË'å~4îÉùsŸÅƒ»uõ¯§|ä¡{pÛ@P¡áöjð!ß²P&½ƒ¢šç4 d0„½ž‡Å<”óðwò°†‡)ß)>“ÅŒËä°Ú¬& î(´}zNïMZl§ëíãÞ#Y?©Ç¶ 0¿ ëT`¹ƒÿ1A5“ذ|¦ ð™Ãu“;1Ÿ‡i7¦¸ñ—(eø^Šø JÿZ?™ƒýlÄg ­GÈ€2^L×3å£/kÒ¶•zõøbzŽïq|¯Mô£ÔÙˆÏ>lw->•Üm¤•#£Ÿbš¶…ø„ö÷Ŭ–“f|·á»¶cßk”²Ñaí²•Rð»à€ác¦ÿ}ʶqó¹§x‰ÿ²æ)íTm—öœîjÝ/ô¢¾RÿYÆ톓ÆLÓ1s…±ìr„/[#Ö7m1ûlû›ŽÉŽ[qWŽ«Ï½ÓýKÏÏaÏ÷ºÌ¬Ì}|Ç²Š³ö{ü;ý?l œ–›ƒ÷ü£Ø þRÎnËþEŽ'§*GM õçÖæäþ<ï ºÚËÉ”ªµ)"r5&^b„0¥4ÛR<±&Ũ÷aµ´¤5‘fQLnM¤9Ĺ#‘æQ›|0‘Ö 9šHkÉ ä™DZGP”Hë‰&Ò° V$Ò’ż˜úËÎÓ™·i)cõ‰´™d²ó•ÑsÊ_¤=Î6$Ò@DŽK¤bæri–ÌäJiqÚiždqw$ÒàŽ$ÒZržûa"­#“ù“‰´ždñ¿O¤3˜ßñ_$Ò2[÷f"m$Wë͉´‰\£¿&‘6“RýÙªöÍí=í7´4‹ÍM=M⦎Îë»Ú7·õˆ“7MKŠg‹‹::6oivtuvt5õ´wl›ž±p"Z‰¸›¨mê™&.Þ¶iúÒö-*®¸ª¥«½ueËæ[šºtojÙÖÜÒ%Š1&æ×´tu+™’éÅÅÓgŒ•NDnï›Äž®¦æ–­M]׊­ã"vµlnïîiéB`û6qõôUÓÅHSO˶±i[³XŸª¸¼µµ}S njéêiB䎞6ê5;ºÚ»›Û7)½uOOÍ «zZv¶ˆW6õô´twl«lêÆ¾pdõíÛ:º§‰»ÚÚ7µ‰»šºÅæ–îöÍÛ°pãõâø:"–6á\¶mëØ‰Mîl™†ãníjénkß¶YìV¦œ¨-ö´5õ(“ÞÚÒÓÕ¾©iË–ëqͶvb­¸H»Ú{Ú°ã­-Ýâ²–]âÊŽ­MÛž˜®iÓŠDÛ·vvuì¤c,ìÞÔÕÒ² ;kjnÚØ¾¥½[kkêjÚ„C²µoê¦ABˆMÛ «wtut¶àH¯Z´t ¨R³»cËNìYÁÞÖÒÒ¬ôˆÃÞÙ²+aÇ[::®UæÓÚÑ…mîi+LykǶ¬Ú!657ãÄ‘Z›vlUÖ ÉÜ“\Ó¦®,ëÜÒÔƒ­lížÞÖÓÓyEQÑ®]»¦7%–f®Ìtl¹èß•õ\ßÙ’X.¥•­[–âòoS–n]_e«/—w"}jppbaš˜dÍÓg$º@2¶wötOïnß2½£ksÑòš¥¤Š´“Íøôàsi!ÍDħ óM˜ÚD:H'¹žtQ¬6„Šho"Sð]BŠÉ |D²±:°| ÖÉBLwa-廉¶ÛA¶‘éh5/ü­•`jebµ´ö4L-Æú›°…¥Xo#–¦·+’UÒŽrV©¹™ìÀq4!déÆZ-ˆÓL1DRˆÏjã?•¯¡©îTI Ž«ÿMÇÑ_®îj¹Û)­{h‰2Ö­tü×"¬ëý;Šˆˆ×BׯKZh®™¶ª´½1VQ¬­©Ð¢‡ö¶bÕ_¦ÇåØc+ÖßD×2‰¹‰¶­ð„Úr¦ÛT½)ÞEGÐLë%çÖ=_º—çŽUtt;iŸWR¸’ï¦e•˜ïNÌK¥Y=EBZì‘(ý¶Ñt¥g3­­pÙ¶DÍÈwâ¿íGLÔmJ¬Ë6ÚÇÎÄ(•:Óôn¥ßÝ´ßm؇Hǧ®òø¾EJ§&Juu¥·biÅÝ„ð-øïúÄ>ÛŠTQûÚ˜ØI»è¾lKÌx+mW$Ëð½‹rE]·mÙ9tǨ¢òMk‚SEZ·ÓtI:ÒµQfÒBGª¤šèÞ߈5¶Ð¾Õ±µQîh¢kÛ’Xë:ƒ$½š3UFÝI!…¤šò…²ã[4½ %ÅÒ˶¨R07•5ÙBÇÛÖö6:ÚæÔUj+X[=©3ÞB%Òµ©õi¥ü¦R´™¶Vø/hÞJiÓ“èµƒŽ¨ÿ©+®òVÖÝA×CÝO*7÷\B¹&JߎD½N*—zcÙJ÷GåÀNrê–E8:åßtʇé»fSbÏLOŒ¹è\OW'¥`úþèJe+Žqib÷oKíºiû7¹«P-¥ò¢3Á?5 ʉZPvÍD©9ƒÊËñ³P¹±ó=t<Ý”–Óé6cùrìa)Õ£U›-Çt™Ï }dÁFh!m°™ØIbd4’Õ°€Ì ß–Uâ{!æ•÷t˜GzoÂçc~.Âç ð âw>Ëñ9„‡ŠQŒEø.Jä 1? k¼†ß@ZPå½óµø^”x× ¼ßÕ‰übÌã›Ä@«üQ úý"pÒÓ04¯€8»/@äô~Ú÷)ó·á)Á'‡_f–ÒøÉ“Ÿ°ÅŸ€åБ„"Å>êü¨ÿ#M†åC0’¿‚õ½¡ÙÁwç½³ú÷ó~·š¼ƒ3{§øÈ;½ïÄßáßvõïXWP‹;{Ï  êz_è{ùþóEAËóÁç™àÓËŸÞý4;–cÁcL䑨#Lߣ`y4øhÑ£ìÃM>´(|àþIÁ¡û‡ïg”¿ßo²Ö<Ëa)™‡4\ö4;|r®ÄiYð;ˆO>ËñéÀç>h÷ zŸ"X*ÍfïÃ=¾{ î¹ñž÷ð·÷ÞÞw;Û»·o/óäÎw2Ý‘)ÁŽmÁm‹¦½aÏjm˜]­Ánôây“kbR°‘Ö­-®]4%hÛVó8a-l­`—³ì!öEV«[ Wà3Ž0RDo¬±,./ZΞ’Zê²±µ%Kz—°‹k¦kÍZ-zmÑ»‹>Y¤i\áÿš'k^¬a¥š)E5RM »&«Ö·Úv®¶‚eµ¶¬f:LVYFÑxµ4Zv[”?»K˜^ðp úNÔ¯*(¨;¥]Y×EÖÅáŽxÞ*å[Z±6®¹#NV¯]×pàËѽ’J]¼dUC<æÖÅ›1!)‰^Lþ.Ríîî) ((Àôü&; ¸¡[…’T9)è†n”QÝ´(jð»@)C€R°ö†n¢|)…j%¥vw¢9ZYý¢ φÿ zt<¥ endstream endobj 24 0 obj 16178 endobj 25 0 obj <> endobj 26 0 obj <> stream xœ]ÔÏŽ¢@ð;OÁqö0ª ™IŒ‰£câaÿd}„Ö%Y‘ |û嫯w7ك溺]Jg›ývßwSöm¼6‡0¥§®oÇp»ÞÇ&¤Çpîú¤´íš)^ùws©‡$›kÛ.ûþt].“ìûüì6ôiÝ^áS’}Û0vý9}ú±9Ìׇû0ü —ÐOiž¬ViNó<ŸëáK} ™W=ïÛùq7=žç’>CHů RšknCÝ„±îÏ!Yæù*]îv«$ôíϪ–OÍÏzœ‡óÐ<7YÍYý ³ÒoèF?ú£ì¿¢‡Êþ«¯K¿øüô z¥Ñ=ZÎý¢Ö fŒ1úµF¿Àlô+ֵؘ-úa³Øü¾ÿ?؋ѯøŒ~õµè˜þû5úK_—þ™‹9¾±x¥qæü9*Òæ>Žó1ᓟ8º>ü=»†ë€*ÿü¶"S endstream endobj 27 0 obj <> endobj 28 0 obj <> stream xœÝz{|וð=3z?¬‘¬‡­G4b° ø!ƒÌü,„mlìØÛÔ2KX26Ø–b (ä»MÒÄ$ iÒ4Ý´ mÓ”$n ÛÐöÛ@ZÒývÓlø¶é3¡Ð6}†,´¡ý%Ë{æÎÈ–)Í~¿ý}}cfæÞsÏ9÷Üó¼wPzlOœÈ8aI°$šœèÖïÛBÈ öƒ#Ñ'÷3Wì7aŸŽÄÜ|×5ì#½þP2‘JÌŸ&$pEOŽÅ“+Ÿzƒ+!l3ÂÿÄË€M•ØgX…R¥Öhuzƒ±ÀÄ™-…V›ÝQTìt¹=7‘ÿÿ/åÄFÊ5Ä$?ç\ì$)&Ï2}QìÍ>³­Óþ¿”BCŸ`y…|`ÈíPHzIŒ$Èídùذ ZqìòŽ’@M¾t#®àƒR0"‡^Šwyüê†ÓßJ^"—çΰGÉ“dR„C#òz¾­C"çV|l»+f>Äûãøa@†^ˆù)ÙÆ¼Ä¼M“çdù ÈE¨Çw Jø¢Ì …tþ Ó“(…Žì$ûÉ=HM/åšk?'Úé÷×Fò2šÉmäŠ÷ÎÁêÈô ìc¹†º‰ÝÅ|“a¦ÆÎCÈ÷!…Ÿ¡”°ën¨ŸÿÁÅv#,dKˆöF£L 1e?d–L_bçéž¾œƒM·L¿ÇFÿïæP=¤Aj2ý›ìmÙ˜Ò¯4€ ÊÐâ$o7lí ÷twunÞÔÑÞvskËÆæ¦ õëCë‚uk׬^µ²vÅòeKWû«*+”•–Ìæù¼EV3g*0êuZZ¥T°h¿ >‘† [›£Bƒmª¬àŠë++„ÆH†ò|)J…¦& ¢>ÂgJñÍG2Aĸ3(ag0ãW“ÕâŸy­^àOBï¦l?P/„ùÌ»´}3m+JiLjŸ)¨T¢´|C¦qïàDCe„ãzÝza}\WYAŽëôØÔc+³@H‡k6˜ +3Dc§Å•6Dc™ŽM= õ.Ÿ/\YÑœ)êéYOYfTë3jÊ’E'‡øã§'î?É‘‘rCLˆE·õdØ(ÒN° ŸÊ˜Ë3 …úÌÂoáÊã™ ¡¾!S.rmÙ<3OËì”Q–p?ñ‚ËÞ½8•!ªî/Dlf˜õØÜã/W#êzb¢Qà'"Ñ“Óã;ž&Ž ÉT7éèA'§¿}È•i¼?œá"ƒ°2,/½qsK¦pÓÖž SÒÈF‚ÿêß —Ï<ƒÓñ÷† ª•ƒöùD5:$;°“ßÔ#õy²Ãõ< úËÃ&"ŽœÎØºÅ‘ñÜÈ yD@Û¶töLd%Í1¡5~(šßÞµK4ŒÀe þêò 3_ëS\¥jŽ ñe)* ©ò ÐoD’ Žv þ*½Þuá¥f _+ ‘OƒÐ‘ÿí,B<*º©\r„®žL°Á¨l±†ãÕ~¤ˆFÐ`CõÔ˜¿ÌX…ÐŒuE±†:{(‰L–±®ÏH¿L•ñ7иâ&"õ’"/aSÏ·H`úÂñÞõB€Ôp½ˆl_^VÚ0ÑÈx#®ÆÝßãòe‚a´pX艇E·C -¼à¢Î¦¾ÒÕÓÒ)´lêíY! " ˆì% ×±z\tÀŒ¦DÃ÷0.6ŒˆøFl¡ÕøÌ¨K4xs¨p 7´šïÉa£™…|C¼^Æûs˜*EwZߔ㦻Èg}“ËöIWeƒÃ¼<1RhD¥6å†0Má€ýs}‰º,žïâBXä3ÁŽqm¢z¨–eeP˶êšÓËSª‰øp8ו™i,wå+7³ögºM× 7ç†ù ÐÒ9!2d†%oÎÑ…ƒ+Ì.š Ä€0÷ò†4 è‰ãÁ ̃+E&BslBèìYM±1ŸÜá: Îe!-ÐÒª¬ÀÔ:.À½›ŽáÞÎÞžoq¸7¼·«çy˜õ‘Pøø|ëù;L eD¨;¼Ø9mÆŽ†â»¾$dœŽ*(€öûO¡0M¤ÿ$#Á8i¢R:Q08¢F‚9lÂ4lœÂèuœˆ* ê”AMP40FÆuDÐóù6î.´@^0€\Ç‘j3Ÿ„ñãÚ KÂGŒ $á½Ý³Sw÷ö¼`À í¢Oœ($^è.Eƒhl,+ |Lt”ÛѰlÄŽ¦Áa-šIX‹‚¨ eôBH„׉ð: ®ájtQ°’£í;2 zÀÖ†$ïüW×÷®h©0&• î7•(œ€g‡§qª!Eä¯Á§•:‰ØMöb§V kµ£E [¸¾°…Õ™Œ¦¾°ÑrÄ ãNhw‚ß &'L;á’Ž9á "N:8á².8á´tB }¿Žâ¯”^§4‡)M‡ªÀQ^çpŠõå.Qàë”W’"ã·H×­Ò5–»¶ßrË FH]¹™ŠêÊËÍR[äÇÔÖšâßâj¨)-s`É2¥Ùaó-]n.[êã6ÎÇîÜ÷h{ç¡;³OžŸj|b’i8³v6säàÔ7îÿ0»ÅÕÜìRìu6ŸúAvzêRIèž~Cp£W©õjÎ †C_¸€ÕêûÂ*­–A­ZŽ˜!i† ªÍt!’|夈¾g„CÑÔfß’å…V‹ùÙë`þQlsoéÕæÉg™R\q^=lGv·$Ýê<{)O*›P ¹/Øi´ ¸¹2p&“BÁ©Yk¡±À\€f5›S*Ô«E_X–Œ߸:¬´oÎ ¬pÖ G(Û)›j¤Í÷‹BÔZàÓÇÔ–Ø‚ZÂ*”@¾FåH².®.Ä@la¬pè¹ç(~ãô»l/ú›‹¬ γ« ŒF—Êåöè,ía£Žs±lñ¦0k¿ä×=pÌ3 ]TÇœJSR4.Ö.ß,”Ua·l4.ØÞÊ'º®~pëºÿkM‹æ…–­Š,½ãÞ‰µóüùƒÇÏí²üZ±uû³ûþuÒ#Åeÿ s}"ȽžS)•J0²œÒf·Ÿœ> ,®i"v`ˆ³WÛ;ì{Òž±_°_¶kM¬Õܶšô\×.°éˆzZ j‡F¼C8—¡oû-}·–‹Y[3år-¬~ž*ßF¯ ?»aÙŠUuGÖ|nêß@ ÿáãCÙ§ï\^2õʬòX³ìEv’x .ø–ZS€y4F»Í¦Â=•—¨ Ø›,Åa»Å­Ò±F@[X¡Ó³¬©Î ^/L{á¼Nyá /ôBŸÚ½€C~:jòÂnĸD‘^§xÇòPÿ N¼°ê².x!â©qÖ §½ñÂ/ö¸’t´Ã A/ð”fíEˆÐ!„ß „¤(ºn‹ò·1%“c¦¤Ò·äDÔb ácqµR*.ébÊ-[p /­eàß³÷†à—És¯ŒB >û@0²§eS×êrOeéÊ@•‡M IœSï3:|[¯%¾úpsáŸït̯ï§uÄ™mUðèïvâ%ãÁv71-¥EÉûlXGl&‹Ñdl ›\š›:Â:A{†#>à}Àù«Îú Ã§}ñÁ$i7èƒjßGU¹φŒèn˜&ì6«¸:»fŽs.>¿ûógNýâì®aÕÄÔ¥pÄž»¥ OÃìíÍ¿}ÿ¯Ù«®Ðæ×DTL…²5°·tj•Ƶoú"óeÅ'pµA·® @Ͳ…Ž"…Qglkƒj 7RæMaÏ…³óµ¼ %ƳYXZ[À&˜i(Û ¾ù©‡o{hÏ£ßÿþ²Š¥7ßôõ@ŠÙ½®ìG?œúúº×m›‡z>:ýkx=û©:mZŒL¶¸Èbx|«…#ªÇ·’Â#Åp¸hBɕټ‰k$ݨؼ6ÜÜØ×ר46öÝÒ´¡/âÁV$‚æ!±mhˆâÜ¡é‹ì/Ù—1§•à±ÃQTd0«KJXÞÀÊJb6»q·€Û°)¬ÖÙUl[Xe#Ö¶0áH´t”Á…2/ƒH`;X†{"¹‹íÇG+˲)Êûoñ•oh Ý{O+BæIÞŒi²–ÖóL ,] …ê\ªdæAt{ö){ÛÁì¹-_yîÀ¡®ÁÒÐç>=ÑmY]]ßÁ¾œ½6õÅ¢PÓÒ2(Úup‚½ï™š=¿v²V±}¨»C˜ÙG(ºh^"¸S¯"‹Cåð¸E¸i0Yô*‡ÍînÓÚXÝ7Ì÷ÀVX= ð@í8ã»<ö@‡˜ ª=pÙ<ñ@„B½8M»G<ô€ßy9–Û±¹qP'UιQ L~N±œ[“ Kâ†Pkk^IÌ/ˆó¦ÖåÕ@†´¡ýŸÇµ‹¾wW°Ç@,*¢*.ÒšÐõ9ÖÖŽm~1¼] ±b¨/†šbÀ®µŸôb8“׿R Š9[ §‹!R Áb ÅðmÈkí“ó\.ÍÝJ®Û6⭪ܞѮ—¨¢Æ^Æ>ÿ³ó?}ã'çÎÿŸì›ë:n^½¦µ÷ƒSþˇüéƒ?½õôW~ý»'¿!íÅ:ÝÃ~؈‡Dƒ+‹•ÊB§AQ¨¸ÉëT´‡NÂqºMaÎNìíèÄ—òJÖD®øgs÷lØåŸs6Y‚ùÈg³ÞRÈKÒ;Pî@MÀžz6[X=¼½çžåÇ:wî‡ÿ¶zÕÏ-åì÷~ð“ÍÜgï ynö•ÿiꯎÿÃ×î©‘üqÖôÖÆB¸/8m¶˜/ÃX½ZC œÑ4@ô`Ð+õ z£cÚ04M@ Ä€- èY ±¹lpÕïØàUœ°Á“6ˆÙ Ëõ6PØ`ô …±Á#6¸+oÌjz#ßJ.ÊåY¢ÔØ€§ÈÈkÅÛ”àLnžGæNuÙlpÖ§mÉ! ëd yÍ·¡¿Mg:lf\ÄÀÃq» êèdÅÉí\Å­ë ÊêG~¸n„Ô-Á dV9)QÛ"PÜÿH{q+´¸:° «Â döÙÐÐË0ѳ ³{Å ÕÛÄü<ÛñhíÎ¥M®J¶¤{Š_;ï²þ,û%Ñž&tÊ—”_!NXü™Å¦×™u6ëtº]6g‘³-\„éÔlÅP3›Ôa½v»AnxÓ »¡Å ånðRàÐ7|Ç ÏÒCn¸Í [)Æ*7ø)Í;”ìUŠ&áìÎáÔ¹1¹aÚ —ÜpÞ ¯»á˜º!á†>:ŽÖâØY7œrÃa7t¸!è†j7ðn ”iŽPšËnwC$G6£ìÄÈÿ+å®;‡KGIqŸS(,].%mB戅–¦¿/~úÓg^ì_ô•ÅNúüÔ…¶¾¡,~úµÂ #EÓ÷ NÙÅœGck-Öúw0ß- ©`£F­¶¹].l&›×æ·±‹OX£ŠØ-LElßvq,Æ•†µ›Á±Epp$Aß"h_þE0ãLÙÚ–ïGr¦˜Mneæ€CÌË–Ö”âÞfQâ1@Ìv8ȼóòÉÖý¡RalÕǺ7O<´ÿ¥Gw>â=Cþ¦†-÷|æ,úâ—} w þ–•ËCå•_Ìó§QOɪÀÒú•ãZ{q_ñø1·õZ–5¤ÍÉm æî€ˆ»¼=ô‰7òà Q.§ß7F‚!ƒ^oVk4f†±Ú8VËF–53„é KÐÕ¹ ½Lƒ£˜1tØ HC8?(gvS9æ–4%5ZñÍ>VîàV¡×+ ŒNÉ(9£3°Jµ²/Œ{òj=øô`Õ«‡VÏ* çs`åà opáàIîâ ÍAŒƒzj8Pp0‚cg8x„ƒU Á«œààq¶rPNéémŠó$ECú.Љð5:D9!ÍaK9à9à8¸ÀÁYŽp€ð$ª9 ÜÜ3_ßÜÓ^~ÌO¢³ˆÀK>ì͸ =êaòÀÓ ò´øRfN}x÷ÔùQfÃ!Ø‘O)×4»®j¯=Ä&0 €¦ßU>‚º-&‚ è œÎéRhí¬¹ÐÜV²F  ¸ é‚]P킼MÏu² ãbÞ’¾Šš­ Ÿ?Ó±³>yþ÷cÙ+dßËþò1æàäWý*k?U^{ï÷ï_}—UÒö»_ž”¾“«RÙ> >­aÕ c×éL&Ë(\N›ƒa9ñ4(­±ØÂêô?ÔFË ´¸Àå½ ®ºà;.8ä‚rX] pÁœqÁVŠSCqjé¼JQ§Ø·¹`¥ÑÓöîÁªß7)~Æ êf<§^ÖMß 69s΂¥/âúEÜQ›S¤#÷L* ¢5ů¢y[yÔ¦hà~2ÛÀ´Ý‘ݘէ_žê™œdùÓÚÙ™Ý?ev53÷IJ¡Ü×ßfçÔ/˜yÒ· #ÓnÌ ÈmÁ Äm²ÛljÁ$,\äR—«â®vݷ¨P»K,%c›êl€‰À ‚’BKq_øcv°[XéêrÅNü:D=CNRÁ£µ./gÐÅÒBÇÓ:ÇJuÎLˆTæçÃr8ÒS¹è™­àÙ3ù¹ÁµúýÑ„+î½í®Ñ=¿y¶7«M]ÚÿdqèâÆµ"÷ÅŽ«<ûòÉ[·¯ï+iI<™Èv—ñ„þ¾Œ!¤àNý¯úL«ÿÂx¥ß6½^7]<ûË•l£êS¸ù‡O’®ˆÚ—m˜ý•ŽüKµÙË«ªÅ⯉ Ü‚÷¿+ë! ø.Ãéˆ"E:UÏåÌ3¤…}€4â½\AˆáN„ùð>ŠýöEx›Œ³á&ä³yô"_ǽÈ3†·ïÎ) l„Jðù#l/Àoá·L/{€ý û–b…R§¼Sù’òšêNÕ5õ€úûšç´iíu]L÷–~­þ¢a¥á÷Æt5^R%ê†jˆ#~ñTÌ.¦˜°tô&Yó–™õc"ÃÈT 2 ·Y¬5»ä¶ÏXwËm%) ÿ(·UÄJŽÊm59@þ—ÜÖ+,“ÛZÌ÷å¶F¡Gn뉛ùþ̯«˜_Ém#YÊrr»€8ÙQz…ø+§I¶Onã~E¡—Û Ñ(Êå6K–)r[A)†ä¶’¸ËmY 8&·ÕäŠâ'r[C(_•ÛZâV¾'·uÌ[*“ÜÖ“šwä¶lÓ rÛHviÊíR£ýCýÐΡôÐxŒEÓQ¾?‘Ü?6´s0Í/è_È/©^\ÍoH$vÇùõ‰±db,šJŒVéÖ_¶„ߌ,š¢é ¾y´¿ªuhG\Âå;ãcC¡Äpl]ª?>‹ñ•üõÃ×÷yK|,%B–TUWW-žE¡•"FÙPŠòé±h,>ÛÍ'æÊÃÅw¥Òñ1òÝUU|G4MóÑÑß5CØ>00Ô§ÀþøX:ŠÈ‰ô ½kÏØP*6Ô/ΖªšYKžV:Óñ½qþæh:O%FCÑÎ…’u &Rü¾Á¡þA~_4ÅÇâ©¡£8¸c??—†ÇÑ(®et4±YîW ÜcñÔàÐèN>E5#QóéÁhZ\ôH<=6ÔÞ¦I"Õ´Õ¾¡ô N<Oñmñ}üæÄHtô™*IÔÍj–IŽ%öR+Sýcñø(NEw ¥‘Û`t,ÚCµ õ§¨FP|2:ZÙ°g,‘Œ£¤ÛÐ:‹ˆJÚL%†÷âÌ"öh<gD±÷Ƈ‘'N$v‹ëHŒ¡ ±ô`ežä‰Ñ4’&øh,† Gm%ú÷ŒˆvB5§sÂEûÇ8–ަ‘ËHªj0N®ôû÷íÛW•MÓ–©BÎþKïOÆe{Œ‰\F†[Ñü£¢éöPûŠ‹èlnåÛ“¨ŸFŽ—*øœ.®Z,OjJ¦SU©¡áªÄØN{c+©'Cd'Þi¼8‰á&F¢Øb«Ÿ$H’ì'ck¡<È~²ßKH5YŒ7O6 VLJ‘ž'ë±=†Tâ3Jù&È(¦SùhnK°µY–¢‰RW`«éû‘C+ÒíÀÑ|¾<é¤!L·!„ #í:’Bü8ŽÆèO*ñþï¨ÿ»q~†ÿ KÍà,AÙªñ¯ Wp#.³<*gxÜx¶!äÊSͧéˆ(ÿ¾ÇÈn„%¨_?<âÅ©5S8§½å*òîFŒNŠÕA)Eý¤él£«ë3¶ãŒHßO-›Ãì§¼E‘8'°=(kzÙCךBL‘.·¶Îü·v¹±¯tRéöÒ9o¦p±Ÿ¢c!ì§äuI:ë¢R$*êbJ"Î;HÛQªÏ¥}nT¦Ü^Èä<¼L•í2JçØ+K)ÒTÈú Ïwçà©|9ŸÉŸ›§zŠR­K–ÁÑ4ÅíGø0þí—£nµ"͵CŽ«}4JåP¾ê j·QßÞ"´¡âwòЄï ò»á ønûÍØÇ7 ‚ZüJGŸO€"ا§àØ)Ðù¯¹ Æ_]Xê=8×ý‹À[ÝäÊz®ú\ǹñs™sÊsÀv¿ÅÚ½‰Bß/ýiÿ!Ô}¼ß=ÿ]Fü­ÃN댧"§’§Ø—6,ò’“à±ïÅ_<öâù•‰Ó ï &q¼/´¿0ýûÜdÈk:zð(sì($BÝQàã«~ŒM>Ÿ{Ôíõ¶î³Œë3ðÐÝ1ï±OÃýí^/¹;r7sønðÞ ‡? ÿ€Á½Àíá÷0éÈ´7Õ7íMâÄ ¼G7L{‹EÝêÛ­b§½¢€_ï¯ 4žÞ¢é«ñö‰ ·Cp»ÖØxpÛƒÛžØÆní-÷ú{ôFz™Ã½—{o/,ÝJ\¹9™X/[Ƕ³ öAö«Ötnôy;M¢í`ÛƒmìÍïÆ ¼×ÔÁ&½©±1mðn`ÜM®n{ÀÖmS70u3€F n¿iÚĘL}¦ƒ&ÖDêsØJ8 ‡wu–—·œTOonɨ;¶fàÞLI§ø nêͨîÍîÞ­=Ç>¾ûHÈÓ’YÒÙ“‰xÂ-™6‚bcœç¸„©Tºœ^*/O—¼Ë·§h?•Þƒ½4)/O¥(ÞØI§)„§ðmŒ‘K RiL:i(')ñNcH,²CÀö¶o"MYNÙÒÙ¤®ø_ÿ,ûb endstream endobj 29 0 obj 8586 endobj 30 0 obj <> endobj 31 0 obj <> stream xœ]’Ënƒ0E÷|…—é"ól$„” ±èCMûÄR¤b,Cü}=3i+u:Æ3×GŒÃº=¶fXÂW7©3,¢Œv0O7§@\à:˜@ÆBj¹¯è­ÆÎ¡ï=¯óckú©,ƒðÍïÍ‹[Åf¯§ <á‹Óàs›úì×盵_0‚YDT•ÐÐûœ§Î>w#„Ôµmµß–uë[þ ÞW "¦µd5i˜m§Àuæ AE•(›¦ Àè{IÄ-—^}vΗJ_EYTyމÓ9a–È)ó9c>!çÄ1õÄyŠüÈ|DÞq ñž¿'Èâ"F®™)ÿÈL™'fÊlˆ“½gqºIöÏÑG²Þ ³ž!³A½ìŸçÈì_ dÿ˜rØ?Ãs%û”Ãþ)Õ³F9ìŸQ û§döÏÄýãHðÎüŒZ¨›s~Ìt±h¾8ÙÁÀïݳ“Å.z¾Bl± endstream endobj 32 0 obj <> endobj 33 0 obj <> endobj 34 0 obj <> endobj 1 0 obj <>/Contents 2 0 R>> endobj 4 0 obj <>/Contents 5 0 R>> endobj 7 0 obj <>/Contents 8 0 R>> endobj 10 0 obj <>/Contents 11 0 R>> endobj 13 0 obj <>/Contents 14 0 R>> endobj 16 0 obj <>/Contents 17 0 R>> endobj 19 0 obj <>/Contents 20 0 R>> endobj 22 0 obj <> endobj 35 0 obj <> endobj 36 0 obj < /Producer /CreationDate(D:20160511122016+03'00')>> endobj xref 0 37 0000000000 65535 f 0000045254 00000 n 0000000019 00000 n 0000002678 00000 n 0000045398 00000 n 0000002699 00000 n 0000005430 00000 n 0000045542 00000 n 0000005451 00000 n 0000008065 00000 n 0000045686 00000 n 0000008086 00000 n 0000010637 00000 n 0000045832 00000 n 0000010659 00000 n 0000013123 00000 n 0000045978 00000 n 0000013145 00000 n 0000016180 00000 n 0000046124 00000 n 0000016202 00000 n 0000017930 00000 n 0000046270 00000 n 0000017952 00000 n 0000034217 00000 n 0000034240 00000 n 0000034437 00000 n 0000035069 00000 n 0000035544 00000 n 0000044217 00000 n 0000044239 00000 n 0000044443 00000 n 0000044868 00000 n 0000045156 00000 n 0000045199 00000 n 0000046410 00000 n 0000046508 00000 n trailer < <083E4673965B1122E28B87BF4B622F25> ] /DocChecksum /AE2F0CF6AF1C5C99D2D3B845E6278745 >> startxref 46683 %%EOF zuluCrypt-6.2.0/docs/zuluMount-cli flowchar.jpg000066400000000000000000001401561425361753700215730ustar00rootroot00000000000000ÿØÿàJFIFÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿ 0"ÿÄÿÄÿÚ ïÀbÅ1´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕMQ´ÕM\¦Q)äuóè,¡çs5öŸ@òzkì¦ÄO±0ÆdŸ@ 1¬ç{c—¤R+Èëæ Ð«µ¶É»¯§[fÞ›–5ñú‰ÅV~ÄÆÇ½Ls>Ì­†Ä­‹GÌ^>ÃåhWæ9½¼^)}ö¾ º:Vn§¼u¶m¬:²ÞÁ­¸kÜ‘^Õ Tf5œïlrô€ EhÝ|ÞÞ§·íà{xÞ·íà{xÞ·íà{xÞ·íà{xÞ·íà{xÞ·íà{xÞ·íà{xÞ·íà{xÞ·íà{xÞ·íà{xÞ·íà{³Ý/prt€òzj¦6š£iª6š£iª6š£iª6š£iª6š£iª6š£iª6š¹L¢$N£:Õçg(Ìk9ÞØåé¨ÎµyÁÙÊ4·eV}ìéêÖÛ™g“¿›M1GOÔÆØµ@˜Ös½±ËÒ'Qj󃳔bÊ1yΉÑͰ1yÎ1ëî˜cYÎöÇ/HÔÛ#›tiͺAͺAͺAͺAͺAÍáê§’Ý æÝ æÝ æÝ æÝ æÝ æéRVB—£ÏÃ;­{ œÿE£zß|ûKdÆÿ?£ç£ŸMsÏÐòê_´A¹Í¿¡[0Ï…®{š?]À2â'¦Þâªsëм{Ç`hÌlfãzë× Îà5¥ÎêüéÄ4ÌŒ¬YA¥Fÿ9ò¶í\ßA;A[ ù{ÓfÿÒÞ»ã@–ìîžvþƒJv‰u8ú‚$|>ëM¶[:Æø„ÄÙwu3¾¾M±¡çkäN ÝO÷ëiŸwrLk¶>ʈÓ7¿¡§Åïa·LÛ A 'Àõç³™—ÑÙz¤+`GÉAz4¢wZzð¡’ çÏ¥¨SËpßÁ§´}Øahõf¶Ÿfƒ—¢z‚¶Ÿ¯`OPÔ¾ôŽ(±‹ÜÝñú7Äø©{Íÿ¼3Ôõ=@Oõ½< } ôJ˜£óïg.®?”¶ÖI™¢iì̧¥.îòÝ_>Û-@>ˆR;MM²å›ûâÓÜpÜDó;õÑ0¶j& ãè‘<íÌÉ]¢`{˜ñ¹J¶kìj cÉÍ^º^N¾Yštþg}F¥¥+Ýâúž}öÆ:€} åèO y-­N®pÓ9”Èœ_r%óè†Öª'´EµÉÒ°"ÛZ¼gίèÃXi@%ÊZoA™Ï¸Rà„îscÏ_6&U«‰”b{ôbe³ùwÙøú‚$úÊ'П@ äD[^±ÄE±ÎlmÐ"-ˆ‹b%²$+`4^Ï_\¹6Þ§F!02§ T°×S € ô'ÐO¡< } ô‰æ„ÀMdÇç®Öß·r1Ô+` ô'ÐO¡< } ôåF;àO¡>€} åèO «ôè´ùšÒî +SîžÚѹëDQÍ!Ðnr+nÕÈSÎ÷²å ôoKÎ[^õìqñŸf:ÿ¼‡ÉŽÓ×î'´r[5ž‘/œVÀ>„ú ô'”O¡>€ž§F>›d}¹ [vˆ–ùz¶Ì\ÅéJO‡Nj€ùôn\åÙß´EµÏ¸VÓèO ŸBy@úè ´¡Þ‘Ç_7”±òBÙñ=&(¹ea51»¯¡©[_É?ŬPv‹?u¶mW_È[ËK)î}è'ù)Ò’’>¯Ÿ]¼0OÑ­¯#ý+¢l”rBŸ©bz$-›EDKs0èùÍœïÕ¿5ÇËÓßP›H>„ò€ ô'Ш¦8¶þ‡g.ÕÆ§Ý¡«‹|h㤄ÿ[ÉjëSv„é=>Ûærôõ×L¯ÍÐhŸBy@ŸByCçÑÅ®Cìå WGÍN†¨™X. ân¥Ñ¡Š¦±*ö¦ØªÄÞ§-qδæÜèO(ŸB}¯-^-ÖÈß,¸µ  Ù§KÇ»CÞ†zŸBy@ŸBy@ USožÂWF1:Úf­ø™ûvwñ×s A ŸBy@úè_`‰˜-/Xú4Ç7ë¢rÙDÏÛÊ­‚$O¡< O¡< bÊ'ëØZ°qôKW›ûÑ¥Ï三•³¸¬üúVÆ)óZ®_JõKÄÇ`ã‡bäsCžÛ¥«0g¥ 'ОP>„ú ô'” ô'”yËV¬}/½8|ú^€|ÚÖDô8½¼uêX²á²} åèO cðŒì9A 'ОP'ОP DDÑù÷·”ñŒÎÐôn´„úȶ­¹ü÷²­©¨ÒžðûZ¾~ý~{ ø47!«n·?»•ú†žæZ„H ô'” ô'” ô„ú } ôO¡< O¡ËO3Òszç¢:yÀŒ­,‘;-OfÓ;WJÍ)n‰€é(O¡ÇÕ>„ú°èI¬} åñ¿Ùç–:¾g\ôGO8 5°DÏõ¼¬èM³–-©ã&â4¾îã˜Åï6¡CÑz€IB}>­}z Úz€“Z}ŸB}èO(s=4Í)Ï,¶Æ2ÈŒ²#,ˆË"2ŽÁdFY–De‘dmÐרæè'П@'П@úÊ} ô ô'Ð ô'Ð>„ò€ŸB}jmã8~çñÿØÀ} ôO¡< 'П@5µµ$oDçV¯DçGDçGDçFånttNttNttNttNtu›ma°VÀQ–‡æ_¦€ŸBy@O¡>€B‘^G_0^„ÕmI ODòbÊh¥â¨›^ôµæ*´÷&bÕ¨¶¹:B— Qí[¨KEÔ!u]BpÈgê¶áu]BP…Ô!u Ü- ]>„ò€gr­sꜨꜨꜨꜨꜨꜨꜨꜨꜨꜨꜭˆ·ªègpŠò:ù‚ô‚¶ÐÁXIù\LñXh`¬'|¤4·I€˜µj-®N¥À ^Wªåz0 ²[e €k'd!“HžÀqu§ÐžP5]]©ŽUóS³—q§˜ÌÖðn%ìÃm‹- Ä‰ÊÔòn±ë¬C+K!²›ºe»Ít´¾zèrôeuísäzcuãuãuã÷~È:ñÈ:ñÈ:ñÈ:ñÁ–jò½W+Ñ„_x¦0æ«cl4b`Ñû’&†_ŸvÊ 8²ÓUµä=}˜‚æ¤MI{Øm\”'Q—`8úš{‚|ž˜~7Ûõº³Î}>¾l8é̬áÜûõ:Ù·pL`­¥âcÌÞ+8þPK³— 5sna–”>žsf>tü¿QYÏB}n€ ô'ÐÕåzè;ã=A®rrRDÊË@‰ê CÇÐ+3ÛY­Ôõ=@OPònd‰è'H5v¼LqË®œ!.ˆK¢脺!.ê“D%Ñ tB]—D+­ê[ ô0Ø} ô} ôO¡< 'П@ŸB}Äð '¨ êz€ž '¨ =ÀúÊ} ô ô'ÐèO(bË Õ¦å[eÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÕ9QÙzŸC ‚%>„ò< ž('Š â‚x ž$Ö'ÐÑÓ-O¡ùÉú4(ûÚSHusxµš[vbj´tes¾¹U¥¤olbøm"m”2”=C¶©YE3ÑE§¹0ÒPæ!qõ~ˆç)ÖÔ'µKSèO(úÊ·R9ßwáiI«˜o"yÜ×·9·`Žwr°‡âø“š‚Rô:-(?»›¤m­ôÇ/Fº&.ŒJªZ¡0ãô48ú¦S+`èO(úÊA¼µx‡n×>!ÛŽ!ÛŽ!ÛŽ!ÛŽ!ÛŽ!ÛŽ!ÛŽ!ÛÏ9‡n8‡n8‡n8‡n8‡n8‡n8‡n8‡n8‡n'Ð1Ô"@O¡< èO(4ñ”Å ì%` îTî€} åèO  óS“E$ÑI4RM“E$ÑI4RM“E$ÑI4RM¿/ý*IÔ&ŠI¢’h¤š)&ŠI¢’h¤š)&ŠI¢’h¤š)&ŠI¹Í¹ô'ÖÔO¡>€ã»;l¼Œ¬NÓ#hL fF,¡§Š&ˆ˜ÁœB} Û¤ŸBUÿ'ý£'zëù ²ð:0K©¡[xSF–ØÕõ´}ÖÉæXöð}†J8í}gà ~6ôâq^FÑ^€ ø(VÜÌÿÔgqõZŽìy=²×eoŽ&Q‰”be™F&Q‰”be™F&Q‰”be™F&Q‰”bÔ 5þlŒL£(ÄÊ12ŒL£(ÄÊ12ŒL£(ÅCS~¶è'HÿÄ405@ 342P`!#1"$%ABE ÿÚÿà$ɬ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(æñÏøÅË™Ä?>þDŒf¥&ŒDX30Ç/k»GÆRhÇx~d-8ɧi CÙæÞ}åË™Ä?>ð›ú‡dòŽì°ÞnC ²•’RTÇ+ä²COxfžõrȯ+s`NÅÂöæ¸ùé!ˆæ‘ ¯ËÏHw1àiD bŒ±²û¶øQóÒæ) d“Ÿ‘ìd!·b9ëňÖÞÍï(~\Î!ù÷—,³‘ˆWÉŽ-È×¼Ò×)>ÕRCEYKäe“pEr»ùѽô.hD:¤òƹ#9ƒÉ êCü*dkF±Ë”_9@‘ªk‘h^ú“dÖÐÜC‡}!I¡Ä;Ê—3ˆ~Æ(~\Î"ìÓ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠáîÏ/þÊQƒddddddddddddddddddddddddddd@'ð«ßW»¡ù ½õ{º—ð›ßW’K0ZèÝ ð ³aäI Ï+p‰Bx™§8Ž·—&‡åü&÷Õä¿TP„Ø`>ö'þáêû÷þLQ‡&‡åü&÷ÕäíÇu‡‘‚6f§^+`l˜q‰6GæÐ‹B9rh~_Âo}^î‡åü&ÈœÀÂ:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:Â:zÆcaaaaaaaaaaaaaUÂÿÅçÔ?‘½Ú±–u5„ÜCù-šâà¶-Ø»ü“ˆWÉ¡ý;_EO䇷*Öâ8³ù·òÎ#‰®L©›ËÀF˜6`o乩ÊD—´7^)¤ßÆÈX &·3//.@Ë0¸-@߯v0RyN\°Ý”eÇø K O³) šÉÏ„æ)Ü Ú¬Õ³-ßÕZ>Èá'Ç6$;^fOç)r‰=±Ž[‚ðe; ý Ü˜Ô G±²m⪧Þê%&„HG1CmžcÀ,k?²é`›F HoqA|±Ù£\à…dÿæ¼ ñ1>a—«ÿa’£SŽ‹>1”‡ \‰; §Ñ‘ÂHÉ¥ÓÜ6äüiŸ\yŸéòÿoì8XÃqZ#l¾fÔ³' z’Ú3EÃBõâmÈÖò1\;v 7 FZÀ˜‰í ©… °,y…#o'œ¼iL¿MlûPoí쌞£NQ±=£•£6‹‹EŢⰠ3(„ˆ Š›ÂˆüHa…†q›–rÑqh¸´\Z.&µ³c:šÎ¦³©¬êh—êí×þ¢<~5N´mâûGx;yÔÖu5MgSYÔÖu5MgSYÔÓ]«)v1"mw»‹]Å®â×qk¸µÜZî-w`qœÈB{Frqq–\!çêºî-w»‹]Å®â¬9Œ>ÃV‘E0¿´¥Í2ɬ±Žg°mÚ, b–P±Ø,šÑÈ Ùÿñ…=˜½†v7ö³;¸i/õÊ›jéÁ²(kÑú÷®3´›‘sàì'Ô96ͼDn»ZŽŒ©ÁNÄ·B]تGÔØÁÞå»4˜Ô½¶‡¹^›¹œH¤õlÿÀ“4MvŸû¯Ò&=U™ªÌ…økF1¯ì y™0s 6å'$×ú6AÖvÉ·ã\ð¤o'ä\ø; õEÓèúðµ'¬s…Ç@¬ ²D/b¡'?w‹„¬aóM^E Âý„bòpÓfçÜ6é<- Í^ȤjÓ£ ÷¼k›x^ûŸa>¡ï)X#y<åá8ÇL!Åä8M34[¹¶ ÎòócR_éù¡­2¡ŠnuÃí ¿³rB]‚³ù·ºçÁØO¨{ì›|¼ºFì Œ ƒ—Êr 6c=Ò“nknknknkni£'[s[s[s[s[sT¥6ouσ°ŸP÷A`:Àu€ëÖ¬Gªá¯€ëÖ¬X°eÙ’vvxjȈcˆ£Û×ùù—>Â}C›{§÷ Æ­0ûa A©wUþ~eσ°ŸPæÞéýÑ©4“³ÆH5%5Dqî«üüËŸa>¡Ì{µc+·jÊvA@±H ûÊÿ?2çÁØO¨s)üº¯óó.|„ú‡/‹_=á\RÅ‹?º¯óó.|„ú‡"VÁüB ø„ÕÉJè)ƒ yvaÖq“qM|N qôÎH2ÞÝggæWùù—>Â}CÚ[ âIIå>_“:H4;î H=ìî†*WäžÑäžsu¥––^L¼™iŠoø¦1¢£tì£Ä"†a—ß_çæ\ø; õv‹䉨³¼d š»§v‹úœ¦Nw’¢ÈÍí¯óó.|„ú‡ƒäK³§aüûr"M3¿eZÛùø×ùù—>Â}CÂôôƒÂRh³Ê1‹Î ñœfÎQ²rB>$&µEåª/-áyZ±°–©¹FÉ·GæÎÎÞžàûk%Þ7/v;ð”¥È¨mÁxWùù—>Â}CÈ¿!ôo} $â1‹‰VÉ0Šá’ÿ î~ø~ýtßþ\ÌѹT0™N*F¬(ѯõ¼+ÆÎ΋‹EÅ¢â„Ï\ö¼G0JWG¦?éçÁØO¨xÿ¶5'eÿž|a)¸*4=Óêú=?ÄôÚo&xK° y• Q{ Ÿa>¡í FU:e!Ì|ÈW,Ð貌#÷O¨sèôÿdá4è)€°æ3<”)–HuÎçÁØO¨r$M=:z ‹ËëËi¨2jbe©õ}Ÿïá4ô‚éè2ÀšÁ2Â:Â:Á"jšŒ5PÅ3yv·>Â}C¼ŸPçÑéý¤É©_'¾GOnç1k"×5¬‰ŒfMjÃ&¾VQ¾5 žûŸa>¡ÞO¨sèôþÈ×$KF"òæy3¨X0ЮÂ~ÛŸa>¡ÞO¨sèôþÂRhÄöäUþ»ؘÉÃÂçÁØO¨w“êú=?°´}âva3€Œþl®|„ú‡-É[Â[£Lìüéõ}ŸÏ³7oôÊrhCv;¶8°íFd•¸D¹£x±Ç³›»ýØïæC̶™é±!*²·”'›4h%c ÂŒ¼Ác‰T¬£Ä!~¿a>¡îÐÅJü“Ú<“În´²ÒËÉ—“-1MÿÆ4Tn”x„PÌ2ògÔ9ôz>ïÕð±õµÅ¸S~Gû¡êÿ&é—% 1ùÆî¦~+Oò‡Ö/ÔPò|€JŸÃþ„)5ÀØþž²5Á¨•¡ØO¨x»´X·Ôå2s¼íh6Fo|ú‡>OçÎ-8<^ðïç²5!ÆSaÆ$€â5B@BEÌ¡\C”¦"ÍT-bM¸ÆNÑU„á¯àí²ŸPð!"(Ó;öU­¿Ÿ¶}CŸG§ö«n·þ{*µ¼»Iõ %Þ7/v;ð”¥È¨mÁ{'Ô9ôzbjÐ2(Àb‘\5b>׌»ÀuøÍÐ*|T–‡ÇÆôž4ÌÆ yLÛ]£k ÓJ^šY“±yíÝ&Iâž% )Ç‘{ÙEÿê=“êú=?³%1MN‰"¥ Õ¼Ôi–J‡ÍäÝ­€FÍzü*eåý´¼ÆàäZ¶G2DÔ­h0 L¦Ö,ÂG­hr#NÙW+Ö¶9¡¡&7™eÄ=”aÿ/dú‡>Oí¤!Í=0:zuõ|¬àE5&¦À{Û•Þ\ò‚%C¯ËÄcrHpaÃÙ>¡Ï£Óû©õО›MäÏ v¯2¡Š"¶}CŸG§÷Sꢜ"F0Æg’…2É áÈŸPçÑéýÔú‡éd8M= ºz °&°L°Ž…X¦ PtÔ`ɪ†)›Ë•>¡Ï£Óû©õÕÑéüéõ}ŸÝO¨~®OçO¨sèôõfÉF|Ë 2Â̰³,,Ë 2Â̰³,,Ë 2Â̰³,,Ë 2Â̰³,,Ë 2Â̰³,,Ë 2¬I }Cõtz:}CŸG§«Ÿo¶¥õú‡êèôþtú‡>—©ñ”gŸoÚB@LÖÁ$#ˆÈ–‚)9†Â™"1ÌÃŽÈ‹ [bÚMp?u/¨§Ô?WG§ó§Ô9ç¢w»G‚ݬEãcÛ}¼áb,÷?ýJ°o} Ò´½_îÝwjr€q#å§ÛKê"FX4Ö 5ƒMC ïÓÕƒ€ÜéõÆçÛö”Q*˜£2íG~U ójãˆ^ˆå 2$Å—b;ðDXC÷ÒúžØuÓès§Ô;Ÿo¶¥õ=°ê§‡PçO¨v&©º\X°`:Àu€ëÖ¬XVB†¬X°`:Àu€ëÖ¬X€-‘{aÔ?O¡ÎŸPï.|Œ:‡éáÔ9Óêåσ±‡Pý<:‡:}C¼¹ðvNÕ«·®Ö¡-Pý4:‡:}C¼¹ðvƒté¼ø·éáÔ9ÓêåσÞSŒ+8 8 8 8 8 8 8 8 8oX|K8 8 8 8 8 8 8 8 8G»èutú‡ysà÷ñϳ£ùw°êéõòçÁïâŸ2rhB×m˼â6 R˜xÝ¢\çO¨w—>üüO)5³ÊMlP!å ÒÒ™‰!§R:¥êZ¥êUFCÕÔö8]Hé­-g´rñ£ùw†<£ú§:}C¼¹ð{ø‡çãddy¼KU‡!¸BHðç®M‰ÄöQ XÙ ÷iŽBªM¸xÑ„ÆQØ çãGòìI=±z„—¨Iz„—¨Iz„—¨Iz„—¨Iz„—¨Iz„²_P’õ /P’õ /P’õ /P’õ /P’õ (ß”§ã>¡ây<“adØY6M…“adØY6M…“adØY6M…“adØY6M…“adØY6M…“adØY6"Lƒ¹ð{ø‡çÙÑü»?W¶‡Éã>¡ãgêöü?â¹ð{ïÆR–ÜÖÜÖÜÖÜÖÜÖÜÖÜÖÜÖÜדêÛšÛšÛšÛšÛšÛšÛšÛšÛš¥iv6~¯¼&ÞåØ6À|aòxϨ+`Wâ5,«?UݢдJv‚9 °4^Àš9`×nÎÌ¥h0a’Š™"52DjvC =°4ZqxFØ')1œ‰Íí‚+|{4¾ˆŽ3.ñ\ø;uîÏÕPZ5‘8xyªÆ,šÁ,n (´,Á˜b5X#–± W¤11x|ç2 À£RûáûôêÀÕ þ^Dp”rn2‡ÉâPn«‰€Ãkð›¶xqêU¿ðš!ÐoQ”ñm{|$ðpãy¸ªÿsûq%{ñ½þ‚Íê4ãMÓ.FrwsïS‹k§ý›‡ýÿ~$ì,žñ\ø;uîÏÕNŒ²«9Vÿׇə‹ê £O}Ÿ«ÛðÿŠçÁØÃ¨we‹8GXGXGXGXGXGXGXGXGXGXGMXÎl#¬#¬#¬#¬#¬#¬#¬#¬#¬#¨S3Oß8´áéð^Ÿéð^Ÿéð^Ÿéð^Ÿéð^ŸéðE§Óà½> Óà½> Óà½> Óà½> Óà½> Óà‚‚7>ÆCôðêõŸ™sàìaÔ?O¡ßXùù—>ÆCº Jhã•c•c•c•c•c•c•c•c•c•c•c•dï¬|üËŸc¡ÝSø?Wcçæ\ø;uêŸÀ¦H ddddddddddddddddddddddddddddddddddddFM6öXùù—>ÆCº§ð.!ùþ’—ÕöXùÔÌlw»‹]Å®â×qk¸µÜZî-w»ˆ‘´fìg]äk#0j÷4þÄ??~ðüÜÃh{$HÆ~¶Ê‰#ìóm\Ú_WÙcçPêíîŸÜÙ⦤zÿÔa’³`6y´Y´GzŽs…ì3µ£âY,ƒXÿr¹dW™ãQFˆ‚=£…¬¶,˜iŒQ—üÞ¨ïäÌ[$ƒØ”국⹊BÎG÷ÉթZÇõ$pþ$"QΦ³©¢Y¬¨uö÷Oîx —µ_‚R¼Í{åò™ü¨ѵ  kœ,Rµj¤o¶"ƹA ðBä!L…'úOʹ-fF´b;GˆcyB VbcS ^‘aŠ‘¯x+„ôìNÖ"áõ¥R—²C½½Óû¾!ùöOçäMˆQJv9ô¾¯ºC½½Óû¾"ìÓ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸­qZâµÅkŠ×®+\V¸ª?SÝ¡ÞÞéÿ­½Óû˜uö÷OýmîŸÜèw·ºê,’c‹‹EÅ¢âÑqŒâå¸Ò¯<¹ÞÞéÿ¨¹ðw¶“WƒVÝâ}íîŸú‹ŸƒÝeœœœœœœœœœœœœœœœœœœœœœœœœœœœUëV³œœœœœœœœœœœœœœœœœœœœœœœœœœœ+"4•îŸú‹Ÿ„þ_ÛÒûJ÷OýEσÂ/fsl¦”œ•;KlBžà‘,i›Yv'°ÅˆEÚRûJ÷OýEÏ å|¯št'k­¤ÉA®¨Å²1K±&Û(¢Š=P¯„L"a˜DÂ"Ixìˇ~«œx¿°i3W¨¢—òni‹ú6HÉ™39X¸‹à9¤mFÓi´Ø…$þ,çúìÆM ßrSÄro°¦Ðü)ûy$QŠ1(ÅYF<¸]Æï’VQF&% rá¿_„ÕPYl¶[,RåÃw%|¬³"Ì„Æùpãë Å1ðßZƒd`—u« þ êI±pÿšâk‰„J_ k‰®&¸˜®M¤lFÔm6£8ýd¤æß]Ñ'ï꛾TÊe2ŒY‰O— þ;ŽIyôdú,S¸¿²ïá¿UÉ2Ë-Yg‘ù8k×·)Rí)Pü9ÂýQUØŒ®ß’ò_;,\ø~߈ՆL×#\lÔ(%ÝjÉE®»å_Õ¾53 HÂF¹ „(%ütlFÄlFÄlFÄlFÄlFÄl_QÄñÑL®Túcãéøž9¯%™/%¢ý:cãéæ­HÂF0‘„r0‘„Œ$a# Çü/)´ÍŒØÍŒØÍŒØÍŒØÍŒ‹µõ3÷r£ŒJõçoeÉ/&È›"l‰²&È›"l‰²&È›"g¨Ú¨Ú¨Ú¨Ú¨Ú¨SO¦~îVY‘e—ÎÞÏÏmt?¨¦SçL®TÊõ£‡îé|;vj5F£Q¨Ôj¥Ùâù,¿A—Ë"ùeê#óÐü/V_ä¿AúøúYh´6Z²ï‘ÄM˜ÈÆF21‘S0‘ŒŒdc# /¡šäk‘®F¹äk‘®F¹äk‘®D ÓþúN•›Yµ›Yµ›Yµ›Yµ›Yµ›Yµ›Yµ›Yµ›Yµ‹Õ}ÛБ‰ˆ‘G¡‰ˆÑEtÇÇÐq=½ Ñ‘e™_–YfFCwÑA%jF£Q¨Ôj5F£Q¨Ôj5F¡z/æÛ£$dŒ‘’2FHÉ#$dŒ‘’2FHÉ#$dŒ‘’2FHÉ#$dŒ‘’øü^ýwcîøü^Ô|òÿ®éþr~;P÷|~)EQEQEQEzž¥QEQEEzÿà¯ÿÄ, !012@QAPa`Rq"Bp€ÿÚ?þ¦Œµ–²ÖZËYk-e¬µ–²ÖZËYk-e¬µ–²ÖZËYk-e¬µ–²ÖZËYk-e¬µ–²ÖZËYk-e¬µ–²ÖQïéöùñ5;wôûyÒtEiò&WvT« º²¤EÀ«"7Àn‚u!Ó©Û¿§Ûõš¿ÞÚËYk-e¬µ–²ÖZËYk-e¬£úXw.v§oÒùn²æU•c|wu;~–Ëz…B‹wS·éS¡–FYde‘–FYde‘–FYde‘–CÔmSùë%JýŠMô#¦—]’‚‘(¸õúèé7ÔI.›²Òÿ¡J®„áo&1rèGMG‘()ƒ&¹š°ù^.œ(ª5UAª:oÇKØ•6I:”)À§ Ue8í–—øò#U6J6ºxzp¯ºªÞ‹£©©n\\U"¾„ë¶RQ'+·´£ÿm³ËŠ« • ™VEÕ°§øêû¨ËKKxÔ°J›e«ë~¹ì’­JlÕσ§ V͵RQµÓ~2qèGQKzSQ%7.DŠ*T©QÑ’Ttð2HÉ#$Œ’2HÉ!ɾ¼˜êÓ¨zm–¯¯°Rk¡™P”Ü¿“Œ³K#è¶>Œqô==&ºx NLÂÌ?¦aý0±Å®¾,4éÅòe.¤£k§2¸ŒTzr%¦™(¸õð´û¶6\\ËŠ—:u¡vÍnœÄ©Ãc• ‹‹‹‹„ë³QV>tu¯Å2…j-E¨¢vjʼ9‘•Ê»----"©³V\)áÆN=ê§×}Í"Zôæ©5ÐŽªù+]ç$º’Õõãä‘–FY$97á_#,Œ²2Ⱦ[[èb‘…˜L,zrúÈÁÈŽœVûU%¥ëÁ£ò¨•6\‹‘TT¹"«f¬~y‘‹—Ah¯‘B+ãuéÅGÐÕ:øqtuØÓ-(ZèZËKYÐCUðåÂ73§&QRê5GO”àÄëÈ”ÔIJ¯—£ó²] N#Eöê÷x‰µÐZÏäÌŒ±2ÄËëz¤Ÿ62µÔŒ”·è¶ORŸVµd…¬Œ‘/²øû2ÄzÞ‡©'ücwa‘†Fda‘†Fda‘†F Séô{·*Š¢¥È®äûŸÓè÷m’ª(ZéB”â4÷'ÜþŸM¤ø™"d‰’&H™"d‰’&H™"d‰’$¸¿ü^iª˜¢b‰Š&(˜¢b‰Š&(˜¢MQÓêtûvT¸¸©q^u;¹*] R1HÅ#ŒR1HÅ#ŒR1HÇ-Ü,ÂÌ,ÂÌ,ÂÌ,ÂÌ,ÂÌ,–›Š®îŸnËKKKKJ f§w'G§-îG©R¨ª.[jŠ­•B|*jvîÇVІc1˜Ìffc1˜ÌIÕד£Ð§œh$Sóe¥Ëx øÜQ®#àŠq¡GQpê>= K] 1.…(jvùRIq/²è—ÇÙ|}•|}—ÇÙ|}—ÇÙ|}Žq÷¸º™be‰–&X™be‰–&X™be‰–$暢þú çC 0£ 0£ 0£ 0£ 0£ 0£ 0£ 0£ 0¡ª:}—vãt...Gä\„ê\\…Çr}Ïè4»·©iiiiF[ÑâZ(аJ›“îAZêfü3~¿ ߆oÃ7á›ðÍøfü3~¿ ߆oÃ7á›ðÍøfü3~ Õ×ù´›èY/E’ôY/E’ôY/E’ôY/E’ôY/E’ôY/E’ôY/E’ôY/E’ôY/E’ôY/E’ôY/E’ôY/E’ôY/E’ôY/E¯ÇÑùå×råÍŸkñô~yRè³ýœN'Néþĸò§Úü}’¥J•*T©R¥J•*T©ÀàT©R¥J•*T©7ÿÿÁ_ÿÄF !13’"2@s‘± 0AQqáCar“¡²ÁÒ#4BPRÑ`b‚cƒ ¢ðÿÚ?ÿô žö¶}¥_Cį¡âWÐñ+èx•ô©¬®teŸ>õ6Òˆæuõ&²;[Ÿcš£9ò¥ ÀSmRô¡JÞ´æ@k$Ë\å›(¸>(EsÉõް¨B`²tbt¡´€¥6¦¾Œ0ÙÖ£Ò¡ÕJ_Muþ¨úô°»ô×óÓ ?[“à@p9†AUò’-•‹ õOÄ©¯FK.tˆ›:û–M”Ð+îY0:F(%>#çÉÄ;±2#'ÉÃ;µGdI‚çÒZ²²D¿ÏhOöqPÔØ€”"ˆñds¥:“ÞùЈrÊ( 2wjÈ=SÃÉ–zÏà²xäÎJ‰—R‚!LµŽ¤çIrcF<§ì\‡és„O$a`9Ôšé(Î-“f(úkOöqRÊö¢(Ê´ê}ižÕ®¨¾T}:ëýQõéaw;éþ2ÿT}zXSìwÑi ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½D‘Cëÿèªn Ò¯¡âWÐñ+èx•ô9¶!«¸’ÑÏìBÚÞ¢ÛÇù'™(yŒíë>\ÍâUU;øŸò ,ÏJ!™áÍôª1«È)ƒ1þ9IæAI¹Œøž†l>Î¥-ÿþ5Fs»z‚¤óIÝ$¢ç7ùuªM3àN`vsmÕ&ò¥ ÎÎÞž”3.Q9¯ìíÕ Ê£Ó§g þ×V›¬Aí´|P{l:•9Çùu*N3wièÜþÁ4×ÿ!?,hfRd¥å“óÛñ “ Æ¥Vƒlôù+Óm¿´—8Èb;Ø;’‰ÐwÀêƾ¡Ö«ÍgñÁFss¨Ô©dðr†ÄtMi ÌJ±íF*a‡JHÆ7«±A†bTg&G†%EÙÝÉ£ôÂö•”r“-å SYLgU¶k'†Ðà"Öêš““ÁŽÚói‘ 3¢Ì†º‹DìYKfL¥o2“ Š¢ü×ü¡É·IßåÑÚƒ…‡öŽMº-·Òyœ›´›ñ58ÔÉ™=g›Frë±¾#Þ²ËJj£BŠåª£BŠp‚æP&yÝJ¦[›‰ëO9²T¤úÖPèE—„å®tß×&9¢$=yW´5µÉiÏ€æIöµÊ+žàêrçHç³âØgÒ—ºÀ‹Ý¤yœ‘°èþÏEºn³ÑÍm¡·È!—¶™±³¯œç6$Šnh6?’¿îOܯà{“÷+øäýË:#bâÖÑúôeï2hòQ³—‘ÔD©Ÿ,â:K1Óè)C4Ù_À÷'îWð=Éû•ür~åÜŸ¹>UÍiÐíí>…ù¨ð/Í@÷~j¼ óP=àN£•Aœªü@¥ˆ;EEO“wcՠωçZ,8oÿgI~j¼ óP=à_šïüÔxæ {À¿5Þù¨ð/Í@÷~j¼5¹LM€'Êèm”Ïjt6Êgµr°\ÐéH‡XW-ÀºR¶dÿP· nÖÎ5;'ño@^î¤^í#åh{„Ã9ÏKÉ0ƃÚÏk]Þ€òÏô.žERƒ…HÔ{:iØÞÕ&oOEºn³ÑÑÓêýJcžÝ¬?œj0vOâÞ‚­Ùéé9Ρœ+ê!W[èäÑ2§8öuj&#¡Ä™ê jWoÀUÛðvü]¿WoÀQ“_U¹…]¿WoÀUÛðvü]¿Fšé Á-<öíaüãQƒ²óÜÀê3ëWÁ⯃Å^7мnxÜ*ñ¸Fô­ÚÃùÆ£dþ-鲓¸kt¡fžÎ¥EÂG³É7æ·â¤Ñ!­å{Qò7¥nÖÎ5;'ñoJZì¦"Ð^PÖå0I0Ý ;5ÉFô­ÚÃùÆ£dþ-é]µ‰óŸÞò½¨ùÒ·k猓ø·¤†èlcšê$2~N\÷lÿ{Êö£äoJݬ?œj0vOâÞ†¸ƒÙZÍcÏÁU÷.J%':‚s¡â%2˜Â­fd5\ÎU‡·Ø³b4žÏÙ«{w«ÆoWÞª=&Wµ#zVíaüãQƒ²ó³}‚Õ˜¦²³Ü]ßÑÖ³"8z-_ŠÏkTØàF½¥Hÿ­k2±W’õB®#Ïý+X¬Z!THî*¨¯öÖ«¢ïbÏc›ÝZÌx<ü¯j>Fô­ÚÃùÆ£dþ-æL™(Y­þ]gQ¤Ó#ÚµÞ£­L™("ìWâ8»§¶˜ìr©ßÄór½¨ùÒ·k猓ø·™UسӪrO>©Ö)ºÅŸ£ÔÝO“‹ìw3+Ú‘½+v°þq¨ÁÙ?‹|´E¯2òÍÄÚU'iR.”íSkƒ»Š®#m•¨Mí²¿&kÚîâ‹A„Z˜´ yFHÙZ.¥Ô †Y´LêþJ¸¨ÊÕ1XDrªÚÔÅžI‹S_Ú5sü[Pé9/ÕF’u&Q‘ª»z ;I¾\¯j>Fô­ÚÃùÆ£dþ-òÂöùb{8§û8¦ ŽJrö©0Hs w¬¤½ þ!§¼´Q5•‘Ãv‹ô½(E†Ð×´‰Ie?óÁe?óÁæ];P&²,Þ²@†rÊæ‡~!¬¨3ôÄ z“DÃgIBõ”Q‹6ºŒ2zûÕür~åÜŸ¹_À÷'îM…ðÜÇ;5’²^ŸN Ñƒa_ý-þáÿÒ2liì_ý!Ìyi ÕXïPž#8¹Î¢A±Bo*÷6$çH¨Ÿˆæ1†ˆ ©G‚^](eÍwZ¥3K’œý‹&-y.mjÄgº“è¸8£žý VúlîYY¦éˆ²ÙZåùg—‰Lu&@k‹m'j‚ÎUîa§šçO‰›¢ËQd8B­YEùDH±3 €»àPú.Ñ*¤Ò?K{zVíaüãQƒ²ùf-nw•Ìu…roÊ Y¨F¥ú(ÉrÓýd¢W:o¤Œ S˜"rL†\fËLhÆ m`JK•‡ƒF©ÍD}2ê}¨CœåÖ¿ó—ûd ½ñ)sêµD®tßIG§7µä¸€¿õÒd³YÖ¡´Ú’A5½ƒ™dþ-Ô2m“xy$‹ ­«˜ö0MÅA¢'F %@x­œÓÝ ‚#g)ÊEE‰AÏmPF$4eJ•«&mØæ—(TDå„V²“KhšìYKhÖø“m~”æ0MÕ(q!ÈÄE„Ú¡µ6sæ¹ý‚JQaµãÒ-“j•ÕÓ7k猓ø·™I£ðÏÃQ¤!¶}²òòõl“ø·PɶMáååX+ë½8&aÂÇ4Ö©ÍÎòqŸ2‹mA£PnÖÎ5;'ño2ERƒgñRëÔ$Ñ2©>·vvs ìŸÅº†M²oe8u;³¨ª.:c{T›¿QnÖÎ5;'ño;=¾ÕønŸ¡Ë=„t•0ûj_ˆï`RhçÁÙ?‹u ›dÞÙ9 …øn—¡Ê¶e}&hŸr®MïS9ÇÓ©·k猓ø·¡®gÚª.oµU{V“W›Åà¿Fõú1x-6…\MÁuŸjÍ`⃲ê6ɼ: ö4÷…P#¸ª¢hZm>Åú7ø/ѽy¼^ ²Ý긃 ­Î+@úÕZ«v°þq¨ÁÙ?‹uØ;'ñn¡“l›ÃUÏxoyY¡Îî 6GyšÓ¹ª¸ÏW±1{W±1•zõy>ö¬æ0÷T³šæüVcÁç·k猓ø·]ƒ²ê6ɼ59 çv¥@v5O¯¥©óŽ­Iù‡Óg5»X8Ô`ìŸÅºì“ø·PɶMᨗ8È&M¬øJZLþ*“M^VíaüãQƒ²ë°vOâÝC&Ù7†£D]·âuJ_§õ1änÖÎ5;'ñoI[Û½^3z¼nõQé ìŸÅº†M²o Aîʯ+žlk–®J4¿L.N‹Øî á)§C¢òöõ¦Ö½Ý 6ÅËRÌíB“b5¦Ç9µ.FºTi.FºTi'42#œÓ"N‰ ‘ê¨X ¬~“@Ÿojt://oP£F`‹AêF§–×F¤"6r=¾Z?ÄÉ~$fÏøŠÊq†×ÈÐ…~¸Ô`ìŸÅ¼ý*GýkYÀõм—ªqéX¬ ÅbÑ ¢GqUE¶µ]{{ÞêÖcÁè`ìŸÅº†M²o AÝã–/¨Tçæä¿øþãÁd¿ô²Ÿù಩POé3»¦Ÿ2$EJ +y *º¡}VQµ+-õܲ?YœSÿ<Zm-Ȩ†Ö¡ûxù^ X¬¯ô9N ›n*#cr°¥®£!*õ;'ño2dÈ)Aÿb¿ÅÝ=´Çc”…Nþ'Ÿdþ-Ô2m“xj¦Â$‹hòŸÃ¨y·z>„בœÛžs­N¢%HÌ®M­ÌìT„149FÎJ“Y#)'Q¤fSÀn™›½(42 êVõ§< çZžöŒ÷Z‰vFî[Ð3SmPÞ»N§dþ-òÓu‹?G©ºŸ'Øît“ø·PɶMá¨Òn˜ø©ާÊ%¶Fu–)´‚;B>¨çó)™#(‚¤y7NJ‹ßZåifvªo2jh{¥JÅE™QJª¨Uä£Ê óÛÞxù ìŸÅ¿¶dÛ&ðéàìŸÅºƒàÂc¢Ð“fèTŽQÈzfTœòóDgtl1BÉjí_þ/ª.ýeÆ’ËZÝæÉ;ز@}+&>²Ê¿åD—b“åÉI YÎoyãä¬&>VRl×å`{°¿+Ý…ùXì(Í… ¬›*h—[¿h~OÊ9ðÙ ”iJ«®žÉü[©Ts›Jy®¥R‡Îl±rÕÒ£E5Ïa6Ð2š0¨æ›U>!SuŠÌæË8†se‹–p&Ñ:ŠäÉ/ì¥J!gð.«žÞóÇdÎ.ý¢6Éœ]ÓÁÙ?‹u#ê]½ç:6Éœ]ûDm“8»§ƒ²êTÃÀªU…xÜ*ñ¸tm“8»öˆÛ&qwOdþ-×[µ‡óJ6Éœ]ûDm“8»§ƒ²ë­ÚÃùÆ¥dÎ.ý¢6Éœ]ÓÁÙ?‹uÖíaüãQ|bÒàÛ@O‹ÉE“˜ÖõuOûMt¥19Ùãl™ÅÝ<“ø·]nÖÎ51Ö8H¦äî/Îö~ÑdÎ.éàìŸÅºëv°þqÐ fßBµØJµØJµØJµØJµØJµØJµØJµØJµØJ•Lç´ íú+]„«]„«]„«]„«]„«]„«]„«]„«]„£@š½×£l™ÅÝ<“ø·]nÖÎ:]ÎújõG¯FÙ3‹ºx;'ñnºÝ¬?œt»ôéK‚´×ޱ>sýQÄë® ­qm ö,ØP©Ä¢Î¾ÓýôðvOâÝu»X8è!w;éÌÉ€&F”ÂÉ€&F”Â8Ñ(Ç1žÐe/BÉÚÓ'Å´¡±^æÏ8<ÍÌÑä§/j ™£ÉN^Ôèñê‘TÜã0 i•“0 e:{˜Æ èÚSƒŸMŸ¦vóêŽ']|7Xá$êbâsï³§ƒ²ë­ÚÃùÇA ¹ßNd(°ÄÝ ÙÚ Ät0Ö¶uNÅ•(„„açÑuJl„X]E>†ÉÍÙÓšlxm§›D¶r\¬F€(JÛXñ'#ÂO ¨LtJ¢i#Cé 9³’tH¹³±“³˜ÿTq:“ß)ÑW#‚¹üÈÇà®F?r1ø+‘Á\Œ~ äcðW#‚¹üÈÇà£Dl8®™ÏðW#‚¹üÈÇà®F?r1ø+‘Á\Œ~ äcðW#‚¹üG$+ ixs ìŸÅ¼Èކ’ñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜñÜ©º‘—Á7kç.ç}5Gú£‰Ô£z‡Wg®Þ<È;'ño27¨uˆž¿Ð&íaüã ‡&¸ÔlìWoÀUÛðvü]¿WoÀUÛðvü]¿WoÀQmÒÊWoÀUÛðvü]¿WoÀUÛðvü]¿WoÀSæ× …¢]º”oPôªT]G£1%9së·2Éü[ätg΋m’ü8ÍŸñ5Ô*dÈ*-ˆ&‹\ùj› ʼnî.©†N©PåÔ6‡Jnªê@¹úBaRc¦<‚‘”Ì‚Œ¦dšçȶÔÊ N£Ú¨ˆ‚i¬'9Ö&°œçXŒâXebåifvªÌÞ-©R{¤c§%×úݬ?œjQ¶Lâír7¨|‘ŒY×Qkf¢¶&ÌJ}U®U—­ÎœíP!ø‡¹GѪ®Ú”LšØE“‘êQ <׺7%K°#ÛµÒ©ŽíòeæG(d&ŒW—€h™Ù%’äG+¤Pm-5‰Ú²Ÿùಟùà|Ͳ®ÄØ­í°ûPkšØùІojufØ™ë·1¯_ ÍM²ë—hô/ÎGÜϵF?úb¾­_ÁUµ½¯©Då2ǸP9‚ÏŠ`ý%â—ro)P¥”¹7‚ˆKÛHw„éé:N;ÑQ ©dt­¦Ù¬¥ÇNœ½Š m…“=þH;P mBÊX ಚ¼á :&$Ý4ù *Y u²3ܲ_úYKºùR²Ô"•ÛÅC°2c½çHø(ž¿Ð&íaüãR²gk‘½CäsàIöµÊ#iƒ!™=J´÷Îbt[Ü£˜E³©Ýu'Eˆàb;²À¢°¹´ê`õ‚¹8†Ö[i@ ’,åœòàŒE)¡6”¢C°¦ˆîeg&u§E‚Yœ+Q^÷S’l7Jc±ç$Ríö¦RäÿÞ_EËA-¤Dˆu…:$W÷vX=vñè#z…¸L sßFÀãb|A9¾SL‚Ë7zOg&^[ü ©é‰‚u7µò• k)Ο¬â¯FäæHÒçÄqi˜$§Ä›å4ùO9ÔŠät™éB“¢9¢Æ¹Õ 1+êM‰IåÍë%>SÎu"Ÿ)纑šs iôÙÜ…)ÌXE¡MÎqýN*'¯ô »X8Ô£l™ÅÚäoPó(¼L Ö‰œð3o0¹Í¬úJÐ8HÏ]¼zÞ¡Ö"zÿ@›µ‡óJ6Éœ]®=‚×4…æñx/7‹Áy¼^ Íâð^o‚óx¼›Åà¼Þ/æñx/7‹Áy¼^ г&Ö‡ivÏÑè^o‚óx¼›Åà¼Þ/æñx/7‹Áy¼^ Íâð^o‚óx¼Iää ½˜lp’¼‰ðþ•äO‡ô¯"|?¥yáý+ÈŸé^DøJò'ÃúW‘>Ò¼‰ðþ•äO‡ô¯"|?¥¢#óßDÙüIú+ÈŸé^DøJò'ÃúW‘>Ò¼‰ðþ•äO‡ô¯"|?¥yáý+ÈŸé^DøJò'ÃúE­$Ìδݬ?œjQ¶LâïÚ#l™ÅÚþIµ?#ºVíaüãR²g~ÑdÎ.×òM©ùÒ·kç”m“8»[sÎU¿ˆñ Ôâ;ç#îgÚ¿9s>ÕùÈû™ö¯ÎGÜϵ~r>æ}«ó‘÷3í_œ¹Ÿjüä}ÌûWç#îgÚ¿9s>ÕùÈû™ö¯ÎGÜϵ9æ+â9À éuO°zuü“j~Gt­ÚÃùÆ¥dÎ.Öݵ‰óŸÛ2M©ùÒ·kç”m“8»[vÖ'Î|™ïkgÚUôH]Îú~ÊÞóÇ›’mOÈï!… E¡Ä¹ò¶~B¸ïÚ® {ãö«ˆøýªâ¾?j¸ïÚ® {ãö«ˆøýªâ¾?j¸ïÚ® {ãö¦µÐà´Sk‰I°ƒüu#±¢C%¡¦Œº»Ç¥EŠÜ²4ØÂá0Ï·ZvÖ'Î|»ôè)]‰»Ð˜êU>¦óZÂsg–‹¢ ªL Žm×ÙÓ7¼ñæä›Sò;ÉdÎ.ײ“¸kT ¹„R}&žÚnR ÐÏh¬(Nƒ(“`\¤62‡P6•ËAö´¦6 ˆ”ÜORs I–¹Éì{hÄe½lH™ó9¢³j–OKÔ7e9L!ÎspkóP=à_šïÉ[ 47žPÔ×Oô;ÉdÎ.ײ“¸kL‰Ê†06VV§ÉòŽí}jBN³ÙÐeþ à²Ró›RaL¸šêÑ\‹ŸFt¿ÙDdJR¨"ÖLš§U‹$ÿ® ;"L>ªÕ•4Ô]ûly±âÙ„÷™¶é3Ú¿òþ‚þSزgH™NÅB™kIÎ’Î%¡ðèƒéšxåb:“HÎ*Œf8E¶ºÐ”:.v‹':ÓCÎl[Oc”_ý-2s©5Õ§º"ÖØIÎè"ÃkÄÝhô©Á{¡ËB‡ÄÙÖ;ù±¶Lâí{)Ù;†¹ ¹ßMN«S¢Å ¼Õ›Ô‚Rdç¨7¼ñçÆÙ3‹µì§dîä)ö;è´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i ëHoZCzÒÖÞ´†õ¤7­!½i é½ç>6Éœ]¯e;'pý»)Ù;†µdÎ.ײ“¸~Ý”ìÃZ²gkÙNÉÜ?i›%H¹­¬NÒ¿îOܯà{“÷+øäýÊþ¹?r|'Gƒ'´´Ê ûµžYÌs›9f§È¹D`À8Ûm¦±m¯« ù’”¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JS(QœÿðªR;™-ž¶zÙëg­ž¶zÙëg­ž¶zÙëg­ž¶zÙëg­ž¶zÙëg­ž¶zÙëg­ž¶zÙéÚ°h·ñWú8ËmŠßèã-µþ+£Ò:6yã.h bz"Ôq€YTFò‚ò¤"¡L“q‚cFXv)Ž™ñ3Xô–Úÿ¿Ñé9jîHè‡#€„G'(|ߪæ,ˆy(˜NÐp´Gô­µþ+£ÒùÓ`›˜ËÞm$$€¸§‰ DI(BA‘¹Œ½æÒDÇE003 ÀÄF ¿ƒ"ä·¥m¯ñ[ýe¶¿ÅI !‚|’ù%òKä—É/’_$¾I|’ù%òKä—É3d\ÌAô+ä—É/’_$¾I|’ù%òKä—É/’_$¾Hi”ÆG&óĦÀÌAî®V]LäÿFêâÃ裔I¨¹þ”jƒŸJˆMBFÅ_·ô¥O'áÍ œÈ9 €ƒ"?¢?x”øõƒ$`<#Câ•Òˆ[3˜? .G%ÌVO½9•¢$A!6r =B’ ÏùÆ›ûÓל`zºg2³†Uþh¡ǰéÓj9SÓ!Ó[Ô’sª ò#ø v24á kA‰äŸ"£1æ(ÃÖŽˆÌ}ØaÈxIV‰ š'èËàåí}.¨ð9¢ý΋ヂxc¤ýDAfŸ¦ pf(dÌ²ŽŠÇщ°%ž0¡ ÇÑXú+Ecè¬}áÄÊt+¼ÂÐ: æ]Ô»©wRî¥ÝK‰¿ˆvɺ—u.ê]Ô»©[ €pÀˆpÅ »TܨˆÈý½ú¤Dò ìjyÿ*[Í\LÚ‚a=— %Ìy]èM­ b¥¼ÕÅ¿1‹ø‹/÷¾Gâfá€1R›0ºˆ‰.ÏŒ„«ˆä§HäpÿË@ÅK T§^d€`{Û!È."Æ¥¿¡,‘–,ÓòBü¨ˆû£DÎÚ€™ÁP'::‡€€ñ¹ÿ¤3rj°u™/ž‡ý:,ÙÁÞÍ ѯÊåÙ©(yp,;/!uÆÃí~‡i ^‘ÍH‚¢ÎÅ :.X‹4’Á9’´‘ýÑÏú°æPêëìø‰æœS?’ÊvYNËhNùXÞf¥‚¼ØQ½òï™=½¤ T§#$œâcx@õ35àhO6(ä`L”üÐbоJeÛÖ K´DЇžô|ÿ}œ T§d£ÁöàÈpŪ}qå`îMyÀd9ÔðMÜHщ…l²Š”¯Øqñ'ÌŒ/‚eÁTÖu\A‰`hŒ@‰9,¥g°gdjh‰Œ¯œ‡ QŒg†MFÙÅJüñãa‘|o©#$bGâKÀ:‹,vOÒKC;7dD˜´ü€ Ÿ°Yò_  ÂÁ í@Á,FaFKcf»#@Êg7}_š¾ÓĸÚadØ·ëÈ 0xðL`â|XÈ  YÄ‘ä×ȆÑÆ@â=0Q‹î.'J1¼m ePÄH¾$ÉMÁP<`pô¢7ab¸Šç@&]â!Ì™QÖ P(_3hÒÆ¾Xð¤(„äh¡žðøRÔfˆÀ,š ù|Ô€ƒì1Ràr°V¿ cÁÞ™h&xÍ(7:®P’ÍÝžnâVgÁ}›’À±bò>uG% & #‘p«v‘±@>K1y,|PÃÒrS‰YŸâ˜(pQ Rˆ8Š$àŽÞ˜R€-¯–óG€Š3;É€`íˆA'Ñ4€Nê+ï' %BÇ"=«§P„V(h2!‚E1–°oL;¡Ž8&D1;ð ˜R;ØR25QÁ Ÿ)žI‡XŸ¡Ýu—“"Ñ™“¢n¸{T¦4a†?Μ4…ü`Zb°Ï…Ky£Æa„0°Wšâ^±³0Ð~ê o 8¾3*[cšû,T¤f :bUÃ’‘ &b8Œ  "ˆ ~¸d·š<† ž$¬ Øéž«™—J¦ñ9”Ï´EJ6"RÕF<ƒÝwãhw’Kœ«•ò€‹“OÒ:[Í\›‘Sï¡ßu7°“ƒ¦uˆtúQ‘g=‡êgt½½¶*SfCëã)ßhôúš¢)›„pþDºˆb|È >€•Š»_n§àù³ë‹ûÞhô>üE8;&´~?Lˆ%Öê8ùš]?Åpa¾Dt_Mô»s@¥u.¨À þN*T·š8PïÐ…Ý-ò¾pdújëéï­MUÁªõ‹ý¬Èh¾aGôŠïÌÏ…?zßÂÅJ–óGHÂú|Î òNéS?PÌSÚäóE€yèºÿ*[Í0ä”Lš®_ˆ@`p&=F#âøþ*T·š8Ñ[[„j—P~ Žpxø©dš5ùP<»5%#Ç%¼ÑÀCP˜j€CÁÖd¡`³:` êœâ!û¡“náàƒì†,yÑ®ä‘FP¬r& ì¡XäLÙ>t7™†<„qØ£ê— MÍ% d›ˆ<E Å"8bj€û ¦Þ%1Rršq » Nei9áÔ¤€– Ì ý¤îŽ|Õ‡2‡W_gÄO0<â™ü–S²Êv[BwÊÀ¾ó5,æÂï?~ÈèñíÄ¥¼ÑÀ åáâhAÄ ó3!ë|ï¢æ,W<=Bq‘ÕŽ ¥ „Utˆ"‚År> €Å <ÂUG8Àu« Þ!¬Á b1št¡´>Vä@Dɇ˜Àð©NFÉ@Á=(«ä¦]½b»DH¨yïNê*wÏ÷‡Ky£€šú%2Mïˆ!'¤HD Gu:÷“¦æ2÷›I(Æ4ÉLñ4QûA¬É9%0‘aÅ ¢ÅÆ™*ÅÆi¦ !Щ71—¼ÚH @âLZH§?\5›)E‘ç??Äñ~ƒÃ%?+rhΓ!Χ‚nâFˆà,L+dxd·š8ÙE@ cƒ!Ffû7þpÉ]@ÇýO©YìÙš"c+ç!Ãcá“QáRÞhà„¹‡)Ÿêˆ?ÒœõTÚfeNNµ†7—‰H¦Q ƒöšd FwqmP7#È ®1‘ =¢ŒÄz `£Ü\N$”cxÚ@Ê¡ˆ‘|I’,.›ƒ: xÀàéD,nà ÅqÎ €L»ÄC™2£¬ P¾fÑ¥|¤€¯ÐÞ-æŽÌ‚¯Ä”ˆû—v“y A C]ÛEÔ°Ñì0:ߨ`8a"6&dÄE³ÿ("‘ ŒÀŽò@ ;bIôM ºŠûɉP±ÈjéÔ!Š ‚`ÄCÌe¤¬ÓÎècŽ ‘ NüæŽö”ŒTpBgÊg’aÖ'èwáRÞháÏ9úE£‘©$Gâ¥Õ…ktÂg¶H8“¹ôGœ3Y¸Ù†ÂÁ^hC‰zÆÌÃ@û¨4Q¼€àrøÌ©mŒjkÂ¥¼Ñï©LÔhNÆÔ“ð¶-Þ^{­~Ü–óG”ÿ L 4AÙÛ£ž ­#á™ÓÌ'~Pì„þ 2fÆ4NÅ8» P@¸tb|Ã{„\9±ä€4Ë è¾OУ\ÿGŠbQ0¡æº×áÊÆLî®Ó¢ºtG±ÎCÉö‡+˜AÑ @ ~–ÿŸ˜(0‚(0J*Ì@ÁÕ%»H(}¢)ÌñÒŒ”LQ@‰‚QM…]ÀS€“rPãè|÷ZÿJ•-ÿ>ë_ñéR¥1Þ@¦O˜ªÝKº—u.ê]Ô»©wRî¥ÝKº”LpÊ亗u.ê]Ô»©wRî¥ÝKº—u.ê\É.L“¯ÿ¥J–*T©b¥J–(Û[̲† œäuÈœÃiˆH•,Püæ‹"Ÿœ÷Lß_?Î%K蘳—.júÑ_Z+ëE}h¯­õ¢¾´WÖŠúÑ /ŒFI}h¯­õ¢¾´WÖŠúÑ_Z+ëE}h¢¹ÍÏ‘ÿ¢¥KŠ©RÅbJëÆÏØêœ0œ˜tAà„3 Æ>ñK€5‚QX!]eÿ™'sM‡5S+ì™rÈapàeDy†>$y†>%,ýµN¡Mmˆ®ù4HÁч4Y¸£‡Ÿ°Õ›>¨òì ^Þð–+Db2Ì*&â2L£Æ0S2¨€1vD6i ·Ø…2 ¶L†wNÚÚÓI7€%þ)®bj鎀†=Pœ!ÈH‚ ˜áþ¸j¸Â-«QEQEQEœ°mG¯¦¢Š(¢Š(¢†ƒ¤lå½RÇŒÙXú+Ecè¬}¢±ôV>ŠÇÑXú+Ecè¬}¢±ôV>ŠÇÑXú+Ecè¬}¢±ôV>ˆ®f 0áÏÛâ±VÓNùO –ÓOa)LHuöt+Ecè¬}¢±ôV>ŠÇÑXú+D+@( ¶ÊÇÑXú+Ecè¬}¢±ôV>ŠÇÑ7|ø+M=†ÌÞ˜e¼—Ê|ÉAañ(8öB­4G#$”pä‡@–ÍŒqGÂèªb:5Ù?9 ¿&gBÒ ]¹&B¬<œ' d¡ç ™((Ù1Ž?h¾ÂX𙨊 ‡]tΧZÓdΧZÓeÀ˜ÃÄÑr"hL†:Âh–Leœœ›Æ#ÜŠ–ÓO»{À±D8 ÀÈ:mä²éɨ®ö¾Q,$A‘,éESÏA(8d#&g¹?!›îª)÷ˆYMÙAH8LH)š@æ¾:>:¼8¬x&`SȰ҂^P¡`F.S¸Ì{ÕòŸ#wQ›&QàPʲ…¦Ru•ýF°îæøe0‘ BK$ŠgÞø‘5PBˆóàŒÄÞ¹Ži¡…DÍùágÍcÝx€’Æ=5¹ˆ ˜`tc‚˜2¬FÇð¡ p_$<Ea™ w2¦Ÿ¸Š–ÓOl‡zÏPÈ÷ˆ‚`Öf.±lŠi(¡Ð‚„é`@š:8n«Ý‰BƈaLÀ e P§…¦‹2 ÕñÞÂé ʈ§ ê¬2&íLC‘èŠÓA  `#ùˆ‘ r\žkx)‡g Dè\frGzH2‚8FO9R  ˆ¡ÀÅ@ã¹lIÎi·æŽ“ÎT£Ž“™‚¤Ð+º@R)ÍÔLVÌ]§¸-¦žIÇî΀&&æ2÷›KÈtæqkUekê_)ô-4þ©N`˜WÉ/’_$¾I|’ù%òKä—É/’_$dÏ‘s1د’_$¾I|’ù%òKä—É/’_$/Žz°à›5»£wFîݺ7tnèÝÑ»£wFî†Læ (Tîݺ7tnèÝÑ»£wFîݺ#1m×ýê*T b¥J*X:BÞ ™õJ(P¡B… (Qû¬™bŠ¿è b¥Š*X¬ÔƒAÖÏ[=lõ³ÖÏ[=lõ³ÖÏ[=lõ³ÖÏ[=lõ³ÖÏ[=lõ³ÖÏ[=lõ³ÖÏ[=lõ³ÖÏ[=lõ³ÖÏ[=lõ³Ð)îDqý0©b±y¯Î!Óàh¦ 0`Áƒ QI@4‘”à†Œ€LD‰•"X 8숬€ÀΊ F1&^Vu:Ö›x0&%» Â^#ˆ!x¢Þµæ¿e–óWÔ,á;b±dÇlv(¤R®–o@$p2‚•âK¡ 0ÇÄH»ê€ü‡qpæ‚i“DÄÍ¢jD„NK@ €„1@Žˆægù@E(ªjˆy3€Su™ÿ9ÖxÈìnêàF ö¤ØØCÒ(é€ä¦õ”K-}!SI̶!Š3Nië!,ô X€À`^Dzµ øŽÉÈ&³žÁB Iùš™]:«§T <Ä2l`Ky«Š9<Ä\S ±~’CŒ0‰R9QT BSƒ3E޽nC D0ø¡i&±‰«ì‰þSXhŽ5(œI¦½€‘Ì!æDbs_#ì™rÔÿ‡€rÌÌ‘ÁJø}X¤X_ñ’ÙÈÙ`„[¹:&ÀšÂC–p‚xæÎAô+7„ѧ AWåd3p\Ž¾Æ–óW·± t=~ &&œGy¯ÙRÞjã$ÄöR”¥)JR”¥)JRœ¥)JR”¥)JR”¥”KWì©o5{uæ¯xKy«Û¯5{Â[Í^Ó ñbÐEÅ| Áƒ9#†!¸‘€@ ŠhHàsŒÜ¼uæ¯á∶0>Q‡˜ ÔKå¸ëÍ^Ùà°LHŽŠúÑ_Z+ëE}h¯­õ¢¾´WÖŠúÑ_Z+ëE}h¯­õ¢¾´WÖŠúÑ_Z+ëE}h¯­õ¢¾´WÖŠúÑ_Z+ëE o Ѥ«ëE}h¯­õ¢¾´WÖŠúÑ_Z+ëE}h¯­õ¢¾´WÖŠúÑ_Z+ëE}h¯­õ¢¾´WÖŠúÑ_Z+ëE}h¯­I¡ëáy«Û"Ø*÷‹Ìüš½²-‚®çË3â¡L’«v™ñòA(–U‚À°cËÀC!”Ã3‚>‚„4+ªäp·™ø/5{H°]ì˜ÀFA2ÆÈÉ žb˜2î£36W {ÍÈN RKjˆ“ºü7Q-1ò) ”ÃÂaE0°Ø4™QX,Ⱥ ‚ᘡ?û±'—|8˜@60 ˜Ghᣠã|p„ˆÁÑKPOv<Èäh¡žðøB8ƒJ^ÔÂD,_¤èÀX*á˜ËHMÔ ï6B‘§"×Tù`£¢ "40+‚`j€X˜a"ì„c¸ŒTMÄd˜1MaPVž' E·8±BÀs¼?Ú)¯ Ô,Až]Ê«ŒÜ%æiÖ^L‹FBfN‰ºáí– ½€±HA5d뉳FøkÌý¹Ze lY+Ecè¬}¢±ôV>ŠÇÑXú+Ecè¬}¢±ôV>ŠÇÑXú+Ecè¬}¢±ôV>ŠÇÑXú+Ecè¬}¢±ôV>ŠÇÑXú+Ecè¬}¢±ôV>ŠÇÑXú+Ecè¬}¢±ôV>ŠÇÑXú+Ecè¬}¢±ôV>ŠÇÑBƈT?üÿÿÚ óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óß¾ûï¾ûï¾ûï¾ûï¾ûï¾ûï¾ûï¾ûï¾ûï¾ûï¾ûß<óÏûï¾ûï¾ûï¾÷Ï<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ò¿}÷ß}÷ß}÷ßóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<¯ß}÷ûì³ß}÷ßüóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ+÷ß}÷ïn{ß}÷ÿ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óËüóÏ<óß<óÏ<»Ï<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ8óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÎ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ:?þuóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óoý÷ß?óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ç<óÏ<óÍÖß}÷ßžëÏ<óÏ<óݼóÏ<óÏ<óÏ<óÏ<óÏ/çï<óÏ<†ïy½?þ÷mKÿ<óÏ;Å|óÏ<óÏ<óÏ<óÏ<óýâ<óËœ÷ß³Î:ßßuÛÏ<òƒ½õÍ<óÏ<óÏ<óÏ<óÏ>õ¥?Ï<óËÚçN·Ç¾ç/üóÏ<³ÛÛõ/<óÏ<óÏ<óÏ<óÇ=øÇnWÏ<óÏ-_ß}÷ÜíóÏ<óÏ9Ë,²Ço<óÏ<óÏ<óÏ<ýï¾ûï½óÏ<óÏ,ÿïxõï<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<¹w¼óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ó<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óR·ïŒãï<óÏ<óÏ<óÏ8犵ë?|óÏ<óÏ<óÏ<óÏ<óÎ>ÿß}÷ß}§ß<óÏ<óÏ<ò»=÷ß}÷úõóÏ<óÏ<óÏ<óÏ<òßH¯µá6ïÏ<óÏ<óÏ:ÛÝ<Óøý÷×üóÏ<óÏ<óÏ<óÏ<ñ[|õû}õïLóÏ<óÏ<óÏ0ö×8Ö6÷ <óÏ<óÏ<óÏ<óÏ<÷|=÷ß}ø<óÏ<óÏ<ó˘Ëß}÷Þ]ÿÏ<óÏ<óÏ<óÏ<óÏ<óóO½ë¼óÏ<óÏ<óÏ<óÏ>9û\÷ÏýËîzßÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ2µÿ}÷ß^ëï<óÏ<óÏ<óÏ<óüóÏ<óÏ<óÏ<óÏ<óÏ<ó÷òÇzç½_Ï<óÏ<óÿ}÷O}÷Þ=ûÏ8Û.±Ï_±ëíyÓÏ<ðÃŽ8ëŽ8ãžóÏ<óÏ<ÿlúëVòÝöóË.u2$åð¡ái=óÏ<óÏ<óÏ<óÏ<óÏ<óÏ=öïý?ß}÷Þ¼óÎ|óÏ<óÏ<óÎ|óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ïÿÿÿÿÿÿÿÿÿÿÿÿÿÜóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÎ(÷ßkߎ¾{γë-½÷ÝtóÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÊ=÷ß~¿ÿîBì1ß}÷ß<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<òÓŽ8ãŽ8ãŽ8ãŽ8ãŽsÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÎ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùóÏ<óÏ<óÏ<óÏ<óÏ<óϽ÷ß}÷ß}ûoy×_}÷ß}÷ß}÷ß|óÏ<óÏ<óÏ<óÏ<óÏ<òï}÷ß}÷ßjË;>A0Ø÷ß}÷ß}öÞ<óÏ<óÏ<óÏ<óÏ<óÏ<ã,²Ë,²Ë,²Ë,²…²Ë,²Ë,²ËÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏ<óÏÿÄ,!1aAQ 0@PqÁ`¡ð±Ñpáñ€ÿÚ?ú¥¢»2 †C!Èd2 †C!Èd2 †C!Èd2 †C!Èd2 †C!Èd2 ‚GgÏ{°‚I•¦®4Õø¥=®{Ýf4!ÊË_Á%ß$S/èpÒÄÀæœ*Ð¥ÿCªýÄ­ ”¨×î¬pç÷A#£Uýø+kQ!!R‚$˜ÜT“q·ÉwÙu­sÞñ–>½Èd2 †C!Èd2 ‚Ggáoõ­x[üªœÈÝl~HÝgø6BHT¿-¯ –IceÙ,–ü¶¼+I¨}jªª©´¯§šd~E),e.4ñÈ¢¦1¥ò&Ó”KOBK5Wè­–QU*¨è%%–Å—£ZÔ–®ÖT,‡4¡I+ • i|‘lN„*šI{:½¾ï¸ÒUàœU%4ê¹›…,­ ´å ›³ ïŒøv|ÊXg¡â”Ñ îJ2&,jWŸ4±Í¥ãè»%$±,N‡¿ë1?ôX W\èu šœ9¹•CÓö k‘|ä•¡¹r%&©I% š´75di)Ô„^‘n)v3áYpr%ðcJ2ç[ ªÝsYK/Be%±-‰lKa&J+v¥AˆÄb1Œ]%"ªƇÁ&èR”Qxô°ÆÖ:Ÿ¤ïlf³S9œJÔI¸Ýè'5]{“‚%±-…¹ ÷,Oµk¥4²ºŠö/¯¡œBÖWdÐÑÂXË#‰2mù!);±ßèT‚/ö¤«‡9k¦è1¥ð…s|Ðnmÿ?&,‚81G~ÉÓÐÆØH— ”¤lÔUެ/^£"à@ž ‘9‘2ý؆ŒSˆàÇÙŠaŠZ£M_šÄŠ£«ê¥a‹n+®k"5ÂI(]«IÜlÓ‰%h%Yv-MÆý8’Øl¸]Ö`!°µ¨švñijc¹ÓTœÕv·%>ݸR1¥ÊS!;BFµŠÑPá™uÔ3@ßv6Ýø¦VbZŠÐ$I]šÈ‹JãYŸ#VŸÛð79É]bË~¿Xigù‘5G¡åšåÓ­j6Û—Ê”Žœ\ò„$®Ï(4>‡¡°ºhèøF$iNÑ+íÿ?Ø¡?¿Ã†BW¿è²–‡ÅIíCCV ôF·3Fê­akÏ(Ž©ØJ(¼MÆmAè1«C€LÐf¬Ò¾€ZËêÿþœ©^+Jl4]ØI²õ,$ݹ,úñ[Â21BEžÿÁ 1ò&¢'’ϯøˆÄb1Œ#ˆÄb¤Oü.ò—Kÿÿbñ7¸+OahšŸ(q:Áqh†¡ðµÑ¤±Èd2 †C!È'kÈÜ)0³ 0³ 0³ 0³ 0³ 0±ì.[Ü¥ÿpHœ@Þ[û—Ì Ëák£c‘¦œ>T›p¸\¹. 7TI)ƒI8¸ÔÌBg¡ À6@Aòª°†ä7!¹ ÈnCr܆å#£`I)Í()3z| ¯D5ndw[ 7 Ú†çDB©Ôhnµ4Vy. !Nƒ,$„ÏR.·‘J ”lÃû Îr+žÄ¹ûCÞHÂ6î(F"”C&ÐÄA¹€Äb1‰jœ‰)® wõô² €À`0 €À`0 @üÎI$tS"f¥ß"và{Ê„ˆ ™=Fšpù,ø œ¢‚4…b*‰où0U§àiXB¬"’ÜoH¯ü“™$O%ŸÏcØö=cØö=cØö=cØö=cØHÓh¹™Ìæs9œÎg3™Ìæs9œÎg3™Ìæs9œÎg3™Ìæq5Â}½‹¤“n'‚¨ÔPœO¤ô­vö.“BGaÑ6)-ú(Üûù—PœÆä'GŽœï¥c·FÒ‚[ؖĶ%±-‰lKb[ؖĶ%±-‰l$–"Kb[ؖĶ%±-‰lKb[?ðWÿÄ-!a1AQ‘¡ q0@±ðñPÁ`áÑp€ÿÚ?þRT‹/fY{2ËÙ–^̲öe—³,½™eìË/fY{2ËÙ–^̲öe—³,½™eìË/fY{2ËÙ–^̲öe—³,½™eìË/fY{2ËÙ–^̲öe—³,½™eìË/fY{2ËÙ–^̲öe—³,½™eìË/fY{2ËÙUk¯æ~‚IS§N”ÓÀHð~-Å_¡ÇëÁùŸœ©³¥G¹[Í{Y¤M¦ò˜žE¥Ò_°˜ÎpSË$¢°ñK­ióÜvÓ]½‘$Q§ìjªr¿êÿ£·3• ]kA§ìs%:þŒEwçcõ«ÌÈd2 †C!Èd2 †C!Èd2 †C!Èd2 †C!Èd2 †C!Èd2®Ï1,½™eìË/fY{2ËÙ–^̲öe—³,½™eìË/fY{2ËÙUkð¼;𼎗i(ÔH«zðe;{Še:´2UˆéÇü/#¥© %`ˆhI—N?áXÉ£µ±ÚØílv¶;[­ŽÖÇkcµ±ÚØílv¶;[gñäèä^ÂÚŸ…s4ür±BÂt4š†G]ƒQà¤)šÃÉaV_KqQ9¨ÚM-LcÃɦdAéjÓ-Ì=ÍÖ÷ZP„„¼oŸDæb³Á:"¿èáì`‹_ÙkO–B•—]üš3?`ÓNRM¸B€ÒjïF&ËãZX®¦Ä)™ø¶’–4N“j{ÀÔ𨡡&µJø¤–5¥õg¿¯3DÕ ¥ Ñ+OˆÊŸo¢’#ƒëz¡BJT12JNÿ“"e#ù`†ò‚¸”(j…¶Ü¾ª&BQDJhÊœ’œ+8Ûæ^¸úƒÅøA$,<ÆHëi"‘ƒêASÃÈ„MHjCRÔdC%¼òpåËåòù|¿åIÔV„$·ƒi)f^ñ¶Ü¿Ç¹–CUWø]*Ì%äXƒhg ði§ÏÀ³—1xk—§™‡½*Ó7ÉI’<ÆÕ‚0g‘ccôDMSð†l¤”áI‚Ö¼ á´¨…‡»C­ÕI„|¡6¥,§ßþ ÊLEå¥.$2ð™hЉGnœ“RÝø._QL<ǧ¢r“!k#ûñŠ’Pˆ°”䞈J x`¼Å@ðK›&HêBíÀÕÏ÷É=V4àd§?(1~¤&WV>Êm Ís!­J“êÄIm·/Ò¦ÖNb.Ðß™‰?B›UBVbÐÛ˜Ù‹ðÁÂv4/%¡<†špÿ☠¾´$5"ñÚ4Ó‡è, 5Šôìd–b" ¥B¤ItjÅ(b,FR™MJóP)ˆÀ¦’Æ“Åì\cBz8 9Z@š#·'M>ü‰Y¨ ¦S$¡.üŠDݽ i¼÷÷¥LR޾]1à$’Kib'>( =ÍèíÁ +ÈÇ13òÝBxJp7MÅ¿Ò.šþÿÁÉRpý¢®”HŸoÛ1W[x²tzF’Â8$Y¨º]'!žGšÈJuÖ˜ðE+¶Ü¿Ä¦ÕQŒTg'æZ 9ˆÈg1üŒƒ°vÁØ;`샰v3O/Ãû-¥V'`ËÃE‹0+ˆÑbú9‡ödIJæÃDáÑ[–4)ïÀ°È_ì­uˆ$•ÑÈü÷íÑóv'„ÑÁ*ËÄ“«zp,­Ò¼Š„¼F6Ó„ÿÁ%dÉ>D,ˆ‘ÑÈüHØØØØØØØØØØØØØØØØØØ˜ÕüoIp\Áp\Áp\Áp\Áp\Áp\Áp\Z–Ÿ§ÇåIK!1àÜTNTQDº®Z‘"âöÐeñ¢£×዆Zkʵ¦Pµ®æh܃‰œ±¯brôó¾î*ÆZ“Èìý–n*Øy:.µ`”Üa7*À­£ÇýĤ P«Ö†9µw~^A\`9ƒÇìpážI×ÂüÂpÇ:`>!‘b¤¤°ãéJø!}ɬ‰:R–IÃ)x”žTÞLƒxZ·4x† ¶(½t"GVSŽÔ©I—Ã+{úÓ ¡áqV¯†E ,@RÞÔ¹• Ö/çAøj o$Æ…d J¬­Î5¸ˆ„ w*9L u‚“ŒŠ ÙdRI¹»Gfü'쪚ÌkÍÁâé@Âið)+W'=MÊ/gQüFVMFøþ¹|A‚QÒ¾K â9Œ>¿TË QqjÈ®'—VøçZ¦VŸ§ÊMHQÃ@$/imÿ)„æ²Í–"#zW‰Í”DDoKÛ ã‘¨s¢0Dɰ÷ ¢$£0F|)ÿVf"äO97Mâ(*” Q=QÀf/P†l²†àÚˆÁC`ã.¾§`T‚hÈ\"ÄÙvÇʈÈ•b؆æMŸ2¡üXax ÕXÛ¨2´­©ª#A°[äÖ£Œ¯#“yâ~„¡>¡áÓzˆãòeèŽ+dµMð7Y,­Çá9›œÙ`_˜^ôL5@*O~B… ¼µë{e6&„d„T(…pM¥a<¾„ X)H„’‡ ¢þ4 À€¦‚¼Î©»nE¾,"R«`»EÏ´0ùÂX(š{š[Gü¸£ò–(P§#`ó•šI‹O–¥J•!A¬‹cez‚ÝgÎl+ȤàE®Æ|ÉY¦ °¼…ÃÇå B‹‰¹GQ>äXDŒ±1ôªT©R¥J•*›±“•mc@ª$ª ?H¡B… (P£[öÊ€&Uƒ:Ô‘u“³³Õ—æ‰v†„ã 8p­K^¼äæ*Kr×K©ir—†~b… (ÈØµ BFLùLX™¿!£Ÿ‚Pþ.ŽÏ„üʶ†Œ£bjˆ-uR±åmzR$˜C(ÀÝ«®)$ê4¨dXaE÷ÖiXØ0Â$‹ï¬Õ€1B2 ì»b婪}Z%ñ°Ï HÕY„²UÀ3KØp ­»&7fä©#Тð7ìù™øÀå[Æ´D5£Iãבn42À€ÒrAû D½jº_ ªTäQf¸i&Ø_.Ôe@@|ÀZÞ7‰“ËZ&)`Üiþ]e˜;/, ço…Ô>9›Óœ2² ¬¤È&¤â+Šb›nJ rÅKU³¡Á,›Ò‰#’šRÎÈàsÔoRÅH«‚”Í”¼çê«È8%J‡3ts¿ž•q£Áá8#’t`ÉxŽq51ð†ŽñÎ^TÁ©³"½ñQ/DD8F“4ë• †–hB^kHÉ(X‚û×{â|!)Ò®¨B6)V2“mJÎÔ‹9ÀH%˜ÌP-âƒÞÍ'? +-0®wr{7´SyA¼÷†Ä}\9€ËÀ7[V|™ºÅƒ‘ë/ÆÆɤT&"øŠ6óÁà]‚Ý´ ¥”ƒ›—$ï«…fŽªxíø3OѲ’—Äó8<ô£.àݰÁ_äǃQ…0ò^-Æ^¬í)è?¼DAmb=(±(jØáxuÚx‚$‰¯Ö,-‘8%,ˆjÛ<î96åH~à°›ŸZA½¡~N¼ÛQ ·]Þ˜4ú⢂†z›¥P} ”¥ÍŽ9yšÐ`8„ˆá?iý¾fAŒ/.‡‹¯Ô¶³U9çÑ·/° ¢Ë–ðÙµ,º,V9=›éôî§ào]v ·»pÝ|rÝ·ÏØZÆÀ•åIâJsºüÊT©R¦BÍÁ‰ D:#¯Ì¥J•*`S¦!7˜0²m<>üÓý€ØÄÞÒd“:Ð AYùŽ:tëÙëÜœLDÃó:téÓ ûdêI©‹çìD„u©q’´u ±Ë5‹ÍˆOôÜ·Ï¢°ÕÒ®e_Üþ¾Iz‚$ºÊñM×õÙFŸú'7Ÿg¦8Ô JùGÒæ[•’2|‡")CŠà9øN)8Í‹›»¾û £Oý ·Ý3õr¶ÚÖ~œ:q&åhª•`*â½Á v7o±f‰^ ¯Êîþ(Óör2a¢Mñ‘U´}ä>ð/‘¢Ébcy@ ß?Ïü¶Q§æ¥+A8BÃ$ùªÝÓ¡Vö§ì2?P*€]Zâcäg„èÄ{E›>”T-Å}þÓ-û¨Áa…1… O a%0^Ò‡‘A9¹Š~üÍÐSÞ]AI¬ï’?´Äo±=t$¥€O:þŸ…X%Å'…:Ó”|ÿÚ²‡—úPÒ~Ãù FŸåë$sxæÁO:5üŒ)"Ì*9`ð(8Ò&à& àðMÈðŠ@˜s<Ýü—•iN]pLŽÏÞ¢«Sk—pê¥Ð™´å™  rzÐh‘3Èb“—xÿµÅÈÔ?â¥óå©|¯†ŠKì%3"äÿ6 HÌÌÞ#•)7@ü¢dÁ)æ®xŸ‰”iùþù8íc TG á¾yR¨.J2®+•ûØ\òx›6©Ü¬2px½Oº +€8­*LIýžƒgN‘àò6ô ª\HY)"©èÏÎi‰àK Ìh9xÇá¥~ *€ejsŽ™¯n/²#L1EõØÖñ :œ¯öøÝ€ VU©¥2YÉ£Ÿd…‰ ´GFÊÂHž›¼yçð’?³ÐLnE}xЧÂÁÁ+½F$!6.ÛZR})œYÂu¥‚,"#Ì¥S¦9W³µ½‘Ú[Ò³U` ÁÞœá¨Äì -É2MF'`YnI’iU)EŠ,0Íè’ѼÁBe›SÍ©%±&é˜ñ¥y‡9W³µ0”H›5 ¸ •&Ñ@}IH#©ð'†Ðd|è†.$\ðdûvœse-â¶67ú’F2›A—}(EJ4GŸž80HÙ)°°v['’sÂJ4üKã/8‡¤ü†3ŸB^]P‚MKÏ…Cwq „ÁlÚ`˜pA2Äág;äÈ­ÜX¦fL]„î´”Ô%…FH~)†“æ@DqÆÚ´ A FÈ-…CŸ×j@‘2ÀâgУÀˆ9l9 Õ¨ƒ\™Çw®ŠM­[5>N¿!B… ÐuŒE¡ƒì MØÈ‘(—Ÿ€h ~"Ò¤ Ö*'¶ümò]ü jFÆè _ H1d6ZébˆiØ™î³w#¢`…2ŽÅ$ù1»3:ÑSš\¾)bÄŽhOaNâ#QºF§†€Y˜mI± bˆ&b±zjôJàM/­*A„äŽD`0“–p £a HK‰oŠj€…ÉTH$ޏ<T©)…1£øOÖàÈgÄ(@FFãðÍÚDäƒKbÁ¼¶KºÍõñéÚ—<"+¿²¤³ÎÕÊ©¨¾÷i²ï×1r ^óXo€>L—ð5Ø=pT¿#u”º·Y iùáh‰Á+†¥ù®›>”ÊÂÈÜn}€6øc”8ºìãõ€n7Ëwwî_úul‹Çvæu5¥ƒúyÜp›Ÿ` Žt0üîOfúSÍ׋Åz4üA§àÁH$/áMº9ü‘Φ¡Œ¹ú¨u¤Á$‚Q-@ÇZhI¸5Î|xäó(\1˜b^/¼é …î¡âpw«÷ðIÈ2ïDûNI´ 127ÿKåü/ãðÌ<òˆO‡“JÏ+ÒŠrÃÚÍõ„<ËéV¸¤ÅÊ@¬oj„¯¶‹V"bczv$R„–zøL€ËsCùm7p 3¨Sňcàí["/fÑÆ¦ª¢IؼÚw¤°#Â&fgjK„Ìp‰™™Ú˜›Äô¡±‹±0±ŠM7#2VÁkß% ðY,òw¾¼([¯;ƒ€IXÍ* ê{sΛ÷’öÌEY]Oаª£ÄÀ”ð¨.fKÜ#Æ(a°„•&Œqûw耪ÀÚåÜ:©t&m9A¦B蜞´äLò¤åÞ?íF1r5ø©|ùj_+ᢒç{ Lȹ?ͨ337ˆÇ¥D MÐ?( Y0J`y«ž'â_úu“{ŽŸï‡Å†J€ßPH³­ÃœÚ“_ˆ¥S0φ™ŽÈÿ 2ÂPyOý£©”I‘;JQ À¼fÑÆðøPB‘µ&IÎÍ$IkxˆòJ$2@»ýhA‹žwgu29‘þ]°£ˆ£ÖŠÙ¤¶`î³çòX/€¼}Ü1¡/ᾊ¢ Æ‘ Ѝßí_„‰•ÀV•¦$þÏAγ§HðyzPÕ ®$,ŽÎ”‘Ôôgç4Äð%„æ4¼cðïýÓpH¢&9ÿ€Ù!9üDIÚBÀ`˜±É&"­ìš’‰R‹PØa±­A Mˆ²`· š ó:¦í¹¨}@L”YféÍCÊqCʤ&gDj-S#]‰0³«zš ó:¦í¹£Ä3Ô%×j‡qKà ËÓ4%6"É‚Ü(‰ B$M£h¥U 2:Y`Öå#ÂûY¨ó~Avú%v ]©Àƒ˜Y„”C¶Ø•`5ZšS%œ—ú0iöHQ¸’ +Dth¬$‰é»Áמ ÿÔU³c4ûÒ*F‚}Lð2ºS( Ç£ÀÓ-íöçí80æÊ[Ålloõ$Œe6,ƒ.2úPŠ”h‹q<>p`‘²Sa`ì¶O$æ?‡êöÁGѳáÛÝŽúø­»B$ŒŸX%ƒ4Ö:ÀY·Àåwj|äJ‹Û5wo˜‰µ ƒP$ÈÖ f»~7G®Pa΂Î"UÛ~6ù.þƒ µ#ct¯„ˆ¤ ² -t±D4ìL÷Ù»‘Ñ0B™Gb’|‡˜Ý™h©Í._±bG4§°§qƒ¨Ý#SÃ@,Ì6ƒ$Ø…±D±ˆØ½5z% p&—Ö• ÂrG"0IÇÊ/Èî`ùKÏñ/ý2º»á.q;ÒKÃ~Œ2z”êeðuP!&“èC(0e¦ˆwR|PCÆ‹I`ù•½wñY6M€ _ml«þ¤M+Å=7‰€ò &3Õ•½|H|~Mó¥ ÝCQ„-ÛçJ’Iae–效ò¼Ëd{Þx¡««7·µÄFÊ@È)i`Ö¥ýŸ5 f&¤¶¶†Q»|–ÍántÛB¤­ž¦“3†Ì5B&ºÆ¦$w–Ï…„„A9B×S>T.,À_ÆúÝD3çQ&ÅÃÂcÒžð¥Ò?Ò¿‘F”©w# ë/"Ž‚Oö—…aUN '肉ë/™½cï`Ò†¨õ9 \O¬»õÌ\ƒW¼ÖÀ`“%Á| v\/ÈÝe.­Ö_ÔŸú~ê8ÙŽíÌêkKôó¸á7>Àèaø=ÜžÍô¦›¯Šô,iú£ÿOи^ê'z¿œƒ#Ɖ±Í9¼®x… @(¤ ÀKOIXVÎd“Æ¡–uÿ`ñ 4ˆÜØx²ïúËÿOÍ,8I—Ú¢Õ_I•‚Pž½M éϪ ÓÁTÙPW†›ÙÊ›1x…óÿ4ôñÑþÇ­·½þÌPr¼þÐÿÓÿOý?ôÿÕÃü–«c…{¾¾ï¯»ëîúû¾¾ï¯»ëîúû¾¾ï¯»ëîúû¾¾ï¯»ëîúû¾¾ï¯»ëîúû¾¾ï©‘r®®Ÿ§Ÿúë²qý“µÿ§÷#¨Ñ,—}RˆnÈ|‚Z»'š Õ$‹˜,[ ÛTäHòÔR ­D#¼ Å!.%Gš xÓ—À(¦è`—,TZXÊbP,”¤€–MÑ“4rVˆâŸ •H˪[Æ1jP*€]]("ñ Hð!ý~©µÿ§è¥ÈÜ–ËšIÅE=€ù¼©Ù^Bfô!ä|ÇÀê i¹Ì1ÄyC^†¯‘G˜¦™i>çAX%bž!F¶´Ý{øQõ¶‰$sÔ(VÃ(=_?‚f%"â¡jN›€Y/;œi VV­È¶oô6žo½G‰ˆ10y%J•EPPåL;ˆ,ÄÑUaœqfÍï÷ïÀ0|;'šliø&H^… ™D¢ Ûm"–ã3b"fw¤²%Rò£¯U¹W3½Ä&1ˆ¸Ùh\íè”Ãm"… ™D¢ Ûm"ƒé‚ ƒz›Š@5™/˜«Ç¸ˆ‹†¨Úh‚Çê»_¿Ù8þÍÚýû÷ å•)Ú}7N:téÓ§Nžé2(yIø}GN:téÓ§N#Á5á b,Ëþ7~ýù§ïßš~ýù Ç‚Fð)(ZeØiôLj —"äÒ2LEt™F¦?d~üÖæf€GѨû#"˯³Áúã÷æ…"ëdàÆHñãÇ>ãfRF‘@]¦ÉbÅ£±‘ —¦U¶ûm»Øv.1^õ§½iïZ{Öžõ§½iïZ{Öžõ§½iïZµÒYÇ1W½iïZ{Öžõ§½iïZ{Öžõ§½iïZ m!¨rˆLO þÍ8€‘†Ù>â,X±bÅ‹,X±bÅ‹,X±bÅŠ›D”ÁX_D×zãønÞåÇ÷ø_÷.?¸õߣâ©"Â`ÄÃåô”©R¥J•*T¯J` 4¯œúJT©R¥J•*b–«,Œ„ €cÙw.? €.;,öÏÓc–@±*¥…ù* ‚……8Ö‡—¸/„×rã rp¬ìðð§8"Y!$A{p˜Ö§_i0 j5* „X½ÓEÙp‹‚˼k0Eœ­ŒF‘ê#I"H‘'‰Cäø—ÈóøA-y¨,[ ñPK^Fê Ã|R଒ Ñ{MG+B 2 Ñ<Àƒ^»øøÓþåÇðÝÉÀ4»QÌ‚JõK…“{‚éKÂ[p¤6{<ÔxRè½¢ ¡{oS¶u˜#˜f¥T$eÕöÎj{Èat ÒJ‡ÃH¿x†•à7qžk2e1ÿT‚hˆ¢t™¡L˜Ø@­ïŸŠIM K‰™e >¥q •ÎÀ_…Y««Ö ¼bAàf S¸cfɬ'— ® Rã? A®H6„úbW‚xgn9 [°&ûL‘È©Êq뙤)Z‰àFT† „`Dÿ =Az!ËøÐLÙ‹•æwˆ<(†Œˆ7Xç58Ò2Χ­°݈þP|`ijy/ÁB¸|( d”6?è¡Z  ‚'øQº¶ÒÛ’í"¡x-pÎÓ| D´p¼4×2+‰?­2Y¦Éÿ-å^ Ç«@ˆ`ZÇÂÀ`áxSx ²ùJˆ7³ã^»øøÓþåÇð‰huøTï‚´ ”i•¹ ‘zkr¡6WÒ—{fI—=h` æ‰/âÔa.IžUaÂ!ÛHm-¿åAH  WL«Bôð§}«ÄêiJ ÀHbTwŠ6¨˜Q`lTØÄØH€;4§½ 2",^ ¶)HóV·'PãMrÊgcAÛe0Œ›ÇœøS¸Ö Ü%EŒ‡ÒWy¿Grã ¾xMh¼×Œ!o4­bB0E§Õ¤?•°%ä玑Ñê³àÙj×REð(BÈA8…Þ(Aq#Öe»ë]³Ò‘EÉ”lÈS6ios–°KéZÄ „`‹O«NîŸF2ªa² Ë9\TÄè­ ‹ÆôŽó®piú'fDHÁxËNîŸF2©Fà`Æ@€µY(‘)µ- :üJû’ƒ5‰ª<žÿ,Bì΀„Ç OÓ^Êè8™yFÁJ'ÅêG•ñÃÀh×QWÚ3èÃ&R‰;Z“qSfƒ4N ø]dåPh ¨c3áRšºJQ{cZ2°À[„uãHæUÔ*è•'ÊÞ ¸" VùQ&1@¼WN·§‹à ¡Å¨Âa@”Nm ¹šä0↹øÂ0 ئqS\k{ ÅǰÙI–ËlÿŠH#@%j0ià²d±tš `ˆX(K‘éŠ(Ø=Eʼn¥@D&Df ­«B âŽÐJª®9!k8¥hzæ |Zg Î6å2,…±Æ¥ABT4D±(NçæŸúb!` ^|+b O,y†ßÂq¡ß¸é´DG^ܾ"ʤ³j0íÉ$XÁ0'§*¿¡n@pV8P¸qÌHÌãðÛ4úI`ËLE¦­”LTJ¨e¤FŠ©àeêO]«´qÐãËKUåˆU˜+Õ†°KáQvi!+°»æÎC ­Q‹M„X ÿ­ew‰–6>U&þ’ i›ðSLfá[TÁÒô:!¼7r<ÊcVK–K¯Ð‰zˆ×äð©¸O¢´'hœ°’p<>ÿ×zãöp… §€é;Q§ºKÁ7»v…‘L¢¶ÚÇê/_úŠ%A3_jWµ+Ú•íJö¥{R½©^Ô¯jWµ+Ú•íJö¥{R½©^Ô¯jTà¯jWµ+Ú•íJö¥{R½©^Ô¯jWµ+Ú•íJö¥{R½©^Ô¯jWµ( q'ÿ /ýzëÓÿD‹Rµ`lI”¡B…€…$–L<¹$Û!` RÓ‰W#Óƒ¯Š“F.GìžEmæâ^|)ø œ×ƒúW£VÎÑA!$ƒqûÃÇMó N˜®k \LN¿ “b ã5¨‡ßÁTaùA†UXÅû\ß‹ÿYƒžà*€[WÎlp C’T‚Ü8¯9Ѩ$¤²i[í;ß JGAe› £ˆoÙªmÀ¬mrh‚ÜJ&€âTÌXx¸ø”(|Ã…'Ôh|ÄàN ªP½I RkÔ£x’kÑÈ1G¢‰øÌyÕÃQÔ4˜¢šPÆ.×ò§­< Þ]sjfüà±2u^4@°‹‰ NB ç¨ÊÝ×?i`0}µ¡Kr—jj€…ÉUeÉ ` »ø­Š<±æ4`û_R[[C(ݾKf¢¶˜N “%øÔÊ*Jã(kgX©CˆÂI âvÞÿF-Ð]rïKÊ,57N\*Õ3ãöŒEEæF„a6¤ ¤f•i–&#z"ûpcc3ì/ÍÃØÓÚž f"gÄTÌðµÈä|(vjš¼Ö¡lB€V³* […K¹#(äMéJ<ØfâYûLÕö—PF¹žË£ I6<ߦzk’Y#Š´®Þôɨxûlߎñ$ÂA‘A‰ù…*T©R¥J•*T©R¥J•*T©R¥J•*T©R¥J•*T©R¥J•*T©R¥J•*T©R¥K“¨•‚Bö|¿þÿÙzuluCrypt-6.2.0/docs/zuluMount-cli flowchar.odg000066400000000000000000000334321425361753700215620ustar00rootroot00000000000000PKµ²½BŸ.Ä++mimetypeapplication/vnd.oasis.opendocument.graphicsPKµ²½Bmeta.xmlSÁnœ0¼÷+Û+ tÁrë)R+u{ŽŒyÙ:Ù&lÿ¾– 4«jÅ ¿™7óžÇÅùk½7ÐF(Y¢(‘’«FÈS‰~¿ùz¨>êùYp âCÒúXæ9ª4t)•hÐ’*f„¡’u`¨åTõ W Ý¢é,´œœ[!_KôÛÚžb<Žc0ÆÒ'åyŽçê mø×ºQ ÇФ`pDxÅNï55a·–z ÆU™—r_-gÛK)u5=Ñ–ÌÖI&xù_Ѧí½ŠÖçªëfÝîvʤèîm3a?¸>é¦io]Šóc·uf™ÿ&`üŒv1øÿ´ùuÚK 6Á#¨ZS6]GUÌ—Â5ÌÞ|' £ØSŸ¤GÑ”Ð0-ð \Ñpº'äÇ(£Ž“D^‹‹4º°ûÍ çÕcúóÒõCmOáx ¦ŠÿA_Žì $8²ÒÕ£¨5|Ÿ'ÄIº/þò(äp~:g_½Mõ©×ê¸Å‡4Ik€œ2’&Ùá@‰jž%,o8O³¸Îò‹ü»Ò¢|}«f ¥±‚{󹪧æ.8ƒ´%Š ÂUw›Ç·^{õPK^ óÏ»+PKµ²½B settings.xmlåZËr"7Ýç+\]Y$ ÌÃöS†)ŒML ÆÄàI&;Ñ}ÅjÝ.ImÌßGà0Ð`¬F©TÅ ?º¥sŽ®®tøêókÌN^@Hм”OKÁ ð#Ê'õàiØ.TƒÏ®p<¦!Ô" Ó¸*HPJ‘'z:—µÅëz ^C"©¬qƒ¬©°† ðÕ´Úúèš%[Œp}Î:mˆ|L'‡¢,F¯ÏGÄ7ÑfÂbaVx¥T:/.þ^–1e‡r™±…ãDk±ïlE8…1c·V½Pµ_ûå›öåf­¹H%h¬üaå«¥q? TAl|ädùØh¬š²öBaöæ=AÖ¼ïç|¥Ò )€ 1 V/Õ<Ñ/)WA£p^:¿*nã|» c• ^®V.*¹á§‘šfá_TÏÎÏrÃßL3õWªÕjéPüBL’å¼B´É³ìݲs´Ã‰ù!ŠaÖ‰6dJ%´+ ãe7Kü*hÔ‘K{lÀ4Æ„IȃßÈ7m| ôŽp’ Ѱì‚W"͉Þ'¸'bB¹ôGb¾w)‡G0ÓÃè/U[è‡ÞYú¨‘ŸÅôY*ïÈ&›‘¹G÷5®«¹d2ÐGíÞw¸e4¦œ(è#›[³uõÕ4tY÷Rù¢tðµ´¹šm.[´Ü.™ëÈ·‰O$|:¿Ö"Ä:ŽçfLßhð£w¤u…{Œ<˜¢#o0ÕFn1>áUÝFtgÎCc ZSÂ'ðˆ‹JÁƒO@öA<â,{SYc³¥c ›®cï\Çý]A÷PmEŽcàš(ˆiföê˜þj†üê÷× 92ñ!a§úråG‡ù|·ö|èm»îžy¯jwh“°ZÑôté/ˆBá‘ã8ÚìkË8¾ý ëøægi3^CsËM¶³¢ËD4º‡ÄúOÄøg¤Ä׌‡ë]¯—½†ìÔám¥ÅƒTØÀý‘þR3IØüI‚¸!Š?±¸¦J/th\áé±»£õñãO©ðó’ (—1üTâÈUç1‚èdO´06½OÓ¹jÊ£æ}6»v^YèFzCäÔ™3rä„1I™Ò´•Nä‰:$¢ú”8¯iâÆ{GTènÈ©ëíøoJJx?å¡J}¥Ùi+ækÄg~zvë×$|öQ“¬sìí>æ&Ñ—ŸŸÎ“EoSµ/¬ä'¸£Q6tyinZƒÞóÕt´ CÊÀ¯†Ô‹~Óò½å‘óuâJ‹$z!gs«º"SO|«á°Œ›Žy¨u¤4h£ˆIfAàXÞõuØŸ’Liûº\­'ý–FÕ¦Ùó´,,ˆŽN Íç˜:&vÉ|»/°ò&†³‚Îl¥f™¹(3Nõ’倿c*ÝL >Ú øºø˜õ·Jgu~Š ½¿vs~J"ŸtŒ‡'lO¬úX…b+ŒâÖGÙÅ]ÿìÐøPK’ýÁ.!PKµ²½B content.xmlí\Û’£¸¾ÏSPNr“-0’×twåP¹šI¥²»U©Ü¤hmv8ð¡÷%r™÷Ë“ä—8X²ÁÐY÷öNO_ ÒÿëðýgçÃÃ1MŒ=/«8ÏîȲÏÂ<гÍÝâûïþl²ÅÃý¯>äëuòU”‡»”gµæY  àΪUÓ{·Ø•Ù*ª¸ZeAÊ«U®ò‚g×J¥^ɹš–ª~Jf³Kb•»æÇz.³ ÕxƒÇù3Kb•;*ƒÃ\fA  ªìë|.ó±JÌu¨§EPÇg«8&qöùn±­ëbµ\ë@¬¼Ü,‘ïûKÙÛ/8ìéŠ]™Hª(\ò„‹Éª%²Ð²£MyÌ]Ÿ U—”íÒG^Ά&¨ƒ ©%¯€¶+sÞ@*¦_ûÍlíÚoF`·A9[Ï$±®*$š¯*$RyÓ ÞŽÈ—-?A§¼|úxÒ«2;— Õ  ˸˜½Í†ZåÏó¼_ª`hŒ].Û¶³lžêÃUòC×¼TÈëäa„=ây:С%P˜|/T¾7"D5€—MwO\E£CÿýÓÇoÃ-Oƒq”gl›|EBþë…FÃî¹ú~/}‹º›u.—Ø­*äÂè/ç•ÉvW-\ÚÜÑB%H '-ª»$áµÑtŠv°ÿEóØt™"»º[ü÷?ÿî—© ¢¬Sò¤qf&Á#ôôªä‚*õ¦.w¢on ²1;L¾Q|û”>æI‡Ö®â0D´ƒ))Ã<Éa=u¹ÑtìUü#lÓ¡¿•¸\Ûé3pÀ?‡ªB”ƒOæo!r3„ æ¼I„œ"ÄÞ$BôfaËy“¹7Cˆ¼I|¼ÛáóFý4»BÎõÓþ z›~Ù7ƒˆ~YŽZénsíåh-Üv<æÑSÿн÷d!!Jߦ¤hrsñŒÚ"C-tdõÜÖgdü²fnûþÄ×Á.©í!Ô3yjVÛ à—ÉZº¯t´bJÔ$Ç4YÅPÆmÉô§$x‡ËðêLÀx¿Yµ’¢s¤7m]U„,â{]㜳å3Ú=? ëùBú­æ­~苺Oƒ8³Âù¢Ý&϶âÐ.27É1ÅéÓr˜É6l#×n¯ÝžŸ ³„R9È6}5×UÈÓÞO†`þزkç¿¶ñã/R_.P¿­ ˆ&òÿ ‚X irpÒtÓ†b©pvUÇ œtN<'Ó9Á‰lX¢AaY{j³­ q3€&µ}Hà‘÷jhH)ü«º‰ ÌóÏ”ÿùÊé ¡éŽ I4 ,±ÑNÈ[÷{[ä"H7©G „Ù«¡éZ”2MßS9CÓg®æ8;t N÷ypz#pŠ|§ÇÓ…E>,Lº êéá!Õ,¡½˜Èr„NHõhêÁ^´xàJñšÞóâA“(`"X¤,lkºì<ÍH r±o@÷«©§c«€bdÙ®«ª'´Xf´ÌqÆðôŸç:û¬û  ¬B6¬kz Ñ݃€„°í¨Cj ýàB=ÏÍ€„é9¬X‹HP<»d>¬h<_z®H‹I˜ `1Ú#† xä ÍàD~µt‰j©¥À“@åëù’Z ‡Q\æ»ûxwïîãì>ff'®æ>ÜI÷-×½ø,÷¢2¤7:Zz‚1™ÌO²ü==y÷/ïþåµýKÓ&~xxúÍ£h’¿f\j¿u\Žü§…÷ÿPKÇàþ´ õPPKµ²½B‚ì]k££Thumbnails/thumbnail.png‰PNG  IHDRÆg?žjIDATxœí{pÕÖÇeŒmllðu±1 6`À15±ã@&@ȃ 4°.›‡ÙÎtÚ”ÎÎn“¦ûG3ûÇfÒÝÍ$Óbšd›¶ -¯2Ð:ašá^vˆC € ü~Ûð Ÿp,ëÞ««+ý$é~?“0’î‘tÎñW¿#ýt~?” c´Ó^’Ä@R€H Ib )@ $ˆ¤1 ’Äè•Táú–Ö¸‚ãW„,†•*™Ÿe¼.Àý8|IO1 |€H ãqIÚþÖ7¾õ}¾ºõ¿¾7»dŬ¢¥W/œ:¼ýíUÿú+}O”ÿ¦`é?ªŽ6iZÞÔ9%òòþ-oLûú£—O¢<~0>þãÿ>²ú‡:Ïâv¼&©³GË/Uºvñ‹u¯m“ÿ£¢£¥»Â’WS3gÔž=!KJ.“–•súà®ÞÎÖø¤ä¶ëµ¬@w{cfNQgëµüEkjÿ^1³èñ$ßD¹XOç­›7äCÕWWÉ’’÷j¹zqÎÂÕò~Üâåò¦Î)¾P¹/uröäYWÎg;v¶4Tìýý@_OѲ/œü¨½ùjK]¼}bV.?‹ÃG‡×$•~_nGS}RJúКjváÕ “§ùÅѱã't47´6\.^õ®<¹€¼ýþo<-o‰365#ûâ§Ë[Û®_)yö¥þžc{ÞeŠOòM˜œœ–!/óƒÈËq Iµç*cãd ûÚ¤æºj¶ã'»Êæ.þV&&.~tL\GKCZæÌüÅk{:[¼¤'É{’*ßôêÌÂ%—Oùô¯[z:Z}©òÆèè¶:&qÜýó—m~mÝš—ß;¶ûñi“O–¿?>õÞžöfV a\ ?Ô@oFN¡/}ʇvWîÝ|£¯+àùAäå¬ÙóäãLž9··«Mº#ßì»;Fñòõ5ŸËg5jÔÍ~vY”òY,í;ñš¤ÖüäŽ!‘¯~寇—¯W®®ûùVùß`77ü§kÌVe»¬ŒêF*mʬ%ÏÿŒ¯ªvd»<üÍRùß<Ã6ò³x¯I 8$ˆ¤1aHJ§?D8z%¥ç}!>@$ˆ¤1 ’Ä@R€H Ib )@ $ˆñ²¤\{è½7]^–”$|ì¡'ßÄ{\RÀ~ )@ $5§° > $¥¦¼ì•Œœ‡®œ96eöü®Ö뾉™,ìnñs¯ÖWW;¾—ú=ý‚4ÄÇ"õ Ÿ|Î銋$¥flrjnñ7Û›êræ=ydç/yØÝW¿Þ ôc«*ãðkéGvþ’%KNܶóKECe·¤ìo0ãtlÏ;±c¢câêÎU°d,‰É©, Ks]uFNaã•ó Öl8¸íÍîö挜‡úºÛÙ×ÒÏÞÃv¼}ëFow{SÿÁm3WªÖ‰ *[%esûµSíÙ“Óç.ìliàÉXš»;øÓs‹—_úüðÉ›6%§©öüýóŸ’ ¤fd'ù&òú{}öGGþô«€ÇXo»g¾wN÷ÎÈ¿}ûVBRJgË5¶EõÁô¬ÜyÇÿüÞ3Þ®®Ü_ñáï|é™MµZ.óG§ÄUìý}çÝ´ý-ž—LƒÏöm»9ÐßÝÖøÈêÑsXYO!mFÈ&+{FçW w£™Ð ½’2|6}›]£Ú³‘”W•ùh'ùOÒ\Øò ùïã?þOʤûz;[ã“’Ùv&,ù¯»íº2ìààmæ>˜–¿ .>ñÀþ;d5XÃIÆ ®W‹SÃ_Vʘäõ[‹¡b;» ¤¹JŸ–wæÈž´)³¿—“Ó3㓃”Ð8iÃj­}=쪰úŒ!±ï‰/+o>ó~~`'»Ö'MÍ»zá³ø$/cÑUl=zí+¿‘òJFÜÆ>¼|½rU• –1«hi°ÓYaœ®¯ä>>m2»*T»Øo¨,””ªýÜsØÚp™]ë-õ夣©^¹—uªò¯9¶'sp¸9¨°ÏJqÏ¡W!zîÙ cqb¾l6TVIÊ¿ýÜsK»À seƒq2Ya;Ue‰¤ÌÿÁ¬îBseµqrοq óæÊ¶;'¦~ó©lí1T–L–ˆRùÚІ͕ÆIω¢¢¢É[äÀDaŽ ½®¹²ÿ±Î]DîÀ§BÃ#ªwN!¤†ÑaœtI Ø ã¤H*Jsã.T`¸¹"ŸÄìyuÚ-)w¥}¶èU£·qÀJ‰à8Öc«¤Ü5êcØ*)|B#0()cO.ò^¥;TÑ‘pÇQ””øôJûs‹È _WþÝÒd=|Êþ '0&èADîk\W!“á\åAܘJ ¢®+$eiÀ¸»RêຒLJʶìâ ×Ǭ•²3›…˜©Æq]©0.)²©º\WJDy!Ã2«Öœ:0uN‰vIdz¼)1]éo¸[0îêTuåp¶“öF–ø¡èéÊË^Qf>I—ÂRA´]¯Un©¯iª«™Yôx}uÕ¹ã{ùîUû·÷÷v5~yî‰õ?WU@à /ÂkieÃîÞ4»x9K€¡ê¥€ OHòk5G¨ëJ…qWg t'~WT™OZ.L2\˜eV•y#äe¹|ɳ/Ü uD0ÝX÷ÂÇÿÈyÔ ÿËÆ— žX72†VÃû‡²ÐluÈ*‰ÙÀ§Êvr—(I‘ù„§‚èioVèï•Äwa¤Lº¯rïfžž•áàœ]ø†žèKã 0ü{É¿á[­³>"`\R*C¥Êv¢Lÿ0ó‰ažŽm“8þæ@ÿ=Ù_7\I§P6|ýðí{IÙð  Ùj‘ç‹r{ésª¶ˆÖ•:CµÂ¿Õ¬èP DÓ“SÞf­”¥éu8"‡©ØÓ ‘ûC0ðñ`É‚nuE'*{@²¬$áûAv/¥êVÉDÏ*St¸¢¼ª‘Ü ùí¹²ñª9@ZÉ¢G¦yqWúá`៪S4²¿‡Û}Â:Žý‰ÀN°Ï‰@žÐÜDB'í—Š(<3“’ÏÌd‡¤DÇu3Ù!)qqéLvHJD\=“’ Ìd‡¤„Ãí3Ù!) ÖáÔ¬vHJ\l›ÎO;“݈¤<㔊à&ÊŽéü'ÊVF•Ñ4Ĉ¤<ã” ÿùŒ¶Mç—†B3¨>WN9ð¹Î)'8¶MçWN5"A#)—:åDƉ×6Ll7+)W;å€dÁLvS9$—;åÄ"¦¬”Ûrbâö²œð^† *\!Bìê 鈓Ÿ;Ê7ýÔp† ‘ÓKãÒ‘0$Å“:èL/Ð')¸«¿§óÖÍ…O>g¬zþØüA,H*lØ_® t‡v1cs¦›ëªKž}i ¿'ÜZÙÿÂ`@RzQýÍt8ž3-³±É*÷n¾Ñ×U´¬”¶þ¶IY…9Ó¾ô)9…vUÐ* )@ $ˆ¤1”qL¾9Q¶2äc£¤ bþ}mT™ˆ/}ÍIb )@ $ˆ¤1”—±ÿŸIy›ÁÁA¼6®’Ä@RîÀp@NAéÃûóÄBR®Áæ€ï› )@ $ˆ¤"«£qó”˜Ì€ $ågEÛ®Û£’rÄÿæimŽÆÑÆ±&Ê<ªÏŠêÆùlßÖì‚E&g[ƒ{)£ú¬hXÑ82²Ñ²¢V?—mò¬füoJôûâÉÝÃðädNŽA+åx)|_œu–DÍàC>@ $匙7ûãp¬•”y¯šÍYrhOGx4÷_öÇá—w”5×Ugä6^9¿`͆ƒÛÞìnoÎÈyèö­…‹kÿ^qk ?ztl|Rrnñr¾¯2QÎÑÝ›f/g†}wí*¿œòŒ:]sþ¹{Øöm~ýñþ#¬ ëw*²šw¶^Ë_´F>š¥NE11.)î(ûdW™Üû—>?|òÃߦMÉiª=ÿü§äÎ365#{ ¿¯hY©¼ªÜWéšûËÆ— žX7²À ¿_NÒíšSùQ•¹{ØZ¯}n…‡+Ê©ÈkÎŽf©SQLŒKŠ;ʘ-+wÞñ?¿÷̆·«+÷W|ø;_z¦4äU=š¹ÝFî=œ('Ñ—Æ ¨|w’"K΄Œl=®¹`TæD`G8õÑûUaýNE^sÉz§¢˜—”ÊQv¾â£YEK忇,‘¹K¾Ã6.Xûc¶psàÆ™#{ØrúÔþ݃[ߗ++,)%}èå2b4éjk J ÐÂâO>ûÛV¹XíÙ“Óç.ìli(|bÝÿ½²úŸ^Û¶ëÍ lKX5GþO¹%`@ §hÙ‹ÊÕ‰Y9ƪʀ˜Ìàš'¾-@\#)à )@ŒqIÙöîq)î ¤ì|·Š¸wIb )@Œ’rËD†»jk?BHJr•Ã,ÑFIÏI†J%åŠX ªo–XŠ#þ<%%y4VÂfœ ÍTRÀ½@R€Hê+ØÌ÷šSê««saHj²ž´c.$ÅÇ?ú{:ʹˆD‘”ò™ÜÙ©,úb.F¬†Œ¹°±úÃ8š!„¤¸›ÇL¬Ú1’âãy®ÔsÁ¾.a3N…f!)I€2ì&Iu0æBùU’°b.ÁþŽERÞ1$Ȥ1‚JÊ“yž"%…àW#¢¤€«¤1 ’Ä@R€H Ib )@ $ˆ¤1 ’Ä@R€H Ib )@ $ˆ¤1ÿ¬¶HŒ`ÞFoIEND®B`‚PKµ²½BConfigurations2/images/Bitmaps/PKµ²½BConfigurations2/popupmenu/PKµ²½BConfigurations2/toolpanel/PKµ²½BConfigurations2/statusbar/PKµ²½BConfigurations2/progressbar/PKµ²½BConfigurations2/toolbar/PKµ²½BConfigurations2/menubar/PKµ²½B'Configurations2/accelerator/current.xmlPKPKµ²½BConfigurations2/floater/PKµ²½B styles.xmlÝ[ïnÛ6ÿ¾§04lßdý±ÓÆ^œ¡[1`ÀZ Kû´DI\)Q ¨8ÎKìãÞoO²#)Ê”-9òâ$]V`¨xGñîǻߑgõêÇ»œNn1¯+VN0õ ."“"]9Ÿ?ýâ^:?^sÅ’„Dx³¨Îq!ÜJl)®&0¹¨–Z¸rj^,ªHµ,PŽ«¥ˆ–¬Ä…™´´µ—j)=¢^6vºR¶g |'ÆN–º¹h=~e¥lÏŽ9ÚŒ,uS{zÂÆN¾«¨›07by‰ٳ⎒âËÊÉ„(—ž·Ùl¦›Ù”ñÔ ‹…§¤­ÁQ«WÖœ*­8ò0År±Ê ¦gts,ÐXû¤®mRQçkÌGCƒ:ØÕ’ã TÀ]—ã^dÏéÄ×m::ºnÓ˜£ ñÑq¦”»¡2‹Ç‡Ê,¶çæHdû{é}¡ú߇ßvqÅó±kIÝT'åh7µ¶=Ÿ1Öš*'èdW憾?÷ô³¥½9ª¾áD`n©GGÕ#D£q–÷z.¾•!ßú:ÚkÐTÑÐK݃PåüA/<ŽKÆE H2žta•°¥ŒLät˜2¤Ô¨¦<Ž{UÁœ™ôÉëÞ¼ùÖéTƒã°Ø E­MQJ6÷øžÔiÓBcW(xÚ–²„ÕE¬÷AˆïJ̉!ª¦-;oèpBUÍD8Ÿþð¤Ì•õµ)yV™ kSSu)½¾’ÖB®ó/˜OÔߥ9+çç ¼bZJ˜bw+ÇŸø“ПÌ|=Ì’0ær, ý{Ç»¾Ò”ãÕ´)Ø=– ˆàíÊI9*39F·yvKhrA ÀË×W‚³/"ž2àôogó7(q´ ¡´•¼ I’„-7ð*—•š½ æÊçQ%âH-ÖYJ‰$b.ª«J$Ï$ÆL«"ZfÈiÔʺˆD­¶M½{åT$/exh9T=ì®9FPÁ~ #‘”…ØÍY ¯§Ük#JœlHc™?ò”£Þ" Q§¡Ñ ·`A4¨¬¬À+oØ­V]úuàm]aŽ1Û¸jñIÁk¬`Tƒf»¾G%«~ø¡YM>âÍä–£Bv<ÐúnŠ ˆc L.õ:%””[ĉÎ)³TEî”p^ 5FQ‘Ö(…!\¨’Ep°åóMß’@C¨0†Þà”áÉç_´ÐL«¶•Àù¡¡F¾3×ÒmwéFvŸIãƒüü±Ï4IïCª}BÀwÌúVuÐþVc؃V¥×‡Vš‘}/Zѯ]$v²Þ„ Mš[*€ûxìœN *û53À{%±c“ņÄòÐâG¹ó ‡hÎ[áÌÔNœ†rê¡<‚¼”GKŒHÚ#Ó¥´o²d°ÖƒaNS™ÄHÅÍ'÷LV %’BýYW‚$[•%%ŠåýÉv¦á…4Ƭ™òxÒ'£8Ê}'ifIôd(VG(Ç2E­AÊK……{×E£+Üö ï—¾üQ ®M”TÝ2²C¶…ÓÕÊ‹‰Êq¨Ž~Ô"Wž–WÎ?ÿÕœõ+æÔœœ.Ek´{ýð†ˆvŸEo`o¶ùšQçÖÌ8¿øNeÙ1OOÀ!|ª>ºk 'xl@x}ÍΆP ãüÕ!4?#B—¯¡‹³!N篡7gChö*ñy{>|^)O_ž ¡ù+åéÅz<øgƒèâÿEÔ–¸¹±yC¯£-Xn;©tXß"š+D3hnÝQ}K鎵”fX5B2¬ç¾ÿUÈÕ*Ѫƒ˜ŽÀÍšÈj!lïi–H"2Îê4s›ß VôtKÞÁU›ž·/\6}=fVç¹\Èàa®dÚ*Ëô€âº£Ôg÷¦A×¼¯‰x,àÆê¶P=(«ÁÎË{ÎH<¹AE5ùQºFÑ—çkÂhl¡ õFÚõÎrüˆÂ~KFûò[‘)/vî¼=š[ù°“**>p^fHš;j:Ç”à¤'¨Øm_Lõ)4ɶK<«]ô@›ˆ­ÿđ؄¬›Ñ½Ý"ÓšE¼ý…Ø=è<¶¡4 .zJ¾ú¯§gÔöÐt›Þï6é´l6Í4÷Ц¦Š§„³á¢[RÒOÒúžÃË.ÛÓ¸þPl莟ʔѦË\z†¸×éû(+×,Þ¾¤¥ÇUM!}z²W²Åš<Ø­~>ï†_úÇ«nCød7õêëuò„f÷€hŽÝ#á Â*Â_i Ïç'²t)x ŸÞð5…?s¹ŸEºÝŽðô퟼µ§÷»Mg’$Š‹¯kÆ$¹^eÿ"9 ®’­ gO»Mv7}vR1É0Šåyøå™åè4çáœa0£ÓÃ`ô"Tõr u¯÷æ>¾f4>º'¢•¯ºyOg„Hò豈æU5Ž|=¼tžåjÙ÷%Bï¼ï¬½5”„^D4÷Ò±{öq€·÷Zó(¿À’_'F®œSìR´… \g—~ÿà;=:GBo Lì ëô 3ªÖk€ ƒéÅÂ7MËðít¡zœ0Œ“Ý7ÆòÃJŽˆ‘åÉp€~ˆË¢l¾övå Z\ìÁƒ ”Mº”Ëo›íZ3ËÊøàeÐܲF£J¨°Üî¾3§äl>ïžíϵ×rµ~ùÎÞ1:úæ_ «F§œÑ# HrUZÞ¾”ÆY‰qg—Þë/¢v|±‹Ñ]>Ø‘ˆÚ\oò–^ÿ¿‹¸þPK{.‹—&W1PKµ²½BMETA-INF/manifest.xml­SÁnà ½÷+"î­§ %íaÒ¾ ûFœ S5?©m¦©S£õfcû½g=ÓìÏÎV'ˆÉxlÙ+a öÁ¡eŸ‡úíw›Æ)4=$’— *s˜®iËrDéU2I¢r$ié`çuv€$öË™éš-lÙnSÝøzc¡.óq¼u÷ÙÚ:(:¶Lܹ=;茪i Ð2‚5ZQi'ìø,˜/uò!ªp4:1±F‡R¼¬x‡—àLb*¯M@T|HOÖiÚõÙ¸‡cv_¨ŒM‚.!8Ü!1N ¦ú*–w½rœmL[¡´ %õQèãß›ýëÁ»J' <®—+ý§Ñ£î7â×Ý}PKªåÇÞPKµ²½BŸ.Ä++mimetypePKµ²½B^ óÏ»+Qmeta.xmlPKµ²½B’ýÁ.! Bsettings.xmlPKµ²½BÇàþ´ õP =content.xmlPKµ²½B‚ì]k££*Thumbnails/thumbnail.pngPKµ²½B'Configurations2/images/Bitmaps/PKµ²½B@'Configurations2/popupmenu/PKµ²½Bx'Configurations2/toolpanel/PKµ²½B°'Configurations2/statusbar/PKµ²½Bè'Configurations2/progressbar/PKµ²½B"(Configurations2/toolbar/PKµ²½BX(Configurations2/menubar/PKµ²½B'Ž(Configurations2/accelerator/current.xmlPKµ²½Bå(Configurations2/floater/PKµ²½B{.‹—&W1 )styles.xmlPKµ²½BªåÇÞy1META-INF/manifest.xmlPK6Î2zuluCrypt-6.2.0/external_libraries/000077500000000000000000000000001425361753700174335ustar00rootroot00000000000000zuluCrypt-6.2.0/external_libraries/lxqt_wallet/000077500000000000000000000000001425361753700217735ustar00rootroot00000000000000zuluCrypt-6.2.0/external_libraries/lxqt_wallet/BUILD_INSTRUCTIONS000066400000000000000000000011631425361753700246020ustar00rootroot00000000000000 The build system in use is cmake To build make sure you have the following packages installed(packages may be named differently in your distribution): g++ gcc cmake kde-devel( if you want to build KDE/KWALLET support ) qt4-devel Build instructions are below: mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=`kde4-config --prefix` -DCMAKE_BUILD_TYPE=RELEASE .. make make install To build without KDE/KWALLET support,pass "-DNOKDESUPPORT=true" as one of the arguments in the third stage above To build without gnome/secret_service support,pass "-DNOSECRETSUPPORT=true" as one of the arguments in the third stage above zuluCrypt-6.2.0/external_libraries/lxqt_wallet/CMakeLists.txt000066400000000000000000000005131425361753700245320ustar00rootroot00000000000000cmake_minimum_required( VERSION 3.0.2 ) find_package( PkgConfig ) if( WIN32 ) add_library( lxqt-wallet-backend STATIC backend/fake_wallet_backend.c ) set_target_properties( lxqt-wallet-backend PROPERTIES COMPILE_FLAGS "-Wall -s -pedantic" ) else() add_subdirectory( backend ) endif() add_subdirectory( frontend ) zuluCrypt-6.2.0/external_libraries/lxqt_wallet/LICENSE000066400000000000000000000025761425361753700230120ustar00rootroot00000000000000/* * copyright: 2013 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ zuluCrypt-6.2.0/external_libraries/lxqt_wallet/README.md000066400000000000000000000015201425361753700232500ustar00rootroot00000000000000lxqt_wallet =========== This project seeks to give a functionality for secure storage of information that can be presented in key-values pair like user names-passwords pairs. Currently the project can store the information in KDE's kwallet,GNOME's secret service or in an internal system that use libgcrypt as its cryptographic backend. The internal secure storage system allows the functionality to be provided without dependencies on KDE or gnome libraries. This project is designed to be used by other projects simply by adding the source folder in the build system and start using it. The front end is build on Qt/C++ and has an optional dependency on KDE's kwallet and GNOME's secretservice. The project allows other Qt based project's to target one API and use it for secure storage of information in different secure storage systems.zuluCrypt-6.2.0/external_libraries/lxqt_wallet/SOURCE000066400000000000000000000001051425361753700227120ustar00rootroot00000000000000 project's homepage is: https://github.com/mhogomchungu/lxqt_wallet zuluCrypt-6.2.0/external_libraries/lxqt_wallet/backend/000077500000000000000000000000001425361753700233625ustar00rootroot00000000000000zuluCrypt-6.2.0/external_libraries/lxqt_wallet/backend/CMakeLists.txt000066400000000000000000000034211425361753700261220ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) INCLUDE(FindPkgConfig) find_file( GCRYPT_INCLUDE_FILE gcrypt.h ) find_path( GCRYPT_INCLUDE_PATH gcrypt.h ) find_library( GCRYPT_LIBRARY gcrypt ) if( NOT GCRYPT_INCLUDE_FILE ) MESSAGE( FATAL_ERROR "could not find gcrypt header file" ) else() MESSAGE( STATUS "found gcrypt header file: ${GCRYPT_INCLUDE_FILE}" ) endif() if( NOT GCRYPT_LIBRARY ) MESSAGE( FATAL_ERROR "could not find gcrypt library(libgcrypt.so)" ) else() MESSAGE( STATUS "found gcrypt library: ${GCRYPT_LIBRARY}" ) endif() get_filename_component( GCRYPT_LIBRARY_PATH ${GCRYPT_LIBRARY} DIRECTORY ) add_library( lxqt-wallet-backend STATIC lxqtwallet.c ) if( CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0 ) if( WIN32 ) set_target_properties( lxqt-wallet-backend PROPERTIES COMPILE_FLAGS "-Wall -s -pedantic -Wformat-truncation=0 -I${GCRYPT_INCLUDE_PATH}" ) else() set_target_properties( lxqt-wallet-backend PROPERTIES COMPILE_FLAGS "-Wall -s -fPIC -pedantic -Wformat-truncation=0 -I${GCRYPT_INCLUDE_PATH}" ) endif() else() if( WIN32 ) set_target_properties( lxqt-wallet-backend PROPERTIES COMPILE_FLAGS "-Wall -s -pedantic -I${GCRYPT_INCLUDE_PATH}" ) else() set_target_properties( lxqt-wallet-backend PROPERTIES COMPILE_FLAGS "-Wall -s -fPIC -pedantic -I${GCRYPT_INCLUDE_PATH}" ) endif() endif() if( WIN32 ) set_target_properties( lxqt-wallet-backend PROPERTIES COMPILE_FLAGS "-Wall -s -pedantic -I${GCRYPT_INCLUDE_PATH}" ) else() set_target_properties( lxqt-wallet-backend PROPERTIES COMPILE_FLAGS "-Wall -s -fPIC -pedantic -I${GCRYPT_INCLUDE_PATH}" ) endif() set_target_properties( lxqt-wallet-backend PROPERTIES LINK_FLAGS "-pie" ) TARGET_LINK_LIBRARIES( lxqt-wallet-backend "${GCRYPT_LIBRARY}" ) link_directories( "${GCRYPT_LIBRARY_PATH}" ) zuluCrypt-6.2.0/external_libraries/lxqt_wallet/backend/README000066400000000000000000000052521425361753700242460ustar00rootroot00000000000000 This source file is the one responsible for secure storage information in key-pair fashion. It has a dependency only on gcrypt and it is designed to be used in other projects simply by dropping the source file in the middle of the build tree and start using it. A simple use case for it is in applications that want to store securely their user's account credentials but do not want to tie themselves to desktop environments through the use of KDE kwallet or gnome gnome-keyring Encrypted file documentation. A newly created file or an empty one takes 64 bytes. The first 16 bytes are used for pbkdf2 salt. This salt is obtained from "/dev/urandom" and will not change when the wallet is updated. The second 16 bytes are used to store AES Initialization Vector. The IV is initially obtained from "/dev/urandom". The IV is stored unencrypted and will change on every wallet update. Everything from 32nd byte onward is store encrypted. The third 16 bytes are "magic string" bytes. The first 11 bytes are used to store a known data aka "magic string" to be used to check if decryption key is correct or not. The remaining 5 bytes are used to store file version number. The fourth 16 bytes are used to store information about the contents of the load. The first 8 bytes are a u_int64_t data type and are used to store the load size The second 8 bytes are a u_int64_t data type and are used to store the number of entries in the wallet. The load starts at 64th byte. The file is encrypted using CBC mode of 256 bit AES and hence may be padded to a file size larger than file contents to accomodate CBC mode demanding data sizes that are divisible by 16. Key-Pair entries are stored as singly linked list nodes in an array. Interesting video on why traditional linked lists are bad: http://www.youtube.com/watch?v=YQs6IC-vgmo A node of a linked list has 4 properties. First 4 bytes of the node are a u_int32_t data type and are used to store the size of the key. Second 4 bytes of the node are a u_int32_t data type and used to stores the size of the value. The 8th byte of the node will be the beginning of the key. The 8th byte of the node plus the size of the key will be the beginning of the value. The sum of the two 4 bytes plus the length of the key plus the length of the value will point to the next node in the list. An empty node takes 8 bytes.A key is not allowed to be empty necessitating it having at least one character making the minimum allowed size for the node to be 9 bytes. The size of the key in the node is managed by a u_int32_t data type. The size of the value in the node is managed by a u_int32_t data type. The above two data types means a node can occupy upto 8 bytes + 8 GiB of memory. zuluCrypt-6.2.0/external_libraries/lxqt_wallet/backend/fake_wallet_backend.c000066400000000000000000000024401425361753700274530ustar00rootroot00000000000000/* * * Copyright (c) 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "lxqtwallet.h" int lxqt_wallet_exists( const char * wallet_name, const char * application_name ) { if( wallet_name && application_name ){} return 0 ; } lxqt_wallet_error lxqt_wallet_delete_wallet( const char * wallet_name, const char * application_name ) { if( wallet_name && application_name ){} return lxqt_wallet_no_error ; } void lxqt_wallet_application_wallet_path( char * path_buffer, uint32_t path_buffer_size, const char * application_name ) { if( path_buffer && path_buffer_size && application_name ){} } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/backend/lxqtwallet.c000066400000000000000000001113701425361753700257320ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "lxqtwallet.h" #ifndef _WIN32 #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include #pragma GCC diagnostic warning "-Wdeprecated-declarations" #define VERSION 200 #define VERSION_SIZE sizeof( short ) /* * below string MUST BE 11 bytes long */ #define MAGIC_STRING "lxqt_wallet" #define MAGIC_STRING_SIZE 11 #define MAGIC_STRING_BUFFER_SIZE 16 #define PASSWORD_SIZE 32 #define BLOCK_SIZE 16 #define IV_SIZE 16 #define SALT_SIZE 16 #define FILE_BLOCK_SIZE 1024 #define PBKDF2_ITERATIONS 10000 #define NODE_HEADER_SIZE ( 2 * sizeof( uint32_t ) ) #define WALLET_EXTENSION ".lwt" struct lxqt_wallet_struct{ char * application_name ; char * wallet_name ; char key[ PASSWORD_SIZE ] ; char salt[ SALT_SIZE ] ; char * wallet_data ; uint64_t wallet_data_size ; uint64_t wallet_data_entry_count ; int wallet_modified ; }; /* * Encrypted file documentation. * * A newly created file or an empty one takes 64 bytes. * * The first 16 bytes are used for pbkdf2 salt. * This salt is obtained from "/dev/urandom" and will not change when the wallet is updated. * * The second 16 bytes are used to store AES Initialization Vector. * The IV is initially obtained from "/dev/urandom". * The IV is stored unencrypted and will change on every wallet update. * * Everything from 32nd byte onward is store encrypted. * * The third 16 bytes are "magic string" bytes. * The first 11 bytes are used to store a known data aka "magic string" to be used to check if decryption key is correct or not. * The remaining 5 bytes are used to store file version number. * * The fourth 16 bytes are used to store information about the contents of the load. * The first 8 bytes are a uint64_t data type and are used to store the load size * The second 8 bytes are a uint64_t data type and are used to store the number of entries in the wallet. * * The load starts at 64th byte. * * The file is encrypted using CBC mode of 256 bit AES and hence may be padded to a file size larger than file contents to * accomodate CBC mode demanding data sizes that are divisible by 16. * * Key-Pair entries are stored as singly linked list nodes in an array. * Interesting video on why traditional linked lists are bad: http://www.youtube.com/watch?v=YQs6IC-vgmo * * A node of a linked list has 4 properties. * First 4 bytes of the node are a uint32_t data type and are used to store the size of the key. * Second 4 bytes of the node are a uint32_t data type and used to stores the size of the value. * The 8th byte of the node will be the beginning of the key. * The 8th byte of the node plus the size of the key will be the beginning of the value. * * The sum of the two 4 bytes plus the length of the key plus the length of the value will * point to the next node in the list. * * An empty node takes 8 bytes.A key is not allowed to be empty necessitating it having at least one character * making the minimum allowed size for the node to be 9 bytes. * * The size of the key in the node is managed by a uint32_t data type. * The size of the value in the node is managed by a uint32_t data type. * The above two data types means a node can occupy upto 8 bytes + 8 GiB of memory. * */ static void _lxqt_wallet_write( int x,const void * y,size_t z ) { if( write( x,y,z ) ){} } static void _lxqt_wallet_close( int x ) { if( close( x ) ){} } static void _lxqt_wallet_read( int x,void * y,size_t z ) { if( read( x,y,z ) ){} } static char * _wallet_full_path( char * path_buffer,uint32_t path_buffer_size,const char * wallet_name,const char * application_name ) ; static void _create_application_wallet_path( const char * application_name ) ; static gcry_error_t _create_key( const char salt[ SALT_SIZE ],char output_key[ PASSWORD_SIZE ],const char * input_key,uint32_t input_key_length ) ; static gcry_error_t _create_temp_key( char * output_key,uint32_t output_key_size,const char * input_key,uint32_t input_key_length ) ; static void _get_iv_from_wallet_header( char iv[ IV_SIZE ],int fd ) ; static void _get_salt_from_wallet_header( char salt[ SALT_SIZE ],int fd ) ; static void _get_volume_info( char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ],int fd ) ; static void _get_random_data( char * buffer,size_t buffer_size ) ; static void _create_magic_string_header( char magic_string[ MAGIC_STRING_BUFFER_SIZE ] ) ; static int _wallet_is_compatible( const char * ) ; static int _password_match( const char * buffer ) ; static int _volume_version( const char * buffer ) ; static void _get_load_information( lxqt_wallet_t,const char * buffer ) ; static lxqt_wallet_error _lxqt_wallet_open( const char * password,uint32_t password_length, const char * wallet_name,const char * application_name,char * buffer, int * ffd,struct lxqt_wallet_struct ** ww,gcry_cipher_hd_t * h ) ; int lxqt_wallet_library_version( void ) { return VERSION ; } char * _lxqt_wallet_get_wallet_data( lxqt_wallet_t wallet ) { if( wallet == NULL ){ return NULL ; }else{ return wallet->wallet_data ; } } static int _failed( gcry_error_t r ) { return r != GPG_ERR_NO_ERROR ; } static int _passed( gcry_error_t r ) { return r == GPG_ERR_NO_ERROR ; } inline static void _get_header_components( uint32_t * first,uint32_t * second,const char * str ) { memcpy( first,str,sizeof( uint32_t ) ) ; memcpy( second,str + sizeof( uint32_t ),sizeof( uint32_t ) ) ; } uint64_t lxqt_wallet_wallet_size( lxqt_wallet_t wallet ) { if( wallet == NULL ){ return 0 ; }else{ return wallet->wallet_data_size ; } } uint64_t lxqt_wallet_entry_count( lxqt_wallet_t wallet ) { if( wallet == NULL ){ return 0 ; }else{ return wallet->wallet_data_entry_count ; } } static lxqt_wallet_error _exit_create( lxqt_wallet_error r,gcry_cipher_hd_t handle ) { if( handle != 0 ){ gcry_cipher_close( handle ) ; } return r ; } static lxqt_wallet_error lxqt_wallet_create_1( gcry_cipher_hd_t * h,const char * password, uint32_t password_length,char * key,char * iv, char * salt ) { gcry_error_t r ; gcry_cipher_hd_t handle ; if( gcry_control( GCRYCTL_INITIALIZATION_FINISHED_P ) == 0 ){ gcry_check_version( NULL ) ; gcry_control( GCRYCTL_INITIALIZATION_FINISHED,0 ) ; } r = gcry_cipher_open( h,GCRY_CIPHER_AES256,GCRY_CIPHER_MODE_CBC,0 ) ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_open_failed ; } handle = *h ; _get_random_data( salt,SALT_SIZE ) ; r = _create_key( salt,key,password,password_length ) ; if( _failed( r ) ){ return lxqt_wallet_failed_to_create_key_hash ; } r = gcry_cipher_setkey( handle,key,PASSWORD_SIZE ) ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_setkey_failed ; } _get_random_data( iv,IV_SIZE ) ; r = gcry_cipher_setiv( handle,iv,IV_SIZE ) ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_setiv_failed ; }else{ return r ; } } lxqt_wallet_error lxqt_wallet_create( const char * password,uint32_t password_length, const char * wallet_name,const char * application_name ) { int fd ; char path[ PATH_MAX ] ; char iv[ IV_SIZE ] ; char key[ PASSWORD_SIZE ] ; char salt[ SALT_SIZE ] ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] = { '\0' } ; gcry_cipher_hd_t handle = 0 ; gcry_error_t r ; if( password == NULL || wallet_name == NULL || application_name == NULL ){ return _exit_create( lxqt_wallet_invalid_argument,handle ) ; } if( lxqt_wallet_exists( wallet_name,application_name ) == 0 ){ return _exit_create( lxqt_wallet_wallet_exists,handle ) ; } r = lxqt_wallet_create_1( &handle,password,password_length,key,iv,salt ) ; if( _failed( r ) ){ return _exit_create( lxqt_wallet_gcry_cipher_encrypt_failed,handle ) ; }else{ _create_magic_string_header( buffer ) ; r = gcry_cipher_encrypt( handle,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE,NULL,0 ) ; _create_application_wallet_path( application_name ) ; _wallet_full_path( path,PATH_MAX,wallet_name,application_name ) ; fd = open( path,O_WRONLY|O_CREAT,0600 ) ; if( fd == -1 ){ return _exit_create( lxqt_wallet_failed_to_open_file,handle ) ; }else{ /* * first 16 bytes are for PBKDF2 salt */ _lxqt_wallet_write( fd,salt,SALT_SIZE ) ; /* * second 16 bytes are for AES IV */ _lxqt_wallet_write( fd,iv,IV_SIZE ) ; /* * third 16 bytes are for the magic string */ _lxqt_wallet_write( fd,buffer,MAGIC_STRING_BUFFER_SIZE ) ; /* * fourth 16 bytes block that holds information about data load sizes */ _lxqt_wallet_write( fd,buffer + MAGIC_STRING_BUFFER_SIZE,BLOCK_SIZE ) ; _lxqt_wallet_close( fd ) ; return _exit_create( lxqt_wallet_no_error,handle ) ; } } } lxqt_wallet_error lxqt_wallet_create_encrypted_file( const char * password,uint32_t password_length, const char * source,const char * destination,int(*function)( int,void * ),void * v ) { gcry_error_t r ; int fd_dest ; int fd_src ; char iv[ IV_SIZE ] ; char key[ PASSWORD_SIZE ] ; char salt[ SALT_SIZE ] ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] = { '\0' } ; char file_buffer[ FILE_BLOCK_SIZE ] ; uint64_t size ; uint64_t i ; uint64_t j ; uint64_t l ; int k ; gcry_cipher_hd_t handle = 0 ; struct stat st ; if( password == NULL || source == NULL || destination == NULL ){ return lxqt_wallet_invalid_argument ; } if( stat( destination,&st ) == 0 ){ return lxqt_wallet_failed_to_open_file ; } r = lxqt_wallet_create_1( &handle,password,password_length,key,iv,salt ) ; if( _failed( r ) ){ return _exit_create( lxqt_wallet_gcry_cipher_encrypt_failed,handle ) ; }else{ fd_dest = open( destination,O_WRONLY|O_CREAT,0600 ) ; if( fd_dest == -1 ){ return _exit_create( lxqt_wallet_failed_to_open_file,handle ) ; } fd_src = open( source,O_RDONLY ) ; if( fd_src == -1 ){ _lxqt_wallet_close( fd_dest ) ; return _exit_create( lxqt_wallet_failed_to_open_file,handle ) ; } /* * first 16 bytes are for PBKDF2 salt */ _lxqt_wallet_write( fd_dest,salt,SALT_SIZE ) ; /* * second 16 bytes are for AES IV */ _lxqt_wallet_write( fd_dest,iv,IV_SIZE ) ; fstat( fd_src,&st ) ; size = ( uint64_t )st.st_size ; _create_magic_string_header( buffer ) ; memcpy( buffer + MAGIC_STRING_BUFFER_SIZE,&size,sizeof( uint64_t ) ) ; gcry_cipher_encrypt( handle,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE,NULL,0 ) ; /* * write third 16 byte and fourth 16 to the header */ _lxqt_wallet_write( fd_dest,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ) ; i = 0 ; j = 0 ; l = 0 ; while( 1 ){ k = (int)read( fd_src,file_buffer,FILE_BLOCK_SIZE ) ; if( k == 0 ){ break ; } r = gcry_cipher_encrypt( handle,file_buffer,FILE_BLOCK_SIZE,NULL,0 ) ; _lxqt_wallet_write( fd_dest,file_buffer,FILE_BLOCK_SIZE ) ; if( k < FILE_BLOCK_SIZE ){ break ; } i += FILE_BLOCK_SIZE ; j = ( i * 100 / size ) ; if( j > l ){ if( function( (int)j,v ) ){ break ; } l = j ; } } function( 100,v ) ; _lxqt_wallet_close( fd_dest ) ; _lxqt_wallet_close( fd_src ) ; return _exit_create( lxqt_wallet_no_error,handle ) ; } } lxqt_wallet_error lxqt_wallet_change_wallet_password( lxqt_wallet_t wallet,const char * new_key,uint32_t new_key_size ) { char key[ PASSWORD_SIZE ] ; gcry_error_t r ; if( wallet == NULL || new_key == NULL ){ return lxqt_wallet_invalid_argument ; }else{ r = _create_key( wallet->salt,key,new_key,new_key_size ) ; if( _failed( r ) ){ return lxqt_wallet_failed_to_create_key_hash ; }else{ memcpy( wallet->key,key,PASSWORD_SIZE ) ; wallet->wallet_modified = 1 ; return lxqt_wallet_no_error ; } } } static lxqt_wallet_error _exit_open( lxqt_wallet_error st, struct lxqt_wallet_struct * w,gcry_cipher_hd_t handle,int fd ) { if( handle != 0 ){ gcry_cipher_close( handle ) ; } if( fd != -1 ){ _lxqt_wallet_close( fd ) ; } if( w != NULL ){ free( w->wallet_name ) ; free( w->application_name ) ; free( w ) ; } return st ; } static lxqt_wallet_error _lxqt_wallet_open_0( gcry_cipher_hd_t * h,struct lxqt_wallet_struct * w, const char * password,uint32_t password_length,int fd,char * buffer ) { gcry_error_t r ; gcry_cipher_hd_t handle ; char iv[ IV_SIZE ] ; if( gcry_control( GCRYCTL_INITIALIZATION_FINISHED_P ) == 0 ){ gcry_check_version( NULL ) ; gcry_control( GCRYCTL_INITIALIZATION_FINISHED,0 ) ; } r = gcry_cipher_open( h,GCRY_CIPHER_AES256,GCRY_CIPHER_MODE_CBC,0 ) ; handle = *h ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_open_failed ; } _get_salt_from_wallet_header( w->salt,fd ) ; r = _create_key( w->salt,w->key,password,password_length ) ; if( _failed( r ) ){ return lxqt_wallet_failed_to_create_key_hash ; } r = gcry_cipher_setkey( handle,w->key,PASSWORD_SIZE ) ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_setkey_failed ; } _get_iv_from_wallet_header( iv,fd ) ; r = gcry_cipher_setiv( handle,iv,IV_SIZE ) ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_setiv_failed ; }else{ _get_volume_info( buffer,fd ) ; return gcry_cipher_decrypt( handle,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE,NULL,0 ) ; } } lxqt_wallet_error lxqt_wallet_create_decrypted_file( const char * password,uint32_t password_length, const char * source,const char * destination,int( *function )( int,void * ),void * v ) { gcry_error_t r ; int fd_dest ; int fd_src ; struct stat st ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] = { '\0' } ; char file_buffer[ FILE_BLOCK_SIZE ] ; uint64_t size ; uint64_t i ; uint64_t j ; uint64_t l ; uint64_t n ; uint64_t t ; gcry_cipher_hd_t handle = 0 ; struct lxqt_wallet_struct * w ; if( password == NULL || source == NULL || destination == NULL ){ return lxqt_wallet_invalid_argument ; } if( stat( destination,&st ) == 0 ){ return lxqt_wallet_failed_to_open_file ; } w = malloc( sizeof( struct lxqt_wallet_struct ) ) ; if( w == NULL ){ return _exit_open( lxqt_wallet_failed_to_allocate_memory,NULL,handle,-1 ) ; } memset( w,'\0',sizeof( struct lxqt_wallet_struct ) ) ; fd_src = open( source,O_RDONLY ) ; if( fd_src == -1 ){ return _exit_open( lxqt_wallet_failed_to_open_file,w,handle,-1 ) ; } r = _lxqt_wallet_open_0( &handle,w,password,password_length,fd_src,buffer ) ; if( _failed( r ) ){ _lxqt_wallet_close( fd_src ) ; return _exit_open( lxqt_wallet_failed_to_open_file,w,handle,-1 ) ; } if( _password_match( buffer ) && _wallet_is_compatible( buffer ) ){ fd_dest = open( destination,O_WRONLY|O_CREAT,0600 ) ; if( fd_dest == -1 ){ _lxqt_wallet_close( fd_src ) ; return _exit_open( lxqt_wallet_failed_to_open_file,w,handle,-1 ) ; } _get_load_information( w,buffer ) ; size = w->wallet_data_size ; i = 0 ; j = 0 ; l = 0 ; n = size / FILE_BLOCK_SIZE ; for( t = 0 ; t < n ; t++ ){ _lxqt_wallet_read( fd_src,file_buffer,FILE_BLOCK_SIZE ) ; gcry_cipher_decrypt( handle,file_buffer,FILE_BLOCK_SIZE,NULL,0 ) ; _lxqt_wallet_write( fd_dest,file_buffer,FILE_BLOCK_SIZE ) ; i += FILE_BLOCK_SIZE ; j = ( i * 100 / size ) ; if( j > l ){ if( function( (int)j,v ) ){ break ; } l = j ; } } size = size - i ; if( size > 0 ){ _lxqt_wallet_read( fd_src,file_buffer,FILE_BLOCK_SIZE ) ; gcry_cipher_decrypt( handle,file_buffer,FILE_BLOCK_SIZE,NULL,0 ) ; _lxqt_wallet_write( fd_dest,file_buffer,size ) ; } _lxqt_wallet_close( fd_src ) ; _lxqt_wallet_close( fd_dest ) ; function( 100,v ) ; return _exit_open( lxqt_wallet_no_error,w,handle,-1 ) ; }else{ _lxqt_wallet_close( fd_src ) ; return _exit_open( lxqt_wallet_wrong_password,w,handle,-1 ) ; } } static lxqt_wallet_error _lxqt_wallet_open( const char * password,uint32_t password_length, const char * wallet_name,const char * application_name,char * buffer, int * ffd,struct lxqt_wallet_struct ** ww,gcry_cipher_hd_t * h ) { gcry_error_t r ; gcry_cipher_hd_t handle = 0 ; char path[ PATH_MAX ] ; int fd ; size_t len ; struct lxqt_wallet_struct * w ; _wallet_full_path( path,PATH_MAX,wallet_name,application_name ) ; fd = open( path,O_RDONLY ) ; if( fd == -1 ){ return _exit_open( lxqt_wallet_failed_to_open_file,NULL,handle,fd ) ; } w = malloc( sizeof( struct lxqt_wallet_struct ) ) ; if( w == NULL ){ return _exit_open( lxqt_wallet_failed_to_allocate_memory,NULL,handle,fd ) ; } memset( w,'\0',sizeof( struct lxqt_wallet_struct ) ) ; len = strlen( wallet_name ) ; w->wallet_name = malloc( sizeof( char ) * ( len + 1 ) ) ; if( w->wallet_name == NULL ){ return _exit_open( lxqt_wallet_failed_to_allocate_memory,w,handle,fd ) ; }else{ memcpy( w->wallet_name,wallet_name,len + 1 ) ; } len = strlen( application_name ) ; w->application_name = malloc( sizeof( char ) * ( len + 1 ) ) ; if( w->application_name == NULL ){ return _exit_open( lxqt_wallet_failed_to_allocate_memory,w,handle,fd ) ; }else{ memcpy( w->application_name,application_name,len + 1 ) ; } r = _lxqt_wallet_open_0( &handle,w,password,password_length,fd,buffer ) ; if( _failed( r ) ){ return _exit_open( lxqt_wallet_gcry_cipher_decrypt_failed,w,handle,fd ) ; }else{ *ww = w ; *ffd = fd ; *h = handle ; return lxqt_wallet_no_error ; } } lxqt_wallet_error lxqt_wallet_open( lxqt_wallet_t * wallet,const char * password,uint32_t password_length, const char * wallet_name,const char * application_name ) { struct stat st ; uint64_t len ; char * e ; int fd ; struct lxqt_wallet_struct * w = 0 ; gcry_cipher_hd_t handle = 0 ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] ; gcry_error_t r ; if( wallet_name == NULL || application_name == NULL || wallet == NULL ){ return lxqt_wallet_invalid_argument ; } r = _lxqt_wallet_open( password,password_length,wallet_name,application_name,buffer,&fd,&w,&handle ) ; if( r != lxqt_wallet_no_error ){ return r ; } if( _password_match( buffer ) ){ if( _wallet_is_compatible( buffer ) ){ fstat( fd,&st ) ; len = (uint64_t)( st.st_size - ( SALT_SIZE + IV_SIZE + MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ) ) ; if( (int64_t)len <= 0 ){ /* * empty wallet */ *wallet = w ; return _exit_open( lxqt_wallet_no_error,NULL,handle,fd ) ; }else{ _get_load_information( w,buffer ) ; if( w->wallet_data_size > len ){ /* * Wallet is corrupt somehow,lets clear it. */ w->wallet_data_size = 0 ; w->wallet_data_entry_count = 0 ; w->wallet_modified = 1 ; } e = malloc( len ) ; if( e != NULL ){ #ifndef _WIN32 mlock( e,len ) ; #endif _lxqt_wallet_read( fd,e,len ) ; r = gcry_cipher_decrypt( handle,e,len,NULL,0 ) ; if( _passed( r ) ){ w->wallet_data = e ; *wallet = w ; return _exit_open( lxqt_wallet_no_error,NULL,handle,fd ) ; }else{ free( e ) ; return _exit_open( lxqt_wallet_gcry_cipher_decrypt_failed,w,handle,fd ) ; } }else{ return _exit_open( lxqt_wallet_failed_to_allocate_memory,w,handle,fd ) ; } } }else{ return _exit_open( lxqt_wallet_incompatible_wallet,w,handle,fd ) ; } }else{ return _exit_open( lxqt_wallet_wrong_password,w,handle,fd ) ; } } int lxqt_wallet_volume_version( const char * wallet_name,const char * application_name,const char * password,uint32_t password_length ) { int fd ; int version ; struct lxqt_wallet_struct * w = 0 ; gcry_cipher_hd_t handle = 0 ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] ; gcry_error_t r ; if( wallet_name == NULL || application_name == NULL ){ return -1 ; }else{ r = _lxqt_wallet_open( password,password_length,wallet_name,application_name,buffer,&fd,&w,&handle ) ; if( r != lxqt_wallet_no_error ){ return -1 ; }else{ if( _password_match( buffer ) ){ version = _volume_version( buffer ) ; _exit_open( lxqt_wallet_no_error,w,handle,fd ) ; return version ; }else{ _exit_open( lxqt_wallet_wrong_password,w,handle,fd ) ; return -1 ; } } } } int lxqt_wallet_read_key_value( lxqt_wallet_t wallet,const char * key,uint32_t key_size,lxqt_wallet_key_values_t * key_value ) { const char * e ; const char * z ; uint64_t k = 0 ; uint64_t i = 0 ; uint32_t key_len ; uint32_t key_value_len ; if( key == NULL || wallet == NULL || key_value == NULL ){ }else{ e = wallet->wallet_data ; z = e ; k = wallet->wallet_data_size ; while( i < k ){ _get_header_components( &key_len,&key_value_len,e ) ; if( key_len == key_size && memcmp( key,e + NODE_HEADER_SIZE,key_size ) == 0 ){ key_value->key = e + NODE_HEADER_SIZE ; key_value->key_size = key_len ; key_value->key_value = e + NODE_HEADER_SIZE + key_len ; key_value->key_value_size = key_value_len ; return 1 ; }else{ i = i + NODE_HEADER_SIZE + key_len + key_value_len ; e = z + i ; } } } return 0 ; } int lxqt_wallet_has_key( lxqt_wallet_t wallet,const char * key,uint32_t key_size ) { lxqt_wallet_key_values_t key_value ; return lxqt_wallet_read_key_value( wallet,key,key_size,&key_value ) ; } int lxqt_wallet_has_value( lxqt_wallet_t wallet,const char * value,uint32_t value_size,lxqt_wallet_key_values_t * key_value ) { const char * e ; const char * z ; uint64_t k = 0 ; uint64_t i = 0 ; uint32_t key_len ; uint32_t key_value_len ; if( key_value == NULL || wallet == NULL ){ return 0 ; }else{ e = wallet->wallet_data ; z = e ; k = wallet->wallet_data_size ; while( i < k ){ _get_header_components( &key_len,&key_value_len,e ) ; if( key_value_len == value_size && memcmp( value,e + NODE_HEADER_SIZE + key_len,value_size ) == 0 ){ key_value->key = e + NODE_HEADER_SIZE ; key_value->key_size = key_len ; key_value->key_value = e + NODE_HEADER_SIZE + key_len ; key_value->key_value_size = key_value_len ; return 1 ; }else{ i = i + NODE_HEADER_SIZE + key_len + key_value_len ; e = z + i ; } } return 0 ; } } lxqt_wallet_error lxqt_wallet_add_key( lxqt_wallet_t wallet,const char * key,uint32_t key_size, const char * value,uint32_t key_value_length ) { char * e ; char * f ; uint64_t len ; if( key == NULL || wallet == NULL ){ return lxqt_wallet_invalid_argument ; }else{ if( key_size == 0 ){ return lxqt_wallet_invalid_argument ; }else{ if( value == NULL || key_value_length == 0 ){ key_value_length = 0 ; value = "" ; } len = NODE_HEADER_SIZE + key_size + key_value_length ; f = realloc( wallet->wallet_data,wallet->wallet_data_size + len ) ; if( f != NULL ){ #ifndef _WIN32 mlock( f,wallet->wallet_data_size + len ) ; #endif e = f + wallet->wallet_data_size ; memcpy( e,&key_size,sizeof( uint32_t ) ) ; memcpy( e + sizeof( uint32_t ),&key_value_length,sizeof( uint32_t ) ) ; memcpy( e + NODE_HEADER_SIZE,key,key_size ) ; memcpy( e + NODE_HEADER_SIZE + key_size,value,key_value_length ) ; wallet->wallet_data_size += len ; wallet->wallet_modified = 1 ; wallet->wallet_data = f ; wallet->wallet_data_entry_count++ ; return lxqt_wallet_no_error ; }else{ return lxqt_wallet_failed_to_allocate_memory ; } } } } int lxqt_wallet_iter_read_value( lxqt_wallet_t wallet,lxqt_wallet_iterator_t * iter ) { uint32_t key_len ; uint32_t key_value_len ; const char * e ; if( wallet == NULL || iter->iter_pos >= wallet->wallet_data_size ){ return 0 ; }else{ e = wallet->wallet_data + iter->iter_pos ; _get_header_components( &key_len,&key_value_len,e ) ; iter->entry.key = e + NODE_HEADER_SIZE ; iter->entry.key_size = key_len ; iter->entry.key_value = e + NODE_HEADER_SIZE + key_len ; iter->entry.key_value_size = key_value_len ; iter->iter_pos += NODE_HEADER_SIZE + key_len + key_value_len ; return 1 ; } } int lxqt_wallet_read_value_at( lxqt_wallet_t wallet,uint64_t pos,lxqt_wallet_key_values_t * key_value ) { char * e ; char * z ; uint64_t k = 0 ; uint64_t i = 0 ; uint32_t key_len = 0 ; uint32_t key_value_len = 0 ; if( wallet == NULL || wallet->wallet_data_entry_count == 0 || pos > wallet->wallet_data_entry_count ){ return 0 ; }else{ e = wallet->wallet_data ; z = e ; while( 1 ){ _get_header_components( &key_len,&key_value_len,e ) ; if( k == pos ){ key_value->key = e + NODE_HEADER_SIZE ; key_value->key_size = key_len ; key_value->key_value = e + NODE_HEADER_SIZE + key_len ; key_value->key_value_size = key_value_len ; break ; }else{ i = i + NODE_HEADER_SIZE + key_len + key_value_len ; e = z + i ; k++ ; } } return 1 ; } } lxqt_wallet_error lxqt_wallet_delete_key( lxqt_wallet_t wallet,const char * key,uint32_t key_size ) { char * e ; char * z ; uint64_t k = 0 ; uint64_t i = 0 ; uint32_t key_len ; uint32_t key_value_len ; uint64_t block_size ; if( key == NULL || wallet == NULL ){ return lxqt_wallet_invalid_argument ; }else{ e = wallet->wallet_data ; z = e ; k = wallet->wallet_data_size ; while( i < k ){ _get_header_components( &key_len,&key_value_len,e ) ; if( key_len == key_size && memcmp( key,e + NODE_HEADER_SIZE,key_size ) == 0 ){ if( wallet->wallet_data_entry_count == 1 ){ memset( wallet->wallet_data,'\0',wallet->wallet_data_size ) ; free( wallet->wallet_data ) ; wallet->wallet_data_size = 0 ; wallet->wallet_modified = 1 ; wallet->wallet_data = NULL ; wallet->wallet_data_entry_count = 0 ; }else{ block_size = NODE_HEADER_SIZE + key_len + key_value_len ; memmove( e,e + block_size,wallet->wallet_data_size - ( i + block_size ) ) ; memset( z + wallet->wallet_data_size - block_size,'\0',block_size ) ; wallet->wallet_data_size -= block_size ; wallet->wallet_modified = 1 ; wallet->wallet_data_entry_count-- ; } break ; }else{ i = i + NODE_HEADER_SIZE + key_len + key_value_len ; e = z + i ; } } } return lxqt_wallet_no_error ; } lxqt_wallet_error lxqt_wallet_delete_wallet( const char * wallet_name,const char * application_name ) { char path[ PATH_MAX ] ; _wallet_full_path( path,PATH_MAX,wallet_name,application_name ) ; unlink( path ) ; return lxqt_wallet_no_error ; } static lxqt_wallet_error lxqt_wallet_close_exit( lxqt_wallet_error err,lxqt_wallet_t * w,gcry_cipher_hd_t handle ) { lxqt_wallet_t wallet = *w ; *w = NULL ; if( handle != 0 ){ gcry_cipher_close( handle ) ; } if( wallet->wallet_data_size > 0 ){ memset( wallet->wallet_data,'\0',wallet->wallet_data_size ) ; #ifndef _WIN32 munlock( wallet->wallet_data,wallet->wallet_data_size ) ; #endif free( wallet->wallet_data ) ; } free( wallet->wallet_name ) ; free( wallet->application_name ) ; free( wallet ) ; return err ; } lxqt_wallet_error lxqt_wallet_close( lxqt_wallet_t * w ) { gcry_cipher_hd_t handle ; int fd ; char iv[ IV_SIZE ] ; char path[ PATH_MAX ] ; char path_1[ PATH_MAX + 16 ] ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] ; lxqt_wallet_t wallet ; uint64_t k ; char * e ; gcry_error_t r ; if( w == NULL || *w == NULL ){ return lxqt_wallet_invalid_argument ; } wallet = *w ; if( wallet->wallet_modified == 0 ){ return lxqt_wallet_close_exit( lxqt_wallet_no_error,w,0 ) ; } gcry_control( GCRYCTL_INITIALIZATION_FINISHED,0 ) ; r = gcry_cipher_open( &handle,GCRY_CIPHER_AES256,GCRY_CIPHER_MODE_CBC,0 ) ; if( _failed( r ) ){ return lxqt_wallet_close_exit( lxqt_wallet_gcry_cipher_open_failed,w,0 ) ; } r = gcry_cipher_setkey( handle,wallet->key,PASSWORD_SIZE ) ; if( _failed( r ) ){ return lxqt_wallet_close_exit( lxqt_wallet_gcry_cipher_setkey_failed,w,handle ) ; } _get_random_data( iv,IV_SIZE ) ; r = gcry_cipher_setiv( handle,iv,IV_SIZE ) ; if( _failed( r ) ){ return lxqt_wallet_close_exit( lxqt_wallet_gcry_cipher_setiv_failed,w,handle ) ; } _create_magic_string_header( buffer ) ; memcpy( buffer + MAGIC_STRING_BUFFER_SIZE,&wallet->wallet_data_size,sizeof( uint64_t ) ) ; memcpy( buffer + MAGIC_STRING_BUFFER_SIZE + sizeof( uint64_t ),&wallet->wallet_data_entry_count,sizeof( uint64_t ) ) ; r = gcry_cipher_encrypt( handle,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE,NULL,0 ) ; if( _failed( r ) ){ return lxqt_wallet_close_exit( lxqt_wallet_gcry_cipher_encrypt_failed,w,handle ) ; } _wallet_full_path( path,sizeof( path ),wallet->wallet_name,wallet->application_name ) ; snprintf( path_1,sizeof( path_1 ),"%s.tmp",path ) ; k = wallet->wallet_data_size ; if( k == 0 ){ fd = open( path_1,O_WRONLY|O_CREAT,0600 ) ; if( fd == -1 ){ return lxqt_wallet_close_exit( lxqt_wallet_gcry_cipher_open_failed,w,handle ) ; }else{ _lxqt_wallet_write( fd,wallet->salt,SALT_SIZE ) ; _lxqt_wallet_write( fd,iv,IV_SIZE ) ; _lxqt_wallet_write( fd,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ) ; _lxqt_wallet_close( fd ) ; rename( path_1,path ) ; return lxqt_wallet_close_exit( lxqt_wallet_no_error,w,handle ) ; } }else{ while( k % 32 != 0 ){ k++ ; } e = realloc( wallet->wallet_data,k ) ; if( e != NULL ){ wallet->wallet_data = e ; r = gcry_cipher_encrypt( handle,wallet->wallet_data,k,NULL,0 ) ; if( _failed( r ) ){ return lxqt_wallet_close_exit( lxqt_wallet_gcry_cipher_encrypt_failed,w,handle ) ; }else{ fd = open( path_1,O_WRONLY|O_CREAT,0600 ) ; if( fd == -1 ){ return lxqt_wallet_close_exit( lxqt_wallet_gcry_cipher_open_failed,w,handle ) ; }else{ _lxqt_wallet_write( fd,wallet->salt,SALT_SIZE ) ; _lxqt_wallet_write( fd,iv,IV_SIZE ) ; _lxqt_wallet_write( fd,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ) ; _lxqt_wallet_write( fd,wallet->wallet_data,k ) ; _lxqt_wallet_close( fd ) ; rename( path_1,path ) ; return lxqt_wallet_close_exit( lxqt_wallet_no_error,w,handle ) ; } } }else{ return lxqt_wallet_close_exit( lxqt_wallet_failed_to_allocate_memory,w,handle ) ; } } } char ** lxqt_wallet_list( const char * application_name,int * size ) { char path[ PATH_MAX ] ; char ** result = NULL ; char ** result_1 ; char * e ; int count = 0 ; uint32_t len ; struct dirent * entry ; DIR * dir ; if( application_name == NULL || size == NULL ){ return NULL ; } lxqt_wallet_application_wallet_path( path,PATH_MAX,application_name ) ; dir = opendir( path ) ; if( dir == NULL ){ return NULL ; } while( ( entry = readdir( dir ) ) != NULL ){ if( strcmp( entry->d_name,"." ) == 0 || strcmp( entry->d_name,".." ) == 0 ){ continue ; } len = ( uint32_t )( strlen( entry->d_name ) - strlen( WALLET_EXTENSION ) ) ; if( len > 0 ){ result_1 = realloc( result,sizeof( char * ) * ( ( size_t )count + 1 ) ) ; if( result_1 != NULL ){ e = malloc( len + 1 ) ; if( e!= NULL ){ memcpy( e,entry->d_name,len ) ; *( e + len ) = '\0' ; result_1[ count ] = e ; result = result_1 ; count++ ; } } } } *size = count ; closedir( dir ) ; return result ; } int lxqt_wallet_exists( const char * wallet_name,const char * application_name ) { struct stat st ; char path[ PATH_MAX ] ; if( wallet_name == NULL || application_name == NULL ){ return lxqt_wallet_invalid_argument ; }else{ _wallet_full_path( path,PATH_MAX,wallet_name,application_name ) ; return stat( path,&st ) ; } } void make_path( const char * e ) ; char * home_path( void ) ; void lxqt_wallet_application_wallet_path( char * path,uint32_t path_buffer_size,const char * application_name ) { char * e = NULL ; #ifndef _WIN32 struct passwd * pass = getpwuid( getuid() ) ; snprintf( path,path_buffer_size,"%s/.config/lxqt/wallets/%s/",pass->pw_dir,application_name ) ; #else e = home_path() ; snprintf( path,path_buffer_size,"%s/.config/lxqt/wallets/%s/",e,application_name ) ; free( e ) ; #endif if( e && path && path_buffer_size && application_name ){} } static char * _wallet_full_path( char * path_buffer,uint32_t path_buffer_size,const char * wallet_name,const char * application_name ) { char path_1[ PATH_MAX - 16 ] ; lxqt_wallet_application_wallet_path( path_1,sizeof( path_1 ),application_name ) ; snprintf( path_buffer,path_buffer_size,"%s/%s%s",path_1,wallet_name,WALLET_EXTENSION ) ; return path_buffer ; } static void _create_application_wallet_path( const char * application_name ) { char path[ PATH_MAX ] ; #ifndef _WIN32 char * e ; lxqt_wallet_application_wallet_path( path,PATH_MAX,application_name ) ; for( e = path + 1 ; *e != '\0' ; e++ ){ if( *e == '/' ){ *e = '\0' ; mkdir( path,0755 ) ; *e = '/' ; } } #else make_path( path ) ; #endif if( application_name ){} } static gcry_error_t _create_temp_key( char * output_key,uint32_t output_key_size,const char * input_key,uint32_t input_key_length ) { gcry_md_hd_t md ; unsigned char * digest ; gcry_error_t r = gcry_md_open( &md,GCRY_MD_SHA256,GCRY_MD_FLAG_SECURE ) ; if( _passed( r ) ){ gcry_md_write( md,input_key,input_key_length ) ; gcry_md_final( md ) ; digest = gcry_md_read( md,0 ) ; if( digest == NULL ){ r = !GPG_ERR_NO_ERROR ; }else{ memcpy( output_key,digest,output_key_size ) ; } gcry_md_close( md ) ; } return r ; } /* * gcry_kdf_derive() doesnt seem to work with empty passphrases,to work around it,we create a temporary passphrases * based on provided passphrase and then feed the temporary key to gcry_kdf_derive() */ static gcry_error_t _create_key( const char salt[ SALT_SIZE ], char output_key[ PASSWORD_SIZE ],const char * input_key,uint32_t input_key_length ) { char temp_key[ PASSWORD_SIZE ] ; gcry_error_t r = _create_temp_key( temp_key,PASSWORD_SIZE,input_key,input_key_length ) ; if( _passed( r ) ){ return gcry_kdf_derive( temp_key,PASSWORD_SIZE,GCRY_KDF_PBKDF2,GCRY_MD_SHA256, salt,SALT_SIZE,PBKDF2_ITERATIONS,PASSWORD_SIZE,output_key ) ; }else{ return r ; } } static void _get_iv_from_wallet_header( char iv[ IV_SIZE ],int fd ) { lseek( fd,SALT_SIZE,SEEK_SET ) ; _lxqt_wallet_read( fd,iv,IV_SIZE ) ; } static void _get_salt_from_wallet_header( char salt[ SALT_SIZE ],int fd ) { lseek( fd,0,SEEK_SET ) ; _lxqt_wallet_read( fd,salt,SALT_SIZE ) ; } static void _get_volume_info( char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ],int fd ) { lseek( fd,IV_SIZE + SALT_SIZE,SEEK_SET ) ; _lxqt_wallet_read( fd,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ) ; } static void _get_load_information( lxqt_wallet_t w,const char * buffer ) { buffer = buffer + MAGIC_STRING_BUFFER_SIZE ; memcpy( &w->wallet_data_size,buffer,sizeof( uint64_t ) ) ; memcpy( &w->wallet_data_entry_count,buffer + sizeof( uint64_t ),sizeof( uint64_t ) ) ; } static void _get_random_data( char * buffer,size_t buffer_size ) { int fd ; fd = open( "/dev/urandom",O_RDONLY ) ; if( fd != -1 ){ _lxqt_wallet_read( fd,buffer,buffer_size ) ; _lxqt_wallet_close( fd ) ; }else{ gcry_create_nonce( buffer,buffer_size ) ; } } static int _password_match( const char * buffer ) { return memcmp( buffer,MAGIC_STRING,MAGIC_STRING_SIZE ) == 0 ; } static void _create_magic_string_header( char magic_string[ MAGIC_STRING_BUFFER_SIZE ] ) { uint16_t version = VERSION ; /* * write 11 bytes of magic string */ memcpy( magic_string,MAGIC_STRING,MAGIC_STRING_SIZE ) ; /* * write version information in the remaining 5 bytes of the 16 byte buffer */ memcpy( magic_string + MAGIC_STRING_SIZE,&version,sizeof( uint16_t ) ) ; } static int _wallet_is_compatible( const char * buffer ) { uint16_t version ; memcpy( &version,buffer + MAGIC_STRING_SIZE,sizeof( uint16_t ) ) ; /* * This source file should be able to guarantee it can open volumes that have the same major version number */ return version >= VERSION && version < ( VERSION + 100 ) ; } static int _volume_version( const char * buffer ) { uint16_t version ; memcpy( &version,buffer + MAGIC_STRING_SIZE,sizeof( uint16_t ) ) ; return ( int )version ; } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/backend/lxqtwallet.h000066400000000000000000000342501425361753700257400ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LXQTWALLET_H #define LXQTWALLET_H #ifdef __cplusplus extern "C" { #endif #include /* * NOTE: For documentation on how to use this API,look at the end of this header file. * * NOTE: This API takes anything of any size,most arguments takes "char *" or "const char *" for convenience * since most typical use case will be storage of strings and these argument types will aleviate this use case * from casting if the API was using "void *" or "const void *" as some would expect. */ typedef struct lxqt_wallet_struct * lxqt_wallet_t ; /* * error values */ typedef enum{ lxqt_wallet_no_error = 0, lxqt_wallet_wrong_password, lxqt_wallet_wallet_exists, lxqt_wallet_gcry_cipher_open_failed, lxqt_wallet_gcry_cipher_setkey_failed, lxqt_wallet_gcry_cipher_setiv_failed, lxqt_wallet_gcry_cipher_encrypt_failed, lxqt_wallet_gcry_cipher_decrypt_failed, lxqt_wallet_failed_to_open_file, lxqt_wallet_failed_to_allocate_memory, lxqt_wallet_invalid_argument, lxqt_wallet_incompatible_wallet, lxqt_wallet_failed_to_create_key_hash, lxqt_wallet_libgcrypt_version_mismatch }lxqt_wallet_error; /* * key can not be NULL, * a NULL value or a non NULL value of size 0 will be taken as an empty value. */ lxqt_wallet_error lxqt_wallet_add_key( lxqt_wallet_t,const char * key,uint32_t key_size,const char * key_value,uint32_t key_value_length ) ; /* * open "wallet_name" wallet of application "application_name" using a password of size password_length. * * The rest of the API except lxqt_wallet_create() are undefined if this function returns a non zero number */ lxqt_wallet_error lxqt_wallet_open( lxqt_wallet_t *,const char * password,uint32_t password_length, const char * wallet_name,const char * application_name ) ; /* * create a new wallet named "wallet_name" owned by application "application_name" using a password "password" of size "password_length". */ lxqt_wallet_error lxqt_wallet_create( const char * password,uint32_t password_length,const char * wallet_name,const char * application_name ) ; /* * give a list of all wallets that belong to a program * Returned value is a NULL terminated array of strings with names of program wallets. * size argument will contain the number of wallets managed by the program * The caller of this function is expected to free() the returned value. * The caller of this function is expected to free() all individual entries in the returned array */ char ** lxqt_wallet_wallet_list( const char * application_name,int * size ) ; /* * return the version of the library used to create the volume. * -1 is returned on error */ int lxqt_wallet_volume_version( const char * wallet_name,const char * application_name,const char * password,uint32_t password_length ) ; /* * return the version of this library. * return value will be something like 200 for version 2.0.0 */ int lxqt_wallet_library_version( void ) ; /* * delete a key. */ lxqt_wallet_error lxqt_wallet_delete_key( lxqt_wallet_t,const char * key,uint32_t key_size ) ; /* * delete a wallet named "wallet_name" of an application named "application_name" exists */ lxqt_wallet_error lxqt_wallet_delete_wallet( const char * wallet_name,const char * application_name ) ; /* * close a wallet handle. */ lxqt_wallet_error lxqt_wallet_close( lxqt_wallet_t * ) ; /* * Check if a wallet named "wallet_name" of an application named "application_name" exists * returns 0 if the wallet exist */ int lxqt_wallet_exists( const char * wallet_name,const char * application_name ) ; /* * returns a path to where the wallet file is stored. * on return path_buffer will contain something like "/home/$USER/.local/application_name/wallets" */ void lxqt_wallet_application_wallet_path( char * path_buffer,uint32_t path_buffer_size,const char * application_name ) ; /* * returns the amount of memory managed data consumes. */ uint64_t lxqt_wallet_wallet_size( lxqt_wallet_t ) ; /* * returns the number of elements in the wallet */ uint64_t lxqt_wallet_wallet_entry_count( lxqt_wallet_t ) ; typedef struct{ const char * key ; uint32_t key_size ; const char * key_value ; uint32_t key_value_size ; }lxqt_wallet_key_values_t ; typedef struct{ uint64_t iter_pos ; lxqt_wallet_key_values_t entry ; }lxqt_wallet_iterator_t ; /* * iterate over the internal data structure and return an entry at the current interator position. * Any operation that modifies the internal data structure invalidates the iterator. * * 0 is returned when the end of the list is reached or on error * 1 is returned otherwise and the info at the current iterator position is returned through the "lxqt_wallet_key_values_t" * structure in the iterator. * * Loot at the example at the end of this header file to see how to use this function. */ int lxqt_wallet_iter_read_value( lxqt_wallet_t,lxqt_wallet_iterator_t * ) ; /* * 1 is returned if a matching key was found and key_value structure was filled up. * 0 is returned if a matching key was not found. * Content of the key_value returned are undefined after an entry is added or removed from the list */ int lxqt_wallet_read_key_value( lxqt_wallet_t,const char * key,uint32_t key_size,lxqt_wallet_key_values_t * key_value ) ; /* * returns 1 if a wallet has a key and 0 otherwise */ int lxqt_wallet_wallet_has_key( lxqt_wallet_t,const char * key,uint32_t key_size ) ; /* * returns 1 if value was found in one of the entries. * returns 0 otherwise. * If an entry is found,key_value argument will be filled up * Content of the key_value returned are undefined after an entry is added or removed from the list */ int lxqt_wallet_wallet_has_value( lxqt_wallet_t,const char * value,uint32_t value_size,lxqt_wallet_key_values_t * key_value ) ; /* * change the wallet password */ lxqt_wallet_error lxqt_wallet_change_wallet_password( lxqt_wallet_t,const char * new_password,uint32_t new_password_size ) ; /* * get a file given by argument "source" and create an encrypted version of the file given by argument "destination" using * a password "password" of length "password_length" * * function is an argument pointer to a function that takes an interger and returns an integer.The input argument will * show progress in percentage.If the return value of the function is non zero,the process will terminate. */ lxqt_wallet_error lxqt_wallet_create_encrypted_file( const char * password,uint32_t password_length, const char * source,const char * destination,int( *function )( int,void * ),void * ) ; /* * get an encrypted file given by argument "source" and create an un encrypted version of the file given by argument "destination" using * a password "password" of length "password_length" * * function is an argument pointer to a function that takes an interger and returns an integer.The input argument will * show progress in percentage.If the return value of the function is non zero,the process will terminate. */ lxqt_wallet_error lxqt_wallet_create_decrypted_file( const char * password,uint32_t password_length, const char * source,const char * destination,int( *function )( int,void * ),void * ) ; /* * undocumented API */ char * _lxqt_wallet_get_wallet_data( lxqt_wallet_t wallet ) ; /* * below is a complete program that tests the library functionality,it may be useful as a * source of how the use the API */ #if 0 #include "lxqtwallet.h" #include #include #include /* * This source file shows how the library can be used */ static const char * wallet_name = "wallet_name" ; static const char * application_name = "application_name" ; #define stringsAreEqual( x,y ) strcmp( x,y ) == 0 int main( int argc,char * argv[] ) { lxqt_wallet_t wallet ; lxqt_wallet_error r = lxqt_wallet_no_error ; const char * f ; const char * z ; const char * command ; char ** p ; lxqt_wallet_key_values_t value ; lxqt_wallet_iterator_t iter ; int a ; int b ; if( argc < 2 ){ printf( "wrong number of arguments\n" ) ; return lxqt_wallet_invalid_argument ; } command = argv[ 1 ] ; if( stringsAreEqual( command,"create" ) ){ /* * create a new wallet * additional arguments: password * eg ./wallet create xxx */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_create( f,strlen( f ),wallet_name,application_name ) ; } }else if( stringsAreEqual( command,"add" ) ){ /* * add an entry to the wallet * additional arguments: password key key_value * eg ./wallet add xxx alicia abc */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r != lxqt_wallet_no_error ){ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occurred" ) ; } }else{ f = argv[ 3 ] ; z = argv[ 4 ] ; r = lxqt_wallet_add_key( wallet,f,strlen( f ) + 1,z,strlen( z ) + 1 ) ; lxqt_wallet_close( &wallet ) ; } }else if( stringsAreEqual( command,"read" ) ){ /* * read an value in a wallet through its key * additional arguments: password key key_value * eg ./wallet read xxx alicia */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r != lxqt_wallet_no_error ){ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occurred" ) ; } }else{ f = argv[ 3 ] ; if( lxqt_wallet_read_key_value( wallet,f,strlen( f ) + 1,&value ) ){ printf( "key=%s:value=%s\n",value.key,value.key_value ) ; }else{ printf( "key=%s:value=(NULL)\n",f ) ; } lxqt_wallet_close( &wallet ) ; } }else if( stringsAreEqual( command,"print" ) ){ /* * print all entries in the wallet * additional arguments: password * eg ./wallet print xxx */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r == lxqt_wallet_no_error ){ iter.iter_pos = 0 ; while( lxqt_wallet_iter_read_value( wallet,&iter ) ){ printf( "key=%s\tkey value=\"%s\"\n",iter.entry.key,iter.entry.key_value ) ; } lxqt_wallet_close( &wallet ) ; }else{ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occurred" ) ; } } }else if( stringsAreEqual( command,"delete" ) ){ /* * delete a key from a wallet * additional arguments: password key * eg ./wallet delete xxx alicia */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r == lxqt_wallet_no_error ){ f = argv[ 3 ] ; r = lxqt_wallet_delete_key( wallet,f,strlen( f ) + 1 ) ; lxqt_wallet_close( &wallet ) ; }else{ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occurred" ) ; } } }else if( stringsAreEqual( command,"change" ) ){ /* * replace wallet key * additional arguments: old_password new_password * eg ./wallet replace xxx zzz */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r == lxqt_wallet_no_error ){ f = argv[ 3 ] ; r = lxqt_wallet_change_wallet_password( wallet,f,strlen( f ) ) ; lxqt_wallet_close( &wallet ) ; }else{ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occurred" ) ; } } }else if( stringsAreEqual( command,"value" ) ){ /* * returns a key with a particular value * additional arguments: password value * eg ./wallet value xxx zzz */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r == lxqt_wallet_no_error ){ f = argv[ 3 ] ; if( lxqt_wallet_wallet_has_value( wallet,f,strlen( f ) + 1,&value ) ){ printf( "key=\"%s\"\nkey size=%d\n",value.key,value.key_size ) ; }else{ printf( "key=\"\"\n" ) ; } lxqt_wallet_close( &wallet ) ; }else{ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occurred" ) ; } } }else if( stringsAreEqual( command,"version" ) ){ /* * return the version of the library used to create the volume * additional argument: password * example ./wallet version zzz */ if( argc < 3 ){ printf( "wrong number of arguments\n" ) ; }else{ f = argv[ 2 ] ; printf( "%d\n",lxqt_wallet_volume_version( wallet_name,application_name,f,strlen( f ) ) ) ; } }else{ puts( "unknown option" ) ; } return r ; } #endif #ifdef __cplusplus } #endif #endif zuluCrypt-6.2.0/external_libraries/lxqt_wallet/changelog000066400000000000000000000001561425361753700236470ustar00rootroot00000000000000 - version 1.0.0 - initial release - libgcrypt is used for encryption and decryption of the internal wallet zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/000077500000000000000000000000001425361753700236125ustar00rootroot00000000000000zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/CMakeLists.txt000066400000000000000000000320631425361753700263560ustar00rootroot00000000000000 cmake_minimum_required(VERSION 3.0.2) if( WIN32 ) cmake_policy(SET CMP0020 NEW) endif() INCLUDE(FindPkgConfig) # # set below variable to "false" if you want to build a static library # set(BUILD_SHARED "false") set(LIBRARY_VERSION "2.0.0") add_definitions(-I${PROJECT_BINARY_DIR}/frontend) add_definitions(-I${PROJECT_BINARY_DIR}/backend) add_definitions(-I${PROJECT_BINARY_DIR}/src/lxqt_wallet/frontend) add_definitions(-I${PROJECT_BINARY_DIR}/src/lxqt_wallet/backend) add_definitions(-I${PROJECT_BINARY_DIR}) INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) if( APPLE ) file( WRITE ${PROJECT_BINARY_DIR}/osx_keychain.h "#define OSX_KEYCHAIN 1" ) else() file( WRITE ${PROJECT_BINARY_DIR}/osx_keychain.h "#define OSX_KEYCHAIN 0" ) endif() file( WRITE ${PROJECT_BINARY_DIR}/translations_path.h " #define TRANSLATIONS_PATH \"${CMAKE_INSTALL_PREFIX}/share/lxqt/translations/lxqt-wallet/\" ") if(QT5) find_package(Qt5Widgets REQUIRED) find_package(Qt5Core REQUIRED) find_package(Qt5DBus REQUIRED) set(CMAKE_INCLUDE_CURRENT_DIR ON) include_directories(${Qt5Widgets_INCLUDE_DIRS}) include_directories(${Qt5DBus_INCLUDE_DIRS}) add_definitions(${Qt5Widgets_DEFINITIONS}) set( KF5 "true" ) else() find_package(Qt4 REQUIRED) SET(QT_USE_QTCORE TRUE) SET(QT_USE_QTGUI TRUE) add_definitions(-I${Qt4_INCLUDE_DIR}) add_definitions(-I${QT_HEADERS_DIR}) INCLUDE(${QT_USE_FILE}) INCLUDE(${QT_USE_FILE}) endif() if( APPLE ) SET(NOSECRETSUPPORT "true") endif() if(NOSECRETSUPPORT) SET(SECRET_SUPPORT "false") file(WRITE ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_SECRET_SUPPORT 0\n") else() pkg_check_modules(LIBSECRET libsecret-1) if(LIBSECRET_FOUND) add_subdirectory(libsecret) SET(SECRET_SUPPORT "true") file(WRITE ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_SECRET_SUPPORT 1\n") else() SET(SECRET_SUPPORT "false") file(WRITE ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_SECRET_SUPPORT 0\n") endif() endif() if( CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0.0) set( CMAKE_CXX_STANDARD 20 ) MESSAGE( STATUS "Setting C++ version to C++20" ) else() set( CMAKE_CXX_STANDARD 14 ) MESSAGE( STATUS "Setting C++ version to C++14" ) endif() set( CMAKE_CXX_STANDARD_REQUIRED ON ) set( CMAKE_CXX_EXTENSIONS OFF) if(NOKDESUPPORT) SET(KDE_SUPPORT "false") SET(KWALLET_SUPPORT "false") file(APPEND ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_KWALLET_SUPPORT 0\n") else() if(KF5) find_package(Qt5Widgets REQUIRED) find_package(Qt5Core REQUIRED) cmake_policy(SET CMP0012 NEW) find_package(KF5Wallet QUIET) find_package(KF5Notifications QUIET) if(KF5Wallet_FOUND AND KF5Notifications_FOUND ) file(APPEND ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_KWALLET_SUPPORT 1\n") SET(KDE_SUPPORT "true") SET(KWALLET_SUPPORT "true") else() file(APPEND ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_KWALLET_SUPPORT 0\n") SET(KDE_SUPPORT "false") SET(KWALLET_SUPPORT "false") endif() else() find_package(KDE4 QUIET) if(KDE4_FOUND) include(KDE4Defaults) include_directories(${KDE4_INCLUDES}) add_definitions(-I${KDE4_INCLUDE_DIR}) add_definitions(-I${Qt4_INCLUDE_DIR}) add_definitions(-I${QT_HEADERS_DIR}) SET(KDE_SUPPORT "true") if(NOKWALLETSUPPORT) SET(KWALLET_SUPPORT "false") file(APPEND ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_KWALLET_SUPPORT 0\n") else() find_library(LIBKWALLETBACKEND libkwalletbackend.so) if(NOT LIBKWALLETBACKEND) # some distributions do not have libkwalletbackend.so for reasons i currently do not know # look for libkwalletbackend.sp.4 when the above happen find_library(LIBKWALLETBACKEND libkwalletbackend.so.4) if(NOT LIBKWALLETBACKEND) file(APPEND ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_KWALLET_SUPPORT 0\n") SET(KWALLET_SUPPORT "false") else() SET(KWALLET_SUPPORT "true") file(APPEND ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_KWALLET_SUPPORT 1\n") endif() else() SET(KWALLET_SUPPORT "true") file(APPEND ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_KWALLET_SUPPORT 1\n") endif() endif() find_library(LIBKDEUI libkdeui.so) if(NOT LIBKDEUI) # adding this one just in case the same case as above happen find_library(LIBKDEUI libkdeui.so.5) endif() if(NOT LIBKDEUI) SET(KDE_SUPPORT "false") message(STATUS "could not find libkdeui.so or libkdeui.so.5,please make sure you have kde development libraries installed and try again") endif() find_library(LIBKDECORE libkdecore.so) if(NOT LIBKDECORE) # adding this one just in case the same case as above happen find_library(LIBKDECORE libkdecore.so.5) endif() if(NOT LIBKDECORE) SET(KDE_SUPPORT "false") message(STATUS "could not find libkdecore.so or libkdecore.so.5,please make sure you have kde development libraries installed and try again") endif() else() file(APPEND ${PROJECT_BINARY_DIR}/storage_manager.h "\n#define HAS_KWALLET_SUPPORT 0\n") SET(KDE_SUPPORT "false") SET(KWALLET_SUPPORT "false") endif() endif() endif() if(KWALLET_SUPPORT) message(STATUS "\n--------------------------------------------------------------------------") message(STATUS "kwallet support found,will build kwallet functionality") message(STATUS "-----------------------------------------------------------------------") else() message(STATUS "\n--------------------------------------------------------------------------") message(STATUS "kwallet support NOT found, support will be discovered at runtime through dbus") message(STATUS "-----------------------------------------------------------------------") endif() if(SECRET_SUPPORT) message(STATUS "\n--------------------------------------------------------------------------") message(STATUS "libsecret support found,will build libsecret functionality") message(STATUS "-----------------------------------------------------------------------") else() message(STATUS "\n--------------------------------------------------------------------------") message(STATUS "libsecret support NOT found,will not build libsecret functionality") message(STATUS "-----------------------------------------------------------------------") endif() set(UI_FILES changepassworddialog.ui password_dialog.ui) set(MOC_FILES changepassworddialog.h password_dialog.h task.h lxqt_kwallet-dbus.h) set(MOC_FILES_1 changepassworddialog.h password_dialog.h lxqt_kwallet.h task.h) set(MOC_FILES_2 changepassworddialog.h password_dialog.h lxqt_kwallet.h task.h) set(MOC_FILES_3 changepassworddialog.h password_dialog.h task.h lxqt_kwallet-dbus.h) if( WIN32 ) set(SRC lxqt_windows_dpapi.cpp lxqt_osx_keychain.cpp changepassworddialog.cpp password_dialog.cpp lxqt_wallet.cpp) set(SRC_1 lxqt_windows_dpapi.cpp lxqt_osx_keychain.cpp changepassworddialog.cpp password_dialog.cpp lxqt_wallet.cpp lxqt_kwallet.cpp) set(SRC_2 lxqt_windows_dpapi.cpp lxqt_osx_keychain.cpp changepassworddialog.cpp password_dialog.cpp lxqt_wallet.cpp lxqt_kwallet.cpp lxqt_libsecret.cpp) set(SRC_3 lxqt_windows_dpapi.cpp lxqt_osx_keychain.cpp changepassworddialog.cpp password_dialog.cpp lxqt_wallet.cpp lxqt_libsecret.cpp) else() set(SRC lxqt_windows_dpapi.cpp lxqt_osx_keychain.cpp changepassworddialog.cpp password_dialog.cpp lxqt_internal_wallet.cpp lxqt_wallet.cpp lxqt_kwallet-dbus.cpp ) set(SRC_1 lxqt_windows_dpapi.cpp lxqt_osx_keychain.cpp changepassworddialog.cpp password_dialog.cpp lxqt_internal_wallet.cpp lxqt_wallet.cpp lxqt_kwallet.cpp ) set(SRC_2 lxqt_windows_dpapi.cpp lxqt_osx_keychain.cpp changepassworddialog.cpp password_dialog.cpp lxqt_internal_wallet.cpp lxqt_wallet.cpp lxqt_kwallet.cpp lxqt_libsecret.cpp) set(SRC_3 lxqt_windows_dpapi.cpp lxqt_osx_keychain.cpp changepassworddialog.cpp password_dialog.cpp lxqt_internal_wallet.cpp lxqt_wallet.cpp lxqt_libsecret.cpp lxqt_kwallet-dbus.cpp ) endif() if(BUILD_SHARED) set( LIBRARY_TYPE "SHARED") else() set( LIBRARY_TYPE "STATIC") endif() if(QT5) Qt5_WRAP_UI(UI ${UI_FILES}) if(KDE_SUPPORT) if(KWALLET_SUPPORT) if(SECRET_SUPPORT) Qt5_WRAP_CPP(MOC ${MOC_FILES_2}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC_2} ${MOC}) target_link_libraries(lxqt-wallet secretlib) target_link_libraries(lxqt-wallet "${Qt5Widgets_LIBRARIES}") target_link_libraries(lxqt-wallet "${Qt5Core_LIBRARIES}") target_link_libraries(lxqt-wallet "${Qt5DBus_LIBRARIES}") target_link_libraries(lxqt-wallet KF5::Wallet KF5::Notifications) else() Qt5_WRAP_CPP(MOC ${MOC_FILES_1}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC_1} ${MOC}) target_link_libraries(lxqt-wallet "${Qt5Widgets_LIBRARIES}") target_link_libraries(lxqt-wallet "${Qt5Core_LIBRARIES}") target_link_libraries(lxqt-wallet "${Qt5DBus_LIBRARIES}") target_link_libraries(lxqt-wallet KF5::Wallet KF5::Notifications) endif() else() if(SECRET_SUPPORT) Qt5_WRAP_CPP(MOC ${MOC_FILES_3}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC_3} ${MOC}) target_link_libraries(lxqt-wallet secretlib) target_link_libraries(lxqt-wallet "${Qt5Widgets_LIBRARIES}") target_link_libraries(lxqt-wallet "${QtCore_LIBRARIES}") target_link_libraries(lxqt-wallet "${Qt5DBus_LIBRARIES}") else() Qt5_WRAP_CPP(MOC ${MOC_FILES}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC} ${MOC}) target_link_libraries(lxqt-wallet "${Qt5Widgets_LIBRARIES}") target_link_libraries(lxqt-wallet "${QtCore_LIBRARIES}") target_link_libraries(lxqt-wallet "${Qt5DBus_LIBRARIES}") target_link_libraries(lxqt-wallet "${LIBKDEUI}") target_link_libraries(lxqt-wallet "${LIBKDECORE}") endif() endif() else() if(SECRET_SUPPORT) Qt5_WRAP_CPP(MOC ${MOC_FILES_3}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC_3} ${MOC}) target_link_libraries(lxqt-wallet secretlib) target_link_libraries(lxqt-wallet "${Qt5Widgets_LIBRARIES}") target_link_libraries(lxqt-wallet "${QtCore_LIBRARIES}") target_link_libraries(lxqt-wallet "${Qt5DBus_LIBRARIES}") else() Qt5_WRAP_CPP(MOC ${MOC_FILES}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC} ${MOC}) target_link_libraries(lxqt-wallet "${Qt5Widgets_LIBRARIES}") target_link_libraries(lxqt-wallet "${QtCore_LIBRARIES}") target_link_libraries(lxqt-wallet "${Qt5DBus_LIBRARIES}") endif() endif() else() Qt4_WRAP_UI(UI ${UI_FILES}) if(KDE_SUPPORT) if(KWALLET_SUPPORT) if(SECRET_SUPPORT) Qt4_WRAP_CPP(MOC ${MOC_FILES_2}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC_2} ${MOC}) target_link_libraries(lxqt-wallet secretlib) set(link_libraries "-L${KDE4_LIB_DIR} -L${QT_LIBRARY_DIR} ${LIBKDEUI} ${LIBKDECORE} ${LIBKWALLETBACKEND}") else() Qt4_WRAP_CPP(MOC ${MOC_FILES_1}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC_1} ${MOC}) set(link_libraries "-L${KDE4_LIB_DIR} -L${QT_LIBRARY_DIR} ${LIBKDEUI} ${LIBKDECORE} ${LIBKWALLETBACKEND}") endif() else() if(SECRET_SUPPORT) Qt4_WRAP_CPP(MOC ${MOC_FILES_3}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC_3} ${MOC}) target_link_libraries(lxqt-wallet secretlib) set(link_libraries "-L${KDE4_LIB_DIR} -L${QT_LIBRARY_DIR}") else() Qt4_WRAP_CPP(MOC ${MOC_FILES}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC} ${MOC}) set(link_libraries "-L${KDE4_LIB_DIR} -L${QT_LIBRARY_DIR} ${LIBKDEUI} ${LIBKDECORE}") endif() endif() else() if(SECRET_SUPPORT) Qt4_WRAP_CPP(MOC ${MOC_FILES_3}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC_3} ${MOC}) target_link_libraries(lxqt-wallet secretlib) set(link_libraries "-L${KDE4_LIB_DIR} -L${QT_LIBRARY_DIR}") else() Qt4_WRAP_CPP(MOC ${MOC_FILES}) add_library(lxqt-wallet ${LIBRARY_TYPE} ${UI} ${SRC} ${MOC}) endif() endif() endif() if( WIN32 ) set_target_properties(lxqt-wallet PROPERTIES COMPILE_FLAGS "-Wextra -Wall -s -pedantic ") else() set_target_properties(lxqt-wallet PROPERTIES COMPILE_FLAGS "-Wextra -Wall -s -fPIC -pedantic ") endif() set_target_properties(lxqt-wallet PROPERTIES SOVERSION "${LIBRARY_VERSION}") if( WIN32 ) TARGET_LINK_LIBRARIES(lxqt-wallet -lcrypt32 -lbcrypt "${link_libraries}" lxqt-wallet-backend) else() TARGET_LINK_LIBRARIES(lxqt-wallet "${link_libraries}" lxqt-wallet-backend) endif() if( APPLE ) find_library(COREFOUNDATION_LIBRARY CoreFoundation REQUIRED) find_library(SECURITY_LIBRARY Security REQUIRED) TARGET_LINK_LIBRARIES(lxqt-wallet ${COREFOUNDATION_LIBRARY} ${SECURITY_LIBRARY}) endif() if(BUILD_SHARED) install(TARGETS lxqt-wallet RUNTIME LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") install(FILES lxqt_wallet.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/lxqt") file( WRITE ${PROJECT_BINARY_DIR}/lxqt-wallet.pc "prefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${CMAKE_INSTALL_PREFIX} libdir=${CMAKE_INSTALL_FULL_LIBDIR} includedir=${CMAKE_INSTALL_FULL_INCLUDEDIR}/lxqt Name: lxqt_wallet Description: lxqt secure storage system Version: ${LIBRARY_VERSION} Libs: -L${CMAKE_INSTALL_FULL_LIBDIR} -lQtGui -lQtCore -lgcrypt Cflags: -I${CMAKE_INSTALL_FULL_INCLUDEDIR}/lxqt \n") install(FILES ${PROJECT_BINARY_DIR}/lxqt-wallet.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig/ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) endif() zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/README000066400000000000000000000014771425361753700245030ustar00rootroot00000000000000This project seeks to give a functionality for secure storage of information that can be presented in key-pair values like user names-passwords. Currently the project can store the information in KDE's kwallet,GNOME's secret service or in an internal system. The internal secure storage system allows the functionality to be provided without dependencies on KDE or gnome libraries. The header file with the public API is named "lxqt_wallet.h". This project is designed to be used by other projects simply by adding the source folder in the build system and start using it. The front end is build on Qt/C++ and has an optional dependency on KDE's kwallet and GNOME's secretservice. The project allows other Qt based project's to target one API and use it for secure storage of information in different secure storage systems. zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/changepassworddialog.cpp000066400000000000000000000210041425361753700305030ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "changepassworddialog.h" #include "ui_changepassworddialog.h" #include namespace Task = LXQt::Wallet::Task ; LXQt::Wallet::changePassWordDialog::changePassWordDialog(QWidget *parent, const QString &walletName, const QString &applicationName) : QDialog(parent), m_ui(new Ui::changePassWordDialog), m_walletName(walletName), m_applicationName(applicationName) { m_ui->setupUi(this) ; this->setFixedSize(this->size()) ; this->setWindowFlags(this->windowFlags() | Qt::WindowStaysOnTopHint) ; if (parent) { this->setWindowIcon(parent->windowIcon()) ; } connect(m_ui->pushButtonCancel, SIGNAL(clicked()), this, SLOT(cancel())) ; m_ui->pushButtonOK->setVisible(false) ; m_ui->textEdit->setVisible(false) ; m_ui->textEdit_2->setVisible(false) ; this->installEventFilter(this) ; } bool LXQt::Wallet::changePassWordDialog::eventFilter(QObject *watched, QEvent *event) { if (watched == this) { if (event->type() == QEvent::KeyPress) { auto keyEvent = static_cast< QKeyEvent * >(event) ; if (keyEvent->key() == Qt::Key_Escape) { this->HideUI() ; return true ; } } } return false ; } void LXQt::Wallet::changePassWordDialog::HideUI() { this->hide() ; this->deleteLater() ; } void LXQt::Wallet::changePassWordDialog::changeShowUI(changeFunction && change) { m_change = std::move(change) ; m_banner = m_ui->textEdit->toHtml().arg(m_applicationName, m_walletName) ; m_ui->label->setText(m_banner) ; connect(m_ui->pushButtonChange, SIGNAL(clicked()), this, SLOT(change())) ; connect(m_ui->pushButtonOK, SIGNAL(clicked()), this, SLOT(ok())) ; this->show() ; this->raise() ; this->activateWindow() ; } void LXQt::Wallet::changePassWordDialog::createShowUI(createFunction && create) { m_create = std::move(create) ; this->setWindowTitle(tr("Create a new wallet")) ; m_ui->pushButtonChange->setText(tr("Create")) ; connect(m_ui->pushButtonChange, SIGNAL(clicked()), this, SLOT(create())) ; connect(m_ui->pushButtonOK, SIGNAL(clicked()), this, SLOT(ok_1())) ; m_banner = m_ui->textEdit_2->toHtml().arg(m_applicationName, m_walletName) ; m_ui->label->setText(m_banner) ; m_ui->label_2->setEnabled(false) ; m_ui->lineEditCurrentPassWord->setEnabled(false) ; this->show() ; this->raise() ; this->activateWindow() ; } LXQt::Wallet::changePassWordDialog::~changePassWordDialog() { delete m_ui ; } void LXQt::Wallet::changePassWordDialog::create() { if (m_ui->lineEditNewPassWord->text() == m_ui->lineEditNewPassWord_2->text()) { m_create(m_ui->lineEditNewPassWord->text(), true) ; this->HideUI() ; } else { m_ui->label->setText(tr("Passwords do not match")) ; m_ui->pushButtonOK->setVisible(true) ; m_ui->pushButtonCancel->setVisible(false) ; m_ui->pushButtonChange->setVisible(false) ; m_ui->lineEditCurrentPassWord->setEnabled(false) ; m_ui->lineEditNewPassWord->setEnabled(false) ; m_ui->lineEditNewPassWord_2->setEnabled(false) ; m_ui->label->setEnabled(true) ; m_ui->label_2->setEnabled(false) ; m_ui->label_2->setEnabled(false) ; m_ui->label_3->setEnabled(false) ; m_ui->label_4->setEnabled(false) ; } } void LXQt::Wallet::changePassWordDialog::change() { m_ui->lineEditCurrentPassWord->setEnabled(false) ; m_ui->lineEditNewPassWord->setEnabled(false) ; m_ui->lineEditNewPassWord_2->setEnabled(false) ; m_ui->pushButtonChange->setEnabled(false) ; m_ui->pushButtonCancel->setEnabled(false) ; m_ui->label->setEnabled(true) ; m_ui->label_2->setEnabled(false) ; m_ui->label_2->setEnabled(false) ; m_ui->label_3->setEnabled(false) ; m_ui->label_4->setEnabled(false) ; auto n = m_ui->lineEditNewPassWord->text() ; if (n == m_ui->lineEditNewPassWord_2->text()) { auto c = m_ui->lineEditCurrentPassWord->text() ; auto m = m_change(c, n, false) ; if (m.failedToUnlock) { m_ui->pushButtonChange->setEnabled(true) ; m_ui->pushButtonCancel->setEnabled(true) ; m_ui->label->setText(tr("Wallet could not be opened with the presented key")) ; m_ui->pushButtonCancel->setVisible(false) ; m_ui->pushButtonChange->setVisible(false) ; m_ui->pushButtonOK->setVisible(true) ; m_ui->pushButtonOK->setFocus() ; } else if (m.failedToChange) { m_ui->pushButtonChange->setEnabled(true) ; m_ui->pushButtonCancel->setEnabled(true) ; m_ui->label->setText(tr("Wallet password could not be changed")) ; m_ui->pushButtonCancel->setVisible(false) ; m_ui->pushButtonChange->setVisible(false) ; m_ui->pushButtonOK->setVisible(true) ; m_ui->pushButtonOK->setFocus() ; } else { this->HideUI() ; } } else { m_ui->label->setText(tr("New passwords do not match")) ; m_ui->pushButtonOK->setVisible(true) ; m_ui->pushButtonCancel->setVisible(false) ; m_ui->pushButtonChange->setVisible(false) ; m_ui->pushButtonOK->setFocus() ; } } void LXQt::Wallet::changePassWordDialog::cancel() { m_change(QString(), QString(), true) ; m_create(QString(), false) ; this->HideUI() ; } void LXQt::Wallet::changePassWordDialog::ok() { m_ui->lineEditCurrentPassWord->setEnabled(true) ; m_ui->lineEditCurrentPassWord->clear() ; m_ui->lineEditCurrentPassWord->setFocus() ; m_ui->lineEditNewPassWord->setEnabled(true) ; m_ui->lineEditNewPassWord_2->setEnabled(true) ; m_ui->label->setEnabled(true) ; m_ui->label_2->setEnabled(true) ; m_ui->label_2->setEnabled(true) ; m_ui->label_3->setEnabled(true) ; m_ui->label_4->setEnabled(true) ; m_ui->pushButtonOK->setVisible(false) ; m_ui->pushButtonCancel->setVisible(true) ; m_ui->pushButtonChange->setVisible(true) ; m_ui->pushButtonCancel->setEnabled(true) ; m_ui->pushButtonChange->setEnabled(true) ; m_ui->label->setText(m_banner) ; } void LXQt::Wallet::changePassWordDialog::ok_1() { if (m_ui->label->text() == tr("Passwords do not match")) { m_ui->lineEditCurrentPassWord->setEnabled(false) ; m_ui->lineEditNewPassWord->setEnabled(true) ; m_ui->lineEditNewPassWord->setFocus() ; m_ui->lineEditNewPassWord_2->setEnabled(true) ; m_ui->label->setEnabled(true) ; m_ui->label_2->setEnabled(true) ; m_ui->label_2->setEnabled(true) ; m_ui->label_3->setEnabled(true) ; m_ui->label_4->setEnabled(true) ; m_ui->pushButtonOK->setVisible(false) ; m_ui->pushButtonCancel->setVisible(true) ; m_ui->pushButtonChange->setVisible(true) ; m_ui->pushButtonCancel->setEnabled(true) ; m_ui->pushButtonChange->setEnabled(true) ; m_ui->label->setText(m_banner) ; } } void LXQt::Wallet::changePassWordDialog::closeEvent(QCloseEvent *e) { e->ignore() ; this->cancel() ; } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/changepassworddialog.h000066400000000000000000000074071425361753700301630ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CHANGEPASSWORDDIALOG_H #define CHANGEPASSWORDDIALOG_H #include #include #include #include #include #include #include "../backend/lxqtwallet.h" #include "task.h" #include namespace Ui { class changePassWordDialog; } namespace LXQt { namespace Wallet { class changePassWordDialog : public QDialog { Q_OBJECT public: struct changeArgs { bool failedToUnlock; bool failedToChange; }; using changeFunction = std::function< changeArgs(const QString &old, const QString &New, bool) >; using createFunction = std::function< void(const QString &, bool) >; static changePassWordDialog &createInstance(QWidget *parent, const QString &walletName, const QString &applicationName, createFunction && function) { auto &e = *(new changePassWordDialog(parent, walletName, applicationName)); e.createShowUI(std::move(function)); return e; } static changePassWordDialog &changeInstance(QWidget *parent, const QString &walletName, const QString &applicationName, changeFunction && function) { auto &e = *(new changePassWordDialog(parent, walletName, applicationName)); e.changeShowUI(std::move(function)); return e; } explicit changePassWordDialog(QWidget *parent = 0, const QString &walletName = QString(), const QString &applicationName = QString()); void createShowUI(createFunction &&); void changeShowUI(changeFunction &&); ~changePassWordDialog(); signals: void walletpassWordChanged(bool); private slots: void create(void); void change(void); void cancel(void); void ok(void); void ok_1(void); private: void HideUI(void); void closeEvent(QCloseEvent *); bool eventFilter(QObject *watched, QEvent *event); Ui::changePassWordDialog *m_ui; lxqt_wallet_t m_wallet; QString m_walletName; QString m_applicationName; QString m_banner; std::function< void(const QString &, bool) > m_create = [](const QString &e, bool f) { Q_UNUSED(e) Q_UNUSED(f) }; std::function< changeArgs(const QString &old, const QString &New, bool) > m_change = [](const QString &old, const QString &New, bool) { Q_UNUSED(old) Q_UNUSED(New) return changeArgs {false, false}; }; }; } } #endif // CHANGEPASSWORDDIALOG_H zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/changepassworddialog.ui000066400000000000000000000174401425361753700303470ustar00rootroot00000000000000 changePassWordDialog Qt::ApplicationModal 0 0 580 284 Change Wallet's Password lxqt_wallet_icon.pnglxqt_wallet_icon.png 10 10 561 271 190 240 91 31 C&hange 230 240 101 31 &Ok 90 90 381 31 QLineEdit::Password 90 150 381 31 QLineEdit::Password 90 210 381 31 QLineEdit::Password 20 20 521 31 "XXX" want to change "YYY" password Qt::AlignCenter true 0 60 561 31 Enter Current Password Below. Qt::AlignCenter true 0 120 561 31 Enter New Password Below. Qt::AlignCenter true 0 180 561 31 Re Enter New Password Below. Qt::AlignCenter true 280 240 91 31 &Cancel 10 170 51 31 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt;">An application '</span><span style=" font-family:'Sans Serif'; font-size:9pt; font-weight:600;">%1</span><span style=" font-family:'Sans Serif'; font-size:9pt;">' has made a request for a password of its wallet '</span><span style=" font-family:'Sans Serif'; font-size:9pt; font-weight:600;">%2</span><span style=" font-family:'Sans Serif'; font-size:9pt;">' to be changed</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"><br /></p></body></html> 10 200 51 31 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt;">Enter password information below to create a new wallet '</span><span style=" font-family:'Sans Serif'; font-size:9pt; font-weight:600;">%1</span><span style=" font-family:'Sans Serif'; font-size:9pt;">' for application '</span><span style=" font-family:'Sans Serif'; font-size:9pt; font-weight:600;">%2</span><span style=" font-family:'Sans Serif'; font-size:9pt;">'</span></p></body></html> lineEditCurrentPassWord lineEditNewPassWord lineEditNewPassWord_2 pushButtonChange pushButtonOK pushButtonCancel textEdit textEdit_2 zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/libsecret.c000066400000000000000000000233231425361753700257350ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include /* * The libsecret API we use stores information in key-value pairs. * * The API requires a key to give the key's associated value. * * How can we tell how many and what keys libsecret is holding for us? * * The API does not give a list of keys it is holding for us and we solve this * problem using two schemas. * * Schema "keyValues" holds user provided keys and their associated user provided values. * * Schema "keyID" holds unique numbers generated by the library and these numbers are associated * with user provided keys. * * We also store an entry in libsecret that keeps track of the number of entries * we have. * * In "keyID" schema,we get a list of all user provided keys we are managing by looping over these * unique numbers looking for their corresponding values.These values are user provided keys. * * Once we have all the keys,we use them in "keyValue" schema to get their corresponding values and * then we return all keys and their values in key-value pairs to the library user. * */ #define BUFFER_SIZE 32 static char *_get_string_value_0(const SecretSchema *s, const char *key) { return secret_password_lookup_sync(s, NULL, NULL, "string", key, NULL); } static int _get_string_value(const SecretSchema *s, const char *key) { char *c = _get_string_value_0(s, key); int e; if (c == NULL) { return -1; } else { e = atoi(c); free(c); return e; } } static char *_get_integer_value_0(const SecretSchema *s, int key) { return secret_password_lookup_sync(s, NULL, NULL, "integer", key, NULL); } static int _get_integer_value(const SecretSchema *s, int key) { char *c = _get_integer_value_0(s, key); int e; if (c == NULL) { return -1; } else { e = atoi(c); free(c); return e; } } static int _set_integer_value(const SecretSchema *s, const char *name, const char *key, int value) { return secret_password_store_sync(s, "default", name, key, NULL, NULL, "integer", value, NULL); } static int _set_string_value(const SecretSchema *s, const char *name, const char *key, const char *value) { return secret_password_store_sync(s, "default", name, key, NULL, NULL, "string", value, NULL); } static int _number_of_entries_in_the_wallet(const SecretSchema *s) { int e = _get_string_value(s, "lxqt_wallet_size"); if (e == -1) { return 0; } else { return e; } } static int _clear_integer_value(const SecretSchema *s, int k) { return secret_password_clear_sync(s, NULL, NULL, "integer", k, NULL); } static int _clear_string_value(const SecretSchema *s, const char *k) { return secret_password_clear_sync(s, NULL, NULL, "string", k, NULL); } /* * This function is used to check if a wallet is open or not and force prompt to open it if it is not open. * * write to the wallet and the operation will succeed if the wallet is open. * If the wallet is not open,the operation will block while a user is prompted for a key to unlock it. * If the user fail to unlock it,the operation will fail. */ int lxqt_libsecret_wallet_is_open(const void *s) { const SecretSchema *e = s; return _set_string_value(e, e->name, "lxqt_wallet_open", "lxqt_wallet_open"); } char *lxqt_libsecret_get_value(const char *key, const void *s) { return _get_string_value_0(s, key); } void *lxqt_libsecret_create_schema(const char *schemaName, const char *type) { SecretSchema *s = malloc(sizeof(SecretSchema)); memset(s, '\0', sizeof(SecretSchema)); s->name = schemaName; s->flags = SECRET_SCHEMA_NONE; s->attributes[0].name = type; if (strcmp(type, "string") == 0) { s->attributes[0].type = SECRET_SCHEMA_ATTRIBUTE_STRING; } else { s->attributes[0].type = SECRET_SCHEMA_ATTRIBUTE_INTEGER; } s->attributes[1].name = "NULL"; s->attributes[1].type = 0; return s; } static gboolean _password_store_sync(const char *key, const char *value, const void *kv, const void *id, int ws) { const SecretSchema *keyValues = kv; const SecretSchema *keyID = id; int i = 0; int k; char wallet_size[ BUFFER_SIZE ]; const char *walletLabel = keyValues->name; snprintf(wallet_size, BUFFER_SIZE, "%d", ws); _set_string_value(keyValues, walletLabel, wallet_size, "lxqt_wallet_size"); while (i < ws) { k = _get_integer_value(keyID, i); if (k == -1) { if (_set_integer_value(keyID, walletLabel, key, i)) { if (_set_string_value(keyValues, walletLabel, value, key)) { return TRUE; } else { _clear_integer_value(keyID, i); return FALSE; } } else { return FALSE; } } else { i++; } } return FALSE; } gboolean lxqt_libsecret_password_store_sync(const char *key, const char *value, const void *keyValues, const void *keyID) { int j; if (lxqt_libsecret_wallet_is_open(keyValues)) { j = _get_string_value(keyValues, "lxqt_wallet_size"); if (j == -1) { return _password_store_sync(key, value, keyValues, keyID, 1); } else { return _password_store_sync(key, value, keyValues, keyID, j + 1); } } else { return FALSE; } } static gboolean _exceeded_limit(int k) { /* * We dont expect to manage 10000 entries and getting this far most likely means we are * stuck in an endless loop */ return k == 10000; } gboolean lxqt_libsecret_clear_sync(const char *key, const void *kv, const void *id) { const SecretSchema *keyValues = kv; const SecretSchema *keyID = id; int i = 0; int k = 0; int e; char *c; char wallet_size[ BUFFER_SIZE ]; const char *walletLabel = keyValues->name; int j = _number_of_entries_in_the_wallet(keyValues); if (lxqt_libsecret_wallet_is_open(keyValues)) { while (i <= j) { c = _get_integer_value_0(keyID, k); if (c != NULL) { e = strcmp(c, key); free(c); if (e == 0) { _clear_integer_value(keyID, k); e = _get_string_value(keyValues, "lxqt_wallet_size"); snprintf(wallet_size, BUFFER_SIZE, "%d", e - 1); _set_string_value(keyValues, walletLabel, wallet_size, "lxqt_wallet_size"); _clear_string_value(keyValues, key); return TRUE; } else { i++; k++; } } else { k++; if (_exceeded_limit(k)) { break; } } } } return FALSE; } char **lxqt_secret_get_all_keys(const void *kv, const void *id, size_t *count) { const SecretSchema *keyValues = kv; const SecretSchema *keyID = id; int k = 0; int i = 0; int j; char **c = NULL; char *e = NULL; *count = 0; if (lxqt_libsecret_wallet_is_open(keyValues)) { j = _number_of_entries_in_the_wallet(keyValues); c = malloc(sizeof(char *) * j); if (c != NULL) { while (i < j) { e = _get_integer_value_0(keyID, k); if (e != NULL) { *(c + i) = e; *count += 1; i++; k++; } else { k++; if (_exceeded_limit(k)) { break; } } } } } return c; } int lxqt_libsecret_wallet_size(const void *s) { return _number_of_entries_in_the_wallet(s); } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/libsecret/000077500000000000000000000000001425361753700255665ustar00rootroot00000000000000zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/libsecret/CMakeLists.txt000066400000000000000000000007141425361753700303300ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) include_directories( ${LIBSECRET_INCLUDE_DIRS} ) link_directories( ${LIBSECRET_LIBDIR} ) add_definitions( -I${LIBSECRET_INCLUDEDIR} ) set( SECRETSERVICE_LIBRARY "secretlib" ) add_library( secretlib STATIC ../libsecret.c ) target_link_libraries( secretlib ${LIBSECRET_LIBRARIES} -L${LIBSECRET_LIBDIR} ) set_target_properties( secretlib PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pedantic" ) zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_internal_wallet.cpp000066400000000000000000000262671425361753700305670ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "lxqt_internal_wallet.h" namespace Task = LXQt::Wallet::Task; LXQt::Wallet::internalWallet::internalWallet() : m_wallet(nullptr) { } LXQt::Wallet::internalWallet::~internalWallet() { lxqt_wallet_close(&m_wallet); } void LXQt::Wallet::internalWallet::setImage(const QIcon &image) { this->setWindowIcon(image); } void LXQt::Wallet::internalWallet::openWallet(QString password) { m_password = password; Task::run< lxqt_wallet_error >([ this ]() { return lxqt_wallet_open(&m_wallet, m_password.toLatin1().constData(), m_password.size(), m_walletName.toLatin1().constData(), m_applicationName.toLatin1().constData()); }).then([ this ](lxqt_wallet_error r) { this->opened(r == lxqt_wallet_no_error); }); } void LXQt::Wallet::internalWallet::opened(bool opened) { m_correctPassword(opened); m_opened = opened; if (m_opened) { if (m_loop.isRunning()) { m_loop.exit(); } this->walletIsOpen(m_opened); } } bool LXQt::Wallet::internalWallet::open(const QString &walletName, const QString &applicationName, QWidget *parent, const QString &password, const QString &displayApplicationName) { this->open(walletName, applicationName, [](bool e) { Q_UNUSED(e) }, parent, password, displayApplicationName); m_loop.exec(); return m_opened; } void LXQt::Wallet::internalWallet::open(const QString &walletName, const QString &applicationName, std::function< void(bool) > function, QWidget *parent, const QString &password, const QString &displayApplicationName) { if (parent) { this->setParent(parent); } m_walletName = walletName; m_applicationName = applicationName; m_password = password; m_walletOpened = std::move(function); if (m_applicationName.isEmpty()) { m_applicationName = m_walletName; } if (displayApplicationName.isEmpty()) { m_displayApplicationName = m_applicationName; } else { m_displayApplicationName = displayApplicationName; } if (LXQt::Wallet::walletExists(LXQt::Wallet::BackEnd::internal, m_walletName, m_applicationName)) { this->openWallet(); } else { this->createWallet(); } } void LXQt::Wallet::internalWallet::openWallet() { if (m_password.isEmpty()) { /* * to prevent an unnecessary prompt,try to open a wallet without a password and then * prompt on failure,this will allow a silent opening of the wallet set without a password. */ Task::run< lxqt_wallet_error >([ this ]() { return lxqt_wallet_open(&m_wallet, m_password.toLatin1().constData(), m_password.size(), m_walletName.toLatin1().constData(), m_applicationName.toLatin1().constData()); }).then([ this ](lxqt_wallet_error r) { if (r == lxqt_wallet_no_error) { this->opened(true); } else { /* * passwordless opening failed,prompt a user for a password */ using pwd = LXQt::Wallet::password_dialog; auto _cancelled = [ this ]() { m_opened = false; m_loop.exit(); this->walletIsOpen(false); }; pwd::instance(this, m_walletName, m_displayApplicationName, [ this ](const QString & p) { this->openWallet(p); }, std::move(_cancelled), &m_correctPassword); } }); } else { this->openWallet(m_password); } } void LXQt::Wallet::internalWallet::createWallet() { using cbd = LXQt::Wallet::changePassWordDialog; const auto &w = m_walletName; const auto &d = m_displayApplicationName; cbd::createInstance(this, w, d, [ this ](const QString & password, bool create) { if (create) { m_password = password; Task::run< lxqt_wallet_error >([ this ]() { return lxqt_wallet_create(m_password.toLatin1().constData(), m_password.size(), m_walletName.toLatin1().constData(), m_applicationName.toLatin1().constData()); }).then([ this ](lxqt_wallet_error r) { if (r == lxqt_wallet_no_error) { this->openWallet(m_password); } else { this->walletIsOpen(false); } }); } else { this->walletIsOpen(false); } }); } void LXQt::Wallet::internalWallet::changeWalletPassWord(const QString &walletName, const QString &applicationName, std::function< void(bool) > function) { using args = LXQt::Wallet::changePassWordDialog::changeArgs; auto change = [ this, function = std::move(function) ](const QString & old, const QString & New, bool cancelled)->args { auto _open = [ & ](const QString &password) { return lxqt_wallet_open(&m_wallet, password.toLatin1().constData(), password.size(), m_walletName.toLatin1().constData(), m_applicationName.toLatin1().constData()); }; if (cancelled) { function(false); return {false, false}; } auto result = Task::await([&]()->args{ if (!this->opened()) { auto s = _open(old); if (s != lxqt_wallet_no_error) { return {true, false}; } } auto m = lxqt_wallet_change_wallet_password(m_wallet, New.toLatin1().constData(), New.size()); if (m != lxqt_wallet_no_error) { lxqt_wallet_close(&m_wallet); _open(New); return {false, true}; } else { return {false, false}; } }); if (result.failedToChange == false && result.failedToUnlock == false) { function(true); } return result; }; LXQt::Wallet::changePassWordDialog::changeInstance(this, walletName, applicationName, std::move(change)); } QByteArray LXQt::Wallet::internalWallet::readValue(const QString &key) { lxqt_wallet_key_values_t key_value; if (lxqt_wallet_read_key_value(m_wallet, key.toLatin1().constData(), key.size() + 1, &key_value)) { return QByteArray(key_value.key_value, key_value.key_value_size); } else { return QByteArray(); } } QVector< std::pair< QString, QByteArray > > LXQt::Wallet::internalWallet::readAllKeyValues(void) { QVector< std::pair < QString, QByteArray > > w; lxqt_wallet_iterator_t iter; iter.iter_pos = 0; while (lxqt_wallet_iter_read_value(m_wallet, &iter)) { w.append({ QByteArray(iter.entry.key, iter.entry.key_size - 1), QByteArray(iter.entry.key_value, iter.entry.key_value_size) }); } return w; } QStringList LXQt::Wallet::internalWallet::readAllKeys() { QStringList l; lxqt_wallet_iterator_t iter; iter.iter_pos = 0; while (lxqt_wallet_iter_read_value(m_wallet, &iter)) { l.append(QByteArray(iter.entry.key, iter.entry.key_size - 1)); } return l; } bool LXQt::Wallet::internalWallet::addKey(const QString &key, const QByteArray &value) { /* * For the key,we add +1 to the key size to include the '\0' character in the key to * avoid possible collisions if our keys prefix match */ auto r = lxqt_wallet_add_key(m_wallet, key.toLatin1().constData(), key.size() + 1, value.constData(), value.size()); return r == lxqt_wallet_no_error; } void LXQt::Wallet::internalWallet::deleteKey(const QString &key) { lxqt_wallet_delete_key(m_wallet, key.toLatin1().constData(), key.size() + 1); } int LXQt::Wallet::internalWallet::walletSize(void) { return lxqt_wallet_wallet_size(m_wallet); } void LXQt::Wallet::internalWallet::closeWallet(bool b) { Q_UNUSED(b) lxqt_wallet_close(&m_wallet); } LXQt::Wallet::BackEnd LXQt::Wallet::internalWallet::backEnd() { return LXQt::Wallet::BackEnd::internal; } bool LXQt::Wallet::internalWallet::opened() { return m_wallet != nullptr; } QObject *LXQt::Wallet::internalWallet::qObject() { this->setObjectName(m_password); return this; } void LXQt::Wallet::internalWallet::walletIsOpen(bool e) { m_walletOpened(e); } QString LXQt::Wallet::internalWallet::storagePath() { return QString(); } QStringList LXQt::Wallet::internalWallet::managedWalletList() { char path[ 4096 ]; lxqt_wallet_application_wallet_path(path, 4096, m_applicationName.toLatin1().constData()); QDir d(path); QStringList l = d.entryList(); l.removeOne("."); l.removeOne(".."); if (l.size() > 0) { /* * remove the extension part of a file name */ const QString &q = l.at(0); l.replaceInStrings(q.mid(q.indexOf(".")), ""); } return l; } QString LXQt::Wallet::internalWallet::localDefaultWalletName() { return QString(); } QString LXQt::Wallet::internalWallet::networkDefaultWalletName() { return QString(); } void LXQt::Wallet::internalWallet::log(std::function) { } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_internal_wallet.h000066400000000000000000000075261425361753700302310ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LXQT_INTERNAL_WALLET_H #define LXQT_INTERNAL_WALLET_H #include "lxqt_wallet.h" #include "../backend/lxqtwallet.h" #include "password_dialog.h" #include "task.h" #include "changepassworddialog.h" #include #include #include #include #include "password_dialog.h" #include #include #include #include #include class QWidget ; namespace LXQt { namespace Wallet { class internalWallet : public LXQt::Wallet::Wallet { public: internalWallet() ; ~internalWallet() ; void open(const QString &walletName, const QString &applicationName, std::function< void(bool) >, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()) ; bool open(const QString &walletName, const QString &applicationName, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()) ; bool addKey(const QString &key, const QByteArray &value) ; bool opened(void) ; QByteArray readValue(const QString &key) ; QVector< std::pair< QString, QByteArray > > readAllKeyValues(void) ; QStringList readAllKeys(void) ; QStringList managedWalletList(void) ; QString storagePath(void) ; QString localDefaultWalletName(void) ; QString networkDefaultWalletName(void) ; void log(std::function); void deleteKey(const QString &key) ; void closeWallet(bool) ; void changeWalletPassWord(const QString &walletName, const QString &applicationName = QString(), std::function< void(bool) > = [](bool e) { Q_UNUSED(e) }) ; void setImage(const QIcon &) ; int walletSize(void) ; LXQt::Wallet::BackEnd backEnd(void) ; QObject *qObject(void) ; private: void walletIsOpen(bool) ; void openWallet(QString) ; void createWallet(void) ; void openWallet() ; void opened(bool) ; lxqt_wallet_t m_wallet ; QString m_walletName ; QString m_applicationName ; QString m_displayApplicationName ; QString m_password ; QEventLoop m_loop ; bool m_opened ; std::function< void(bool) > m_correctPassword = [](bool e) { Q_UNUSED(e) } ; std::function< void(bool) > m_walletOpened = [](bool e) { Q_UNUSED(e) } ; }; } } #endif // LXQT_INTERNAL_WALLET_H zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_kwallet-dbus.cpp000066400000000000000000000220531425361753700277660ustar00rootroot00000000000000/* * copyright: 2020 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "lxqt_kwallet-dbus.h" #include "task.h" static auto _service = "org.kde.kwalletd5"; static auto _path = "/modules/kwalletd5"; static auto _interface = "org.kde.KWallet"; LXQt::Wallet::kwallet_dbus::kwallet_dbus() : m_dbus(_service, _path, _interface) { } LXQt::Wallet::kwallet_dbus::~kwallet_dbus() { } void LXQt::Wallet::kwallet_dbus::setImage(const QIcon &image) { Q_UNUSED(image) } bool LXQt::Wallet::kwallet_dbus::addKey(const QString &key, const QByteArray &value) { QDBusReply m = m_dbus.call("writePassword", m_handle, m_folder, key, QString(value), m_applicationName); if (m.isValid()){ return m.value() == 0; }else{ m_log("LXQt::Wallet::kwallet_dbus: writePassword dbus call failed: " + m.error().message()); return false; } } bool LXQt::Wallet::kwallet_dbus::open(const QString &walletName, const QString &applicationName, QWidget *parent, const QString &password, const QString &displayApplicationName) { QEventLoop loop; bool opened; this->open(walletName, applicationName, [&](bool e) {opened = e;loop.exit();}, parent, password, displayApplicationName); loop.exec(); return opened; } void LXQt::Wallet::kwallet_dbus::openedWallet(bool e) { m_log("LXQt::Wallet::kwallet_dbus: kwallet support is provided through dbus API"); if (e) { if (m_applicationName.isEmpty()) { m_folder = "Passwords"; } else { m_folder = m_applicationName; } QDBusReply m = m_dbus.call("createFolder", m_handle, m_folder, m_applicationName); if (!m.isValid()){ m_log("LXQt::Wallet::kwallet_dbus: createFolder dbus call failed: " + m.error().message()); } } m_walletOpened(e); } void LXQt::Wallet::kwallet_dbus::open(const QString &walletName, const QString &applicationName, std::function< void(bool) > function, QWidget *parent, const QString &password, const QString &displayApplicationName) { if (walletName == "default") { m_walletName = Task::await([this](){QDBusReply a = m_dbus.call("localWallet");return a.value();}); } else { m_walletName = walletName; } this->setParent(parent); m_applicationName = applicationName; m_password = password; m_walletOpened = std::move(function); Q_UNUSED(displayApplicationName) struct result{bool success;int handle;}; Task::run([this](){ qlonglong wid = 0; QDBusReply m = m_dbus.call("open", m_walletName ,wid , m_applicationName); if (m.isValid()){ return result{true,m.value()}; }else{ m_log("LXQt::Wallet::kwallet_dbus: open dbus call failed: " + m.error().message()); return result{false,-1}; } }).then([this](result r){ if (r.success){ m_handle = r.handle; if (m_handle == -1){ QMetaObject::invokeMethod(this, "walletOpened", Qt::QueuedConnection ,Q_ARG(bool, false)); m_log("LXQt::Wallet::kwallet_dbus: Failed to get a handle to kwallet, is it enabled?"); }else{ QMetaObject::invokeMethod(this, "walletOpened", Qt::QueuedConnection, Q_ARG(bool, true)); } }else{ QMetaObject::invokeMethod(this, "walletOpened", Qt::QueuedConnection, Q_ARG(bool, false)); } }); } void LXQt::Wallet::kwallet_dbus::walletOpened(bool opened) { this->openedWallet(opened); } QByteArray LXQt::Wallet::kwallet_dbus::readValue(const QString &key) { QDBusReply m = m_dbus.call("readPassword", m_handle, m_folder, key, m_applicationName) ; if (m.isValid()){ return m.value().toLatin1(); }else{ m_log("LXQt::Wallet::kwallet_dbus: readPassword dbus call failed: " + m.error().message()); return {}; } } QVector> LXQt::Wallet::kwallet_dbus::readAllKeyValues(void) { QVector> p; auto l = this->readAllKeys(); auto j = l.size(); for (int i = 0; i < j; i++) { const auto &e = l.at(i); p.append({ e, this->readValue(e) }); } return p; } void LXQt::Wallet::kwallet_dbus::log(std::function f) { m_log = std::move(f); } QStringList LXQt::Wallet::kwallet_dbus::readAllKeys(void) { QDBusReply m = m_dbus.call("entryList", m_handle, m_folder, m_applicationName); if (m.isValid()){ return m.value(); }else{ m_log("LXQt::Wallet::kwallet_dbus: EntryList dbus call failed: " + m.error().message()); return {}; } } void LXQt::Wallet::kwallet_dbus::deleteKey(const QString &key) { QDBusReply m = m_dbus.call("removeEntry", m_handle, m_folder, key, m_applicationName); if (!m.isValid()){ m_log("LXQt::Wallet::kwallet_dbus: removeEntry dbus call failed: " + m.error().message()); } } int LXQt::Wallet::kwallet_dbus::walletSize(void) { return this->readAllKeys().size(); } void LXQt::Wallet::kwallet_dbus::closeWallet(bool b) { QDBusReply m = m_dbus.call("close", m_handle, b, m_applicationName); if (!m.isValid()){ m_log("LXQt::Wallet::kwallet_dbus: close dbus call failed: " + m.error().message()); } } LXQt::Wallet::BackEnd LXQt::Wallet::kwallet_dbus::backEnd(void) { return LXQt::Wallet::BackEnd::kwallet; } bool LXQt::Wallet::kwallet_dbus::opened(void) { if (m_handle == -1){ return false; } QDBusReply m = m_dbus.call("isOpen",m_handle); if (m.isValid()){ return m.value(); }else{ m_log("LXQt::Wallet::kwallet_dbus: isOpen dbus call failed: " + m.error().message()); return false; } } QObject *LXQt::Wallet::kwallet_dbus::qObject(void) { return this; } QString LXQt::Wallet::kwallet_dbus::storagePath() { return {}; } void LXQt::Wallet::kwallet_dbus::changeWalletPassWord(const QString &walletName, const QString &applicationName, std::function< void(bool) > function) { Q_UNUSED(applicationName) Q_UNUSED(function) qlonglong wId = 0; QDBusReply m = m_dbus.call("changePassword",walletName, wId, applicationName); if (!m.isValid()){ m_log("LXQt::Wallet::kwallet_dbus: changePassword dbus call failed: " + m.error().message()); } } QStringList LXQt::Wallet::kwallet_dbus::managedWalletList() { QDBusReply m = m_dbus.call("wallets"); if(m.isValid()){ return m.value(); }else{ m_log("LXQt::Wallet::kwallet_dbus: wallets dbus call failed: " + m.error().message()); return {}; } } QString LXQt::Wallet::kwallet_dbus::localDefaultWalletName() { QDBusReply m = m_dbus.call("localWallet"); if(m.isValid()){ return m.value(); }else{ m_log("LXQt::Wallet::kwallet_dbus: localWallet dbus call failed: " + m.error().message()); return {}; } } QString LXQt::Wallet::kwallet_dbus::networkDefaultWalletName() { QDBusReply m = m_dbus.call("networkWallet"); if(m.isValid()){ return m.value(); }else{ m_log("LXQt::Wallet::kwallet_dbus: networkWallet dbus call failed: " + m.error().message()); return {}; } } bool LXQt::Wallet::kwallet_dbus::has_functionality() { QDBusInterface m(_service, _path, _interface, QDBusConnection::sessionBus()); m.setTimeout(500); QDBusMessage reply = m.call("localWallet"); return reply.type() == QDBusMessage::ReplyMessage; } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_kwallet-dbus.h000066400000000000000000000066611425361753700274420ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LXQT_KWALLET_DBUS_H #define LXQT_KWALLET_DBUS_H #include "lxqt_wallet.h" #include #include #include #include class QWidget; namespace LXQt { namespace Wallet { class kwallet_dbus : public LXQt::Wallet::Wallet { Q_OBJECT public: static bool has_functionality(); kwallet_dbus(); ~kwallet_dbus(); void open(const QString &walletName, const QString &applicationName, std::function< void(bool) >, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()); bool open(const QString &walletName, const QString &applicationName, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()); bool addKey(const QString &key, const QByteArray &value); bool opened(void); QByteArray readValue(const QString &key); QVector> readAllKeyValues(void); QStringList readAllKeys(void); QStringList managedWalletList(void); QString storagePath(void); QString localDefaultWalletName(void); QString networkDefaultWalletName(void); void deleteKey(const QString &key); void closeWallet(bool); void changeWalletPassWord(const QString &walletName, const QString &applicationName = QString(), std::function = [](bool e) { Q_UNUSED(e) }); void setImage(const QIcon &); int walletSize(void) ; void log(std::function); LXQt::Wallet::BackEnd backEnd(void); QObject *qObject(void); private slots: void walletOpened(bool); private: void openedWallet(bool); int m_handle = -1; QString m_walletName; QString m_applicationName; QString m_password; QString m_folder; QDBusInterface m_dbus; std::function m_walletOpened = [](bool e) { Q_UNUSED(e) }; std::function m_log; }; } } #endif // LXQT_KWALLET_DBUS_H zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_kwallet.cpp000066400000000000000000000136261425361753700270410ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "lxqt_kwallet.h" #include "task.h" LXQt::Wallet::kwallet::kwallet() : m_kwallet(nullptr) { } LXQt::Wallet::kwallet::~kwallet() { if (m_kwallet) { m_kwallet->sync(); m_kwallet->deleteLater(); } } void LXQt::Wallet::kwallet::setImage(const QIcon &image) { Q_UNUSED(image) } bool LXQt::Wallet::kwallet::addKey(const QString &key, const QByteArray &value) { return m_kwallet->writePassword(key, value) == 0; } bool LXQt::Wallet::kwallet::open(const QString &walletName, const QString &applicationName, QWidget *parent, const QString &password, const QString &displayApplicationName) { QEventLoop loop; bool opened; this->open(walletName, applicationName, [&](bool e) {opened = e;loop.exit();}, parent, password, displayApplicationName); loop.exec(); return opened; } void LXQt::Wallet::kwallet::openedWallet(bool e) { m_log( "LXQt::Wallet::kwallet: kwallet support is provided through library API"); if (e) { if (m_applicationName.isEmpty()) { m_kwallet->createFolder(m_kwallet->PasswordFolder()); m_kwallet->setFolder(m_kwallet->PasswordFolder()); } else { m_kwallet->createFolder(m_applicationName); m_kwallet->setFolder(m_applicationName); } } m_walletOpened(e); } void LXQt::Wallet::kwallet::open(const QString &walletName, const QString &applicationName, std::function< void(bool) > function, QWidget *parent, const QString &password, const QString &displayApplicationName) { if (walletName == "default") { m_walletName = KWallet::Wallet::LocalWallet(); } else { m_walletName = walletName; } this->setParent(parent); m_applicationName = applicationName; m_password = password; m_walletOpened = std::move(function); Q_UNUSED(displayApplicationName) m_kwallet = KWallet::Wallet::openWallet(m_walletName, 0, KWallet::Wallet::Asynchronous); if (m_kwallet) { connect(m_kwallet, SIGNAL(walletOpened(bool)), this, SLOT(walletOpened(bool))); } else { m_log("LXQt:Wallet::kwallet: Failed to get a handle to kwallet, is it enabled?"); QMetaObject::invokeMethod(this, "walletOpened", Qt::QueuedConnection,Q_ARG(bool, false)); } } void LXQt::Wallet::kwallet::walletOpened(bool opened) { this->openedWallet(opened); } QByteArray LXQt::Wallet::kwallet::readValue(const QString &key) { QString value; m_kwallet->readPassword(key, value); return value.toLatin1(); } QVector> LXQt::Wallet::kwallet::readAllKeyValues(void) { QVector> p; auto l = m_kwallet->entryList(); QString value; auto j = l.size(); for (decltype(j) i = 0; i < j; i++) { const auto &e = l.at(i); m_kwallet->readPassword(e, value); p.append({ e, value.toLatin1() }); } return p; } void LXQt::Wallet::kwallet::log(std::function f) { m_log = std::move(f); } QStringList LXQt::Wallet::kwallet::readAllKeys(void) { return m_kwallet->entryList(); } void LXQt::Wallet::kwallet::deleteKey(const QString &key) { m_kwallet->removeEntry(key); } int LXQt::Wallet::kwallet::walletSize(void) { return m_kwallet->entryList().size(); } void LXQt::Wallet::kwallet::closeWallet(bool b) { m_kwallet->closeWallet(m_walletName, b); } LXQt::Wallet::BackEnd LXQt::Wallet::kwallet::backEnd(void) { return LXQt::Wallet::BackEnd::kwallet; } bool LXQt::Wallet::kwallet::opened(void) { if (m_kwallet) { return m_kwallet->isOpen(); } else { return false; } } QObject *LXQt::Wallet::kwallet::qObject(void) { return this; } QString LXQt::Wallet::kwallet::storagePath() { return m_kwallet->PasswordFolder(); } void LXQt::Wallet::kwallet::changeWalletPassWord(const QString &walletName, const QString &applicationName, std::function< void(bool) > function) { Q_UNUSED(applicationName) Q_UNUSED(function) m_kwallet->changePassword(walletName, 0); } QStringList LXQt::Wallet::kwallet::managedWalletList() { return m_kwallet->walletList(); } QString LXQt::Wallet::kwallet::localDefaultWalletName() { return m_kwallet->LocalWallet(); } QString LXQt::Wallet::kwallet::networkDefaultWalletName() { return m_kwallet->NetworkWallet(); } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_kwallet.h000066400000000000000000000065431425361753700265060ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LXQT_KWALLET_H #define LXQT_KWALLET_H #include "lxqt_wallet.h" #include #include #include #include class QWidget; namespace LXQt { namespace Wallet { class kwallet : public LXQt::Wallet::Wallet { Q_OBJECT public: kwallet(); ~kwallet(); void open(const QString &walletName, const QString &applicationName, std::function< void(bool) >, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()); bool open(const QString &walletName, const QString &applicationName, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()); bool addKey(const QString &key, const QByteArray &value); bool opened(void); QByteArray readValue(const QString &key); QVector> readAllKeyValues(void); QStringList readAllKeys(void); QStringList managedWalletList(void); QString storagePath(void); QString localDefaultWalletName(void); QString networkDefaultWalletName(void); void deleteKey(const QString &key); void closeWallet(bool); void changeWalletPassWord(const QString &walletName, const QString &applicationName = QString(), std::function = [](bool e) { Q_UNUSED(e); }); void setImage(const QIcon &); int walletSize(void) ; void log(std::function); LXQt::Wallet::BackEnd backEnd(void); QObject *qObject(void); private slots: void walletOpened(bool); private: void openedWallet(bool); KWallet::Wallet *m_kwallet; QString m_walletName; QString m_applicationName; QString m_password; std::function< void(bool) > m_walletOpened = [](bool e) { Q_UNUSED(e); }; std::function m_log; }; } } #endif // LXQT_KWALLET_H zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_libsecret.cpp000066400000000000000000000174461425361753700273560ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "lxqt_libsecret.h" #include "task.h" #include /* * adding libsecret header file together with C++ header files doesnt seem to work. * as a workaround,a static library that interfaces with libsecret is used and a "pure" C interface of the * static library is then used in C++ */ extern "C" { char *lxqt_libsecret_get_value(const char *key, const void *); int lxqt_libsecret_password_store_sync(const char *key, const char *value, const void *, const void *); int lxqt_libsecret_clear_sync(const char *key, const void *, const void *); char **lxqt_secret_get_all_keys(const void *, const void *, size_t *count); int lxqt_libsecret_wallet_size(const void *); int lxqt_libsecret_wallet_is_open(const void *); void *lxqt_libsecret_create_schema(const char *schemaName, const char *type); } namespace Task = LXQt::Wallet::Task; LXQt::Wallet::libsecret::libsecret(): m_schema(nullptr, free), m_schema_1(nullptr, free) { } LXQt::Wallet::libsecret::~libsecret() { } void LXQt::Wallet::libsecret::setImage(const QIcon &image) { Q_UNUSED(image); } bool LXQt::Wallet::libsecret::addKey(const QString &key, const QByteArray &value) { if (key.isEmpty()) { return false; } else { if (m_schema && m_schema_1) { return lxqt_libsecret_password_store_sync(key.toLatin1().constBegin(), value.constData(), m_schema.get(), m_schema_1.get()); } else { return false; } } } bool LXQt::Wallet::libsecret::open(const QString &walletName, const QString &applicationName, QWidget *parent, const QString &password, const QString &displayApplicationName) { QEventLoop loop; this->open(walletName, applicationName, [&](bool e) {m_opened = e;loop.exit();}, parent, password, displayApplicationName); loop.exec(); return m_opened; } void LXQt::Wallet::libsecret::open(const QString &walletName, const QString &applicationName, std::function< void(bool) > function, QWidget *parent, const QString &password, const QString &displayApplicationName) { if (parent) { this->setParent(parent); } m_walletOpened = std::move(function); Q_UNUSED(password); Q_UNUSED(displayApplicationName); if (applicationName.isEmpty()) { m_byteArrayWalletName = walletName.toLatin1(); m_byteArrayApplicationName = walletName.toLatin1(); m_walletName = m_byteArrayWalletName.constData(); m_applicationName = m_byteArrayApplicationName.constData(); m_byteArraySchemaName = QString("lxqt.Wallet.%1.%2").arg(walletName, walletName).toLatin1(); } else { m_byteArrayWalletName = walletName.toLatin1(); m_byteArrayApplicationName = applicationName.toLatin1(); m_walletName = m_byteArrayWalletName.constData(); m_applicationName = m_byteArrayApplicationName.constData(); m_byteArraySchemaName = QString("lxqt.Wallet.%1.%2").arg(walletName, applicationName).toLatin1(); } m_schema.reset(lxqt_libsecret_create_schema(m_byteArraySchemaName.constData(), "string")); m_schema_1.reset(lxqt_libsecret_create_schema(m_byteArraySchemaName.constData(), "integer")); Task::run([this]() { return lxqt_libsecret_wallet_is_open(m_schema.get()); }).then([this](bool opened) { this->walletOpened(opened); }); } void LXQt::Wallet::libsecret::walletOpened(bool opened) { m_opened = opened; m_walletOpened(opened); } QByteArray LXQt::Wallet::libsecret::readValue(const QString &key) { if (m_schema) { QByteArray r; std::unique_ptr e(lxqt_libsecret_get_value(key.toLatin1().constData(), m_schema.get())); if (e) { r = QByteArray(e.get()); } return r; } else { return QByteArray(); } } QVector> LXQt::Wallet::libsecret::readAllKeyValues(void) { QVector> p; for (const auto & it : this->readAllKeys()) { p.append({ it, this->readValue(it) }); } return p; } void LXQt::Wallet::libsecret::log(std::function) { } QStringList LXQt::Wallet::libsecret::readAllKeys(void) { if(m_schema && m_schema_1) { class allKeys { public: allKeys(const void * e,const void * f) { entries = lxqt_secret_get_all_keys(e,f,&count); } QStringList keys() { QStringList l; for(size_t i = 0 ; i < count ; i++) { auto e = *(entries + i); l.append(e); free(e); } return l; } ~allKeys() { free(entries); } private: char **entries = nullptr; size_t count; }; return allKeys(m_schema.get(), m_schema_1.get()).keys(); } else { return QStringList(); } } void LXQt::Wallet::libsecret::deleteKey(const QString &key) { if (m_schema && m_schema_1 && !key.isEmpty()) { lxqt_libsecret_clear_sync(key.toLatin1().constData(), m_schema.get(), m_schema_1.get()); } } int LXQt::Wallet::libsecret::walletSize(void) { if (m_schema) { return lxqt_libsecret_wallet_size(m_schema.get()); } else { return -1; } } void LXQt::Wallet::libsecret::closeWallet(bool b) { Q_UNUSED(b); } LXQt::Wallet::BackEnd LXQt::Wallet::libsecret::backEnd(void) { return LXQt::Wallet::BackEnd::libsecret; } bool LXQt::Wallet::libsecret::opened(void) { if (m_schema) { return Task::await([&](){return lxqt_libsecret_wallet_is_open(m_schema.get());}); } else { return false; } } QObject *LXQt::Wallet::libsecret::qObject(void) { return this; } QString LXQt::Wallet::libsecret::storagePath() { return QString(); } void LXQt::Wallet::libsecret::changeWalletPassWord(const QString &walletName, const QString &applicationName, std::function< void(bool) > function) { Q_UNUSED(applicationName); Q_UNUSED(walletName); Q_UNUSED(function) } QStringList LXQt::Wallet::libsecret::managedWalletList() { return QStringList(); } QString LXQt::Wallet::libsecret::localDefaultWalletName() { return QString(); } QString LXQt::Wallet::libsecret::networkDefaultWalletName() { return QString(); } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_libsecret.h000066400000000000000000000070601425361753700270120ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LXQT_LIBSECRET_H #define LXQT_LIBSECRET_H #include "lxqt_wallet.h" #include #include #include #include #include class QWidget; namespace LXQt { namespace Wallet { class libsecret : public LXQt::Wallet::Wallet { public: libsecret(); ~libsecret(); void open(const QString &walletName, const QString &applicationName, std::function< void(bool) >, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()); bool open(const QString &walletName, const QString &applicationName, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()); bool addKey(const QString &key, const QByteArray &value); bool opened(void); QByteArray readValue(const QString &key); QVector> readAllKeyValues(void); QStringList readAllKeys(void); QStringList managedWalletList(void); QString storagePath(void); QString localDefaultWalletName(void); QString networkDefaultWalletName(void); void deleteKey(const QString &key); void closeWallet(bool); void changeWalletPassWord(const QString &walletName, const QString &applicationName = QString(), std::function< void(bool) > = [](bool e) { Q_UNUSED(e); }); void setImage(const QIcon &); int walletSize(void) ; void log(std::function); LXQt::Wallet::BackEnd backEnd(void); QObject *qObject(void); private: void walletOpened(bool); QByteArray m_byteArrayWalletName; QByteArray m_byteArrayApplicationName; QByteArray m_byteArraySchemaName; const char *m_walletName; const char *m_applicationName; QString m_password; QWidget *m_interfaceObject = nullptr; std::unique_ptr m_schema; std::unique_ptr m_schema_1; bool m_opened; std::function< void(bool) > m_walletOpened = [](bool e) { Q_UNUSED(e); }; }; } } #endif // LXQT_LIBSECRET_H zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_osx_keychain.cpp000066400000000000000000000202141425361753700300510ustar00rootroot00000000000000 /* * copyright: 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "lxqt_osx_keychain.h" #include "osx_keychain.h" #if OSX_KEYCHAIN /* * https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/03tasks/tasks.html#//apple_ref/doc/uid/TP30000897-CH205-TP9 * */ #include #include #else #include "lxqt_osx_keychain_private.h" #endif static const char *WALLET_KEYS = "LXQt.Wallet.WalletKeys"; static const char *_walletPrefix = "LXQt.Wallet."; LXQt::Wallet::osxKeyChain::osxKeyChain() { } LXQt::Wallet::osxKeyChain::~osxKeyChain() { } void LXQt::Wallet::osxKeyChain::open(const QString &walletName, const QString &applicationName, std::function< void(bool) > function, QWidget *widget, const QString &password, const QString &displayApplicationName) { Q_UNUSED(widget); Q_UNUSED(password); Q_UNUSED(displayApplicationName); m_walletName = _walletPrefix + walletName.toLatin1() + "." + applicationName.toLatin1(); m_opened = true; function(m_opened); } bool LXQt::Wallet::osxKeyChain::open(const QString &walletName, const QString &applicationName, QWidget *widget, const QString &password, const QString &displayApplicationName) { Q_UNUSED(widget); Q_UNUSED(password); Q_UNUSED(displayApplicationName); m_walletName = _walletPrefix + walletName.toLatin1() + "." + applicationName.toLatin1(); m_opened = true; return m_opened; } struct passwordData { passwordData() = default; passwordData(passwordData &&other) { this->init(std::move(other)); } passwordData& operator=(passwordData &&other) { return this->init(std::move(other)); } ~passwordData() { if (data) { SecKeychainItemFreeContent(nullptr, data); } if (ref) { CFRelease(ref); } } OSStatus status = 0; void *data = nullptr; quint32 len = 0; SecKeychainItemRef ref = 0; private: passwordData& init( passwordData&& other ) { status = other.status; len = other.len; data = other.data; other.data = nullptr; ref = other.ref; other.ref = nullptr; return *this; } }; static bool _status(OSStatus e) { return e == noErr || e == errSecSuccess; } static passwordData _find_password(const QString &key, const QByteArray &walletName) { passwordData s; s.status = SecKeychainFindGenericPassword(nullptr, walletName.size(), walletName.constData(), key.size(), key.toLatin1().constData(), &s.len, &s.data, &s.ref); return s; } static bool _delete_key(const QString &key, const QByteArray &walletName) { auto s = _find_password(key, walletName); if (s.ref) { return _status(SecKeychainItemDelete(s.ref)); } else { return false; } } static bool _add_key(const QString &key, const QByteArray &value, const QByteArray &walletName) { auto status = SecKeychainAddGenericPassword(nullptr, walletName.size(), walletName.constData(), key.size(), key.toLatin1().constData(), value.size(), value.constData(), nullptr); return _status(status); } static void _update_wallet_keys(const QStringList &e, const QByteArray &walletName) { auto s = _find_password(WALLET_KEYS, walletName); auto z = e.join("\n").toLatin1(); if (s.ref) { SecKeychainItemModifyContent(s.ref, nullptr, z.size(), z.constData()); } else { _add_key(WALLET_KEYS, z, walletName); } } void LXQt::Wallet::osxKeyChain::log(std::function) { } void LXQt::Wallet::osxKeyChain::deleteKey(const QString &key) { if (_delete_key(key, m_walletName)) { QString s = this->readValue(WALLET_KEYS); #if QT_VERSION < QT_VERSION_CHECK( 5,15,0 ) auto e = s.split('\n', QString::SkipEmptyParts); #else auto e = s.split('\n', Qt::SkipEmptyParts); #endif e.removeOne(key); _update_wallet_keys(e, m_walletName); } } bool LXQt::Wallet::osxKeyChain::addKey(const QString &key, const QByteArray &value) { if (_add_key(key, value, m_walletName)) { QString s = this->readValue(WALLET_KEYS); s += "\n" + key; #if QT_VERSION < QT_VERSION_CHECK( 5,15,0 ) _update_wallet_keys(s.split("\n", QString::SkipEmptyParts), m_walletName); #else _update_wallet_keys(s.split("\n", Qt::SkipEmptyParts), m_walletName); #endif return true; } else { return false; } } bool LXQt::Wallet::osxKeyChain::opened() { return m_opened; } QByteArray LXQt::Wallet::osxKeyChain::readValue(const QString &key) { auto s = _find_password(key, m_walletName); auto e = reinterpret_cast< const char * >(s.data); auto z = static_cast< int >(s.len); return QByteArray(e, z); } QVector< std::pair< QString, QByteArray > > LXQt::Wallet::osxKeyChain::readAllKeyValues() { QVector< std::pair< QString, QByteArray > > e; for (const auto & it : this->readAllKeys()) { e.append( { it, this->readValue(it) }); } return e; } QStringList LXQt::Wallet::osxKeyChain::readAllKeys() { QString s = this->readValue(WALLET_KEYS); #if QT_VERSION < QT_VERSION_CHECK( 5,15,0 ) return s.split('\n', QString::SkipEmptyParts); #else return s.split('\n', Qt::SkipEmptyParts); #endif } QStringList LXQt::Wallet::osxKeyChain::managedWalletList() { return QStringList(); } QString LXQt::Wallet::osxKeyChain::storagePath() { return QString(); } QString LXQt::Wallet::osxKeyChain::localDefaultWalletName() { return QString(); } QString LXQt::Wallet::osxKeyChain::networkDefaultWalletName() { return QString(); } void LXQt::Wallet::osxKeyChain::closeWallet(bool e) { Q_UNUSED(e); } void LXQt::Wallet::osxKeyChain::changeWalletPassWord(const QString &walletName, const QString &applicationName, std::function< void(bool)> function) { Q_UNUSED(walletName); Q_UNUSED(applicationName); Q_UNUSED(function); } void LXQt::Wallet::osxKeyChain::setImage(const QIcon &e) { Q_UNUSED(e); } int LXQt::Wallet::osxKeyChain::walletSize() { return this->readAllKeys().size(); } LXQt::Wallet::BackEnd LXQt::Wallet::osxKeyChain::backEnd() { return LXQt::Wallet::BackEnd::osxkeychain; } QObject *LXQt::Wallet::osxKeyChain::qObject() { return nullptr; } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_osx_keychain.h000066400000000000000000000062101425361753700275160ustar00rootroot00000000000000/* * copyright: 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LXQT_OSX_KEYCHAIN_H #define LXQT_OSX_KEYCHAIN_H #include "lxqt_wallet.h" #include #include #include #include #include class QWidget; namespace LXQt { namespace Wallet { class osxKeyChain : public LXQt::Wallet::Wallet { public: osxKeyChain(); ~osxKeyChain(); void open(const QString &walletName, const QString &applicationName, std::function< void(bool) >, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()); bool open(const QString &walletName, const QString &applicationName, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()); bool addKey(const QString &key, const QByteArray &value); bool opened(void); QByteArray readValue(const QString &key); QVector> readAllKeyValues(void); QStringList readAllKeys(void); QStringList managedWalletList(void); QString storagePath(void); QString localDefaultWalletName(void); QString networkDefaultWalletName(void); void deleteKey(const QString &key); void closeWallet(bool); void changeWalletPassWord(const QString &walletName, const QString &applicationName = QString(), std::function< void(bool) > = [](bool e) { Q_UNUSED(e); }); void setImage(const QIcon &); int walletSize(void) ; void log(std::function); LXQt::Wallet::BackEnd backEnd(void); QObject *qObject(void); private: bool m_opened = false ; QByteArray m_walletName ; }; } } #endif // LXQT_OSX_KEYCHAIN_H zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_osx_keychain_private.h000066400000000000000000000066001425361753700312530ustar00rootroot00000000000000 /* * copyright: 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LXQT_OSX_KEYCHAIN_PRIVATE_H #define LXQT_OSX_KEYCHAIN_PRIVATE_H using OSStatus = int; class foo; using SecKeychainItemRef = foo *; #define noErr 0 #define errSecSuccess 0 void SecKeychainItemFreeContent(void *e, void *f) { Q_UNUSED(e); Q_UNUSED(f); } void CFRelease(void *e) { Q_UNUSED(e); } OSStatus SecKeychainItemDelete(void *e) { Q_UNUSED(e); return 0; } OSStatus SecKeychainFindGenericPassword(void *foo, quint32 serviceNameLength, const char *serviceName, quint32 accountNameLength, const char *accountName, quint32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef) { Q_UNUSED(foo); Q_UNUSED(serviceNameLength); Q_UNUSED(serviceName); Q_UNUSED(passwordLength); Q_UNUSED(passwordData); Q_UNUSED(accountName); Q_UNUSED(accountNameLength); Q_UNUSED(itemRef); return 0; } OSStatus SecKeychainAddGenericPassword(void *foo, quint32 serviceNameLength, const char *serviceName, quint32 accountNameLength, const char *accountName, quint32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) { Q_UNUSED(foo); Q_UNUSED(serviceNameLength); Q_UNUSED(serviceName); Q_UNUSED(passwordLength); Q_UNUSED(passwordData); Q_UNUSED(accountName); Q_UNUSED(accountNameLength); Q_UNUSED(itemRef); return 0; } void SecKeychainItemModifyContent(void *a, void *b, quint32 c, const void *d) { Q_UNUSED(a); Q_UNUSED(b); Q_UNUSED(c); Q_UNUSED(d); } #endif zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_wallet.cpp000066400000000000000000000156731425361753700266720ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "lxqt_wallet.h" #include "lxqt_internal_wallet.h" #include "../backend/lxqtwallet.h" #include "translations_path.h" #include "lxqt_kwallet-dbus.h" #include "storage_manager.h" #if HAS_KWALLET_SUPPORT #include "lxqt_kwallet.h" #endif #if HAS_SECRET_SUPPORT #include "lxqt_libsecret.h" #endif #include #include #include #include "lxqt_osx_keychain.h" #include "osx_keychain.h" #include "lxqt_windows_dpapi.h" LXQt::Wallet::Wallet::Wallet() { } LXQt::Wallet::Wallet::~Wallet() { } std::unique_ptr LXQt::Wallet::getWalletBackend(LXQt::Wallet::BackEnd bk) { if( bk == LXQt::Wallet::BackEnd::windows_dpapi ) { #ifdef Q_OS_WIN return std::unique_ptr(new LXQt::Wallet::windows_dpapi()); #else return nullptr; #endif } if (bk == LXQt::Wallet::BackEnd::internal) { #ifdef Q_OS_WIN return nullptr; #else return std::unique_ptr(new LXQt::Wallet::internalWallet()); #endif } if (bk == LXQt::Wallet::BackEnd::kwallet) { #ifdef Q_OS_LINUX #if HAS_KWALLET_SUPPORT return std::unique_ptr(new LXQt::Wallet::kwallet()); #else if (LXQt::Wallet::kwallet_dbus::has_functionality()){ return std::unique_ptr(new LXQt::Wallet::kwallet_dbus()); }else{ return nullptr; } #endif #else return nullptr; #endif } if (bk == LXQt::Wallet::BackEnd::libsecret) { #if HAS_SECRET_SUPPORT return std::unique_ptr(new LXQt::Wallet::libsecret()); #else return nullptr; #endif } if (bk == LXQt::Wallet::BackEnd::osxkeychain) { #if OSX_KEYCHAIN return std::unique_ptr(new LXQt::Wallet::osxKeyChain()); #endif } return nullptr; } bool LXQt::Wallet::backEndIsSupported(LXQt::Wallet::BackEnd bk) { if( bk == LXQt::Wallet::BackEnd::windows_dpapi ){ #ifdef Q_OS_WIN return true; #else return false; #endif } if (bk == LXQt::Wallet::BackEnd::internal) { #ifdef Q_OS_WIN return false; #else return true; #endif } if (bk == LXQt::Wallet::BackEnd::kwallet) { if (HAS_KWALLET_SUPPORT){ return true; }else{ #ifdef Q_OS_LINUX return LXQt::Wallet::kwallet_dbus::has_functionality(); #else return false; #endif } } if (bk == LXQt::Wallet::BackEnd::libsecret) { return HAS_SECRET_SUPPORT; } if (bk == LXQt::Wallet::BackEnd::osxkeychain ) { return OSX_KEYCHAIN; } return false; } bool LXQt::Wallet::deleteWallet(LXQt::Wallet::BackEnd bk, const QString &walletName, const QString &applicationName) { QString appName; if (applicationName.isEmpty()) { appName = walletName; } else { appName = applicationName; } if (bk == LXQt::Wallet::BackEnd::internal) { auto e = lxqt_wallet_delete_wallet(walletName.toLatin1().constData(), appName.toLatin1().constData()); return e == lxqt_wallet_no_error; } if (bk == LXQt::Wallet::BackEnd::kwallet) { #if HAS_KWALLET_SUPPORT return KWallet::Wallet::deleteWallet(walletName) == 0; #else return false; #endif } if (bk == LXQt::Wallet::BackEnd::libsecret) { return false; } return false; } bool LXQt::Wallet::walletExists(LXQt::Wallet::BackEnd bk, const QString &walletName, const QString &applicationName) { QString appName; if (applicationName.isEmpty()) { appName = walletName; } else { appName = applicationName; } if (bk == LXQt::Wallet::BackEnd::internal) { return lxqt_wallet_exists(walletName.toLatin1().constData(), appName.toLatin1().constData()) == 0; } if (bk == LXQt::Wallet::BackEnd::kwallet) { #if HAS_KWALLET_SUPPORT return !KWallet::Wallet::folderDoesNotExist(walletName, appName); #else return false; #endif } if (bk == LXQt::Wallet::BackEnd::libsecret) { return false; } return false; } QStringList LXQt::Wallet::walletList(LXQt::Wallet::BackEnd bk) { if (bk == LXQt::Wallet::BackEnd::internal) { char path[4096]; lxqt_wallet_application_wallet_path(path, 4096, ""); QDir d(path); auto l = d.entryList(); l.removeOne("."); l.removeOne(".."); return l; } else if (bk == LXQt::Wallet::BackEnd::kwallet) { #if HAS_KWALLET_SUPPORT return KWallet::Wallet::walletList(); #else return QStringList(); #endif } else if (bk == LXQt::Wallet::BackEnd::libsecret) { return QStringList(); } else { return QStringList(); } } QStringList LXQt::Wallet::translations() { QDir d(TRANSLATIONS_PATH); auto l = d.entryList(); l.removeOne("."); l.removeOne(".."); for (auto& it : l) { it.remove("lxqt-wallet_"); it.remove(".qm"); } return l; } void LXQt::Wallet::setTranslationLanguage(const QString &language) { auto l = "lxqt-wallet_" + language + ".qm"; if (QFile::exists(TRANSLATIONS_PATH + l)) { QCoreApplication::installTranslator([&]() { auto e = new QTranslator(); e->load(l, TRANSLATIONS_PATH); return e; }()); } } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_wallet.h000066400000000000000000000257431425361753700263360ustar00rootroot00000000000000/* * copyright: 2013-2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LXQT_WALLET_INTERFACE_H #define LXQT_WALLET_INTERFACE_H #include #include #include #include #include #include #include #include #include #include namespace LXQt { namespace Wallet { enum class BackEnd { internal, kwallet, libsecret, osxkeychain, windows_dpapi } ; /* * Forward declare the Wallet class */ class Wallet; /* * Check if there is a support for a backend and return true if the back end is supported. */ Q_DECL_EXPORT bool backEndIsSupported(LXQt::Wallet::BackEnd); /* * Delete a wallet. * KWallet backend does not use the applicationName argument. */ Q_DECL_EXPORT bool deleteWallet(LXQt::Wallet::BackEnd, const QString &walletName, const QString &applicationName = QString()); /* * Check if a particular wallet exists. */ Q_DECL_EXPORT bool walletExists(LXQt::Wallet::BackEnd, const QString &walletName, const QString &applicationName = QString()); /* * Get a pointer to a requested backend to be used to gain access to the API.It is advised to call * backEndIsSupported() to check if a backed is supported before calling this function. * * nullptr is returned if there is no support for requested backend. */ Q_DECL_EXPORT std::unique_ptr getWalletBackend(LXQt::Wallet::BackEnd); /* * Return a list of all wallets. * Returned value is undefined if the backend is not supported. */ Q_DECL_EXPORT QStringList walletList(LXQt::Wallet::BackEnd); /* * Get a list of supported languages. */ Q_DECL_EXPORT QStringList translations(); /* * Set language of texts on GUI elements. * See translations() API to get a list of supported languages. * * Setting a language will make a difference only with an internal backend. */ Q_DECL_EXPORT void setTranslationLanguage(const QString &language); /* * Below class is the interface that implements various backends. * See example at the end of this header file to see an example of how to use the interface. */ class Q_DECL_EXPORT Wallet : public QWidget { public: Wallet(); virtual ~Wallet(); /* * Add an entry to the wallet. */ virtual bool addKey(const QString &key, const QByteArray &value) = 0; /* * overloaded method to add a key to the wallet. */ bool addKey(const QString &key,const QString &value) { return this->addKey(key, value.toLatin1()); } /* * overloaded method to add a key to the wallet. */ bool addKey(const QString &key,const char *value) { return this->addKey(key, QByteArray(value)); } /* * Get a value through a key. */ virtual QByteArray readValue(const QString &key) = 0; /* * Get all keys and their respective values from the wallet. * First argument of std::pair is the key. * Second argument of std::pair is the value. */ virtual QVector> readAllKeyValues() = 0; /* * Get all keys in the wallet. */ virtual QStringList readAllKeys() = 0; /* * Delete a key in a wallet. */ virtual void deleteKey(const QString &key) = 0; /* * Return the number of entries in the wallet. */ virtual int walletSize() = 0; /* * Close the wallet. */ virtual void closeWallet(bool option = false) = 0; /* * Return the backend in use. */ virtual LXQt::Wallet::BackEnd backEnd() = 0; /* * Check if a wallet is opened or not. * If the wallet is not open,libsecret backend will block while the user is * prompted for a key to inlock it. */ virtual bool opened() = 0; /* * Return QObject pointer of the backend,not sure why you would want this. */ virtual QObject *qObject() = 0; /* * First open() will return immediately and the status of the unlocking attempt will be returned * through the passed in lambda( third argument ).The lambda will be called with "true" if * the attempt was successful and with "false" otherwise. * * Second open() will block the call waiting for the result of the unlocking attempt. * "true" will be returned if the attempt was successful and "false" will be returned otherwise. * The blocking will be done in a way that does not hang the GUI. * * Optional arguments are not necessary in all backends: * * osx keychain backend: * "password" argument is ignored. * "applicationName" argument is ignored. * "displayApplicationName" argument is ignored. * "widget" argument is ignored. * * libsecret backend: * "password" argument is ignored. * "applicationName" argument is ignored. * "displayApplicationName" argument is ignored. * "widget" argument is ignored. * * kwallet backend: * "password" argument is ignored. * "walletName" argument corresponds to the same name in KWAllet API. * "displayApplicationName" is ignored. * "widget" argument is ignored. * "applicationName" argument corresponds to password folder in KWallet API,default value will * set passwordFolder to KDE's default. Password argument is not used. * * internal: * "walletName" argument is the name of the wallet to open. * "applicationName" argument is the name of the program that owns the wallet. * "displayApplicationName" argument will be used to show the name of the application that is * opening the wallet if a GUI prompt is generated. * "widget" argument is necessary to give generated GUI prompts a parent object. * * If "password" argument is given,it will be used to unlock the wallet. * If "password" argument is not given,a GUI window will be generated to ask the user for the password. * * The "widget" argument can also be set through setParent() method inherited from QWidget. */ virtual void open(const QString &walletName, const QString &applicationName, std::function< void(bool) >, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()) = 0; virtual bool open(const QString &walletName, const QString &applicationName, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()) = 0; /* * This method is defined only with internal backend. * This method is used to set an icon image to be used when the backend produces GUI windows. */ virtual void setImage(const QIcon &) = 0; /* * This method returns PasswordFolder() in kwallet backend and is undefined in other backends. */ virtual QString storagePath() = 0; /* * Change the wallet key. * * The passed in lambda will be called with internal wallet with "true" if the password was * successfully changed and with "false" otherwise. * * The passed in lambda will not be called with kwallet backend. * * This method is defined only in the internal backend. */ virtual void changeWalletPassWord(const QString &walletName, const QString &applicationName = QString(), std::function< void(bool) > = [](bool e) { Q_UNUSED(e); }) = 0; /* * List all wallets managed by an application. * * This method is equivalent to kwallet's "folderList()". * * This method is defined in internal and kwallet backends. */ virtual QStringList managedWalletList() = 0; /* * This medhod is defined only with kwallet backend and it returns the name of the kwallet default local * wallet name. */ virtual QString localDefaultWalletName() = 0; /* * This medhod is defined only with kwallet backend and it returns the name of the kwallet default * network wallet name. */ virtual QString networkDefaultWalletName() = 0; /* * Pass in callable object will be invoked everytime the backend wants to log something. */ virtual void log(std::function) = 0; }; } // namespace lxqt } // namespace wallet #endif // LXQT_WALLET_INTERFACE_H /* * An example use of the API that opens a wallet and then prints all keys and their respective values */ #if 0 class test : public QWidget { Q_OBJECT public: ~test() { m_wallet->deleteLater(); } void print() { for (const auto & it : m_wallet->readAllKeyValues()) { qDebug() << it.first; qDebug() << it.second << "\n"; } } void addKey() { m_wallet->addKey("test key", "test value"); } void deleteKey() { m_wallet->deleteKey("test key"); } public slots: void run() { m_wallet = LXQt::Wallet::getWalletBackend(LXQt::Wallet::BackEnd::internal); m_wallet->setParent(this); m_wallet->open("test", "test", [this](bool walletIsOpen) { if (walletIsOpen) { qDebug() << "wallet is open.\n"; this->addKey(); this->print(); this->deleteKey(); this->print(); QCoreApplication::quit(); } else { std::cout << "Failed to unlock wallet.\n"; QCoreApplication::quit(); } }); } private: LXQt::Wallet::Wallet *m_wallet; }; #endif zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_windows_dpapi.cpp000066400000000000000000000314321425361753700302400ustar00rootroot00000000000000 #include "lxqt_windows_dpapi.h" #include "password_dialog.h" #include "changepassworddialog.h" static const int TEST_VALUE = -1; #include #ifdef Q_OS_WIN #include #include #include class db { public: db(QByteArray&&) = delete; db(const QByteArray &e) : m_delete(false) { ZeroMemory(&m_db, sizeof(DATA_BLOB)); m_db.pbData = reinterpret_cast(const_cast(e.data())); m_db.cbData = static_cast(e.size()); } db() { ZeroMemory(&m_db, sizeof(DATA_BLOB)); } DATA_BLOB *operator&() { return &m_db; } QByteArray data() { auto data = reinterpret_cast(m_db.pbData); auto size = static_cast(m_db.cbData); return {data, size}; } CRYPTPROTECT_PROMPTSTRUCT *prompt(unsigned long flags = CRYPTPROTECT_PROMPT_ON_UNPROTECT) { ZeroMemory(&m_prompt, sizeof(m_prompt)); m_prompt.cbSize = sizeof(m_prompt); m_prompt.dwPromptFlags = flags; m_prompt.szPrompt = L"Enter Password To Unlock LXQt Credentials Storage System"; return &m_prompt; } ~db() { if (m_delete) { LocalFree(m_db.pbData); } } private: bool m_delete = true; DATA_BLOB m_db; CRYPTPROTECT_PROMPTSTRUCT m_prompt; }; template static QByteArray _entropy(QSettings &settings, const QByteArray& entropy, const Function& log) { if(!settings.contains("WindowsPbkdf2Interations")) { settings.setValue("WindowsPbkdf2Interations",50000); } int iterations = settings.value( "WindowsPbkdf2Interations" ).toInt(); BCRYPT_ALG_HANDLE h; auto s = BCryptOpenAlgorithmProvider(&h, BCRYPT_SHA256_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG); if (BCRYPT_SUCCESS(s)) { auto ss = "lxqt_windows_dpapi"; std::array buffer; BCryptDeriveKeyPBKDF2(h, reinterpret_cast(const_cast(entropy.data())), static_cast(entropy.size()), reinterpret_cast(const_cast(ss)), static_cast(strlen(ss)), static_cast(iterations), buffer.data(), static_cast(buffer.size()), 0); BCryptCloseAlgorithmProvider(h, 0); return QByteArray(reinterpret_cast(buffer.data()), buffer.size()); }else{ log("LXQt Wallet::Windows_dpapi: Failed to created PBKDF2 key"); return {} ; } } LXQt::Wallet::Task::future &LXQt::Wallet::windows_dpapi::encrypt(QByteArray data) { return LXQt::Wallet::Task::run([this,data=std::move(data)]()->result { auto entropy = _entropy(*m_settings, m_entropy, m_log); db In(data); db Entropy(entropy); db Out; auto a = L"LXQt Wallet::Windows_dpapi."; if (CryptProtectData(&In, a, &Entropy, nullptr, nullptr, 0, &Out)) { m_log("LXQt:Wallet::Windows_dpapi: Data Successfully Encrypted."); return {true, Out.data()}; } else { m_log("LXQt:Wallet::Windows_dpapi: Failed To Encrypt Data."); return {false, std::move(data)}; } }); } LXQt::Wallet::Task::future &LXQt::Wallet::windows_dpapi::decrypt(QByteArray data) { return LXQt::Wallet::Task::run([this,data = std::move(data)]()->result { auto entropy = _entropy(*m_settings, m_entropy, m_log); db In(data); db Entropy(entropy); db Out; if (CryptUnprotectData(&In, nullptr, &Entropy, nullptr, In.prompt(), 0, &Out)) { m_log("LXQt:Wallet::Windows_dpapi: Data Successfully Decrypted."); return {true, Out.data()}; } else { m_log("LXQt:Wallet::Windows_dpapi: Failed To Decrypt Data."); return {false, std::move(data)}; } }); } #else LXQt::Wallet::Task::future &LXQt::Wallet::windows_dpapi::decrypt(QByteArray data) { Q_UNUSED(data) return LXQt::Wallet::Task::run([]()->result { return {false, {}}; }); } LXQt::Wallet::Task::future &LXQt::Wallet::windows_dpapi::encrypt(QByteArray data) { Q_UNUSED(data) return LXQt::Wallet::Task::run([]()->result { return {false, {}}; }); } #endif LXQt::Wallet::windows_dpapi::windows_dpapi() { } LXQt::Wallet::windows_dpapi::~windows_dpapi() { this->store(); } QByteArray LXQt::Wallet::windows_dpapi::getData() { if( !m_settings->contains(m_settingsName)) { m_settings->setValue(m_settingsName,QByteArray()); } return m_settings->value(m_settingsName).toByteArray(); } void LXQt::Wallet::windows_dpapi::store() { if (m_opened) { auto b = this->encrypt(this->serializeData()).await(); if (b.success) { m_settings->setValue(m_settingsName, b.data); } } else { m_log("LXQt:Wallet::Windows_dpapi: Wallet Not Opened."); } } bool LXQt::Wallet::windows_dpapi::open(const QString &walletName, const QString &applicationName, QWidget *parent, const QString &password, const QString &displayApplicationName) { QEventLoop loop; auto exitLoop = [&](bool e) { Q_UNUSED(e) loop.exit(); }; this->open(walletName, applicationName, std::move(exitLoop), parent, password, displayApplicationName); loop.exec(); return m_opened; } void LXQt::Wallet::windows_dpapi::open(const QString &walletName, const QString &applicationName, std::function function, QWidget *parent, const QString &password, const QString &displayApplicationName) { if (parent) { this->setParent(parent); } m_walletName = walletName; m_applicationName = applicationName; m_settings.reset(new QSettings(m_applicationName, m_walletName)); m_walletOpened = std::move(function); if (m_applicationName.isEmpty()) { m_applicationName = m_walletName; } if (displayApplicationName.isEmpty()) { m_displayApplicationName = m_applicationName; } else { m_displayApplicationName = displayApplicationName; } this->setEntropy(password); auto data = this->getData(); if (data.isEmpty()) { this->createWallet(); } else { this->openWallet(std::move(data)); } } void LXQt::Wallet::windows_dpapi::setEntropy(const QString &e) { m_entropy = e.toUtf8(); } void LXQt::Wallet::windows_dpapi::createWallet() { using cbd = LXQt::Wallet::changePassWordDialog; const auto &w = m_walletName; const auto &d = m_displayApplicationName; cbd::createInstance(this, w, d, [this](const QString & password, bool create) { if (create) { this->setEntropy(password); m_opened = true; m_walletOpened(true); } else { m_opened = false; m_walletOpened(false); } }); } void LXQt::Wallet::windows_dpapi::openWallet(QByteArray data) { this->decrypt(std::move(data)).then([this](result m) { if (m.success) { this->deserializeData(m.data); m_opened = true; m_walletOpened(true); } else { using pwd = LXQt::Wallet::password_dialog; auto _cancelled = [this]() { m_opened = false; m_walletOpened(m_opened); }; pwd::instance(this, m_walletName, m_displayApplicationName, [this,data=std::move(m.data)](const QString &p) { this->openWalletWithPassword(p, data);}, std::move(_cancelled), &m_correctPassword); } }); } void LXQt::Wallet::windows_dpapi::log(std::function function) { m_log = std::move(function); } void LXQt::Wallet::windows_dpapi::openWalletWithPassword(QString e, const QByteArray &data) { this->setEntropy(e); this->decrypt(data).then([this](const result &m) { bool s = m.success; m_opened = s; m_correctPassword(s); if (s) { this->deserializeData(m.data); m_walletOpened(s); } }); } void LXQt::Wallet::windows_dpapi::deserializeData(const QByteArray &e) { const size_t int_size = sizeof(int); int test; auto data = e.constData(); std::memcpy(&test, data, int_size); if (test != TEST_VALUE) { m_log("LXQt:Wallet::Windows_dpapi: CRITICAL: Deleting Stored Data Because It Appears To Be Corrupted."); return; } int s; std::memcpy(&s, data + int_size, int_size); m_log("LXQt:Wallet::Windows_dpapi: Number Of Entries In Wallet Is: " + QString::number(s)); if (s != 0) { const size_t header_size = 2 * sizeof(int); data = data + 2 * int_size; int keySize; int valueSize; for (int i = 0; i < s; i++) { std::memcpy(&keySize, data, int_size); std::memcpy(&valueSize, data + int_size, int_size); auto a = QString::fromUtf8(data + header_size, keySize); auto b = QByteArray { data + header_size + keySize, valueSize }; m_keys.append( { std::move(a), std::move(b) }); data = data + header_size + keySize + valueSize; } } } QByteArray LXQt::Wallet::windows_dpapi::serializeData() { QByteArray data; const size_t int_size = sizeof(int); char buffer[2 * int_size]; std::memcpy(buffer, &TEST_VALUE, int_size); int s = m_keys.size(); std::memcpy(buffer + int_size, &s, int_size); data.append(buffer, 2 * int_size); if (s != 0) { const size_t header_size = 2 * sizeof(int); char buffer[header_size]; for (const auto &it : m_keys) { const auto &key = it.first; const auto &value = it.second; int keySize = key.size(); int valueSize = value.size(); std::memcpy(buffer, &keySize, int_size); std::memcpy(buffer + int_size, &valueSize, int_size); data.append(buffer, header_size); data.append(QByteArray {key.toUtf8(), keySize}); data.append(value); } } return data; } bool LXQt::Wallet::windows_dpapi::opened() { return m_opened; } bool LXQt::Wallet::windows_dpapi::addKey(const QString &key, const QByteArray &value) { m_keys.append({key, value}); return true; } QByteArray LXQt::Wallet::windows_dpapi::readValue(const QString &key) { for (const auto & it : m_keys) { if (it.first == key) { return it.second; } } return {}; } void LXQt::Wallet::windows_dpapi::deleteKey(const QString &key) { for (int i = 0; i < m_keys.size(); i++) { if (m_keys[i].first == key) { m_keys.remove(i); break; } } } QStringList LXQt::Wallet::windows_dpapi::readAllKeys() { QStringList s; for (const auto & it : m_keys) { s.append(it.first); } return s; } QVector> LXQt::Wallet::windows_dpapi::readAllKeyValues() { return m_keys; } int LXQt::Wallet::windows_dpapi::walletSize() { return m_keys.size(); } QStringList LXQt::Wallet::windows_dpapi::managedWalletList() { return {}; } QString LXQt::Wallet::windows_dpapi::storagePath() { return {}; } QString LXQt::Wallet::windows_dpapi::localDefaultWalletName() { return {}; } QString LXQt::Wallet::windows_dpapi::networkDefaultWalletName() { return {}; } void LXQt::Wallet::windows_dpapi::closeWallet(bool e) { Q_UNUSED(e) } void LXQt::Wallet::windows_dpapi::changeWalletPassWord(const QString &walletName, const QString &applicationName, std::function< void(bool) > function) { using args = LXQt::Wallet::changePassWordDialog::changeArgs; auto change = [this, function = std::move(function)](const QString & old, const QString & New, bool cancelled)->args { if (cancelled) { function(false); return {false, false}; } auto a = this->getData(); this->setEntropy(old); auto m = this->decrypt(std::move(a)).await(); if (m.success) { this->setEntropy(New); if (!m_opened) { m_opened = true; m_keys.clear(); this->deserializeData(m.data); } this->store(); function(true); return {false, false}; } else { return {true, false}; } }; LXQt::Wallet::changePassWordDialog::changeInstance(this, walletName, applicationName, std::move(change)); } void LXQt::Wallet::windows_dpapi::setImage(const QIcon &e) { this->setWindowIcon(e); } LXQt::Wallet::BackEnd LXQt::Wallet::windows_dpapi::backEnd() { return LXQt::Wallet::BackEnd::windows_dpapi; } QObject *LXQt::Wallet::windows_dpapi::qObject() { return nullptr; } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/lxqt_windows_dpapi.h000066400000000000000000000100641425361753700277030ustar00rootroot00000000000000/* * copyright: 2020 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LXQT_WINDOWS_H #define LXQT_WINDOWS_H #include "lxqt_wallet.h" #include "task.h" #include #include #include #include #include #include class QWidget; namespace LXQt { namespace Wallet { class windows_dpapi : public LXQt::Wallet::Wallet { public: windows_dpapi(); ~windows_dpapi(); void open(const QString &walletName, const QString &applicationName, std::function< void(bool) >, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()); bool open(const QString &walletName, const QString &applicationName, QWidget * = nullptr, const QString &password = QString(), const QString &displayApplicationName = QString()); bool addKey(const QString &key, const QByteArray &value); bool opened(void); QByteArray readValue(const QString &key); QVector> readAllKeyValues(void); QStringList readAllKeys(void); QStringList managedWalletList(void); QString storagePath(void); QString localDefaultWalletName(void); QString networkDefaultWalletName(void); void deleteKey(const QString &key); void closeWallet(bool); void changeWalletPassWord(const QString &walletName, const QString &applicationName = QString(), std::function< void(bool) > = [](bool e) { Q_UNUSED(e) }); void setImage(const QIcon &); int walletSize(void); void log(std::function); LXQt::Wallet::BackEnd backEnd(void); QObject *qObject(void); private: QByteArray getData(); struct result { bool success; QByteArray data; }; LXQt::Wallet::Task::future &encrypt(QByteArray); LXQt::Wallet::Task::future &decrypt(QByteArray); void setEntropy(const QString &); void store(); void createWallet(void); void openWallet(QByteArray); void openWalletWithPassword(QString, const QByteArray &); void deserializeData(const QByteArray &); QByteArray serializeData(); QString m_walletName; QString m_applicationName; QString m_displayApplicationName; QString m_password; QByteArray m_entropy; bool m_opened = false; std::function< void(bool) > m_correctPassword = [](bool e) { Q_UNUSED(e) }; std::function< void(bool) > m_walletOpened = [](bool e) { Q_UNUSED(e) }; std::function m_log ; QVector> m_keys; std::unique_ptr m_settings; const QString m_settingsName = "LXQtWindowsDPAPI_Data"; }; } } #endif zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/password_dialog.cpp000066400000000000000000000127661425361753700275130ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "password_dialog.h" #include "ui_password_dialog.h" LXQt::Wallet::password_dialog::password_dialog(QWidget *parent, const QString &walletName, const QString &appName, std::function< void(const QString &) > && p, std::function< void() > && q, std::function< void(bool) > * z) : QDialog(parent), m_ui(new Ui::password_dialog), m_password(std::move(p)), m_cancel(std::move(q)) { m_ui->setupUi(this); this->setFixedSize(this->size()); this->setWindowFlags(this->windowFlags()|Qt::WindowStaysOnTopHint); if (parent) { this->setWindowIcon(parent->windowIcon()); } connect(m_ui->pushButtonSend, SIGNAL(clicked()), this, SLOT(pbSend())); connect(m_ui->pushButtonCancel, SIGNAL(clicked()), this, SLOT(pbCancel())); connect(m_ui->pushButtonOK_2, SIGNAL(clicked()), this, SLOT(pbOK_2())); m_ui->pushButtonOK_2->setVisible(false); m_ui->textEdit_2->setVisible(false); m_ui->textEdit->setVisible(false); m_ui->pushButtonOK->setVisible(false); m_banner = m_ui->textEdit->toHtml().arg(appName, walletName); m_ui->labelWalletDoesNotExist->setVisible(false); m_ui->labelHeader->setText(m_banner); *z = [this](bool correctPassword) { if (correctPassword) { this->HideUI(); } else { m_ui->labelHeader->setText(tr("Wallet could not be opened with the presented key")); m_ui->textEdit->setVisible(false); m_ui->labelWalletDoesNotExist->setVisible(false); m_ui->labelHeader->setVisible(true); m_ui->lineEditKey->setVisible(true); m_ui->lineEditKey->setEnabled(false); m_ui->pushButtonSend->setVisible(false); m_ui->pushButtonCancel->setVisible(false); m_ui->pushButtonOK->setVisible(false); m_ui->pushButtonOK_2->setVisible(true); m_ui->pushButtonOK_2->setFocus(); } }; this->installEventFilter(this); this->show(); } bool LXQt::Wallet::password_dialog::eventFilter(QObject *watched, QEvent *event) { if (watched == this) { if (event->type() == QEvent::KeyPress) { auto keyEvent = static_cast< QKeyEvent * >(event); if (keyEvent->key() == Qt::Key_Escape) { this->HideUI(); return true; } } } return false; } LXQt::Wallet::password_dialog::~password_dialog() { delete m_ui; } void LXQt::Wallet::password_dialog::pbSend() { m_ui->textEdit->setEnabled(false); m_ui->labelHeader->setEnabled(true); m_ui->lineEditKey->setEnabled(false); m_ui->lineEditKey->setEnabled(false); m_ui->pushButtonSend->setEnabled(false); m_ui->pushButtonCancel->setEnabled(false); m_ui->pushButtonOK->setEnabled(false); m_ui->pushButtonOK_2->setEnabled(true); m_password(m_ui->lineEditKey->text()); } void LXQt::Wallet::password_dialog::pbCancel() { m_cancel(); this->HideUI(); } void LXQt::Wallet::password_dialog::pbOK() { this->HideUI(); } void LXQt::Wallet::password_dialog::pbOK_2() { m_ui->labelHeader->setText(m_banner); m_ui->textEdit->setVisible(false); m_ui->labelWalletDoesNotExist->setVisible(false); m_ui->labelHeader->setVisible(true); m_ui->lineEditKey->setVisible(true); m_ui->lineEditKey->setEnabled(true); m_ui->pushButtonSend->setVisible(true); m_ui->pushButtonCancel->setVisible(true); m_ui->pushButtonOK->setVisible(false); m_ui->pushButtonOK_2->setVisible(false); m_ui->lineEditKey->clear(); m_ui->lineEditKey->setFocus(); m_ui->textEdit->setEnabled(true); m_ui->labelHeader->setEnabled(true); m_ui->lineEditKey->setEnabled(true); m_ui->lineEditKey->setEnabled(true); m_ui->pushButtonSend->setEnabled(true); m_ui->pushButtonCancel->setEnabled(true); m_ui->pushButtonOK->setEnabled(true); m_ui->pushButtonOK_2->setEnabled(true); } void LXQt::Wallet::password_dialog::HideUI() { this->hide(); this->deleteLater(); } void LXQt::Wallet::password_dialog::closeEvent(QCloseEvent *e) { e->ignore(); this->HideUI(); } zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/password_dialog.h000066400000000000000000000057561425361753700271610ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef PASSWORD_DIALOG_H #define PASSWORD_DIALOG_H #include #include #include #include #include #include #include #include namespace Ui { class password_dialog; } namespace LXQt { namespace Wallet { class password_dialog : public QDialog { Q_OBJECT public: static password_dialog &instance(QWidget *w, const QString &walletName, const QString &appName, std::function< void(const QString &) > && p, std::function< void() > q, std::function< void(bool) > * z) { return *(new password_dialog(w, walletName, appName, std::move(p), std::move(q), z)); } explicit password_dialog(QWidget *parent, const QString &walletName, const QString &appName, std::function< void(const QString &) > && , std::function< void() > && , std::function< void(bool) > *); ~password_dialog(); private slots: void pbSend(void); void pbCancel(void); void pbOK(void); void pbOK_2(void); private: void HideUI(void); void closeEvent(QCloseEvent *); bool eventFilter(QObject *watched, QEvent *event); Ui::password_dialog *m_ui; QString m_banner; std::function< void(const QString &) > m_password; std::function< void() > m_cancel; }; } } #endif // PASSWORD_DIALOG_H zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/password_dialog.ui000066400000000000000000000135771425361753700273470ustar00rootroot00000000000000 password_dialog Qt::ApplicationModal 0 0 501 171 lxqt wallet service lxqt_wallet_icon.pnglxqt_wallet_icon.png 10 10 481 161 20 20 441 81 The application '%1' has requested to open the wallet '%2'.Enter the password below for this wallet to unlock it Qt::AlignCenter true 20 100 441 31 QLineEdit::Password 10 20 461 81 Wallet '%1' does not exist,do you want to create it? Qt::AlignCenter 20 140 61 20 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt;">Wallet </span><span style=" font-family:'Sans Serif'; font-size:9pt; font-weight:600;">'%1'</span><span style=" font-family:'Sans Serif'; font-size:9pt;"> does not exist, do you want to create it?</span></p></body></html> 400 140 71 21 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:9pt;">An application </span><span style=" font-family:'Sans Serif'; font-size:9pt; font-weight:600;">'%1'</span><span style=" font-family:'Sans Serif'; font-size:9pt;"> has requested to open a wallet</span><span style=" font-family:'Sans Serif'; font-size:9pt; font-weight:600;"> '%2'</span><span style=" font-family:'Sans Serif'; font-size:9pt;">. Enter the password below for this wallet to unlock it.</span></p></body></html> 120 130 121 31 &Unlock true 250 140 121 31 &Cancel 200 140 91 31 ok 200 140 91 31 &Ok zuluCrypt-6.2.0/external_libraries/lxqt_wallet/frontend/task.h000066400000000000000000000265301425361753700247330ustar00rootroot00000000000000/* * copyright: 2014-2016 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef __TASK_H_INCLUDED__ #define __TASK_H_INCLUDED__ #include #include #include #include #include /* * * Examples on how to use the library are at the end of this file. * */ /* * This library wraps a function into a future where the result of the function * can be retrieved through the future's 3 public methods: * * 1. .get() This method runs the wrapped function on the current thread * and could block the thread and hang GUI. * * 2. .then() This method does three things: * * 1. Registers a method to be called when a wrapped function finish running. * * 2. Runs the wrapped function on a background thread. * * 3. Runs the registered method on the current thread when the wrapped function finish * running. * * 3. .await() This method does three things: * * 1. Suspends the current thread at a point where this method is called. * * 2. Creates a background thread and then runs the wrapped function in the background * thread. * * 3. Unsuspends the current thread when the wrapped function finish and let the * current thread continue normally. * * The suspension at step 1 is done without blocking the thread and hence the suspension * can be done in the GUI thread and the GUI will remain responsive. * * The future is of type "Task::future&" and "std::reference_wrapper"[1] * class can be used if they are to be managed in a container that can not handle references. * * [1] http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper */ namespace LXQt { namespace Wallet { namespace Task { class Thread : public QThread { Q_OBJECT public: Thread() { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); #else connect(this, &QThread::finished, this, &QThread::deleteLater); #endif } protected: virtual ~Thread() { } private: virtual void run() { } }; template< typename T > class future { public: future(QThread *e, std::function< void() > && start, std::function< void() > && cancel, std::function< void(T &) > && get) : m_thread(e), m_start(std::move(start)), m_cancel(std::move(cancel)), m_get(std::move(get)) { } void then(std::function< void(T) > function) { m_function = std::move(function); this->start(); } T get() { T r; m_get(r); return r; } T await() { QEventLoop p; T q; m_function = [ & ](T && r) { q = std::move(r); p.exit(); }; this->start(); p.exec(); return q; } QThread &thread() { return *m_thread; } void start() { m_start(); } void cancel() { m_cancel(); } void run(T && r) { m_function(std::move(r)); } private: QThread *m_thread; std::function< void(T) > m_function = [](T && t) { Q_UNUSED(t); }; std::function< void() > m_start; std::function< void() > m_cancel; std::function< void(T &) > m_get; }; template< typename T > class ThreadHelper : public Thread { public: ThreadHelper(std::function< T() > && function) : m_function(std::move(function)), m_future(this, [this]() { this->start(); }, [this]() { this->deleteLater(); }, [this](T &r) { r = m_function(); this->deleteLater(); }) { } future& Future() { return m_future; } private: ~ThreadHelper() { m_future.run(std::move(m_result)); } void run() { m_result = m_function(); } std::function< T() > m_function; future m_future; T m_result; }; template<> class future< void > { public: future(QThread *e , std::function< void() > && start, std::function< void() > && cancel, std::function< void() > && get) : m_thread(e), m_start(std::move(start)), m_cancel(std::move(cancel)), m_get(std::move(get)) { } void then(std::function< void() > function) { m_function = std::move(function); this->start(); } void get() { m_get(); } void await() { QEventLoop p; m_function = [ & ]() { p.exit(); }; this->start(); p.exec(); } QThread &thread() { return *m_thread; } void start() { m_start(); } void run() { m_function(); } void cancel() { m_cancel(); } private: QThread *m_thread; std::function< void() > m_function = []() {}; std::function< void() > m_start; std::function< void() > m_cancel; std::function< void() > m_get; }; template<> class ThreadHelper< void > : public Thread { public: ThreadHelper(std::function< void() > && function) : m_function(std::move(function)), m_future(this, [this]() { this->start(); }, [this]() { this->deleteLater(); }, [this]() { m_function(); this->deleteLater(); }) { } future< void >& Future() { return m_future; } private: ~ThreadHelper() { m_future.run(); } void run() { m_function(); } std::function< void() > m_function; future< void > m_future; }; /* * * Below APIs wrappes a function around a future and then returns the future. * */ template< typename T > future& run(std::function< T() > function) { return (new ThreadHelper(std::move(function)))->Future(); } template< typename T, typename ... Args > future& run(std::function< T(Args ...) > function, Args ... args) { return Task::run(std::bind(std::move(function), std::move(args) ...)); } static inline future< void >& run(std::function< void() > function) { return Task::run< void >(std::move(function)); } template< typename ... Args > future< void >& run(std::function< void(Args ...) > function, Args ... args) { return Task::run< void >(std::bind(std::move(function), std::move(args) ...)); } /* * * A few useful helper functions * */ template< typename T > T await(std::function< T() > function) { return Task::run(std::move(function)).await(); } template< typename T, typename ... Args > T await(std::function< T(Args ...) > function, Args ... args) { return Task::await(std::bind(std::move(function), std::move(args) ...)); } static inline void await(std::function< void() > function) { Task::await< void >(std::move(function)); } template< typename T > T await(Task::future& e) { return e.await(); } template< typename T > T await(std::future t) { return Task::await([ & ]() { return t.get(); }); } /* * These methods run their arguments in a separate thread and does not offer * continuation feature.Useful when wanting to just run a function in a * different thread. */ static inline void exec(std::function< void() > function) { Task::run(std::move(function)).start(); } template< typename T, typename ... Args > void exec(std::function< T(Args ...) > function, Args ... args) { Task::exec(std::bind(std::move(function), std::move(args) ...)); } } } } #if 0 // start example block Examples on how to use the library ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * Example use cases on how to use Task::run().then() API ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** templated version that passes a return value of one function to another function -------------------------------------------------------------------------------- - int foo { /* * This task will run on a different thread * This tasks returns a result */ return 0; } void bar(int r) { /* * This task will run on the original thread. * This tasks takes an argument returned by task _a */ } Task::run(foo).then(bar); alternatively, Task::future& e = Task::run(foo); e.then(bar); Non templated version that does not pass around return value ---------------------------------------------------------------- void foo_1() { /* * This task will run on a different thread * This tasks returns with no result */ } void bar_1() { /* * This task will run on the original thread. * This tasks takes no argument */ } Task::run(foo_1).then(bar_1); alternatively, Task::future& e = Task::run(foo_1); e.then(bar_1); ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * Example use cases on how to use Task::run().await() API ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** int r = Task::await(foo); alternatively, Task::future& e = Task::run(foo); int r = e.await(); alternatively, int r = Task::run(foo).await(); ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * * Example use cases on how to use lambda that requires an argument ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * /* * declaring "foo_2" with an auto keyword will not be sufficient here * and the full std::function is required. * * For the same reason,just plugging in a lambda that requires arguments * into Task::run() will not be sufficent and the plugged in lambda must * be casted to std::function for it to compile. * * Why the above restriction? No idea but i suspect it has to do with * variadic template type deduction failing to see something. */ std::function< int(int) > foo_2 = [](int x) { return x + 1; }; Task::run(foo_2, 6).then([](int r) { qDebug() << r; }); alternatively, r = Task::await(foo_2, 6); #endif //end example block #endif //__TASK_H_INCLUDED__ zuluCrypt-6.2.0/external_libraries/tasks/000077500000000000000000000000001425361753700205605ustar00rootroot00000000000000zuluCrypt-6.2.0/external_libraries/tasks/CMakeLists.txt000066400000000000000000000046041425361753700233240ustar00rootroot00000000000000cmake_minimum_required( VERSION 3.0 ) project( tasks ) set( LIB_VERSION "1.2.3" ) set( SO_VERSION "1.0.0" ) add_definitions( -Wextra -Wall -pedantic ) if( CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0.0) set( CMAKE_CXX_STANDARD 20 ) MESSAGE( STATUS "Setting C++ version to C++20" ) else() set( CMAKE_CXX_STANDARD 14 ) MESSAGE( STATUS "Setting C++ version to C++14" ) endif() set( CMAKE_CXX_STANDARD_REQUIRED ON ) set( CMAKE_CXX_EXTENSIONS OFF) INCLUDE( GNUInstallDirs ) INCLUDE( CMakeDependentOption ) find_package( Qt5Core REQUIRED ) QT5_WRAP_CPP( MOC_LIBRARY task.hpp ) include_directories( ${Qt5Core_INCLUDE_DIRS} ) if( MCHUNGU_TASK_INSTALL ) add_library( mhogomchungu_task SHARED ${MOC_LIBRARY} ) set_target_properties(mhogomchungu_task PROPERTIES SOVERSION "${SO_VERSION}") else() add_library( mhogomchungu_task STATIC ${MOC_LIBRARY} ) endif() target_link_libraries( mhogomchungu_task ${Qt5Core_LIBRARIES} ) if( WIN32 ) set_target_properties( mhogomchungu_task PROPERTIES COMPILE_FLAGS "-Wextra -Wall -s -pedantic " ) else() set_target_properties( mhogomchungu_task PROPERTIES COMPILE_FLAGS "-Wextra -Wall -s -fPIC -pedantic " ) endif() if( DEBUG ) QT5_WRAP_CPP( MOC_EXE example.h ) add_executable( example example.cpp main.cpp ${MOC_EXE} ) target_link_libraries( example mhogomchungu_task ) endif() file( WRITE ${PROJECT_BINARY_DIR}/mhogomchungu_task.pc "prefix=${CMAKE_INSTALL_PREFIX} libdir=${CMAKE_INSTALL_FULL_LIBDIR} includedir=${CMAKE_INSTALL_FULL_INCLUDEDIR}/mhogomchungu Name: mhogomchungu_task Description: A Qt5 library that offers task based programming using modern C++ Version: ${LIB_VERSION} Libs: -L${CMAKE_INSTALL_FULL_LIBDIR} -l${Qt5Core_LIBRARIES} Cflags: -I${CMAKE_INSTALL_FULL_INCLUDEDIR}/mhogomchungu \n") if( MCHUNGU_TASK_INSTALL ) install( FILES ${PROJECT_BINARY_DIR}/mhogomchungu_task.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig/ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) install( FILES task.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mhogomchungu ) install( TARGETS mhogomchungu_task LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) # uninstall target configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY ) add_custom_target( uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake ) endif() zuluCrypt-6.2.0/external_libraries/tasks/LICENSE000066400000000000000000000026031425361753700215660ustar00rootroot00000000000000/* * copyright: 2014-2018 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ zuluCrypt-6.2.0/external_libraries/tasks/README.md000066400000000000000000000131671425361753700220470ustar00rootroot00000000000000 Asynchronous programming in Qt/C++ using tasks and continuations. ======== The project seeks to do async based programming in Qt/C++ using modern C++. This library wraps a function into a future where the result of the wrapped function can be retrieved through the future's below public methods: 1. .get(). This method runs the wrapped function on the current thread and could block the thread and hang GUI. This API is useful when you are already in a background thread. 2. .then(). This method does three things: 1. Registers a method to be called when a wrapped function finish running. 2. Runs the wrapped function on a background thread. 3. Runs the registered method on the current thread when the wrapped function finish running. 3. .await(). This method does three things: 1. Suspends the current thread at a point where this method is called. 2. Creates a background thread and then runs the wrapped function in the background thread. 3. Unsuspends the current thread when the wrapped function finish and let the current thread continue normally. The suspension at step 1 is done without blocking the thread and hence the suspension can be done in the GUI thread and the GUI will remain responsive. 4. .queue(). This method runs tasks in a future sequentially and a passed in function will be called when all tasks finish running. This method behaves like ```.then( [](){} )``` if the future is managing only one task. 5. .cancel(). This method can be used to cancel a future. It is important to know that this method does not terminate a running thread that is powering a future, it just releases memory used by a future and this method should be used if a future is to be discarded after it it is acquired but never used. To terminate a thread,call .all_threads() method,locate a QThread instance you want to terminate and call .terminate() method on the instance. 6. .all_threads(). This method returns a vector of QThreads that are powering futures. The vector will contain a single entry if this future powers its own task. If this future manages other futures,then the returned vector will contain QThread pointers that are in the same order as tasks/futures passed to Task::run(). 7. .start(). This method is to be used if a future is to be run without caring about its result. Use this API if you want a future to run but dont want to use any of the above mentioned methods. 8. .manages_multiple_futures(). This method can be used to check if a future powers its own task or manages other futures. Examples of using a future. ======== **1. Example use of .get() method of a future.** ```c++ Task::future& foo = bar() ; int r = foo.get() ; ``` **2. Example use of .await() method of a future.** ```c++ Task::future& foo = bar() ; int r = foo.await() ; ``` **3. Example use an alternative use of .await() method of a future.** ```c++ int foo() ; //function prototype int r = Task::await( foo ) ; ``` **4. Example use of .then() method of a future.** ```c++ void meaw( int ) ; //function prototype Task::future& foo = bar() ; foo.then( meaw ) ; ``` **5. Example use of .queue() method of a future.** ```c++ void meaw() ; //function prototype Task::future& foo = bar() ; foo.queue( meaw ) ; ``` Examples of creating a future. ======== **1. Creating a future that has no result.** ```c++ void bar() ; //function prototype Task::future& foo = Task::run( bar ) ; ``` **2. Creating a future that has result.** ```c++ int foo() ; //function prototype Task::future& foo = Task::run( foo ) ; ``` **3. Creating a future that combines multiple functions. .get() and .queue() on the future will cause passed in functions to run sequentially and in the order they are specified. .await() and .then() will cause passed in functions to run concurrently.** ```c++ void foo() ; //function prototype void bar() ; //function prototype Task::future& foo = Task::run( foo,bar ) ; ``` **4. Creating a future that combines multiple tasks and their continuations that take no argument. .get() and .queue() on the future will cause passed in functions to run sequentially and in the order they are specified. .await() and .then() will cause passed in functions to run concurrently.** ```c++ void foo() ; //function prototype void bar() ; //function prototype void cfoo() ; //function prototype void cbar() ; //function prototype Task::future& e = Task::run( Task::void_pair{ foo,cfoo },Task::void_pair{ bar,cbar } ) ; ``` **5. Creating a future that combines multiple tasks and their continuations that takes an argument. .get() and .queue() on the future will cause passed in pairs to run sequentially and in the order they are specified. .await() and .then() will cause passed in pairs to run concurrently. The result of the future is undefined and a function that takes no argument should be used if .await() method of the future is called.** ```c++ int foo() ; //function prototype int bar() ; //function prototype void cfoo( int ) ; //function prototype void cbar( int ) ; //function prototype Task::future& e = Task::run( Task::pair{ foo,cfoo },Task::pair{ bar,cbar } ) ; ``` Further documentation of how to use the library is here[1] and here[2]. [1] https://github.com/mhogomchungu/tasks/blob/master/example.cpp [2] https://github.com/mhogomchungu/tasks/blob/0bd4fd227aa4f13bba25dff74df06719ada6317d/task.h#L598 zuluCrypt-6.2.0/external_libraries/tasks/task.hpp000066400000000000000000001112231425361753700222330ustar00rootroot00000000000000/* * copyright: 2014-2020 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef __TASK_H_INCLUDED__ #define __TASK_H_INCLUDED__ #include #include #include #include #include #include #include #include #include #include /* * * Examples on how to use the library are at the end of this file. * */ /* * This library wraps a function into a future where the result of the function * can be retrieved through the future's below public methods: * * 1. .get(). This method runs the wrapped function on the current thread * and could block the thread and hang GUI. * * 2. .then(). This method does three things: * * 1. Registers a method to be called when a wrapped function finish running. * * 2. Runs the wrapped function on a background thread. * * 3. Runs the registered method on the current thread when the wrapped function finish * running. * * 3. .await(). This method does three things: * * 1. Suspends the current thread at a point where this method is called. * * 2. Creates a background thread and then runs the wrapped function in the background * thread. * * 3. Unsuspends the current thread when the wrapped function finish and let the * current thread continue normally. * * The suspension at step 1 is done without blocking the thread and hence the suspension * can be done in the GUI thread and the GUI will remain responsive. * * 4. .queue(). This method runs tasks in a future sequentially and a passed in function will be called * when all tasks finish running. This method behaves like .then( [](){} ) if the future is * managing only one task. * * 5. .cancel(). This method can be used to cancel a future. It is important to know * that this method does not terminate a running thread that is powering a future, it just * releases memory used by a future and this method should be used if a future is to be discarded * after it it is acquired but never used. * * 6. .all_threads(). This method returns a vector of QThreads that are powering futures. * The vector will contain a single entry if this future powers its own task. If this future * manages other futures,then the returned vector will contain QThread pointers that are in * the same order as tasks/futures passed to Task::run(). * * 7. .start(). This method is to be used if a future is to be run without caring about * its result. Use this method if you want a future to run but dont want to use any of the above mentioned * methods. * * 8. .manages_multiple_futures(). This method can be used to check if a future powers * its own task or manages other futures. * * * The future is of type "Task::future&" and "std::reference_wrapper"[1] * class can be used if they are to be managed in a container that can not handle references. * * [1] http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper */ namespace Task { template< typename T > class future; namespace detail { template< typename T > void add_void( Task::future< T >&,Task::future< T >&,std::function< T() >&& ) ; template< typename T > void add( Task::future< T >&,Task::future< T >&,std::function< void( T ) >&& ) ; template class functionWrapper { public: template< typename ... Args > auto operator()( Args&& ... args ) const { return (*m_function)( std::forward( args ) ... ) ; } functionWrapper( Function function ) : m_function( std::make_shared( Function( std::move( function ) ) ) ) { } private: std::shared_ptr m_function ; }; template functionWrapper function( Function function ) { return functionWrapper( std::move( function ) ) ; } #if __cplusplus >= 201703L template using result_of = std::invoke_result_t ; #else template using result_of = std::result_of_t ; #endif template using copyable = std::enable_if_t::value,int> ; template using not_copyable = std::enable_if_t::value,int> ; template using has_same_return_type = std::enable_if_t,ReturnType>::value,int> ; template using has_void_return_type = has_same_return_type ; template using has_bool_return_type = has_same_return_type ; template using has_non_void_return_type = std::enable_if_t>::value,int> ; template using has_argument = has_same_return_type,Function,Args...> ; template using has_no_argument = has_same_return_type,Function> ; template using returns_void = has_void_return_type ; template using returns_value = has_non_void_return_type ; } template< typename T > struct pair{ pair( std::function< T() > first,std::function< void( T ) > second ) : value( std::make_pair( std::move( first ),std::move( second ) ) ) { } std::pair< std::function< T() >,std::function< void( T ) > > value ; }; template<> struct pair{ pair( std::function< void() > first,std::function< void() > second ) : value( std::make_pair( std::move( first ),std::move( second ) ) ) { } std::pair< std::function< void() >,std::function< void() > > value ; }; template< typename E, typename F, Task::detail::not_copyable = 0, Task::detail::not_copyable = 0 > pair> make_pair( E e,F f ) { using type = Task::detail::result_of ; return pair( Task::detail::function( std::move( e ) ),Task::detail::function( std::move( f ) ) ) ; } template< typename E, typename F, Task::detail::copyable = 0, Task::detail::copyable = 0 > pair> make_pair( E e,F f ) { return pair>( std::move( e ),std::move( f ) ) ; } template< typename E, typename F, Task::detail::not_copyable = 0, Task::detail::copyable = 0 > pair> make_pair( E e,F f ) { using type = Task::detail::result_of ; return pair( Task::detail::function( std::move( e ) ),std::move( f ) ) ; } template< typename E, typename F, Task::detail::copyable = 0, Task::detail::not_copyable = 0 > pair> make_pair( E e,F f ) { using type = Task::detail::result_of ; return pair( std::move( e ),Task::detail::function( std::move( f ) ) ) ; } template< typename T > class future : private QObject { public: /* * Use this API if you care about the result */ //std::function< void( T ) > template = 0, Task::detail::copyable = 0> void then( Function function ) { m_function = std::move( function ) ; this->start() ; } template = 0, Task::detail::not_copyable = 0> void then( Function function ) { m_function = Task::detail::function( std::move( function ) ) ; this->start() ; } /* * Use this API if you DO NOT care about the result */ //std::function< void( void ) > template = 0, Task::detail::copyable = 0> void then( Function function ) { m_function_1 = std::move( function ) ; this->start() ; } template = 0, Task::detail::not_copyable = 0> void then( Function function ) { m_function_1 = Task::detail::function( std::move( function ) ) ; this->start() ; } template = 0, Task::detail::not_copyable = 0> void queue( Function function ) { if( this->manages_multiple_futures() ){ m_function_1 = Task::detail::function( std::move( function ) ) ; this->_queue() ; }else{ this->then( Task::detail::function( std::move( function ) ) ) ; } } template = 0, Task::detail::copyable = 0> void queue( Function function ) { if( this->manages_multiple_futures() ){ m_function_1 = std::move( function ) ; this->_queue() ; }else{ this->then( std::move( function ) ) ; } } void queue() { if( this->manages_multiple_futures() ){ m_function_1 = [](){} ; this->_queue() ; }else{ this->then( [](){} ) ; } } /* * Below two API just exposes existing functionality using more standard names */ template void when_all( Function function ) { this->then( std::move( function ) ) ; } template void when_seq( Function function ) { this->queue( std::move( function ) ) ; } template = 0, Task::detail::copyable = 0> void when_any( Function function ) { if( this->manages_multiple_futures() ){ this->_when_any( std::move( function ) ) ; }else{ this->then( std::move( function ) ) ; } } template = 0, Task::detail::not_copyable = 0> void when_any( Function function ) { if( this->manages_multiple_futures() ){ this->_when_any( Task::detail::function( std::move( function ) ) ) ; }else{ this->then( Task::detail::function( std::move( function ) ) ) ; } } void when_all() { this->then( [](){} ) ; } void when_seq() { this->queue( [](){} ) ; } void when_any() { if( this->manages_multiple_futures() ){ this->_when_any( [](){} ) ; }else{ this->then( [](){} ) ; } } T get() { if( this->manages_multiple_futures() ){ for( auto& it : m_tasks ){ it.second( it.first->get() ) ; } this->deleteLater() ; return T() ; }else{ return m_get() ; } } T await() { QEventLoop p ; T q ; m_function = [ & ]( T&& r ){ q = std::move( r ) ; p.exit() ; } ; this->start() ; p.exec() ; return q ; } bool manages_multiple_futures() { return m_tasks.size() > 0 ; } const std::vector< QThread * >& all_threads() { return m_threads ; } QThread * first_thread() { return m_threads[ 0 ] ; } QThread * thread_at( std::vector< QThread * >::size_type s ) { return m_threads[ s ] ; } void start() { if( this->manages_multiple_futures() ){ this->_start() ; }else{ m_start() ; } } void cancel() { if( this->manages_multiple_futures() ){ for( auto& it : m_tasks ){ it.first->cancel() ; } this->deleteLater() ; }else{ m_cancel() ; } } future() = default ; future( const future& ) = delete ; future( future&& ) = delete ; future& operator=( const future& ) = delete ; future& operator=( future&& ) = delete ; future( QThread * e, std::function< void() >&& start, std::function< void() >&& cancel, std::function< T() >&& get ) : m_thread( e ), m_start ( std::move( start ) ), m_cancel( std::move( cancel ) ), m_get ( std::move( get ) ) { if( m_thread ){ m_threads.push_back( m_thread ) ; }else{ /* * This object was created by "_private_future< T >()" class. * It has no QThread of its own because it only manages other futures. * */ } } void run( T&& r ) { if( m_function_1 != nullptr ){ m_function_1() ; }else if( m_function != nullptr ){ m_function( std::move( r ) ) ; } } template< typename E > friend void Task::detail::add( Task::future< E >&, Task::future< E >&, std::function< void( E ) >&& ) ; private: void _when_any( std::function< void() > function ) { m_when_any_function = std::move( function ) ; for( auto& it : m_tasks ){ it.first->then( [ & ]( T&& e ){ QMutexLocker m( &m_mutex ) ; m_counter++ ; if( m_task_not_run ){ m_task_not_run = false ; m.unlock() ; it.second( std::forward( e ) ) ; m_when_any_function() ; }else{ m.unlock() ; it.second( std::forward( e ) ) ; } if( m_counter == m_tasks.size() ){ this->deleteLater() ; } } ) ; } } void _queue() { m_tasks[ m_counter ].first->then( [ this ]( T&& e ){ m_tasks[ m_counter ].second( std::forward( e ) ) ; m_counter++ ; if( m_counter == m_tasks.size() ){ m_function_1() ; this->deleteLater() ; }else{ this->_queue() ; } } ) ; } void _start() { for( auto& it : m_tasks ){ it.first->then( [ & ]( T&& e ){ QMutexLocker m( &m_mutex ) ; Q_UNUSED( m ) ; m_counter++ ; it.second( std::forward( e ) ) ; if( m_counter == m_tasks.size() ){ if( m_function_1 != nullptr ){ m_function_1() ; }else if( m_function != nullptr ){ m_function( T() ) ; } this->deleteLater() ; } } ) ; } } QThread * m_thread = nullptr ; std::function< void( T ) > m_function = nullptr ; std::function< void() > m_function_1 = nullptr ; std::function< void() > m_start = [](){} ; std::function< void() > m_cancel = [](){} ; std::function< T() > m_get = [](){ return T() ; } ; std::function< void() > m_when_any_function ; QMutex m_mutex ; std::vector< std::pair< Task::future< T > *,std::function< void( T ) > > > m_tasks ; std::vector< QThread * > m_threads ; decltype( m_tasks.size() ) m_counter = 0 ; bool m_task_not_run = true ; }; template<> class future< void > : private QObject { public: template = 0> void then( Function function ) { m_function = std::move( function ) ; this->start() ; } template = 0> void then( Function function ) { m_function = Task::detail::function( std::move( function ) ) ; this->start() ; } template = 0> void queue( Function function ) { if( this->manages_multiple_futures() ){ m_function = std::move( function ) ; this->_queue() ; }else{ this->then( std::move( function ) ) ; } } template = 0> void queue( Function function ) { if( this->manages_multiple_futures() ){ m_function = Task::detail::function( std::move( function ) ) ; this->_queue() ; }else{ this->then( Task::detail::function( std::move( function ) ) ) ; } } void queue() { if( this->manages_multiple_futures() ){ m_function = [](){} ; this->_queue() ; }else{ this->then( [](){} ) ; } } void when_any() { if( this->manages_multiple_futures() ){ this->_when_any( [](){} ) ; }else{ this->then( [](){} ) ; } } template = 0> void when_any( Function function ) { if( this->manages_multiple_futures() ){ this->_when_any( std::move( function ) ) ; }else{ this->then( std::move( function ) ) ; } } template = 0> void when_any( Function function ) { if( this->manages_multiple_futures() ){ this->_when_any( Task::detail::function( std::move( function ) ) ) ; }else{ this->then( Task::detail::function( std::move( function ) ) ) ; } } /* * Below two API just exposes existing functionality using more standard names */ template void when_all( Function function ) { this->then( std::move( function ) ) ; } template void when_seq( Function function ) { this->queue( std::move( function ) ) ; } void when_all() { this->then( [](){} ) ; } void when_seq() { this->queue() ; } void get() { if( this->manages_multiple_futures() ){ for( auto& it : m_tasks ){ it.first->get() ; it.second() ; } this->deleteLater() ; }else{ m_get() ; } } void await() { QEventLoop p ; m_function = [ & ](){ p.exit() ; } ; this->start() ; p.exec() ; } bool manages_multiple_futures() { return m_tasks.size() > 0 ; } const std::vector< QThread * >& all_threads() { return m_threads ; } QThread * first_thread() { return m_threads[ 0 ] ; } QThread * thread_at( std::vector< QThread * >::size_type s ) { return m_threads[ s ] ; } void start() { if( this->manages_multiple_futures() ){ this->_start() ; }else{ m_start() ; } } void cancel() { if( this->manages_multiple_futures() ){ for( auto& it : m_tasks ){ it.first->cancel() ; } this->deleteLater() ; }else{ m_cancel() ; } } future() = default ; future( const future& ) = delete ; future( future&& ) = delete ; future& operator=( const future& ) = delete ; future& operator=( future&& ) = delete ; future( QThread * e , std::function< void() >&& start, std::function< void() >&& cancel, std::function< void() >&& get ) : m_thread( e ), m_start ( std::move( start ) ), m_cancel( std::move( cancel ) ), m_get ( std::move( get ) ) { if( m_thread ){ m_threads.push_back( m_thread ) ; }else{ /* * This object was created by "_private_future< T >()" class. * It has no QThread of its own because it only manages other futures. * */ } } template< typename T > friend void Task::detail::add_void( Task::future< T >&, Task::future< T >&, std::function< T() >&& ) ; void run() { m_function() ; } private: void _when_any( std::function< void() > function ) { m_when_any_function = std::move( function ) ; for( auto& it : m_tasks ){ it.first->then( [ & ](){ QMutexLocker m( &m_mutex ) ; m_counter++ ; if( m_task_not_run ){ m_task_not_run = false ; m.unlock() ; it.second() ; m_when_any_function() ; }else{ m.unlock() ; it.second() ; } if( m_counter == m_tasks.size() ){ this->deleteLater() ; } } ) ; } } void _queue() { m_tasks[ m_counter ].first->then( [ this ](){ m_tasks[ m_counter ].second() ; m_counter++ ; if( m_counter == m_tasks.size() ){ m_function() ; this->deleteLater() ; }else{ this->_queue() ; } } ) ; } void _start() { for( auto& it : m_tasks ){ it.first->then( [ & ](){ QMutexLocker m( &m_mutex ) ; Q_UNUSED( m ) ; m_counter++ ; it.second() ; if( m_counter == m_tasks.size() ){ m_function() ; this->deleteLater() ; } } ) ; } } QThread * m_thread = nullptr ; std::function< void() > m_function = [](){} ; std::function< void() > m_start = [](){} ; std::function< void() > m_cancel = [](){} ; std::function< void() > m_get = [](){} ; std::function< void() > m_when_any_function ; QMutex m_mutex ; std::vector< std::pair< Task::future< void > *,std::function< void() > > > m_tasks ; std::vector< QThread * > m_threads ; decltype( m_tasks.size() ) m_counter = 0 ; bool m_task_not_run = true ; }; namespace detail { /* * -------------------------Start of internal helper functions------------------------- */ template< typename Type,typename Function > class ThreadHelper : public QThread { public: ThreadHelper( Function function ) : m_function( std::move( function ) ), m_future( this, [ this ](){ this->start() ; }, [ this ](){ this->deleteLater() ; }, [ this ](){ this->deleteLater() ; return m_function() ; } ) { connect( this,&QThread::finished,this,&QThread::deleteLater ) ; } future& Future() { return m_future ; } private: ~ThreadHelper() { m_future.run( std::move( m_result ) ) ; } void run() { m_result = m_function() ; } Function m_function ; future m_future ; Type m_result ; }; template< typename Function> class ThreadHelperVoid : public QThread { public: ThreadHelperVoid( Function function ) : m_function( std::move( function ) ), m_future( this, [ this ](){ this->start() ; }, [ this ](){ this->deleteLater() ; }, [ this ](){ m_function() ; this->deleteLater() ; } ) { connect( this,&QThread::finished,this,&QThread::deleteLater ) ; } future< void >& Future() { return m_future ; } private: ~ThreadHelperVoid() { m_future.run() ; } void run() { m_function() ; } Function m_function ; future< void > m_future ; }; template = 0> Task::future>& run( Fn function ) { using t = Task::detail::result_of ; return ( new ThreadHelper( std::move( function ) ) )->Future() ; } template = 0> Task::future>& run( Fn function ) { return ( new ThreadHelperVoid( std::move( function ) ) )->Future() ; } template< typename T > void add( Task::future< T >& a,Task::future< T >& b,std::function< void( T ) >&& c ) { a.m_tasks.emplace_back( std::addressof( b ),std::move( c ) ) ; a.m_threads.push_back( b.m_thread ) ; } template< typename T > void add_void( Task::future< T >& a,Task::future< T >& b,std::function< T() >&& c ) { a.m_tasks.emplace_back( std::addressof( b ),std::move( c ) ) ; a.m_threads.push_back( b.m_thread ) ; } template< typename T > void add_task( Task::future< T >& f ) { Q_UNUSED( f ) } template< typename T > void add_future( Task::future< T >& f ) { Q_UNUSED( f ) } template< typename T > void add_pair( Task::future< T >& f ) { Q_UNUSED( f ) } template< typename T > void add_pair_void( Task::future< T >& f ) { Q_UNUSED( f ) } template< typename ... T, typename Function, Task::detail::not_copyable = 0 > void add_task( Task::future< void >& f,Function e,T&& ... t ) ; template< typename ... T, typename Function, Task::detail::copyable = 0 > void add_task( Task::future< void >& f,Function e,T&& ... t ) { add_void( f,Task::detail::run( std::function< void() >( std::move( e ) ) ), std::function< void() >( [](){} ) ) ; add_task( f,std::forward( t ) ... ) ; } template< typename ... T, typename Function, Task::detail::not_copyable > void add_task( Task::future< void >& f,Function e,T&& ... t ) { auto a = std::function< void() >( Task::detail::function( std::move( e ) ) ) ; add_void( f,Task::detail::run( std::move( a ) ), std::function< void() >( [](){} ) ) ; add_task( f,std::forward( t ) ... ) ; } template< typename ... T > void add_future( Task::future< void >& f,Task::future< void >& e,T&& ... t ) { add_void( f,e,std::function< void() >( [](){} ) ) ; add_future( f,std::forward( t ) ... ) ; } template< typename E,typename F,typename ... T > void add_pair( Task::future< E >& f,F&& s,T&& ... t ) { add( f,Task::detail::run( std::move( s.value.first ) ),std::move( s.value.second ) ) ; add_pair( f,std::forward( t ) ... ) ; } template< typename F,typename ... T > void add_pair_void( Task::future< void >& f,F&& s,T&& ... t ) { add_void( f,Task::detail::run( std::move( s.value.first ) ),std::move( s.value.second ) ) ; add_pair_void( f,std::forward( t ) ... ) ; } template< typename T > Task::future< T >& future() { return *( new Task::future< T >() ) ; } } //end of detail namespace /* * -------------------------End of internal helper functions------------------------- */ template< typename Fn,Task::detail::copyable = 0 > auto& run( Fn function ) { return Task::detail::run( std::move( function ) ) ; } template< typename Fn,Task::detail::not_copyable = 0 > auto& run( Fn function ) { return Task::detail::run( Task::detail::function( std::move( function ) ) ) ; } #if __cplusplus > 201703L template< typename Fn,typename ... Args > future>& run( Fn function,Args ... args ) { return Task::run( [ function = std::move( function ),... args = std::move( args ) ]()mutable{ return function( std::move( args ) ... ) ; } ) ; } #elif __cplusplus == 201703L template< typename Fn,typename ... Args > future>& run( Fn function,Args ... args ) { return Task::run( [ args = std::make_tuple( std::move( args ) ... ),function = std::move( function ) ]()mutable{ return std::apply( [ function = std::move( function ) ]( Args ... args ){ return function( std::move( args ) ... ) ; },std::move( args ) ) ; } ) ; } #else template< typename Fn,typename ... Args > future>& run( Fn function,Args ... args ) { return Task::run( [ =,function = std::move( function ) ](){ return function( std::move( args ) ... ) ; } ) ; } #endif class progress : public QObject{ Q_OBJECT public: template< typename function > progress( QObject * obj,function fn ) { connect( this,&progress::update,obj,std::move( fn ) ) ; } signals: void update( QVariant x ) const ; private: }; template< typename Fn,typename cb > future>& run( QObject * obj,Fn function,cb rp ) { return Task::run( [ obj,rp = std::move( rp ),function = std::move( function ) ](){ return function( progress( obj,std::move( rp ) ) ) ; } ) ; } template< typename Function, Task::detail::copyable = 0, typename ... T > Task::future< void >& run_tasks( Function f,T ... t ) { auto& e = Task::detail::future< void >() ; Task::detail::add_task( e,std::move( f ),std::move( t ) ... ) ; return e ; } template< typename Function, Task::detail::not_copyable = 0, typename ... T > Task::future< void >& run_tasks( Function f,T ... t ) { auto& e = Task::detail::future< void >() ; Task::detail::add_task( e,Task::detail::function( std::move( f ) ),std::move( t ) ... ) ; return e ; } template< typename ... T > Task::future< void >& run_tasks( Task::future< void >& s,T&& ... t ) { auto& e = Task::detail::future< void >() ; Task::detail::add_future( e,s,std::forward( t ) ... ) ; return e ; } template< typename ... T > Task::future< void >& run( pair< void > s,T ... t ) { auto& e = Task::detail::future< void >() ; Task::detail::add_pair_void( e,std::move( s ),std::move( t ) ... ) ; return e ; } template< typename E,typename ... T > Task::future< E >& run( pair< E > s,T ... t ) { auto& e = Task::detail::future< E >() ; Task::detail::add_pair( e,std::move( s ),std::move( t ) ... ) ; return e ; } /* * * A few useful helper functions * */ template< typename Fn > Task::detail::result_of await( Fn function ) { return Task::run( std::move( function ) ).await() ; } template< typename Fn,typename ... Args > Task::detail::result_of await( Fn function,Args ... args ) { return Task::run( std::move( function ),std::move( args ) ... ).await() ; } template< typename T > T await( Task::future& e ) { return e.await() ; } template< typename T > T await( std::future t ) { return Task::await( [ & ](){ return t.get() ; } ) ; } /* * These methods run their arguments in a separate thread and does not offer * continuation feature.Useful when wanting to just run a function in a * different thread. */ template< typename Fn > void exec( Fn function ) { Task::run( std::move( function ) ).start() ; } template< typename Fn,typename ... Args > void exec( Fn function,Args ... args ) { Task::run( std::move( function ),std::move( args ) ... ).start() ; } template< typename T > void exec( Task::future& e ) { e.start() ; } namespace process { class result{ public: result() = default ; result( int exit_code ) : m_finished( true ), m_exitCode( exit_code ), m_exitStatus( 0 ) { } template< typename E,typename F > result( E&& std_out, F&& std_error, int exit_code, int exit_status, bool finished ) : m_stdOut( std::forward( std_out ) ), m_stdError( std::forward( std_error ) ), m_finished( finished ), m_exitCode( exit_code ), m_exitStatus( exit_status ) { } result( QProcess& e,int s ) { m_finished = e.waitForFinished( s ) ; m_stdOut = e.readAllStandardOutput() ; m_stdError = e.readAllStandardError() ; m_exitCode = e.exitCode() ; m_exitStatus = e.exitStatus() ; } const QByteArray& std_out() const { return m_stdOut ; } const QByteArray& std_error() const { return m_stdError ; } bool finished() const { return m_finished ; } bool success() const { return m_exitCode == 0 && m_exitStatus == QProcess::NormalExit && m_finished == true ; } bool failed() const { return !this->success() ; } int exit_code() const { return m_exitCode ; } int exit_status() const { return m_exitStatus ; } private: QByteArray m_stdOut ; QByteArray m_stdError ; bool m_finished = false ; int m_exitCode = 255 ; int m_exitStatus = 255 ; }; static inline Task::future< result >& run( const QString& cmd, const QStringList& args, int waitTime = -1, const QByteArray& password = QByteArray(), const QProcessEnvironment& env = QProcessEnvironment(), std::function< void() > setUp_child_process = [](){} ) { return Task::run( [ = ](){ class Process : public QProcess{ public: Process( std::function< void() > function, const QProcessEnvironment& env ) : m_function( std::move( function ) ) { this->setProcessEnvironment( env ) ; } protected: void setupChildProcess() { m_function() ; } private: std::function< void() > m_function ; } exe( std::move( setUp_child_process ),env ) ; if( args.isEmpty() ){ #if QT_VERSION < QT_VERSION_CHECK( 5,15,0 ) exe.start( cmd ) ; #else exe.start( cmd,args ) ; #endif }else{ exe.start( cmd,args ) ; } if( !password.isEmpty() ){ exe.waitForStarted( waitTime ) ; exe.write( password ) ; exe.closeWriteChannel() ; } return result( exe,waitTime ) ; } ) ; } static inline Task::future< result >& run( const QString& cmd,const QByteArray& password ) { return Task::process::run( cmd,{},-1,password ) ; } static inline Task::future< result >& run( const QString& cmd, const QStringList& args, const QByteArray& password ) { return Task::process::run( cmd,args,-1,password ) ; } } } #if 0 // start example block Examples on how to use the library ********************************************************** * Example use cases on how to use Task::run().then() API ********************************************************** templated version that passes a return value of one function to another function --------------------------------------------------------------------------------- int foo { /* * This task will run on a different thread * This tasks returns a result */ return 0 ; } void bar( int r ) { /* * This task will run on the original thread. * This tasks takes an argument returned by task _a */ } Task::run( foo ).then( bar ) ; alternatively, Task::future& e = Task::run( foo ) ; e.then( bar ) ; Non templated version that does not pass around return value ---------------------------------------------------------------- void foo_1() { /* * This task will run on a different thread * This tasks returns with no result */ } void bar_1() { /* * This task will run on the original thread. * This tasks takes no argument */ } Task::run( foo_1 ).then( bar_1 ) ; alternatively, Task::future& e = Task::run( foo_1 ) ; e.then( bar_1 ) ; ********************************************************** * Example use cases on how to use Task::run().await() API ********************************************************** int r = Task::await( foo ) ; alternatively, Task::future& e = Task::run( foo ) ; int r = e.await() ; alternatively, int r = Task::run( foo ).await() ; ******************************************************************* * Example use cases on how to use lambda that requires an argument ******************************************************************* auto foo_2 = []( int x ){ return x + 1 ; } ; Task::run( foo_2,6 ).then( []( int r ){ qDebug() << r ; } ) ; alternatively, r = Task::await( foo_2,6 ) ; ******************************************************************* * Example use cases on how to run multiple tasks and wait for all to * to finish before continuing ******************************************************************* Task::future& e = Task::run( fn1,fn2,fn3 ) ; or alternatively, Task::future& f1 = Task::run( fn1 ) ; Task::future& f2 = Task::run( fn2 ) ; Task::future& e = Task::run( f1,f2,f3 ) ; 1.0 .await() can then be called on the future to wait for all tasks to finish before continuing. 2.0 .then() can then be called on the future to invoke a callback on the current thread when all tasks finish. ******************************************************************* * Example use cases on how to run multiple tasks and their continuations * and wait for all to finish before continuing ******************************************************************* std::cout<< "Testing multiple tasks without continuation arguments" << std::endl ; auto fna1 = [](){ _printThreadID(); } ; auto fna2 = [](){ _printThreadID(); } ; auto fna3 = [](){ _printThreadID(); } ; auto ra1 = [](){ std::cout << "r1" << std::endl ; } ; auto ra2 = [](){ std::cout << "r2" << std::endl ; } ; auto ra3 = [](){ std::cout << "r3" << std::endl ; } ; Task::future& e = Task::run( Task::make_pair( fna1,ra1 ), Task::make_pair( fna2,ra2 ), Task::make_pair( fna3,ra3 ) ) ; e.await() ; std::cout<< "Testing multiple tasks with continuation arguments" << std::endl ; auto fn1 = [](){ _printThreadID(); return 0 ; } ; auto fn2 = [](){ _printThreadID(); return 0 ; } ; auto fn3 = [](){ _printThreadID(); return 0 ; } ; auto r1 = []( int ){ std::cout << "r1" << std::endl ; } ; auto r2 = []( int ){ std::cout << "r2" << std::endl ; } ; auto r3 = []( int ){ std::cout << "r3" << std::endl ; } ; Task::future& s = Task::run( Task::make_pair( fn1,r1 ), Task::make_pair( fn2,r2 ), Task::make_pair( fn3,r3 ) ) ; s.then( [](){ QCoreApplication::quit() ; } ) ; #endif //end example block #endif //__TASK_H_INCLUDED__ zuluCrypt-6.2.0/external_libraries/tcplay/000077500000000000000000000000001425361753700207275ustar00rootroot00000000000000zuluCrypt-6.2.0/external_libraries/tcplay/CHANGELOG000066400000000000000000000060321425361753700221420ustar00rootroot000000000000002020-03-02 Version 3.3 - Alex Hornung * Add new --prompt-passphrase option to reduce unlock time when both a passphrase and keyfiles are required (issue #75). 2020-02-27 Version 3.1 - Alex Hornung * Various memory leak/use-after-free bugs (issue #67). * Minor improvements to CMakeLists.txt to allow for empty LIB_SUFFIX and overriding sbin/ vs bin/. 2020-02-27 Version 3.0 - Alex Hornung * Added support for VeraCrypt volumes. See man page for more details. 2014-03-10 Version 2.0 - Alex Hornung * Documented SIGINFO/SIGUSR1 behaviour in man page. * Fixed creation (and volinfo) of 2GB+ volumes on 32-bit architectures, including armhf. * Try without a passphrase first if keyfiles are provided (issue #42). * Fixed handling of disks and volumes with 4k sectors (issue #45). * Add an option to allow TRIM (discards) on the mapped volume (issue #47). * Add an option to use a header-in-a-file for most operations. * Add an option to save a header to a file to the modify operation (issue #43). * Complete API redesign. 2013-07-31 Version 1.1 - Alex Hornung Special thanks to Mike Baker, Joshua Escamilla and Alon Bar-Lev for contributing fixes/improvements! * Added command to request information on mapped volumes. * Added support for full disk encryption. * Added support to query/map volumes using the backup headers instead of the primary headers. * Prefixed dm(4) uuids with CRYPT-TCPLAY-. * Added the 'device' field to all info commands. * Added command to modify/reencrypt a header, allowing passphrase and keyfile changes, as well as restoring from the backup header. * Improvements to Makefile.classic. 2013-05-15 Version 1.0 - Alex Hornung * Fixed bug in hidden volume protection (issue #28). * Added cmake build infrastructure (old single-Makefile option is also still available, using Makefile.classic). * Changed IV gen in mapped devices to plain64 from plain. * Fixed bug in passphrase logic - Truecrypt limits passphrases to 64 bytes (issue #24). * Added unmap option to command line tool (issue #17). * Added option to use /dev/urandom for key material, although this should only ever be used for testing purposes (issue #19). * Complete API overhaul. See man page for details. * Added test framework and tests. * Other minor bugfixes and tweaks. 2012-11-16 Version 0.11 - Alex Hornung Special thanks to Cody Schafer(jmesmon) for providing some of the fixes and to all the people out there packaging tcplay for their distros! If there's any way that I can make your life easier, let me know! Thanks to all the bug reporters as well. * Restored the library/API to working condition * Made it possible to pipe in passwords * Fixed edge case with memcpy copying in and out to the same place * Given up on -Werror, as some Linux distros have warnings even in their standard header files. * Fixed typos zuluCrypt-6.2.0/external_libraries/tcplay/CMakeLists.txt000066400000000000000000000142411425361753700234710ustar00rootroot00000000000000cmake_minimum_required (VERSION 3.0.2) project (tcplay) set (VERSION_MAJOR 3) set (VERSION_MINOR 3) find_package (PkgConfig) include (CheckLibraryExists) set (SRCS_COMMON tcplay.c crc32.c safe_mem.c io.c hdr.c humanize.c crypto.c generic_xts.c) set (SRCS_LINUX crypto-gcrypt.c) set (CFLAGS_LINUX "-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE") set (CFLAGS_WARN "-w") set (CFLAGS_DEBUG "-O0 -g3 -DDEBUG") set (CFLAGS_OPT "-O3") set (CFLAGS_VER "-DMAJ_VER=${VERSION_MAJOR} -DMIN_VER=${VERSION_MINOR}") set (CFLAGS_COMMON "-std=c99 -fPIC ${CFLAGS_LINUX} ${CFLAGS_WARN} ${CFLAGS_VER}") if ($ENV{DEBUG}) set (CFLAGS_COMMON "${CFLAGS_COMMON} ${CFLAGS_DEBUG}") else() set (CFLAGS_COMMON "${CFLAGS_COMMON} ${CFLAGS_OPT}") endif() include_directories(${PROJECT_BINARY_DIR}) pkg_check_modules(DEVMAPPER devmapper) pkg_check_modules(UUID uuid) pkg_check_modules(UUID-OSSP ossp-uuid) find_library(GCRYPT_LIB gcrypt) if (NOT DEVMAPPER_FOUND) message(FATAL_ERROR "Could not find the devmapper library") endif() if (NOT UUID_FOUND) if (NOT UUID-OSSP_FOUND) message(FATAL_ERROR "Could not find the uuid library") else() file( WRITE ${PROJECT_BINARY_DIR}/uuid_source.h "\n#define TCPLAY_USE_OSSP_UUID 1\n" ) endif() else() file( WRITE ${PROJECT_BINARY_DIR}/uuid_source.h "\n#define TCPLAY_USE_OSSP_UUID 0\n" ) endif() if (NOT GCRYPT_LIB) message(FATAL_ERROR "Could not find the gcrypt library") else() set (GCRYPT_LDFLAGS "-lgcrypt -lgpg-error") set (GCRYPT_CFLAGS "") endif() set (CMAKE_REQUIRED_LIBRARIES gpg-error) # gcrypt>=1.5.0 required check_library_exists(gcrypt gcry_kdf_derive "" HAVE_GCRYPT_PBKDF) set (CMAKE_REQUIRED_LIBRARIES "") if (HAVE_GCRYPT_PBKDF) set (SRCS_PBKDF pbkdf2-gcrypt.c) set (LDFLAGS_PBKDF "") set (CFLAGS_PBKDF "") set (PBKDF_BACKEND gcrypt) else() pkg_check_modules(OPENSSL openssl>=1.0.0a) if (NOT OPENSSL_FOUND) message(FATAL_ERROR "Could not find a gcrypt with gcry_kdf_derive() nor OpenSSL >= 1.0.0a") endif() set (SRCS_PBKDF pbkdf2-openssl.c) set (LDFLAGS_PBKDF ${OPENSSL_LDFLAGS}) set (CFLAGS_PBKDF ${OPENSSL_CFLAGS}) set (PBKDF_BACKEND openssl) endif() if (NOT (DEFINED LIB_SUFFIX)) message(STATUS "") message(STATUS "LIB_SUFFIX variable is not defined. It will be autodetected now.") message(STATUS "You can set it manually with -DLIB_SUFFIX= (e.g. 64).") if (CMAKE_SIZEOF_VOID_P EQUAL 8) message(STATUS "\nSetting LIB_SUFFIX=64\n") set (LIB_SUFFIX "64") else() message(STATUS "\nSetting LIB_SUFFIX=\n") set (LIB_SUFFIX "") endif() endif() if (NOT (DEFINED SBIN_DIR)) set (SBIN_DIR "sbin") endif() include_directories(${PROJECT_BINARY_DIR}) add_executable(tcplay-bin main.c ${SRCS_COMMON} ${SRCS_LINUX} ${SRCS_PBKDF}) set_target_properties(tcplay-bin PROPERTIES OUTPUT_NAME tcplay) set_target_properties(tcplay-bin PROPERTIES COMPILE_FLAGS "${CFLAGS_COMMON} ${DEVMAPPER_CFLAGS} ${UUID_CFLAGS} ${UUID-OSSP_CFLAGS} ${GCRYPT_CFLAGS}") target_link_libraries(tcplay-bin ${DEVMAPPER_LDFLAGS} ${UUID_LDFLAGS} ${UUID-OSSP_LDFLAGS} ${GCRYPT_LDFLAGS} ${LDFLAGS_PBKDF}) add_library(tcplay-so SHARED tcplay_api.c ${SRCS_COMMON} ${SRCS_LINUX} ${SRCS_PBKDF}) set_target_properties(tcplay-so PROPERTIES OUTPUT_NAME tcplay) set_target_properties(tcplay-so PROPERTIES SOVERSION ${VERSION_MAJOR}.${VERSION_MINOR}) set_target_properties(tcplay-so PROPERTIES COMPILE_FLAGS "${CFLAGS_COMMON} ${DEVMAPPER_CFLAGS} ${UUID_CFLAGS} ${UUID-OSSP_CFLAGS} ${GCRYPT_CFLAGS}") set_target_properties(tcplay-so PROPERTIES LINK_FLAGS "-Wl,--version-script=${PROJECT_SOURCE_DIR}/tcplay.map") # XXX: revist linking libraries against so. Seems to be more common practice nowadays target_link_libraries(tcplay-so ${DEVMAPPER_LDFLAGS} ${UUID_LDFLAGS} ${UUID-OSSP_LDFLAGS} ${GCRYPT_LDFLAGS} ${LDFLAGS_PBKDF}) add_library(tcplay-static STATIC tcplay_api.c ${SRCS_COMMON} ${SRCS_LINUX} ${SRCS_PBKDF}) set_target_properties(tcplay-static PROPERTIES OUTPUT_NAME tcplay) set_target_properties(tcplay-static PROPERTIES VERSION ${VERSION_MAJOR}.${VERSION_MINOR}) set_target_properties(tcplay-static PROPERTIES COMPILE_FLAGS "${CFLAGS_COMMON} ${DEVMAPPER_CFLAGS} ${UUID_CFLAGS} ${UUID-OSSP_CFLAGS} ${GCRYPT_CFLAGS}") target_link_libraries(tcplay-static ${DEVMAPPER_LDFLAGS} ${UUID_LDFLAGS} ${UUID-OSSP_LDFLAGS} ${GCRYPT_LDFLAGS} ${LDFLAGS_PBKDF}) # Generate pkg-config file tcplay.pc file(WRITE ${PROJECT_BINARY_DIR}/tcplay.pc "prefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${CMAKE_INSTALL_PREFIX} libdir=${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} includedir=${CMAKE_INSTALL_PREFIX}/include Name: libtcplay Description: tcplay as a library Version: ${VERSION_MAJOR}.${VERSION_MINOR} Requires.private: devmapper uuid Libs: -L\${libdir} -ltcplay Libs.private: -lgpg-error -lgcrypt Cflags: -I\${includedir} ") # Installation targets #install(TARGETS tcplay-bin tcplay-static tcplay-so # RUNTIME DESTINATION ${SBIN_DIR} COMPONENT bin # LIBRARY DESTINATION lib${LIB_SUFFIX} COMPONENT lib # ARCHIVE DESTINATION lib${LIB_SUFFIX} COMPONENT lib-dev #) #install(FILES ${PROJECT_BINARY_DIR}/tcplay.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig COMPONENT lib-dev) #install(FILES tcplay_api.h DESTINATION include COMPONENT lib-dev) #install(FILES tcplay.3 DESTINATION share/man/man3 COMPONENT lib-dev) #install(FILES tcplay.8 DESTINATION share/man/man8 COMPONENT bin) # Optional CPack magic set (CPACK_RPM_COMPONENT_INSTALL 1) set (CPACK_DEB_COMPONENT_INSTALL 1) set (CPACK_PACKAGE_NAME "tcplay") set (CPACK_PACKAGE_CONTACT "Alex Hornung ") set (CPACK_PACKAGE_VENDOR "Alex Hornung ") set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "tcplay is a free (BSD-licensed), pretty much fully featured (including multiple keyfiles, cipher cascades, hidden volumes, etc) and stable TrueCrypt implementation.") set (CPACK_PACAKGE_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}") set (CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}") set (CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}") set (CPACK_PACKAGE_VERSION_PATCH "0") set (CPACK_PACKAGE_LICENSE "2-clause BSD") include(CPack) cpack_add_component(bin DISPLAY_NAME bin REQUIRED INSTALL_TYPES all) cpack_add_component(lib DISPLAY_NAME lib REQUIRED INSTALL_TYPES all) cpack_add_component(lib-dev DISPLAY_NAME lib-dev REQUIRED INSTALL_TYPES all DEPENDS lib) zuluCrypt-6.2.0/external_libraries/tcplay/LICENSE000066400000000000000000000024601425361753700217360ustar00rootroot00000000000000Copyright (c) 2011 Alex Hornung . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. zuluCrypt-6.2.0/external_libraries/tcplay/Makefile.classic000066400000000000000000000071321425361753700240120ustar00rootroot00000000000000# either linux or dragonfly SYSTEM?=linux DESTDIR?= PREFIX?=/usr/local LIBSUFFIX?= LIBDIR?=$(PREFIX)/lib$(LIBSUFFIX) MANDIR?=$(PREFIX)/share/man SBINDIR?=$(PREFIX)/sbin INCLUDEDIR?=$(PREFIX)/include # either openssl or gcrypt PBKDF_BACKEND?=openssl # system compiler, normally gcc CC?=gcc INSTALL?=install RM?=rm -f LN?=ln # whether to enable debugging or not DEBUG?=no MAJ_VER=3 MIN_VER=3 # I've given up on -Werror for now; many Linux distros have warnings even in # their standard header files. WARNFLAGS= -Wsystem-headers -Wall -W -Wno-unused-parameter \ -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith \ -Wold-style-definition -Wreturn-type -Wwrite-strings \ -Wswitch -Wshadow -Wcast-align -Wunused-parameter -Wchar-subscripts \ -Winline -Wnested-externs VER_FLAGS= -DMAJ_VER=$(MAJ_VER) -DMIN_VER=$(MIN_VER) -D_FILE_OFFSET_BITS=64 SRCS= tcplay.c crc32.c safe_mem.c io.c hdr.c humanize.c SRCS+= crypto.c generic_xts.c OBJS= tcplay.o crc32.o safe_mem.o io.o hdr.o humanize.o OBJS+= crypto.o generic_xts.o COMMON_CFLAGS= $(WARNFLAGS) -fPIC $(VER_FLAGS) ifeq ($(DEBUG), yes) COMMON_CFLAGS+= -O0 -g -DDEBUG else COMMON_CFLAGS+= -O3 endif ifeq (${SYSTEM}, linux) COMMON_CFLAGS+= -D_GNU_SOURCE LIBS+= -lgcrypt -lgpg-error -ldevmapper -luuid SRCS+= crypto-gcrypt.c OBJS+= crypto-gcrypt.o ifeq (${PBKDF_BACKEND}, gcrypt) SRCS+= pbkdf2-gcrypt.c OBJS+= pbkdf2-gcrypt.o endif ifeq (${PBKDF_BACKEND}, openssl) SRCS+= pbkdf2-openssl.c OBJS+= pbkdf2-openssl.o LIBS+= -lcrypto endif endif ifeq (${SYSTEM}, dragonfly) LIBS+= -lcrypto -ldm -lprop SRCS+= crypto-dev.c OBJS+= crypto-dev.o SRCS+= pbkdf2-openssl.c OBJS+= pbkdf2-openssl.o endif OBJS_PROG= $(OBJS) main.o OBJS_LIB= $(OBJS) tcplay_api.o all: tcplay libtcplay.so libtcplay.a %.o: %.c $(CC) $(COMMON_CFLAGS) $(CFLAGS) -c -o $@ $< tcplay: $(OBJS_PROG) $(CC) $(COMMON_CFLAGS) $(CFLAGS) -o tcplay $(OBJS_PROG) $(LIBS) libtcplay.so.$(MAJ_VER).$(MIN_VER): $(OBJS_LIB) $(CC) -shared -Wl,-version-script=tcplay.map -Wl,-soname=libtcplay.so.$(MAJ_VER).$(MIN_VER) $(LDFLAGS) \ -o libtcplay.so.$(MAJ_VER).$(MIN_VER) $(OBJS_LIB) $(LIBS) libtcplay.so: libtcplay.so.$(MAJ_VER).$(MIN_VER) $(LN) -sf libtcplay.so.$(MAJ_VER).$(MIN_VER) libtcplay.so libtcplay.a: $(OBJS_LIB) $(AR) -rs libtcplay.a $(OBJS_LIB) install: install_program install_lib install_lib_static install_program: tcplay install_man8 $(INSTALL) -d "$(DESTDIR)$(SBINDIR)" $(INSTALL) tcplay "$(DESTDIR)$(SBINDIR)" install_lib: libtcplay.so.$(MAJ_VER).$(MIN_VER) libtcplay.so install_h install_man3 $(INSTALL) -d "$(DESTDIR)$(LIBDIR)" $(INSTALL) libtcplay.so.$(MAJ_VER).$(MIN_VER) "$(DESTDIR)$(LIBDIR)" $(LN) -sf libtcplay.so.$(MAJ_VER).$(MIN_VER) "$(DESTDIR)$(LIBDIR)/libtcplay.so" install_lib_static: libtcplay.a install_h install_man3 $(INSTALL) -d "$(DESTDIR)$(LIBDIR)" $(INSTALL) libtcplay.a "$(DESTDIR)$(LIBDIR)" install_h: tcplay_api.h $(INSTALL) -d "$(DESTDIR)$(INCLUDEDIR)" $(INSTALL) tcplay_api.h "$(DESTDIR)$(INCLUDEDIR)" install_man3: tcplay.3 $(INSTALL) -d "$(DESTDIR)$(MANDIR)/man3" $(INSTALL) tcplay.3 "$(DESTDIR)$(MANDIR)/man3" install_man8: tcplay.8 $(INSTALL) -d "$(DESTDIR)$(MANDIR)/man8" $(INSTALL) tcplay.8 "$(DESTDIR)$(MANDIR)/man8" clean_cmake_mess: $(RM) CMakeCache.txt $(RM) -r CMakeFiles $(RM) CPackConfig.cmake $(RM) CPackSourceConfig.cmake $(RM) Makefile $(RM) cmake_install.cmake $(RM) tcplay.pc clean: clean_cmake_mess $(RM) $(OBJS_PROG) $(RM) $(OBJS_LIB) $(RM) tcplay libtcplay.so* libtcplay.a tcplay.core ktrace.out .PHONY: install install_program install_lib install_lib_static install_man3 install_man8 install_h zuluCrypt-6.2.0/external_libraries/tcplay/README.md000066400000000000000000000133231425361753700222100ustar00rootroot00000000000000About ========== tcplay is a free (BSD-licensed), pretty much fully featured (including multiple keyfiles, cipher cascades, etc) and stable TrueCrypt implementation. This implementation supports mapping (opening) both system and normal TrueCrypt volumes, as well as opening hidden volumes and opening an outer volume while protecting a hidden volume. There is also support to create volumes, including hidden volumes, etc. Since version 1.1, there is also support for restoring from the backup header (if present), change passphrase, keyfile and PBKDF2 PRF function. Since tcplay uses dm-crypt (or dm_target_crypt on DragonFly) it makes full use of any available hardware encryption/decryption support once the volume has been mapped. It is based solely on the documentation available on the TrueCrypt website, many hours of trial and error and the output of the Linux' TrueCrypt client. As it turns out, most technical documents on TrueCrypt contain mistakes, hence the trial and error approach. VeraCrypt support ========== tcplay has support for creating, modifying and mapping VeraCrypt volumes. See the man page for more details. Implementation notes ========== DragonFly BSD uses the hybrid OpenSSL + cryptodev(9) approach that can be found in crypto-dev.c. OpenSSL is only used for the hash/pbkdf2. The encryption/decryption is performed via cryptodev(9) with enabled cryptosoft. On Linux gcrypt is used for the encryption and decryption. For the hash/pbkdf2 either gcrypt or OpenSSL can be used. gcrypt only supports pbkdf2 since its July 2011 release (1.5.0), while OpenSSL has had pbkdf2 since around December 2010, so its easier to find in most distros. The crypto options can be chosen with make/Makefile parameters. Building on Linux is as easy as doing make -f Makefile.classic SYSTEM=linux you can even skip the SYSTEM=linux, since that's the default. To choose the PBKDF backend, you can use either, make -f Makefile.classic PBKDF_BACKEND=openssl or make -f Makefile.classic PBKDF_BACKEND=gcrypt The interface to device mapper is libdevmapper on Linux and libdm on DragonFly. libdm is a BSD-licensed version of libdevmapper that I hacked together in a few hours. On Ubuntu, the following dev packages are needed to build tcplay: apt-get install build-essential libdevmapper-dev libgcrypt11-dev uuid-dev cmake ---------- New in version 1.0 is a cmake build system. tcplay can now be built using: mkdir objdir cd objdir cmake .. make NOTE: building inside the source directory is discouraged, so please do build inside an "objdir" directory. If you happen to do it anyway, you can clean up behind cmake using: make -f Makefile.classic clean_cmake_mess Before running `cmake`, make sure you have `pkg-config` installed; e.g. on a Debian or Ubuntu system you can install it using: apt-get install pkg-config This process will check for dependencies and automatically select whether to use OpenSSL or gcrypt as PBKDF backend. In addition, this process will also generate a .pc file (pkg-config) for the tcplay library. The classic single-file Makefile can still be used for building, however, using make -f Makefile.classic Or, if you only want the command line tool: make -f Makefile.classic tcplay Library ========== In addition to providing a command line tool, tcplay is also available as a library. See the `tcplay.3` man page for more details on how to use the API. TODO: link examples Documentation ========== Please refer to the man pages bundled with tcplay. Download for packaging ========== Latest release can be found as a (source) tarball at: https://github.com/bwalex/tc-play/archive/v3.3.tar.gz Bugs ========== Please report all bugs on the github issue tracker. If appropriate, please attach a small test volume which you think tcplay isn't handling correctly. The reduce_test_vol.sh script in test/ can significantly reduce the size of a volume when compressed by stripping out all the unnecessary data, leaving only the headers. After that, just bzip2 it and it should be fairly tiny. What would be even better is if you could write a small test case to reproduce the issue. The README in the test/ directory has information on how to write tests for tcplay. OS Support ========== tcplay is now available for both DragonFly BSD and Linux. It is a core part of the DragonFly BSD operating system and is available in a number of linux distros. Licensing ========== The project is under a two-clause BSD license. I would consider dual-licensing it if required. Drop me an email to discuss the options. Development ========== tcplay is pretty much stable, but if you find a bug, please report it. If anyone wants to add new features or port it to another OS, I'll gladly merge your changes into this repository so that there is a single point of contact. I've noticed that sometimes bugs are only reported downstream (e.g. in the distro's bugtracker). Please make sure those bugs are also reported upstream on github, otherwise odds are they will never reach me. Bugs in the TrueCrypt documentation ========== The TrueCrypt documentation is pretty bad and does not really represent the actual on-disk format nor the encryption/decryption process. Some notable differences between actual implementation and documentation: - PBKDF using RIPEMD160 only uses 2000 iterations if the volume isn't a system volume. - The keyfile pool is not XOR'ed with the passphrase but modulo-256 summed. - Every field *except* the minimum version field of the volume header are in big endian. - Some volume header fields (creation time of volume and header) are missing in the documentation. - All two-way cipher cascades are the wrong way round in the documentation, but all three-way cipher cascades are correct. zuluCrypt-6.2.0/external_libraries/tcplay/crc32.c000066400000000000000000000125071425361753700220140ustar00rootroot00000000000000/*- * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or * code or tables extracted from it, as desired without restriction. * * First, the polynomial itself and its table of feedback terms. The * polynomial is * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 * * Note that we take it "backwards" and put the highest-order term in * the lowest-order bit. The X^32 term is "implied"; the LSB is the * X^31 term, etc. The X^0 term (usually shown as "+1") results in * the MSB being 1 * * Note that the usual hardware shift register implementation, which * is what we're using (we're merely optimizing it by doing eight-bit * chunks at a time) shifts bits into the lowest-order term. In our * implementation, that means shifting towards the right. Why do we * do it this way? Because the calculated CRC must be transmitted in * order from highest-order term to lowest-order term. UARTs transmit * characters in order from LSB to MSB. By storing the CRC this way * we hand it to the UART in the order low-byte to high-byte; the UART * sends each low-bit to hight-bit; and the result is transmission bit * by bit from highest- to lowest-order term without requiring any bit * shuffling on our part. Reception works similarly * * The feedback terms table consists of 256, 32-bit entries. Notes * * The table can be generated at runtime if desired; code to do so * is shown later. It might not be obvious, but the feedback * terms simply represent the results of eight shift/xor opera * tions for all combinations of data and CRC register values * * The values must be right-shifted by eight bits by the "updcrc * logic; the shift must be unsigned (bring in zeroes). On some * hardware you could probably optimize the shift in assembler by * using byte-swap instructions * polynomial $edb88320 */ #include #include #include "crc32.h" uint32_t crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; uint32_t crc32(const void *buf, size_t size) { const uint8_t *p; uint32_t crc; p = buf; crc = ~0U; while (size--) crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); return crc ^ ~0U; } uint32_t crc32_intermediate(uint32_t crc, uint8_t d) { return crc32_tab[(crc ^ d) & 0xFF] ^ (crc >> 8); } zuluCrypt-6.2.0/external_libraries/tcplay/crc32.h000066400000000000000000000001441425361753700220130ustar00rootroot00000000000000uint32_t crc32(const void *buf, size_t size); uint32_t crc32_intermediate(uint32_t crc, uint8_t d); zuluCrypt-6.2.0/external_libraries/tcplay/crypto-dev.c000066400000000000000000000102161425361753700231670ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "tcplay.h" static int getallowsoft(void) { int old; size_t olen; olen = sizeof(old); if (sysctlbyname("kern.cryptodevallowsoft", &old, &olen, NULL, 0) < 0) { perror("accessing sysctl kern.cryptodevallowsoft failed"); } return old; } static void setallowsoft(int new) { int old; size_t olen, nlen; olen = nlen = sizeof(new); if (sysctlbyname("kern.cryptodevallowsoft", &old, &olen, &new, nlen) < 0) { perror("accessing sysctl kern.cryptodevallowsoft failed"); } } static int get_cryptodev_cipher_id(struct tc_crypto_algo *cipher) { if (strcmp(cipher->name, "AES-128-XTS") == 0) return CRYPTO_AES_XTS; else if (strcmp(cipher->name, "AES-256-XTS") == 0) return CRYPTO_AES_XTS; else if (strcmp(cipher->name, "TWOFISH-128-XTS") == 0) return CRYPTO_TWOFISH_XTS; else if (strcmp(cipher->name, "TWOFISH-256-XTS") == 0) return CRYPTO_TWOFISH_XTS; else if (strcmp(cipher->name, "SERPENT-128-XTS") == 0) return CRYPTO_SERPENT_XTS; else if (strcmp(cipher->name, "SERPENT-256-XTS") == 0) return CRYPTO_SERPENT_XTS; else return -1; } int syscrypt(struct tc_crypto_algo *cipher, unsigned char *key, size_t klen, unsigned char *iv, unsigned char *in, unsigned char *out, size_t len, int do_encrypt) { struct session_op session; struct crypt_op cryp; int cipher_id; int cryptodev_fd = -1, fd = -1; cipher_id = get_cryptodev_cipher_id(cipher); if (cipher_id < 0) { tc_log(1, "Cipher %s not found\n", cipher->name); return ENOENT; } if ((cryptodev_fd = open("/dev/crypto", O_RDWR, 0)) < 0) { perror("Could not open /dev/crypto"); goto err; } if (ioctl(cryptodev_fd, CRIOGET, &fd) == -1) { perror("CRIOGET failed"); goto err; } memset(&session, 0, sizeof(session)); session.cipher = cipher_id; session.key = (caddr_t) key; session.keylen = klen; if (ioctl(fd, CIOCGSESSION, &session) == -1) { perror("CIOCGSESSION failed"); goto err; } memset(&cryp, 0, sizeof(cryp)); cryp.ses = session.ses; cryp.op = do_encrypt ? COP_ENCRYPT : COP_DECRYPT; cryp.flags = 0; cryp.len = len; cryp.src = (caddr_t) in; cryp.dst = (caddr_t) out; cryp.iv = (caddr_t) iv; cryp.mac = 0; if (ioctl(fd, CIOCCRYPT, &cryp) == -1) { perror("CIOCCRYPT failed"); goto err; } if (ioctl(fd, CIOCFSESSION, &session.ses) == -1) { perror("CIOCFSESSION failed"); goto err; } close(fd); close(cryptodev_fd); return (0); err: if (fd != -1) close(fd); if (cryptodev_fd != -1) close(cryptodev_fd); return (-1); } int tc_crypto_init(void) { int allowed; allowed = getallowsoft(); if (allowed == 0) setallowsoft(1); return 0; } zuluCrypt-6.2.0/external_libraries/tcplay/crypto-gcrypt.c000066400000000000000000000125621425361753700237270ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ //#include #include #include #include /* * Yey for gcrypt and its broken includes... * see http://lists.gnupg.org/pipermail/gcrypt-devel/2011-July/001830.html * and http://seclists.org/wireshark/2011/Jul/208 * for more details... */ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include #pragma GCC diagnostic warning "-Wdeprecated-declarations" #include "generic_xts.h" #include "tcplay.h" static int gcrypt_encrypt(void *ctx, size_t blk_len, const uint8_t *src, uint8_t *dst) { gcry_cipher_hd_t cipher_hd = (gcry_cipher_hd_t)ctx; gcry_error_t gcry_err; gcry_err = gcry_cipher_encrypt( cipher_hd, dst, blk_len, /* gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES256) */ src, blk_len); return (gcry_err != 0); } static int gcrypt_decrypt(void *ctx, size_t blk_len, const uint8_t *src, uint8_t *dst) { gcry_cipher_hd_t cipher_hd = (gcry_cipher_hd_t)ctx; gcry_error_t gcry_err; gcry_err = gcry_cipher_decrypt( cipher_hd, dst, blk_len /* gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES256) */, src, blk_len); return (gcry_err != 0); } static int gcrypt_set_key(void **ctx, void *arg1, void *arg2 __unused, const u_int8_t *key, int keybits __unused) { gcry_cipher_hd_t *cipher_hd = (gcry_cipher_hd_t *)ctx; int cipher = *((int *)arg1); gcry_error_t gcry_err; gcry_err = gcry_cipher_open( cipher_hd, cipher, GCRY_CIPHER_MODE_ECB, 0); if (gcry_err) return -1; gcry_err = gcry_cipher_setkey( *cipher_hd, key, gcry_cipher_get_algo_keylen(cipher)); if (gcry_err) { gcry_cipher_close(*cipher_hd); *ctx = NULL; return -1; } return 0; } static int gcrypt_zero_key(void **ctx) { gcry_cipher_hd_t *cipher_hd = (gcry_cipher_hd_t *)ctx; if (*cipher_hd == NULL) return 0; gcry_cipher_close(*cipher_hd); return 0; } static int get_gcrypt_cipher_id(struct tc_crypto_algo *cipher) { if (strcmp(cipher->name, "AES-128-XTS") == 0) return GCRY_CIPHER_AES128; else if (strcmp(cipher->name, "AES-256-XTS") == 0) return GCRY_CIPHER_AES256; else if (strcmp(cipher->name, "TWOFISH-128-XTS") == 0) return GCRY_CIPHER_TWOFISH128; else if (strcmp(cipher->name, "TWOFISH-256-XTS") == 0) return GCRY_CIPHER_TWOFISH; /* XXX: really 256? */ else if (strcmp(cipher->name, "SERPENT-128-XTS") == 0) return GCRY_CIPHER_SERPENT128; else if (strcmp(cipher->name, "SERPENT-256-XTS") == 0) return GCRY_CIPHER_SERPENT256; else return -1; } int syscrypt(struct tc_crypto_algo *cipher, unsigned char *key, size_t klen, unsigned char *iv, unsigned char *in, unsigned char *out, size_t len, int do_encrypt) { struct xts_ctx *ctx; int cipher_id; int err; cipher_id = get_gcrypt_cipher_id(cipher); if (cipher_id < 0) { tc_log(1, "Cipher %s not found\n", cipher->name); return ENOENT; } if ((ctx = (struct xts_ctx *)alloc_safe_mem(sizeof(struct xts_ctx))) == NULL) { tc_log(1, "Could not allocate safe xts_xts memory\n"); return ENOMEM; } err = xts_init(ctx, &cipher_id, NULL, gcrypt_set_key, gcrypt_zero_key, gcrypt_encrypt, gcrypt_decrypt, gcry_cipher_get_algo_blklen(cipher_id), key, klen); if (err) { tc_log(1, "Error initializing generic XTS\n"); return EINVAL; } /* When chaining ciphers, we reuse the input buffer as the output buffer */ if (out != in) memcpy(out, in, len); if (do_encrypt) err = xts_encrypt(ctx, out, len, iv); else err = xts_decrypt(ctx, out, len, iv); if (err) { tc_log(1, "Error encrypting/decrypting\n"); xts_uninit(ctx); return EINVAL; } xts_uninit(ctx); free_safe_mem(ctx); return 0; } int tc_crypto_init(void) { if (!gcry_check_version(GCRYPT_VERSION)) { tc_log(1, "libgcrypt version mismatch\n"); return EINVAL; } if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) return 0; gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN); gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0); gcry_control(GCRYCTL_RESUME_SECMEM_WARN); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); return 0; } zuluCrypt-6.2.0/external_libraries/tcplay/crypto.c000066400000000000000000000153461425361753700224240ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "crc32.h" #include "tcplay.h" int tc_cipher_chain_populate_keys(struct tc_cipher_chain *cipher_chain, unsigned char *key) { int total_key_bytes, used_key_bytes; struct tc_cipher_chain *dummy_chain; /* * We need to determine the total key bytes as the key locations * depend on it. */ total_key_bytes = tc_cipher_chain_klen(cipher_chain); /* * Now we need to get prepare the keys, as the keys are in * forward order with respect to the cipher cascade, but * the actual decryption is in reverse cipher cascade order. */ used_key_bytes = 0; for (dummy_chain = cipher_chain; dummy_chain != NULL; dummy_chain = dummy_chain->next) { dummy_chain->key = alloc_safe_mem(dummy_chain->cipher->klen); if (dummy_chain->key == NULL) { tc_log(1, "tc_decrypt: Could not allocate key " "memory\n"); return ENOMEM; } /* XXX: here we assume XTS operation! */ memcpy(dummy_chain->key, key + used_key_bytes/2, dummy_chain->cipher->klen/2); memcpy(dummy_chain->key + dummy_chain->cipher->klen/2, key + (total_key_bytes/2) + used_key_bytes/2, dummy_chain->cipher->klen/2); /* Remember how many key bytes we've seen */ used_key_bytes += dummy_chain->cipher->klen; } return 0; } int tc_cipher_chain_free_keys(struct tc_cipher_chain *cipher_chain) { for (; cipher_chain != NULL; cipher_chain = cipher_chain->next) { if (cipher_chain->key != NULL) { free_safe_mem(cipher_chain->key); cipher_chain->key = NULL; } } return 0; } int tc_encrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key, unsigned char *iv, unsigned char *in, int in_len, unsigned char *out) { struct tc_cipher_chain *chain_start; int err; chain_start = cipher_chain; if ((err = tc_cipher_chain_populate_keys(cipher_chain, key))) return err; #ifdef DEBUG printf("tc_encrypt: starting chain\n"); #endif /* * Now process the actual decryption, in forward cascade order. */ for (; cipher_chain != NULL; cipher_chain = cipher_chain->next) { #ifdef DEBUG printf("tc_encrypt: Currently using cipher %s\n", cipher_chain->cipher->name); #endif err = syscrypt(cipher_chain->cipher, cipher_chain->key, cipher_chain->cipher->klen, iv, in, out, in_len, 1); /* Deallocate this key, since we won't need it anymore */ free_safe_mem(cipher_chain->key); cipher_chain->key = NULL; if (err != 0) { tc_cipher_chain_free_keys(chain_start); return err; } /* Set next input buffer as current output buffer */ in = out; } tc_cipher_chain_free_keys(chain_start); return 0; } int tc_decrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key, unsigned char *iv, unsigned char *in, int in_len, unsigned char *out) { struct tc_cipher_chain *chain_start; int err; chain_start = cipher_chain; if ((err = tc_cipher_chain_populate_keys(cipher_chain, key))) return err; #ifdef DEBUG printf("tc_decrypt: starting chain!\n"); #endif /* * Now process the actual decryption, in reverse cascade order; so * first find the last element in the chain. */ for (; cipher_chain->next != NULL; cipher_chain = cipher_chain->next) ; for (; cipher_chain != NULL; cipher_chain = cipher_chain->prev) { #ifdef DEBUG printf("tc_decrypt: Currently using cipher %s\n", cipher_chain->cipher->name); #endif err = syscrypt(cipher_chain->cipher, cipher_chain->key, cipher_chain->cipher->klen, iv, in, out, in_len, 0); /* Deallocate this key, since we won't need it anymore */ free_safe_mem(cipher_chain->key); cipher_chain->key = NULL; if (err != 0) { tc_cipher_chain_free_keys(chain_start); return err; } /* Set next input buffer as current output buffer */ in = out; } tc_cipher_chain_free_keys(chain_start); return 0; } int apply_keyfiles(unsigned char *pass, size_t pass_memsz, const char *keyfiles[], int nkeyfiles) { int pl, k; unsigned char *kpool; unsigned char *kdata; int kpool_idx; size_t i, kdata_sz; uint32_t crc; if (pass_memsz < MAX_PASSSZ) { tc_log(1, "Not enough memory for password manipulation\n"); return ENOMEM; } pl = strlen((char *)pass); memset(pass+pl, 0, MAX_PASSSZ-pl); if ((kpool = alloc_safe_mem(KPOOL_SZ)) == NULL) { tc_log(1, "Error allocating memory for keyfile pool\n"); return ENOMEM; } memset(kpool, 0, KPOOL_SZ); for (k = 0; k < nkeyfiles; k++) { #ifdef DEBUG printf("Loading keyfile %s into kpool\n", keyfiles[k]); #endif kpool_idx = 0; crc = ~0U; kdata_sz = MAX_KFILE_SZ; if ((kdata = read_to_safe_mem(keyfiles[k], 0, &kdata_sz)) == NULL) { tc_log(1, "Error reading keyfile %s content\n", keyfiles[k]); free_safe_mem(kpool); return EIO; } for (i = 0; i < kdata_sz; i++) { crc = crc32_intermediate(crc, kdata[i]); kpool[kpool_idx++] += (unsigned char)(crc >> 24); kpool[kpool_idx++] += (unsigned char)(crc >> 16); kpool[kpool_idx++] += (unsigned char)(crc >> 8); kpool[kpool_idx++] += (unsigned char)(crc); /* Wrap around */ if (kpool_idx == KPOOL_SZ) kpool_idx = 0; } free_safe_mem(kdata); } #ifdef DEBUG printf("Applying kpool to passphrase\n"); #endif /* Apply keyfile pool to passphrase */ for (i = 0; i < KPOOL_SZ; i++) pass[i] += kpool[i]; free_safe_mem(kpool); return 0; } zuluCrypt-6.2.0/external_libraries/tcplay/generic_xts.c000066400000000000000000000072601425361753700234120ustar00rootroot00000000000000/* * Copyright (C) 2008, Damien Miller * Copyright (C) 2011, Alex Hornung * * Permission to use, copy, and modify this software with or without fee * is hereby granted, provided that this entire notice is included in * all copies of any software which is or includes a copy or * modification of this software. * You may use this code under the GNU public license if you so wish. Please * contribute changes back to the authors under this freer than GPL license * so that we may further the use of strong encryption without limitations to * all. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR * PURPOSE. */ #include #include #include #include #include #include "tcplay.h" #include "generic_xts.h" static int xts_reinit(struct xts_ctx *ctx, u_int64_t blocknum) { u_int i; /* * Prepare tweak as E_k2(IV). IV is specified as LE representation * of a 64-bit block number which we allow to be passed in directly. */ for (i = 0; i < XTS_IVSIZE; i++) { ctx->tweak[i] = blocknum & 0xff; blocknum >>= 8; } /* Last 64 bits of IV are always zero */ bzero(ctx->tweak + XTS_IVSIZE, XTS_IVSIZE); return ctx->encrypt_fn(ctx->ctx2, ctx->blk_sz, ctx->tweak, ctx->tweak); } static int xts_crypt(struct xts_ctx *ctx, u_int8_t *data, u_int do_encrypt) { u_int8_t block[XTS_MAX_BLOCKSIZE]; u_int i, carry_in, carry_out; int err; for (i = 0; i < ctx->blk_sz; i++) block[i] = data[i] ^ ctx->tweak[i]; if (do_encrypt) err = ctx->encrypt_fn(ctx->ctx1, ctx->blk_sz, block, data); else err = ctx->decrypt_fn(ctx->ctx1, ctx->blk_sz, block, data); if (err) goto out; for (i = 0; i < ctx->blk_sz; i++) data[i] ^= ctx->tweak[i]; /* Exponentiate tweak */ carry_in = 0; for (i = 0; i < ctx->blk_sz; i++) { carry_out = ctx->tweak[i] & 0x80; ctx->tweak[i] = (ctx->tweak[i] << 1) | (carry_in ? 1 : 0); carry_in = carry_out; } if (carry_in) ctx->tweak[0] ^= XTS_ALPHA; out: bzero(block, sizeof(block)); return err; } int xts_init(struct xts_ctx *ctx, void *arg1, void *arg2, set_key_fn _set_key_fn, zero_key_fn _zero_key_fn, encrypt_decrypt_fn _encrypt_fn, encrypt_decrypt_fn _decrypt_fn, u_int blk_sz, u_int8_t *key, int len) { int err; if (len != 32 && len != 64) return -1; ctx->blk_sz = blk_sz; ctx->encrypt_fn = _encrypt_fn; ctx->decrypt_fn = _decrypt_fn; ctx->set_key_fn = _set_key_fn; ctx->zero_key_fn = _zero_key_fn; err = ctx->set_key_fn(&ctx->ctx1, arg1, arg2, key, len * 4); if (err) return -1; err = ctx->set_key_fn(&ctx->ctx2, arg1, arg2, key + (len / 2), len * 4); if (err) { ctx->zero_key_fn(&ctx->ctx1); return -1; } return 0; } int xts_encrypt(struct xts_ctx *ctx, u_int8_t *data, size_t len, uint8_t *iv) { uint64_t sector = *((uint64_t *)iv); int err; if ((len % ctx->blk_sz) != 0) return -1; err = xts_reinit(ctx, sector); if (err) return err; while (len > 0) { err = xts_crypt(ctx, data, 1); if (err) return -1; data += ctx->blk_sz; len -= ctx->blk_sz; } return err; } int xts_decrypt(struct xts_ctx *ctx, u_int8_t *data, size_t len, uint8_t *iv) { uint64_t sector = *((uint64_t *)iv); int err; if ((len % ctx->blk_sz) != 0) return -1; err = xts_reinit(ctx, sector); if (err) return err; while (len > 0) { err = xts_crypt(ctx, data, 0); if (err) return -1; data += ctx->blk_sz; len -= ctx->blk_sz; } return err; } int xts_uninit(struct xts_ctx *ctx) { ctx->zero_key_fn(&ctx->ctx1); ctx->zero_key_fn(&ctx->ctx2); return 0; } zuluCrypt-6.2.0/external_libraries/tcplay/generic_xts.h000066400000000000000000000034041425361753700234130ustar00rootroot00000000000000/* * Copyright (C) 2008, Damien Miller * Copyright (C) 2011, Alex Hornung * * Permission to use, copy, and modify this software with or without fee * is hereby granted, provided that this entire notice is included in * all copies of any software which is or includes a copy or * modification of this software. * You may use this code under the GNU public license if you so wish. Please * contribute changes back to the authors under this freer than GPL license * so that we may further the use of strong encryption without limitations to * all. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR * PURPOSE. */ #include #define XTS_MAX_BLOCKSIZE 16 #define XTS_IVSIZE 8 #define XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */ typedef int (*encrypt_decrypt_fn)(void *, size_t, const uint8_t *, uint8_t *); typedef int (*set_key_fn)(void **, void *, void *, const uint8_t *, int); typedef int (*zero_key_fn)(void **); struct xts_ctx { encrypt_decrypt_fn encrypt_fn; encrypt_decrypt_fn decrypt_fn; set_key_fn set_key_fn; zero_key_fn zero_key_fn; void *ctx1; void *ctx2; uint8_t tweak[XTS_MAX_BLOCKSIZE]; uint32_t blk_sz; }; int xts_init(struct xts_ctx *ctxp, void *arg1, void *arg2, set_key_fn set_key_fn, zero_key_fn zero_key_fn, encrypt_decrypt_fn encrypt_fn, encrypt_decrypt_fn decrypt_fn, uint32_t blk_sz, uint8_t *key, int len); int xts_encrypt(struct xts_ctx *ctx, uint8_t *data, size_t len, uint8_t *iv); int xts_decrypt(struct xts_ctx *ctx, uint8_t *data, size_t len, uint8_t *iv); int xts_uninit(struct xts_ctx *ctxp); zuluCrypt-6.2.0/external_libraries/tcplay/hdr.c000066400000000000000000000256511425361753700216610ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #if defined(__DragonFly__) #include #elif defined(__linux__) #include #endif #include #include #include #include #include #include "crc32.h" #include "tcplay.h" /* Endianess macros */ #define BE_TO_HOST(n, v) v = be ## n ## toh(v) #define LE_TO_HOST(n, v) v = le ## n ## toh(v) #define HOST_TO_BE(n, v) v = htobe ## n (v) #define HOST_TO_LE(n, v) v = htole ## n (v) struct sig_hdr_cfg { const char *sig; uint16_t min_ver; }; struct sig_hdr_cfg sig_hdr_cfgs[] = { { TC_SIG, 0x0007 }, { VC_SIG, 0x0b01 }, { NULL, 0x0000 } }; static const struct sig_hdr_cfg *hdr_cfg_from_sig(const char *sig) { const struct sig_hdr_cfg *cfg; for (cfg = &sig_hdr_cfgs[0]; cfg->sig != NULL; cfg++) { if (strcmp(cfg->sig, sig) == 0) return cfg; } return NULL; } struct tchdr_dec * decrypt_hdr(struct tchdr_enc *ehdr, struct tc_cipher_chain *cipher_chain, unsigned char *key) { struct tchdr_dec *dhdr; unsigned char iv[128]; int error; if ((dhdr = alloc_safe_mem(sizeof(struct tchdr_dec))) == NULL) { tc_log(1, "Error allocating safe tchdr_dec memory\n"); return NULL; } memset(iv, 0, sizeof(iv)); error = tc_decrypt(cipher_chain, key, iv, ehdr->enc, sizeof(struct tchdr_dec), (unsigned char *)dhdr); if (error) { tc_log(1, "Header decryption failed\n"); free_safe_mem(dhdr); return NULL; } BE_TO_HOST(16, dhdr->tc_ver); LE_TO_HOST(16, dhdr->tc_min_ver); BE_TO_HOST(32, dhdr->crc_keys); BE_TO_HOST(64, dhdr->vol_ctime); BE_TO_HOST(64, dhdr->hdr_ctime); BE_TO_HOST(64, dhdr->sz_hidvol); BE_TO_HOST(64, dhdr->sz_vol); BE_TO_HOST(64, dhdr->off_mk_scope); BE_TO_HOST(64, dhdr->sz_mk_scope); BE_TO_HOST(32, dhdr->flags); BE_TO_HOST(32, dhdr->sec_sz); BE_TO_HOST(32, dhdr->crc_dhdr); return dhdr; } int verify_hdr(struct tchdr_dec *hdr, struct pbkdf_prf_algo *prf_algo) { uint32_t crc; if (memcmp(hdr->tc_str, prf_algo->sig, sizeof(hdr->tc_str)) != 0) { #ifdef DEBUG fprintf(stderr, "Signature mismatch\n"); #endif return 0; } crc = crc32((void *)&hdr->keys, 256); if (crc != hdr->crc_keys) { #ifdef DEBUG fprintf(stderr, "CRC32 mismatch (crc_keys)\n"); #endif return 0; } switch(hdr->tc_ver) { case 1: case 2: /* Unsupported header version */ tc_log(1, "Header version %d unsupported\n", hdr->tc_ver); return 0; case 3: case 4: hdr->sec_sz = 512; break; } return 1; } struct tchdr_enc * create_hdr(int iteration_count, unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo, struct tc_cipher_chain *cipher_chain, size_t sec_sz, disksz_t total_blocks __unused, off_t offset, disksz_t blocks, int hidden, int weak, struct tchdr_enc **backup_hdr) { struct tchdr_enc *ehdr, *ehdr_backup; struct tchdr_dec *dhdr; unsigned char *key, *key_backup; unsigned char iv[128]; const struct sig_hdr_cfg *hdr_cfg; int error; key = key_backup = NULL; dhdr = NULL; ehdr = ehdr_backup = NULL; if (backup_hdr != NULL) *backup_hdr = NULL; if ((dhdr = (struct tchdr_dec *)alloc_safe_mem(sizeof(*dhdr))) == NULL) { tc_log(1, "could not allocate safe dhdr memory\n"); goto error; } if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) { tc_log(1, "could not allocate safe ehdr memory\n"); goto error; } if ((ehdr_backup = (struct tchdr_enc *)alloc_safe_mem (sizeof(*ehdr_backup))) == NULL) { tc_log(1, "could not allocate safe ehdr_backup memory\n"); goto error; } if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) { tc_log(1, "could not allocate safe key memory\n"); goto error; } if ((key_backup = alloc_safe_mem(MAX_KEYSZ)) == NULL) { tc_log(1, "could not allocate safe backup key memory\n"); goto error; } if ((error = get_random(ehdr->salt, sizeof(ehdr->salt), weak)) != 0) { tc_log(1, "could not get salt\n"); goto error; } if ((error = get_random(ehdr_backup->salt, sizeof(ehdr_backup->salt), weak)) != 0) { tc_log(1, "could not get salt for backup header\n"); goto error; } error = pbkdf2(prf_algo, (char *)pass, passlen, ehdr->salt, sizeof(ehdr->salt), MAX_KEYSZ, iteration_count, key); if (error) { tc_log(1, "could not derive key\n"); goto error; } error = pbkdf2(prf_algo, (char *)pass, passlen, ehdr_backup->salt, sizeof(ehdr_backup->salt), MAX_KEYSZ, iteration_count, key_backup); if (error) { tc_log(1, "could not derive backup key\n"); goto error; } memset(dhdr, 0, sizeof(*dhdr)); if ((error = get_random(dhdr->keys, sizeof(dhdr->keys), weak)) != 0) { tc_log(1, "could not get key random bits\n"); goto error; } if ((hdr_cfg = hdr_cfg_from_sig(prf_algo->sig)) == NULL) { tc_log(1, "could not find internal header configuration\n"); goto error; } memcpy(dhdr->tc_str, prf_algo->sig, 4); dhdr->tc_ver = 5; dhdr->tc_min_ver = hdr_cfg->min_ver; dhdr->crc_keys = crc32((void *)&dhdr->keys, 256); dhdr->sz_vol = blocks * sec_sz; if (hidden) dhdr->sz_hidvol = dhdr->sz_vol; dhdr->off_mk_scope = offset * sec_sz; dhdr->sz_mk_scope = blocks * sec_sz; dhdr->sec_sz = sec_sz; dhdr->flags = 0; HOST_TO_BE(16, dhdr->tc_ver); HOST_TO_LE(16, dhdr->tc_min_ver); HOST_TO_BE(32, dhdr->crc_keys); HOST_TO_BE(64, dhdr->sz_vol); HOST_TO_BE(64, dhdr->sz_hidvol); HOST_TO_BE(64, dhdr->off_mk_scope); HOST_TO_BE(64, dhdr->sz_mk_scope); HOST_TO_BE(32, dhdr->sec_sz); HOST_TO_BE(32, dhdr->flags); dhdr->crc_dhdr = crc32((void *)dhdr, 188); HOST_TO_BE(32, dhdr->crc_dhdr); memset(iv, 0, sizeof(iv)); error = tc_encrypt(cipher_chain, key, iv, (unsigned char *)dhdr, sizeof(struct tchdr_dec), ehdr->enc); if (error) { tc_log(1, "Header encryption failed\n"); goto error; } memset(iv, 0, sizeof(iv)); error = tc_encrypt(cipher_chain, key_backup, iv, (unsigned char *)dhdr, sizeof(struct tchdr_dec), ehdr_backup->enc); if (error) { tc_log(1, "Backup header encryption failed\n"); goto error; } free_safe_mem(key); free_safe_mem(key_backup); free_safe_mem(dhdr); if (backup_hdr != NULL) *backup_hdr = ehdr_backup; else free_safe_mem(ehdr_backup); return ehdr; /* NOT REACHED */ error: if (key) free_safe_mem(key); if (key_backup) free_safe_mem(key_backup); if (dhdr) free_safe_mem(dhdr); if (ehdr) free_safe_mem(ehdr); if (ehdr_backup) free_safe_mem(ehdr_backup); return NULL; } struct tchdr_enc *copy_reencrypt_hdr(int iteration_count, unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo, int weak, struct tcplay_info *info, struct tchdr_enc **backup_hdr) { struct tchdr_enc *ehdr, *ehdr_backup; unsigned char *key, *key_backup; unsigned char iv[128]; const struct sig_hdr_cfg *hdr_cfg; int error; key = key_backup = NULL; ehdr = ehdr_backup = NULL; /* By default stick to current PRF algo */ if (prf_algo == NULL) prf_algo = info->pbkdf_prf; if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) { tc_log(1, "could not allocate safe ehdr memory\n"); goto error; } if ((ehdr_backup = (struct tchdr_enc *)alloc_safe_mem (sizeof(*ehdr_backup))) == NULL) { tc_log(1, "could not allocate safe ehdr_backup memory\n"); goto error; } if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) { tc_log(1, "could not allocate safe key memory\n"); goto error; } if ((key_backup = alloc_safe_mem(MAX_KEYSZ)) == NULL) { tc_log(1, "could not allocate safe backup key memory\n"); goto error; } if ((error = get_random(ehdr->salt, sizeof(ehdr->salt), weak)) != 0) { tc_log(1, "could not get salt\n"); goto error; } if ((error = get_random(ehdr_backup->salt, sizeof(ehdr_backup->salt), weak)) != 0) { tc_log(1, "could not get salt for backup header\n"); goto error; } error = pbkdf2(prf_algo, (char *)pass, passlen, ehdr->salt, sizeof(ehdr->salt), MAX_KEYSZ, iteration_count, key); if (error) { tc_log(1, "could not derive key\n"); goto error; } error = pbkdf2(prf_algo, (char *)pass, passlen, ehdr_backup->salt, sizeof(ehdr_backup->salt), MAX_KEYSZ, iteration_count, key_backup); if (error) { tc_log(1, "could not derive backup key\n"); goto error; } if ((hdr_cfg = hdr_cfg_from_sig(prf_algo->sig)) == NULL) { tc_log(1, "could not find internal header configuration\n"); goto error; } /* Update signature and min_ver depending on selected PBKDF2 PRF algo */ memcpy(info->hdr->tc_str, prf_algo->sig, 4); info->hdr->tc_min_ver = hdr_cfg->min_ver; HOST_TO_BE(16, info->hdr->tc_ver); HOST_TO_LE(16, info->hdr->tc_min_ver); HOST_TO_BE(32, info->hdr->crc_keys); HOST_TO_BE(64, info->hdr->vol_ctime); HOST_TO_BE(64, info->hdr->hdr_ctime); HOST_TO_BE(64, info->hdr->sz_vol); HOST_TO_BE(64, info->hdr->sz_hidvol); HOST_TO_BE(64, info->hdr->off_mk_scope); HOST_TO_BE(64, info->hdr->sz_mk_scope); HOST_TO_BE(32, info->hdr->sec_sz); HOST_TO_BE(32, info->hdr->flags); HOST_TO_BE(32, info->hdr->crc_dhdr); memset(iv, 0, sizeof(iv)); error = tc_encrypt(info->cipher_chain, key, iv, (unsigned char *)info->hdr, sizeof(struct tchdr_dec), ehdr->enc); if (error) { tc_log(1, "Header encryption failed\n"); goto error; } memset(iv, 0, sizeof(iv)); error = tc_encrypt(info->cipher_chain, key_backup, iv, (unsigned char *)info->hdr, sizeof(struct tchdr_dec), ehdr_backup->enc); if (error) { tc_log(1, "Backup header encryption failed\n"); goto error; } free_safe_mem(key); free_safe_mem(key_backup); if (backup_hdr != NULL) *backup_hdr = ehdr_backup; else free_safe_mem(ehdr_backup); return ehdr; /* NOT REACHED */ error: if (key) free_safe_mem(key); if (key_backup) free_safe_mem(key_backup); if (ehdr) free_safe_mem(ehdr); if (ehdr_backup) free_safe_mem(ehdr_backup); return NULL; } zuluCrypt-6.2.0/external_libraries/tcplay/humanize.c000066400000000000000000000076671425361753700227330ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "humanize.h" static const char prefixes[] = " KMGTPE"; int _humanize_number(char *buf, size_t bufsz, uint64_t num) { const char *prefixp; int ret; uint64_t i, d; prefixp = prefixes; i = num; d = 0; while ((i > 1024) && (*prefixp != '\0')) { d = (i % 1024)/10; i /= 1024; ++prefixp; } if (d > 0) ret = snprintf(buf, bufsz, "%"PRIu64".%"PRIu64" %c", i, d, *prefixp); else ret = snprintf(buf, bufsz, "%"PRIu64" %c", i, *prefixp); if ((ret < 0) || ((size_t)ret >= bufsz)) { errno = ENOMEM; return -1; } else { return 0; } } int _dehumanize_number(const char *buf, uint64_t *dest) { char *endptr; uint64_t n, n_check, d; uint64_t multiplier; size_t len; if (*buf == '\0') { errno = EINVAL; return -1; } len = strlen(buf); if (tolower(buf[len-1]) == 'b') --len; multiplier = 1; switch (tolower(buf[len-1])) { case 'y': multiplier *= 1024; case 'z': multiplier *= 1024; case 'e': multiplier *= 1024; case 'p': multiplier *= 1024; case 't': multiplier *= 1024; case 'g': multiplier *= 1024; case 'm': multiplier *= 1024; case 'k': multiplier *= 1024; break; default: /* * only set error if string ends in a character that * is not a valid unit. */ if (isalpha(buf[len-1])) { errno = EINVAL; return -1; } } d = 0; n = n_check = strtoull(buf, &endptr, 10); if (endptr) { if ((*endptr != '.') && (*endptr != '\0') && (*endptr != ' ') && (endptr != &buf[len-1])) { errno = EINVAL; return -1; } if (*endptr == '.') { d = strtoull(endptr+1, &endptr, 10); if (endptr && (*endptr != '\0') && (*endptr != ' ') && (endptr != &buf[len-1])) { errno = EINVAL; return -1; } } } if (d != 0) { while (d < 100) d *= 10; while (d > 1000) d /= 10; } d *= (multiplier/1024); n *= multiplier; if ((uint64_t)(n/multiplier) != n_check) { errno = ERANGE; return -1; } n += d; *dest = n; return 0; } #ifdef __TEST_HUMANIZE__ #include int main(int argc, char *argv[]) { char buf[1024]; uint64_t n, out; int err; if (argc < 3) return -1; n = strtoull(argv[1], NULL, 10); err = _humanize_number(buf, 1024, n); assert(err == 0); err = _dehumanize_number(buf, &out); assert(err == 0); printf("Converting: %"PRIu64" => %s => %"PRIu64"\n", n, buf, out); err = _dehumanize_number(argv[2], &out); assert (err == 0); printf("Converting: %s => %"PRIu64"\n", argv[2], out); return 0; } #endif zuluCrypt-6.2.0/external_libraries/tcplay/humanize.h000066400000000000000000000027721425361753700227300ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ int _humanize_number(char *buf, size_t bufsz, uint64_t num); int _dehumanize_number(const char *buf, uint64_t *dest); zuluCrypt-6.2.0/external_libraries/tcplay/io.c000066400000000000000000000231771425361753700215140ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #if defined(__DragonFly__) #include #elif defined(__linux__) #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "tcplay.h" void * read_to_safe_mem(const char *file, off_t offset, size_t *sz) { void *mem = NULL; ssize_t r = 0; int fd; if ((fd = open(file, O_RDONLY)) < 0) { tc_log(1, "Error opening file %s\n", file); return NULL; } if ((mem = alloc_safe_mem(*sz)) == NULL) { tc_log(1, "Error allocating memory\n"); goto out; } if ((lseek(fd, offset, (offset >= 0) ? SEEK_SET : SEEK_END) < 0)) { tc_log(1, "Error seeking on file %s\n", file); goto m_err; } if ((r = read(fd, mem, *sz)) <= 0) { tc_log(1, "Error reading from file %s\n", file); goto m_err; } out: *sz = r; close(fd); return mem; /* NOT REACHED */ m_err: free_safe_mem(mem); close(fd); return NULL; } static size_t get_random_total_bytes = 0; static size_t get_random_read_bytes = 0; float get_random_read_progress(void) { return (get_random_total_bytes == 0) ? 0.0 : (1.0 * get_random_read_bytes) / (1.0 * get_random_total_bytes) * 100.0; } static void get_random_summary(void) { float pct_done = get_random_read_progress(); tc_log(0, "Gathering true randomness, %.0f%% done.\n", pct_done); } int get_random(unsigned char *buf, size_t len, int weak) { int fd; ssize_t r; size_t rd = 0; size_t sz; struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; /* 10 ms */ if ((fd = open((weak) ? "/dev/urandom" : "/dev/random", O_RDONLY)) < 0) { tc_log(1, "Error opening /dev/random\n"); return -1; } summary_fn = get_random_summary; get_random_total_bytes = len; tc_internal_state = STATE_GET_RANDOM; /* Get random data in 16-byte chunks */ sz = 16; while (rd < len) { get_random_read_bytes = rd; if ((len - rd) < sz) sz = (len - rd); if ((r = read(fd, buf+rd, sz)) < 0) { tc_log(1, "Error reading from /dev/random(%d): %s\n", fd, strerror(errno)); close(fd); summary_fn = NULL; tc_internal_state = STATE_UNKNOWN; return -1; } rd += r; nanosleep(&ts, NULL); } close(fd); summary_fn = NULL; tc_internal_state = STATE_UNKNOWN; return 0; } static disksz_t secure_erase_total_bytes = 0; static disksz_t secure_erase_erased_bytes = 0; float get_secure_erase_progress(void) { return (secure_erase_total_bytes == 0) ? 0.0 : (1.0 * secure_erase_erased_bytes) / (1.0 * secure_erase_total_bytes) * 100.0; } static void secure_erase_summary(void) { float pct_done = get_secure_erase_progress(); tc_log(0, "Securely erasing, %.0f%% done.\n", pct_done); } int secure_erase(const char *dev, disksz_t bytes, size_t blksz) { size_t erased = 0; int fd_rand, fd; char buf[ERASE_BUFFER_SIZE]; ssize_t r, w; size_t sz; if (blksz > MAX_BLKSZ) { tc_log(1, "blksz > MAX_BLKSZ\n"); return -1; } if ((fd_rand = open("/dev/urandom", O_RDONLY)) < 0) { tc_log(1, "Error opening /dev/urandom\n"); return -1; } if ((fd = open(dev, O_WRONLY)) < 0) { close(fd_rand); tc_log(1, "Error opening %s\n", dev); return -1; } summary_fn = secure_erase_summary; secure_erase_total_bytes = bytes; tc_internal_state = STATE_ERASE; sz = ERASE_BUFFER_SIZE; while (erased < bytes) { secure_erase_erased_bytes = erased; /* Switch to block size when not much is remaining */ if ((bytes - erased) <= ERASE_BUFFER_SIZE) sz = blksz; if ((r = read(fd_rand, buf, sz)) < 0) { tc_log(1, "Error reading from /dev/urandom\n"); close(fd); close(fd_rand); summary_fn = NULL; tc_internal_state = STATE_UNKNOWN; return -1; } if (r < (ssize_t)blksz) continue; if ((w = write(fd, buf, r)) < 0) { tc_log(1, "Error writing to %s\n", dev); close(fd); close(fd_rand); summary_fn = NULL; tc_internal_state = STATE_UNKNOWN; return -1; } erased += (size_t)w; } close(fd); close(fd_rand); summary_fn = NULL; tc_internal_state = STATE_UNKNOWN; return 0; } #if defined(__DragonFly__) int get_disk_info(const char *dev, disksz_t *blocks, size_t *bsize) { struct partinfo pinfo; int fd; if ((fd = open(dev, O_RDONLY)) < 0) { tc_log(1, "Error opening %s\n", dev); return -1; } memset(&pinfo, 0, sizeof(struct partinfo)); if (ioctl(fd, DIOCGPART, &pinfo) < 0) { close(fd); return -1; } *blocks = (disksz_t)pinfo.media_blocks; *bsize = pinfo.media_blksize; close(fd); return 0; } #elif defined(__linux__) int get_disk_info(const char *dev, disksz_t *blocks, size_t *bsize) { uint64_t nbytes; int blocksz; int fd; if ((fd = open(dev, O_RDONLY)) < 0) { tc_log(1, "Error opening %s\n", dev); return -1; } if ((ioctl(fd, BLKSSZGET, &blocksz)) < 0) { close(fd); return -1; } if ((ioctl(fd, BLKGETSIZE64, &nbytes)) < 0) { close(fd); return -1; } *blocks = (disksz_t)(nbytes / blocksz); *bsize = (size_t)(blocksz); close(fd); return 0; } #endif int write_to_disk(const char *dev, off_t offset, size_t blksz, void *mem, size_t bytes) { unsigned char *mem_buf = NULL; ssize_t w; size_t sz; off_t internal_off; int fd; /* Align to block sizes */ internal_off = offset % blksz; #ifdef DEBUG printf("offset: %"PRIu64", internal offset: %"PRIu64"\n", (uint64_t)offset, (uint64_t)internal_off); #endif offset = (offset/blksz) * blksz; if ((internal_off + bytes) > blksz) { tc_log(1, "This should never happen: internal_off + bytes > " "blksz (write_to_disk)\n"); return -1; } if ((bytes < blksz) || (internal_off != 0)) { sz = blksz; if ((mem_buf = read_to_safe_mem(dev, offset, &sz)) == NULL) { tc_log(1, "Error buffering data on " "write_to_disk(%s)\n", dev); return -1; } memcpy(mem_buf + internal_off, mem, bytes); } if ((fd = open(dev, O_WRONLY)) < 0) { tc_log(1, "Error opening device %s\n", dev); return -1; } if ((lseek(fd, offset, (offset >= 0) ? SEEK_SET : SEEK_END) < 0)) { tc_log(1, "Error seeking on device %s\n", dev); close(fd); return -1; } if ((w = write(fd, (mem_buf != NULL) ? mem_buf : mem, bytes)) <= 0) { tc_log(1, "Error writing to device %s\n", dev); close(fd); return -1; } close(fd); if (mem_buf != NULL) free_safe_mem(mem_buf); return 0; } int write_to_file(const char *file, void *mem, size_t bytes) { int fd; ssize_t w; if ((fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { tc_log(1, "Error opening file %s\n", file); return -1; } if ((w = write(fd, mem, bytes)) < 0) { tc_log(1, "Error writing to file %s\n", file); close(fd); return -1; } close(fd); return 0; } static struct termios termios_old; static int tty_fd; static void sigint_termios(int sa) { tcsetattr(tty_fd, TCSAFLUSH, &termios_old); exit(sa); } int read_passphrase(const char *prompt, char *pass, size_t passlen, size_t bufsz, time_t timeout) { struct termios termios_new; struct timeval to; fd_set fds; ssize_t n; int fd = STDIN_FILENO, r = 0, nready; struct sigaction act, old_act; int is_tty = isatty(fd); if (is_tty == 0) errno = 0; memset(pass, 0, bufsz); printf("%s", prompt); fflush(stdout); /* If input is being provided by something which is not a terminal, don't * change the settings. */ if (is_tty) { tcgetattr(fd, &termios_old); memcpy(&termios_new, &termios_old, sizeof(termios_new)); termios_new.c_lflag &= ~ECHO; act.sa_handler = sigint_termios; act.sa_flags = SA_RESETHAND; sigemptyset(&act.sa_mask); tty_fd = fd; sigaction(SIGINT, &act, &old_act); tcsetattr(fd, TCSAFLUSH, &termios_new); } if (timeout > 0) { memset(&to, 0, sizeof(to)); to.tv_sec = timeout; FD_ZERO(&fds); FD_SET(fd, &fds); nready = select(fd + 1, &fds, NULL, NULL, &to); if (nready <= 0) { r = EINTR; goto out; } } n = read(fd, pass, bufsz-1); if (n > 0) { pass[n-1] = '\0'; /* Strip trailing \n */ } else { r = EIO; } /* Warn about passphrase trimming */ if (strlen(pass) > MAX_PASSSZ) tc_log(0, "WARNING: Passphrase is being trimmed to %zu " "characters, discarding rest.\n", passlen); /* Cut off after passlen characters */ pass[passlen] = '\0'; out: if (is_tty) { tcsetattr(fd, TCSAFLUSH, &termios_old); putchar('\n'); sigaction(SIGINT, &old_act, NULL); } return r; } zuluCrypt-6.2.0/external_libraries/tcplay/main.c000066400000000000000000000413621425361753700220250ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "tcplay.h" #ifndef SIGINFO #define SIGINFO SIGUSR1 #endif #define FLAG_LONG_FDE 0xff01 #define FLAG_LONG_USE_BACKUP 0xff02 #define FLAG_LONG_MOD 0xff04 #define FLAG_LONG_MOD_KF 0xff08 #define FLAG_LONG_MOD_PRF 0xff10 #define FLAG_LONG_MOD_NONE 0xff20 #define FLAG_LONG_MOD_TO_FILE 0xff40 #define FLAG_LONG_USE_HDR_FILE 0xfe01 #define FLAG_LONG_USE_HHDR_FILE 0xfe02 #define FLAG_LONG_NO_RETRIES 0xfabc static void sig_handler(int sig) { if ((sig == SIGUSR1 || sig == SIGINFO) && (summary_fn != NULL)) summary_fn(); } static void usage(void) { fprintf(stderr, "usage: tcplay -c -d device [-g] [-z] [-w] [-a pbkdf_hash] [-b cipher]\n" " [-f keyfile_hidden] [-k keyfile] [-x pbkdf_hash] [-y cipher]\n" " tcplay -i -d device [-e] [-p] [-f keyfile_hidden] [-k keyfile]\n" " [-s system_device] [--fde] [--use-backup]\n" " [--use-hdr-file=hdr_file] [--use-hidden-hdr-file=hdr_file]\n" " tcplay -m mapping -d device [-e] [-p] [-f keyfile_hidden] [-k keyfile]\n" " [-s system_device] [--fde] [--use-backup] [--allow-trim]\n" " [--use-hdr-file=hdr_file] [--use-hidden-hdr-file=hdr_file]\n" " tcplay --modify -d device [-k keyfile] [--new-keyfile=keyfile]\n" " [--new-pbkdf-prf=pbkdf_hash] [-s system_device] [--fde]\n" " [--use-backup] [--save-hdr-to-file=hdr_file] [-w]\n" " [--use-hdr-file=hdr_file] [--use-hidden-hdr-file=hdr_file]\n" " tcplay --modify -d device [-k keyfile] --restore-from-backup-hdr [-w]\n" " tcplay -j mapping\n" " tcplay -u mapping\n" " tcplay -h | -v\n" "\n" "Valid commands are:\n" " -c, --create\n" "\t Creates a new TC volume on the device specified by -d or --device.\n" " -h, --help\n" "\t Print help message and exit.\n" " -i, --info\n" "\t Gives information about the TC volume specified by -d or --device.\n" " -j , --info-mapped=\n" "\t Gives information about the mapped TC volume under the given mapping.\n" " -m , --map=\n" "\t Creates a dm-crypt mapping with the given name for the device\n" "\t specified by -d or --device.\n" " -u , --unmap=\n" "\t Removes a dm-crypt mapping with the given name.\n" " --modify\n" "\t Changes the volume's passphrase, keyfile and optionally the hashing\n" "\t function used for the PBKDF password derivation.\n" " -v, --version\n" "\t Print version message and exit.\n" "\n" "Valid options for --create are:\n" " -a , --pbkdf-prf=\n" "\t Specifies which hashing function to use for the PBKDF password\n" "\t derivation when creating a new volume.\n" "\t To see valid options, specify '-a help'.\n" " -b , --cipher=\n" "\t Specifies which cipher to use when creating a new TC volume.\n" "\t To see valid options, specify '-b help'.\n" " -g, --hidden\n" "\t Specifies that the newly created volume will contain a hidden volume.\n" " -x , --pbkdf-prf=\n" "\t Specifies which hashing function to use for the PBKDF password\n" "\t derivation when creating a new hidden volume. By default, the\n" "\t same as for the outer volume will be used.\n" "\t To see valid options, specify '-x help'.\n" " -y , --cipher=\n" "\t Specifies which cipher to use when creating a new hidden volume.\n" "\t By default, the same as for the outer volume will be used.\n" "\t To see valid options, specify '-y help'.\n" " -z, --insecure-erase\n" "\t Skips the erase of the disk. Possible security hazard.\n" " -w, --weak-keys\n" "\t Uses a weak source of entropy (urandom) for key material.\n" "\t WARNING: This is a REALLY REALLY bad idea for anything but\n" "\t testing.\n" "\n" "Valid options for --modify are:\n" " --new-keyfile=\n" "\t Specifies a key file to use for the password derivation, when\n" "\t re-encrypting the header, can appear multiple times.\n" " --new-pbkdf-prf=\n" "\t Specifies which hashing function to use for the PBKDF password\n" "\t derivation when re-encrypting the header.\n" "\t To see valid options, specify '-a help'.\n" " -s , --system-encryption=\n" "\t Specifies that the disk (e.g. /dev/da0) is using system encryption.\n" " --fde\n" "\t Specifies that the disk (e.g. /dev/da0) is using full disk encryption.\n" " --use-backup\n" "\t Uses the backup headers (at the end of the volume) instead of the\n" "\t primary headers. Both normal and backup headers will be modified!\n" "\t This is useful when your primary headers have been corrupted.\n" " --use-hdr-file=
\n" "\t Use the header in the specified file instead of the main header on the\n" "\t disk as source for the modify operation.\n" " --use-hidden-hdr-file=
\n" "\t Use the header in the specified file instead of the hidden header on the\n" "\t disk as source for the modify operation.\n" " --restore-from-backup-hdr\n" "\t Implies --use-backup, no new PBKDF hashing function, no new keyfiles\n" "\t and no new passphrase.\n" "\t In other words, this will simply restore both headers from the backup\n" "\t header. This option cannot be used to restore from a backup header file.\n" " -w, --weak-keys\n" "\t Uses a weak source of entropy (urandom) for salt material. The\n" "\t key material is not affected, as the master keys are kept intact.\n" "\t WARNING: This is a bad idea for anything but testing.\n" " --save-hdr-backup=
\n" "\t Saves the modified header in the specified file instead of updating\n" "\t the header files on disk.\n" "\n" "Valid options for --info and --map are:\n" " -e, --protect-hidden\n" "\t Protect a hidden volume when mounting the outer volume.\n" " -p, --prompt-passphrase\n" "\t Immediately prompt for a passphrase even if a keyfile is supplied.\n" " -s , --system-encryption=\n" "\t Specifies that the disk (e.g. /dev/da0) is using system encryption.\n" " -t, --allow-trim\n" "\t Allow discards (TRIM command) on mapped volume.\n" " --fde\n" "\t Specifies that the disk (e.g. /dev/da0) is using full disk encryption.\n" " --use-backup\n" "\t Uses the backup headers (at the end of the volume) instead of the\n" "\t primary headers.\n" "\t This is useful when your primary headers have been corrupted.\n" " --use-hdr-file=
\n" "\t Use the header in the specified file instead of the main header on the\n" "\t disk.\n" " --use-hidden-hdr-file=
\n" "\t Use the header in the specified file instead of the hidden header on the\n" "\t disk.\n" "\n" "Valid options common to all commands are:\n" " -d , --device=\n" "\t Specifies the path to the volume to operate on (e.g. /dev/da0s1).\n" " -f , --keyfile-hidden=\n" "\t Specifies a key file to use for the hidden volume password derivation.\n" "\t This option is only valid in combination with -e, --protect-hidden\n" "\t or -g, --hidden.\n" " -k , --keyfile=\n" "\t Specifies a key file to use for the password derivation, can appear\n" "\t multiple times.\n" ); exit(EXIT_FAILURE); } static struct option longopts[] = { { "create", no_argument, NULL, 'c' }, { "cipher", required_argument, NULL, 'b' }, { "cipher-hidden", required_argument, NULL, 'y' }, { "hidden", no_argument, NULL, 'g' }, { "pbkdf-prf", required_argument, NULL, 'a' }, { "pbkdf-prf-hidden", required_argument, NULL, 'x' }, { "info", no_argument, NULL, 'i' }, { "info-mapped", required_argument, NULL, 'j' }, { "map", required_argument, NULL, 'm' }, { "keyfile", required_argument, NULL, 'k' }, { "keyfile-hidden", required_argument, NULL, 'f' }, { "protect-hidden", no_argument, NULL, 'e' }, { "device", required_argument, NULL, 'd' }, { "prompt-passphrase", no_argument, NULL, 'p' }, { "system-encryption", required_argument, NULL, 's' }, { "allow-trim", no_argument, NULL, 't' }, { "fde", no_argument, NULL, FLAG_LONG_FDE }, { "use-backup", no_argument, NULL, FLAG_LONG_USE_BACKUP }, { "use-hdr-file", required_argument, NULL, FLAG_LONG_USE_HDR_FILE }, { "use-hidden-hdr-file",required_argument, NULL, FLAG_LONG_USE_HHDR_FILE }, { "modify", no_argument, NULL, FLAG_LONG_MOD }, { "new-keyfile", required_argument, NULL, FLAG_LONG_MOD_KF }, { "new-pbkdf-prf", required_argument, NULL, FLAG_LONG_MOD_PRF }, { "restore-from-backup-hdr", no_argument, NULL, FLAG_LONG_MOD_NONE }, { "save-hdr-backup", required_argument, NULL, FLAG_LONG_MOD_TO_FILE }, { "unmap", required_argument, NULL, 'u' }, { "version", no_argument, NULL, 'v' }, { "weak-keys", no_argument, NULL, 'w' }, { "insecure-erase", no_argument, NULL, 'z' }, { "help", no_argument, NULL, 'h' }, { "no-retries", no_argument, NULL, FLAG_LONG_NO_RETRIES }, { NULL, 0, NULL, 0 }, }; #define _set_str_opt(opt) \ do { \ if ((opts->opt = strdup_safe_mem(optarg)) == NULL) { \ fprintf(stderr, "Could not allocate safe mem.\n"); \ exit(EXIT_FAILURE); \ } \ } while(0) int main(int argc, char *argv[]) { struct tcplay_opts *opts; int ch, error; int info_vol = 0, map_vol = 0, unmap_vol = 0, info_map = 0, create_vol = 0, modify_vol = 0; if ((error = tc_play_init()) != 0) { fprintf(stderr, "Initialization failed, exiting."); exit(EXIT_FAILURE); } atexit(check_and_purge_safe_mem); signal(SIGUSR1, sig_handler); signal(SIGINFO, sig_handler); if ((opts = opts_init()) == NULL) { fprintf(stderr, "Initialization failed (opts), exiting."); exit(EXIT_FAILURE); } opts->interactive = 1; while ((ch = getopt_long(argc, argv, "a:b:cd:ef:ghij:k:m:ps:tu:vwx:y:z", longopts, NULL)) != -1) { switch(ch) { case 'a': if (opts->prf_algo != NULL) usage(); if ((opts->prf_algo = check_prf_algo(optarg, 0, 0)) == NULL) { if (strcmp(optarg, "help") == 0) exit(EXIT_SUCCESS); else usage(); /* NOT REACHED */ } break; case 'b': if (opts->cipher_chain != NULL) usage(); if ((opts->cipher_chain = check_cipher_chain(optarg, 0)) == NULL) { if (strcmp(optarg, "help") == 0) exit(EXIT_SUCCESS); else usage(); /* NOT REACHED */ } break; case 'c': create_vol = 1; break; case 'd': _set_str_opt(dev); break; case 'e': opts->protect_hidden = 1; break; case 'f': if ((error = opts_add_keyfile_hidden(opts, optarg)) != 0) { fprintf(stderr, "Could not add keyfile: %s\n", optarg); exit(EXIT_FAILURE); } break; case 'g': opts->hidden = 1; break; case 'i': info_vol = 1; break; case 'j': info_map = 1; _set_str_opt(map_name); break; case 'k': if ((error = opts_add_keyfile(opts, optarg)) != 0) { fprintf(stderr, "Could not add keyfile: %s\n", optarg); exit(EXIT_FAILURE); } break; case 'm': map_vol = 1; _set_str_opt(map_name); break; case 'p': opts->prompt_passphrase = 1; break; case 's': opts->flags |= TC_FLAG_SYS; _set_str_opt(sys_dev); break; case 't': opts->flags |= TC_FLAG_ALLOW_TRIM; break; case 'u': unmap_vol = 1; _set_str_opt(map_name); break; case 'v': printf("tcplay v%d.%d\n", MAJ_VER, MIN_VER); exit(EXIT_SUCCESS); /* NOT REACHED */ case 'w': fprintf(stderr, "WARNING: Using urandom as source of " "entropy for key material is a really bad idea.\n"); opts->weak_keys_and_salt = 1; break; case 'x': if (opts->h_prf_algo != NULL) usage(); if ((opts->h_prf_algo = check_prf_algo(optarg, 0, 0)) == NULL) { if (strcmp(optarg, "help") == 0) exit(EXIT_SUCCESS); else usage(); /* NOT REACHED */ } break; case 'y': if (opts->h_cipher_chain != NULL) usage(); if ((opts->h_cipher_chain = check_cipher_chain(optarg, 0)) == NULL) { if (strcmp(optarg, "help") == 0) exit(EXIT_SUCCESS); else usage(); /* NOT REACHED */ } break; case 'z': opts->secure_erase = 0; break; case FLAG_LONG_FDE: opts->flags |= TC_FLAG_FDE; break; case FLAG_LONG_USE_BACKUP: opts->flags |= TC_FLAG_BACKUP; break; case FLAG_LONG_USE_HDR_FILE: opts->flags |= TC_FLAG_HDR_FROM_FILE; _set_str_opt(hdr_file_in); break; case FLAG_LONG_USE_HHDR_FILE: opts->flags |= TC_FLAG_H_HDR_FROM_FILE; _set_str_opt(h_hdr_file_in); break; case FLAG_LONG_MOD: modify_vol = 1; break; case FLAG_LONG_MOD_KF: if ((error = opts_add_keyfile_new(opts, optarg)) != 0) { fprintf(stderr, "Could not add keyfile: %s\n", optarg); exit(EXIT_FAILURE); } break; case FLAG_LONG_MOD_PRF: if (opts->new_prf_algo != NULL) usage(); if ((opts->new_prf_algo = check_prf_algo(optarg, 0, 0)) == NULL) { if (strcmp(optarg, "help") == 0) exit(EXIT_SUCCESS); else usage(); /* NOT REACHED */ } break; case FLAG_LONG_MOD_NONE: opts->new_prf_algo = NULL; opts->flags |= TC_FLAG_ONLY_RESTORE; opts->flags |= TC_FLAG_BACKUP; break; case FLAG_LONG_MOD_TO_FILE: opts->flags |= TC_FLAG_SAVE_TO_FILE; _set_str_opt(hdr_file_out); break; case FLAG_LONG_NO_RETRIES: opts->retries = 1; break; case 'h': case '?': default: usage(); /* NOT REACHED */ } } argc -= optind; argv += optind; /* Check arguments */ if (!(((map_vol || info_vol || create_vol || modify_vol) && opts->dev != NULL) || ((unmap_vol || info_map) && opts->map_name != NULL)) || (TC_FLAG_SET(opts->flags, SYS) && TC_FLAG_SET(opts->flags, FDE)) || (map_vol + info_vol + create_vol + unmap_vol + info_map + modify_vol > 1) || (opts->hidden && !create_vol) || (TC_FLAG_SET(opts->flags, SYS) && (opts->sys_dev == NULL)) || (TC_FLAG_SET(opts->flags, ONLY_RESTORE) && (opts->n_newkeyfiles > 0 || opts->new_prf_algo != NULL)) || (TC_FLAG_SET(opts->flags, BACKUP) && (opts->sys_dev != NULL || TC_FLAG_SET(opts->flags, FDE))) || (map_vol && (opts->map_name == NULL)) || (unmap_vol && (opts->map_name == NULL)) || (!modify_vol && opts->n_newkeyfiles > 0) || (!modify_vol && opts->new_prf_algo != NULL) || (!modify_vol && TC_FLAG_SET(opts->flags, ONLY_RESTORE)) || (!modify_vol && TC_FLAG_SET(opts->flags, SAVE_TO_FILE)) || (!(opts->protect_hidden || create_vol) && opts->n_hkeyfiles > 0)) { usage(); /* NOT REACHED */ } /* Create a new volume */ if (create_vol) { error = create_volume(opts); if (error) { tc_log(1, "could not create new volume on %s\n", opts->dev); } } else if (info_map) { error = info_mapped_volume(opts); } else if (info_vol) { error = info_volume(opts); } else if (map_vol) { error = map_volume(opts); } else if (unmap_vol) { error = dm_teardown(opts->map_name, NULL); } else if (modify_vol) { error = modify_volume(opts); } return error; } #undef _set_str_opt zuluCrypt-6.2.0/external_libraries/tcplay/pbkdf2-gcrypt.c000066400000000000000000000052121425361753700235510ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include /* * Yey for gcrypt and its broken includes... * see http://lists.gnupg.org/pipermail/gcrypt-devel/2011-July/001830.html * and http://seclists.org/wireshark/2011/Jul/208 * for more details... */ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include #pragma GCC diagnostic warning "-Wdeprecated-declarations" #include "tcplay.h" extern int zuluCryptIterationCount ; static int get_gcrypt_hash_id(struct pbkdf_prf_algo *hash) { if (strcmp(hash->algo, "RIPEMD160") == 0) return GCRY_MD_RMD160; else if (strcmp(hash->algo, "SHA512") == 0) return GCRY_MD_SHA512; else if (strcmp(hash->algo, "SHA256") == 0) return GCRY_MD_SHA256; else if (strcmp(hash->algo, "whirlpool") == 0) return GCRY_MD_WHIRLPOOL; else return -1; } int pbkdf2(struct pbkdf_prf_algo *hash, const char *pass, int passlen, const unsigned char *salt, int saltlen, int keylen, int iteration_count,unsigned char *out) { gpg_error_t err; int iter ; if (iteration_count) iter = iteration_count ; else iter = hash->iteration_count ; err = gcry_kdf_derive(pass, passlen, GCRY_KDF_PBKDF2, get_gcrypt_hash_id(hash), salt, saltlen, iter, keylen, out); if (err) { tc_log(1, "Error in PBKDF2\n"); return EINVAL; } return 0; } zuluCrypt-6.2.0/external_libraries/tcplay/pbkdf2-openssl.c000066400000000000000000000037221425361753700237300ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "tcplay.h" int pbkdf2(struct pbkdf_prf_algo *hash, const char *pass, int passlen, const unsigned char *salt, int saltlen, int keylen, unsigned char *out) { const EVP_MD *md; int r; OpenSSL_add_all_algorithms(); md = EVP_get_digestbyname(hash->algo); if (md == NULL) { tc_log(1, "Hash %s not found\n", hash->algo); return ENOENT; } r = PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, hash->iteration_count, md, keylen, out); if (r == 0) { tc_log(1, "Error in PBKDF2\n"); return EINVAL; } return 0; } zuluCrypt-6.2.0/external_libraries/tcplay/safe_mem.c000066400000000000000000000113351425361753700226520ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "tcplay.h" struct safe_mem_hdr { struct safe_mem_hdr *prev; struct safe_mem_hdr *next; struct safe_mem_tail *tail; const char *file; int line; size_t alloc_sz; char sig[8]; /* SAFEMEM */ }; struct safe_mem_tail { char sig[8]; /* SAFEMEM */ }; static struct safe_mem_hdr *safe_mem_hdr_first = NULL; void * _alloc_safe_mem(size_t req_sz, const char *file, int line) { struct safe_mem_hdr *hdr, *hdrp; struct safe_mem_tail *tail; size_t alloc_sz; char *mem, *user_mem; alloc_sz = req_sz + sizeof(*hdr) + sizeof(*tail); if ((mem = malloc(alloc_sz)) == NULL) return NULL; if (mlock(mem, alloc_sz) < 0) { free(mem); return NULL; } memset(mem, 0, alloc_sz); hdr = (struct safe_mem_hdr *)mem; tail = (struct safe_mem_tail *)(mem + alloc_sz - sizeof(*tail)); user_mem = mem + sizeof(*hdr); strcpy(hdr->sig, "SAFEMEM"); strcpy(tail->sig, "SAFEMEM"); hdr->tail = tail; hdr->alloc_sz = alloc_sz; hdr->file = file; hdr->line = line; hdr->next = NULL; if (safe_mem_hdr_first == NULL) { safe_mem_hdr_first = hdr; } else { hdrp = safe_mem_hdr_first; while (hdrp->next != NULL) hdrp = hdrp->next; hdr->prev = hdrp; hdrp->next = hdr; } return user_mem; } void _free_safe_mem(void *mem_ptr, const char *file, int line) { struct safe_mem_hdr *hdr; struct safe_mem_tail *tail; size_t alloc_sz; char *mem = mem_ptr; mem -= sizeof(*hdr); hdr = (struct safe_mem_hdr *)mem; tail = (struct safe_mem_tail *)(mem + hdr->alloc_sz - sizeof(*tail)); #ifdef DEBUG fprintf(stderr, "freeing safe_mem (hdr): %#lx (%s:%d)\n", (unsigned long)(void *)hdr, hdr->file, hdr->line); #endif if (hdr->alloc_sz == 0) { fprintf(stderr, "BUG: double-free at %s:%d !!!\n", file, line); return; } /* Integrity checks */ if ((memcmp(hdr->sig, "SAFEMEM\0", 8) != 0) || (memcmp(tail->sig, "SAFEMEM\0", 8) != 0)) { fprintf(stderr, "BUG: safe_mem buffer under- or overflow at " "%s:%d !!!\n", file, line); return; } if (safe_mem_hdr_first == NULL) { fprintf(stderr, "BUG: safe_mem list should not be empty at " "%s:%d !!!\n", file, line); return; } if (hdr->prev != NULL) hdr->prev->next = hdr->next; if (hdr->next != NULL) hdr->next->prev = hdr->prev; if (safe_mem_hdr_first == hdr) safe_mem_hdr_first = hdr->next; alloc_sz = hdr->alloc_sz; memset(mem, 0xFF, alloc_sz); memset(mem, 0, alloc_sz); free(mem); } void * _strdup_safe_mem(const char *in, const char *file, int line) { char *out; size_t sz; sz = strlen(in)+1; if ((out = _alloc_safe_mem(sz, file, line)) == NULL) { return NULL; } memcpy(out, in, sz); out[sz-1] = '\0'; return out; } void check_and_purge_safe_mem(void) { struct safe_mem_hdr *hdr; char *mem; #ifdef DEBUG int ok; #endif if (safe_mem_hdr_first == NULL) return; hdr = safe_mem_hdr_first; while ((hdr = safe_mem_hdr_first) != NULL) { #ifdef DEBUG if ((hdr->alloc_sz > 0) && (memcmp(hdr->sig, "SAFEMEM\0", 8) == 0) && (memcmp(hdr->tail->sig, "SAFEMEM\0", 8) == 0)) ok = 1; else ok = 0; fprintf(stderr, "un-freed safe_mem: %#lx (%s:%d) [integrity=%s]\n", (unsigned long)(void *)hdr, hdr->file, hdr->line, ok? "ok" : "failed"); #endif mem = (void *)hdr; mem += sizeof(*hdr); _free_safe_mem(mem, "check_and_purge_safe_mem", 0); } } zuluCrypt-6.2.0/external_libraries/tcplay/tcplay.3000066400000000000000000000445131425361753700223160ustar00rootroot00000000000000.\" .\" Copyright (c) 2011 The DragonFly Project. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. Neither the name of The DragonFly Project nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific, prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS .\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE .\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, .\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; .\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED .\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, .\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .Dd January 20, 2014 .Dt TCPLAY 3 .Os .Sh NAME .Nm tc_api_init , .Nm tc_api_uninit , .Nm tc_api_has , .Nm tc_api_cipher_iterate , .Nm tc_api_prf_iterate , .Nm tc_api_task_init , .Nm tc_api_task_uninit , .Nm tc_api_task_set , .Nm tc_api_task_do , .Nm tc_api_task_info_get , .Nm tc_api_task_get_error .Nd TrueCrypt volume management .Sh LIBRARY .Lb libtcplay .Sh SYNOPSIS .In tcplay_api.h .Ft typedef int .Fn (*tc_api_cipher_iterator_fn) "void *priv" "const char *name" "int key_length_in_bits" "int ciphers_in_chain" .Ft typedef int .Fn (*tc_api_prf_iterator_fn) "void *priv" "const char *name" .Ft typedef int .Fn (*tc_api_state_change_fn) "void *priv" "const char *state" "int enter_state" .Ft int .Fn tc_api_init "int verbose" .Ft int .Fn tc_api_uninit "void" .Ft int .Fn tc_api_has "const char *feature" .Ft int .Fn tc_api_cipher_iterate "tc_api_cipher_iterator_fn fn" "void *priv" .Ft int .Fn tc_api_prf_iterate "tc_api_prf_iterator_fn fn" "void *priv" .Ft tc_api_task .Fn tc_api_task_init "const char *op" .Ft int .Fn tc_api_task_uninit "tc_api_task task" .Ft int .Fn tc_api_task_set "tc_api_task task" "const char *key" "..." .Ft int .Fn tc_api_task_do "tc_api_task task" .Ft int .Fn tc_api_task_info_get "tc_api_task task" "const char *key" "..." .Ft const char * .Fn tc_api_task_get_error "tc_api_task task" .Sh DESCRIPTION The .Nm tcplay library provides an interface to create, query, map and manage TrueCrypt-compatible volumes. .Pp The .Fn tc_api_init function initializes the library internals and prepares it for use via the API. This function has to be called before using any other API function. If the .Fa verbose argument is non-zero, then the library will output information such as errors via stdout and stderr. .Pp The .Fn tc_api_uninit function clears up all internal secure memory, such as memory used for decrypted headers, passphrases, keyfiles, etc. .Pp The .Fn tc_api_has function checks whether the loaded tcplay library has the feature specified by the .Fa feature argument. The current version of the .Nm tcplay library supports the following features: .Bl -column "some_long_feature" "Description" .It Sy Feature Ta Sy Description .It Li trim Ta Allows enabling discards/TRIM when mapping a volume .El .Pp The .Fn tc_api_cipher_iterate function passes every available cipher chain to the callback provided in the .Fa fn argument. The .Fa priv argument is passed on every call of the callback function. The name of the cipher chain is passed to the callback function in the .Fa name argument. Similarly, the .Fa ciphers_in_chain argument holds the number of ciphers in the current chain, and .Fa key_length_in_bits holds the total key length for the cipher chain, in bits. .Pp The .Fn tc_api_prf_iterate function passes every available cipher chain to the callback provided in the .Fa fn argument. The .Fa priv argument is passed on every call of the callback function. The name of the PKBDF2 PRF algorithm is passed to the callback function in the .Fa name argument. .Pp The .Fn tc_api_task_init function initializes and returns a .Ft tc_api_task opaque pointer that can be used to run .Nm tcplay commands. Each task can be used only for a single .Fn tc_api_task_do call, and must be deallocated using .Fn tc_api_task_uninit . The .Fa op argument can be one of the following: .Bl -tag -width indent .It Sy create Create a new encrypted TrueCrypt volume. .It Sy map Map an existing TrueCrypt volume. .It Sy info Request information about an encrypted TrueCrypt volume. .It Sy info_mapped Request information about a mapped TrueCrypt volume. .It Sy unmap Unmap a mapped TrueCrypt volume. .It Sy modify Modify the TrueCrypt volume by changing the passphrase, keyfiles, PRF algorithm, restoring from a backup header, restoring from a header file or saving to a header file. .It Sy restore Modify the TrueCrypt volume as .Sy modify does, but without changing the passphrase, keyfiles or PRF algorithm. .El .Pp The .Fn tc_api_task_set function allows settting a number of different options for the current task. The following table shows which keys are available on calls to .Fn tc_api_task_set for each of the operations. The letter .Sy M indicates the setting is mandatory, whilst .Sy * indicates the setting is optional. .Bl -column "hidden_header_from_filexxx" "createxxx" "infoxxx" "mapxxx" "unmapxxx" "info_mappedxxx" "modifyxxx" "restorexxx" .It Sy Key Ta Sy create Ta Sy info Ta Sy map Ta Sy unmap Ta Sy info_mapped Ta Sy modify Ta Sy restore .It Li dev Ta "M" Ta "M" Ta "M" Ta "*" Ta Ta "M" Ta "M" .It Li map_name Ta Ta Ta "M" Ta "M" Ta "M" Ta Ta "" .It Li interactive Ta "*" Ta "*" Ta "*" Ta Ta Ta "*" Ta "*" .It Li retries Ta "*" Ta "*" Ta "*" Ta Ta Ta "*" Ta "*" .It Li timeout Ta "*" Ta "*" Ta "*" Ta Ta Ta Ta "" .It Li state_change_fn Ta "*" Ta Ta Ta Ta Ta "*" Ta "*" .It Li weak_keys_and_salt Ta "*" Ta Ta Ta Ta Ta "*" Ta "*" .It Li secure_erase Ta "*" Ta Ta Ta Ta Ta Ta "" .It Li hidden_size_bytes Ta "*" Ta Ta Ta Ta Ta Ta "" .It Li prf_algo Ta "*" Ta Ta Ta Ta Ta Ta "" .It Li h_prf_algo Ta "*" Ta Ta Ta Ta Ta Ta "" .It Li cipher_chain Ta "*" Ta Ta Ta Ta Ta Ta "" .It Li h_cipher_chain Ta "*" Ta Ta Ta Ta Ta Ta "" .It Li protect_hidden Ta Ta "*" Ta "*" Ta Ta Ta Ta "" .It Li fde Ta Ta "*" Ta "*" Ta Ta Ta Ta "" .It Li sys Ta Ta "*" Ta "*" Ta Ta Ta "?" Ta "?" .It Li use_backup_header Ta Ta "*" Ta "*" Ta Ta Ta "*" Ta "*" .It Li header_from_file Ta Ta "*" Ta "*" Ta Ta Ta "*" Ta "*" .It Li hidden_header_from_file Ta Ta "*" Ta "*" Ta Ta Ta "*" Ta "*" .It Li allow_trim Ta Ta Ta "*" Ta Ta Ta Ta "" .It Li save_header_to_file Ta Ta Ta Ta Ta Ta "*" Ta "" .It Li passphrase Ta "*" Ta "*" Ta "*" Ta Ta Ta "*" Ta "*" .It Li h_passphrase Ta "*" Ta "*" Ta "*" Ta Ta Ta "*" Ta "*" .It Li keyfiles Ta "*" Ta "*" Ta "*" Ta Ta Ta "*" Ta "*" .It Li h_keyfiles Ta "*" Ta "*" Ta "*" Ta Ta Ta "*" Ta "*" .It Li new_passphrase Ta Ta Ta Ta Ta Ta "*" Ta "" .It Li new_keyfiles Ta Ta Ta Ta Ta Ta "*" Ta "" .It Li new_prf_algo Ta Ta Ta Ta Ta Ta "*" Ta "" .El The varargs accepted by the .Fn tc_api_task_set function depend on the key being set. .Bl -tag -width indent .It dev The vararg is of type .Ft const char * . It sets the device that contains the TrueCrypt volume to operate on. .It map_name The vararg is of type .Ft const char * . It set the name of the mapped volume. .It interactive The vararg is of type .Ft int . It determines whether the user will be prompted for a passphrase or whether the settings are taken from the arguments set using .Fn tc_api_task_set . .It retries The vararg is of type .Ft int . It determines the number of passphrase retries if .Fa interactive is set. .It weak_keys_and_salt The vararg is of type .Ft int . It determines whether to use a weak source of entropy for key material and/or the salt. .It secure_erase The vararg is of type .Ft int . It determines whether a secure erase is performed as part of the volume creation. .It hidden_size_bytes The vararg is of type .Ft int64_t . If set to .Fa 0 it implies no hidden volume will be created. A positive value implies a hidden volume of the specified size in bytes is created. .It prf_algo The vararg is of type .Ft const char * and must be a valid PBKDF2 PRF algorithm. It determines which PBKDF2 PRF algorithm is used for the outer volume. .It h_prf_algo The vararg is of type .Ft const char * and must be a valid PBKDF2 PRF algorithm. It determines which PBKDF2 PRF algorithm is used for the hidden volume. .It cipher_chain The vararg is of type .Ft const char * and must be a valid .Nm tcplay cipher chain. It determines which cipher chain is used to encrypt the outer volume. .It h_cipher_chain The vararg is of type .Ft const char * and must be a valid .Nm tcplay cipher chain. It determines which cipher chain is used to encrypt the hidden volume. .It protect_hidden The vararg is of type .Ft int . It determines whether the size of the outer volume should be adjusted to protect any hidden volume. Using this mode requires both outer and hidden passphrases and keyfiles. .It sys The vararg is of type .Ft const char * . It determines whether the volume is a system encrypted volume, and if so, which disk is the system disk and hence contains the header. If set to .Dv NULL the volume will implicitly be treated as a non-system encrypted volume. .It fde The vararg is of type .Ft int . It determines whether the disk uses full disk encryption or not. If specified, the device pointed to by the .Fa dev setting should be a whole disk device, not any partition. The device will be mapped or queried as a whole. To access individual partitions, a utility such as .Xr kpartx 8 should be used, which will create additional individual mappings for each partition in the decrypted mapped volume. For more details on full disk encryption, see .Xr tcplay 8 . .It use_backup_header The vararg is of type .Ft int . It determines whether the backup header should be used instead of the regular header to access the volume. .It header_from_file The vararg is of type .Ft const char * . If not .Dv NULL it forces .Nm tcplay to use the header in the specified file instead of the regular outer volume header. .It hidden_header_from_file The vararg is of type .Ft const char * . If not .Dv NULL it forces .Nm tcplay to use the header in the specified file instead of the regular hidden volume header. .It allow_trim The vararg is of type .Ft int . It specifies whether the mapped volume should allow discards (TRIM). .It save_header_to_file The vararg is of type .Ft const char * . If not .Dv NULL it forces .Nm tcplay to write the (modified) header to the specified file instead of replacing the volume headers. .It passphrase The vararg is of type .Ft const char * . It sets the passphrase that .Nm tcplay uses to access the volume. .It h_passphrase The vararg is of type .Ft const char * . It sets the passphrase that .Nm tcplay uses to unlock the hidden volume header. This option is only used if a hidden volume is being created or the .Fa protect_hidden setting is set. Otherwise .Nm tcplay will first use the regular passphrase to try to unlock the outer volume and then try to unlock the hidden volume header with the same passphrase without ever using .Fa h_passphrase . .It keyfiles The vararg is of type .Ft const char * . If not .Dv NULL the given keyfile will be added to the keyfile pool. Multiple calls to set this option with a non- .Dv NULL argument result add additional keyfiles. If .Dv NULL all keyfiles are cleared. .It h_keyfiles The vararg is of type .Ft const char * . If not .Dv NULL the given keyfile will be added to the keyfile pool. Multiple calls to set this option with a non- .Dv NULL argument result add additional keyfiles. If .Dv NULL all keyfiles are cleared. This option is only used if a hidden volume is being created or the .Fa protect_hidden setting is set. Otherwise .Nm tcplay will first use the regular keyfiles to try to unlock the outer volume and then try to unlock the hidden volume header with the same keyfiles without ever using .Fa h_keyfiles . .It new_passphrase The vararg is of type .Fa const char * . It specifies the new passphrase to use when modifying the volume header. .It new_keyfiles The vararg is of type .Fa const char * . If not .Dv NULL the given keyfile will be added to the new keyfile pool. Multiple calls to set this option with a non- .Dv NULL argument result add additional keyfiles. If .Dv NULL all new keyfiles are cleared. When the volume header is modified, it will be reencrypted using the new keyfiles. .It new_prf_algo The vararg is of type .Ft const char * and must be a valid PBKDF2 PRF algorithm. It determines which PBKDF2 PRF algorithm is used when reencrypting the (modified) volume header. .It state_change_fn The first vararg is of type .Fa tc_api_state_change_fn and the second vararg is of type .Fa void * . It allows the consumer to provide a callback function which will be called when starting and stopping a time-intensive sub-operation such as collecting entropy or erasing a volume. The second vararg is passed as the .Fa priv argument to the callback. The .Fa enter_state argument to the callback determines whether .Nm tcplay is starting or stopping the time-intensive sub-task specified in the .Fa state argument. .El .Pp The .Fn tc_api_task_do function runs the task specified in the .Fa task argument. Before running the task, .Fn tc_api_task_do performs a simple sanity check of the arguments set previously using .Fn tc_api_task_set before performing the actual operation. After a call to .Fn tc_api_task_do for the .Sy info or .Sy info_mapped operations, the queried information is available to be accessed using .Fn tc_api_task_info_get . .Pp The .Fn tc_api_task_info_get function can be used to query the result of a .Sy info or .Sy info_mapped operation. The .Fa task argument is the task used in a previous .Fn tc_api_task_do call. The .Fa key argument can be one of the following: .Bl -column "some_long_feature" "very_long_type" "Description" .It Sy Key Ta Sy type Ta Sy Description .It Li device Ta Ft char * Ta Corresponding device node .It Li cipher Ta Ft char * Ta Used cipher chain .It Li prf Ta Ft char * Ta Used PBKDF2 PRF algorithm .It Li key_bits Ta Ft int * Ta Number of key bits .It Li size Ta Ft int64_t * Ta Volume size in bytes .It Li iv_offset Ta Ft int64_t * Ta IV Offset of volume in bytes .It Li block_offset Ta Ft int64_t * Ta Block Offset of volume in bytes .El .Pp The second vararg argument must be of the type specified in the above table. The first vararg argument is always the size of the storage provided in the second argument. For a .Ft char * argument, the size corresponds to the size of the buffer at the provided location and must be of type .Ft size_t . For an .Ft int * or .Ft int64_t * argument, it should be the size of the underlying type. .Pp The .Fn tc_api_task_get_error function can be used to get a detailed error message after a failed .Fa tc_api_task_do call. The .Fa task argument is the task used in a previous .Fn tc_api_task_do call. .Sh NOTES TrueCrypt limits passphrases to 64 characters (including the terminating null character). To be compatible with it, .Nm tcplay does the same. All passphrases (exlcuding keyfiles) are trimmed to 64 characters. Similarly, keyfiles are limited to a size of 1 MB, but up to 256 keyfiles can be used. .Sh RETURN VALUES All functions except .Fn tc_api_task_init and .Fn tc_api_task_get_error return either .Dv TC_OK to indicate that the operation completed successfully, or .Dv TC_ERR_UNIMPL to indicate that the operation is not implemented , or .Dv TC_ERR to indicate that any other error occured. .Pp The .Fn tc_api_task_get_error function always return a valid, but possibly empty (or irrelevant, if not called after an error occurred) string. .Pp The .Fn tc_api_task_init function returns .Dv NULL if an error occurred and an opaque .Ft tc_api_task otherwise. .Sh COMPATIBILITY The .Nm tcplay library offers full compatibility with TrueCrypt volumes including hidden volumes, system encryption (map-only), keyfiles and cipher cascading. .Sh SEE ALSO .Xr tcplay 8 , .Xr kpartx 8 .Sh HISTORY The .Nm tcplay library appeared in .Dx 2.11 . .Sh AUTHORS .An Alex Hornung zuluCrypt-6.2.0/external_libraries/tcplay/tcplay.8000066400000000000000000000425031425361753700223200ustar00rootroot00000000000000.\" .\" Copyright (c) 2011 .\" The DragonFly Project. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. Neither the name of The DragonFly Project nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific, prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS .\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE .\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, .\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; .\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED .\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, .\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .Dd December 8, 2013 .Dt TCPLAY 8 .Os .Sh NAME .Nm tcplay .Nd tool to manage TrueCrypt volumes .Sh SYNOPSIS .Nm .Fl c .Fl d Ar device .Op Fl g .Op Fl z .Op Fl w .Op Fl a Ar pbkdf_hash .Op Fl b Ar cipher .Op Fl f Ar keyfile_hidden .Op Fl k Ar keyfile .Op Fl x Ar pbkdf_hash .Op Fl y Ar cipher .Nm .Fl i .Fl d Ar device .Op Fl e .Op Fl p .Op Fl f Ar keyfile_hidden .Op Fl k Ar keyfile .Op Fl s Ar system_device .Op Fl -fde .Op Fl -use-backup .Op Fl -use-hdr-file Ar hdr_file .Op Fl -use-hidden-hdr-file Ar hdr_file .Nm .Fl j Ar mapping .Nm .Fl m Ar mapping .Fl d Ar device .Op Fl e .Op Fl p .Op Fl f Ar keyfile_hidden .Op Fl k Ar keyfile .Op Fl s Ar system_device .Op Fl t .Op Fl -fde .Op Fl -use-backup .Op Fl -use-hdr-file Ar hdr_file .Op Fl -use-hidden-hdr-file Ar hdr_file .Nm .Fl -modify .Fl d Ar device .Op Fl k Ar keyfile .Op Fl -new-keyfile Ar new_keyfile .Op Fl -new-pbkdf-prf Ar pbkdf_hash .Op Fl s Ar system_device .Op Fl -fde .Op Fl -use-backup .Op Fl -use-hdr-file Ar hdr_file .Op Fl -use-hidden-hdr-file Ar hdr_file .Op Fl -save-hdr-backup Ar hdr_file .Op Fl w .Nm .Fl -modify .Fl d Ar device .Op Fl k Ar keyfile .Fl -restore-from-backup-hdr .Op Fl w .Nm .Fl u Ar mapping .Nm .Fl h | v .Sh DESCRIPTION The .Nm utility provides full support for creating and opening/mapping TrueCrypt-compatible volumes. It supports the following commands, each with a set of options detailed further below: .Bl -tag -width indent .It Fl c , Fl -create Create a new encrypted TrueCrypt volume on the device specified by .Fl -device . .It Fl h, Fl -help Print help message and exit. .It Fl i , Fl -info Print out information about the encrypted device specified by .Fl -device . .It Fl j Ar mapping , Fl -info-mapped Ns = Ns Ar mapping Print out information about the mapped tcplay volume specified by .Ar mapping . Information such as key CRC and the PBKDF2 PRF is not available via this command. .It Fl -modify Modify the volume header. This mode allows changing passphrase, keyfiles, PBKDF2 PRF as well as restoring from a backup header. .It Fl m Ar mapping , Fl -map Ns = Ns Ar mapping Map the encrypted TrueCrypt volume on the device specified by .Fl -device as a .Xr dm 4 mapping called .Ar mapping . The .Ar mapping argument should not contain any spaces or special characters. .It Fl u Ar mapping , Fl -unmap Ns = Ns Ar mapping Removes (unmaps) the .Xr dm 4 mapping specified by .Ar mapping as well as any related cascade mappings. If you mapped a volume using full disk encryption and created mapping for individual partitions using .Xr kpartx 8 , you must remove these prior to unmapping the volume. .It Fl v, Fl -version Print version message and exit. .El .Pp Options common to all commands are: .Bl -tag -width indent .It Fl d Ar device , Fl -device Ns = Ns Ar device Specifies the disk .Ar device on which the TrueCrypt volume resides/will reside. This option is mandatory for all commands. .It Fl f Ar keyfile_hidden , Fl -keyfile-hidden Ns = Ns Ar keyfile_hidden Specifies a keyfile to use in addition to the passphrase when either creating a hidden volume or when protecting a hidden volume while mapping or querying the outer volume. If you only intend to map a hidden volume, the .Fl -keyfile option has to be used. This option can appear multiple times; if so, multiple keyfiles will be used. This option is not valid in the .Fl -modify mode. .It Fl k Ar keyfile , Fl -keyfile Ns = Ns Ar keyfile Specifies a .Ar keyfile to use in addition to the passphrase. This option can appear multiple times; if so, multiple keyfiles will be used. .El .Pp Additional options for the .Fl -create command are: .Bl -tag -width indent .It Fl a Ar pbkdf_hash , Fl -pbkdf-prf Ns = Ns Ar pbkdf_hash Specifies which hash algorithm to use for the PBKDF2 password derivation. To see which algorithms are supported, specify .Fl -pbkdf-prf Ns = Ns Cm help . .It Fl b Ar cipher , Fl -cipher Ns = Ns Ar cipher Specifies which cipher algorithm or cascade of ciphers to use to encrypt the new volume. To see which algorithms are supported, specify .Fl -cipher Ns = Ns Cm help . .It Fl g, Fl -hidden Specifies that the newly created volume will contain a hidden volume. The keyfiles applied to the passphrase for the hidden volume are those specified by .Fl -keyfile-hidden . The user will be prompted for the size of the hidden volume interactively. .It Fl w, Fl -weak-keys Use .Xr urandom 4 for key material instead of a strong entropy source. This is in general a really bad idea and should only be used for testing. .It Fl x Ar pbkdf_hash , Fl -pbkdf-prf-hidden Ns = Ns Ar pbkdf_hash Specifies which hash algorithm to use for the PBKDF2 password derivation for the hidden volume. Only valid in conjunction with .Fl -hidden . If no algorithm is specified, the same as for the outer volume will be used. To see which algorithms are supported, specify .Fl -pbkdf-prf-hidden Ns = Ns Cm help . .It Fl y Ar cipher , Fl -cipher-hidden Ns = Ns Ar cipher Specifies which cipher algorithm or cascade of ciphers to use to encrypt the hidden volume on the new TrueCrypt volume. Only valid in conjunction with .Fl -hidden . If no cipher is specified, the same as for the outer volume will be used. To see which algorithms are supported, specify .Fl -cipher-hidden Ns = Ns Cm help . .It Fl z, Fl -insecure-erase Skips the secure erase of the disk. Use this option carefully as it is a security risk! .El .Pp Additional options for the .Fl -info , .Fl -map and .Fl -modify commands are: .Bl -tag -width indent .It Fl e, Fl -protect-hidden Specifies that an outer volume will be queried or mapped, but its reported size will be adjusted accordingly to the size of the hidden volume contained in it. Both the hidden volume and outer volume passphrase and keyfiles will be required. This option only applies to the .Fl -info and .Fl -map commands. .It Fl p, Fl -prompt-passphrase This option causes .Nm to prompt for a passphrase immediately, even if a keyfile is provided. Normally, if a keyfile is supplied, .Nm will first attempt to unlock the volume using only the keyfile, and only prompt for a passphrase if that first unlocking attempt fails. However, since a failed unlocking attempt can take a non-trivial amount of time, specifying this option can reduce the total unlocking time if both a keyfile and passphrase are required. This option only makes sense if .Fl k or .Fl f are used. .It Fl s Ar system_device , Fl -system-encryption Ns = Ns Ar system_device This option is required if you are attempting to access a device that uses system encryption, for example an encrypted .Tn Windows system partition. It does not apply to disks using full disk encryption. The .Fl -device option will point at the actual encrypted partition, while the .Ar system_device argument will point to the parent device (i.e.\& underlying physical disk) of the encrypted partition. .It Fl -fde This option is intended to be used with disks using full disk encryption (FDE). When a disk has been encrypted using TrueCrypt's FDE, the complete disk is encrypted except for the first 63 sectors. The .Fl -device option should point to the whole disk device, not to any particular partition. The resultant mapping will cover the whole disk, and will not appear as separate partitions. To access individual partitions after mapping, .Xr kpartx 8 can be used. .It Fl -use-backup This option is intended to be used when the primary headers of a volume have been corrupted. This option will force .Nm to use the backup headers, which are located at the end of the device, to access the volume. .El .Pp Additional options only for the .Fl -map command are: .Bl -tag -width indent .It Fl t , Fl -allow-trim This option enables TRIM (discard) support on the mapped volume. .El .Pp Additional options only for the .Fl -modify command are: .Bl -tag -width indent .It Fl -new-pbkdf-prf Ns = Ns Ar pbkdf_hash Specifies which hash algorithm to use for the PBKDF2 password derivation on reencrypting the volume header. If this option is not specified, the reencrypted header will use the current PRF. To see which algorithms are supported, specify .Fl -pbkdf-prf Ns = Ns Cm help . .It Fl -new-keyfile Ns = Ns Ar keyfile Specifies a .Ar keyfile to use in addition to the new passphrase on reencrypting the volume header. This option can appear multiple times; if so, multiple keyfiles will be used. .It Fl -restore-from-backup-hdr If this option is specified, neither .Fl -new-pbkdf-prf nor .Fl -new-keyfile should be specified. This option implies .Fl -use-backup . Use this option to restore the volume headers from the backup header. .El .Pp Sending a .Dv SIGINFO or .Dv SIGUSR1 signal to a running .Nm process makes it print progress on slower tasks such as gathering entropy or wiping the volume. .Sh NOTES TrueCrypt limits passphrases to 64 characters (including the terminating null character). To be compatible with it, .Nm does the same. All passphrases (excluding keyfiles) are trimmed to 64 characters. Similarly, keyfiles are limited to a size of 1 MB, but up to 256 keyfiles can be used. .Sh PLAUSIBLE DENIABILITY .Nm offers plausible deniability. Hidden volumes are created within an outer volume. Which volume is accessed solely depends on the passphrase and keyfile(s) used. If the passphrase and keyfiles for the outer volume are specified, no information about the existance of the hidden volume is exposed. Without knowledge of the passphrase and keyfile(s) of the hidden volume its existence remains unexposed. The hidden volume can be protected when mapping the outer volume by using the .Fl -protect-hidden option and specifying the passphrase and keyfiles for both the outer and hidden volumes. .Sh VERACRYPT SUPPORT .Nm offers both legacy TrueCrypt as well as VeraCrypt support. When creating a new volume, the selected PBKDF2 PRF determines whether the volume will use the TrueCrypt or VeraCrypt format. The formats are identical other than the rounds of the key derivation functions as well as the volume signature and minver fields in the header. Converting volumes from one format or another using .Nm is simply a matter of using the .Fl -modify option specifying a PBKDF2 PRF hash matching the intended target format with the .Fl -new-pbkdf-prf argument. .Pp PBKDF2 PRFs suffixed with .Dv -VC are VeraCrypt PRFs, whilst all others are legacy TrueCrypt PRFs. By default, new volumes are created with a VeraCrypt PRF to offer better security. .Pp NOTE: Failed unlocking attempts even for legacy TrueCrypt volumes now take significantly longer than before, as .Nm will cycle through all PRFs, including the VeraCrypt PRFs with much higher number of PRF iterations. Successful attempts should still take the same amount of time as before, as the legacy PRF settings are tried first. One notable exception is if both a keyfile and a passphrase is required. Normally, .Nm would first attempt an unlock attempt with just the keyfile, and only prompt for a passphrase after that attempt failed. If it is known in advance that both a keyfile and passphrase are required to unlock a volume, the .Fl p option to .Fl -info and .Fl -map can more than halve the time required to unlock the volume. .Sh EXAMPLES Create a new TrueCrypt volume on .Pa /dev/vn0 using the cipher cascade of AES and Twofish and the Whirlpool hash algorithm for PBKDF2 password derivation and two keyfiles, .Pa one.key and .Pa two.key : .Bd -ragged -offset indent .Nm Fl -create .Fl -device Ns = Ns Cm /dev/vn0 .Fl -cipher Ns = Ns Cm TWOFISH-256-XTS,AES-256-XTS .Fl -pbkdf-prf Ns = Ns Cm whirlpool .Fl -keyfile Ns = Ns Cm one.key .Fl -keyfile Ns = Ns Cm two.key .Ed .Pp Map the outer volume on the TrueCrypt volume on .Pa /dev/vn0 as .Sy truecrypt1 , but protect the hidden volume, using the keyfile .Pa hidden.key , from being overwritten: .Bd -ragged -offset indent .Nm Fl -map Ns = Ns Cm truecrypt1 .Fl -device Ns = Ns Cm /dev/vn0 .Fl -protect-hidden .Fl -keyfile-hidden Ns = Ns Cm hidden.key .Ed .Pp Map the hidden volume on the TrueCrypt volume on .Pa /dev/vn0 as .Sy truecrypt2 , using the keyfile .Pa hidden.key : .Bd -ragged -offset indent .Nm Fl -map Ns = Ns Cm truecrypt2 .Fl -device Ns = Ns Cm /dev/vn0 .Fl -keyfile Ns = Ns Cm hidden.key .Ed .Pp Map and mount the volume in the file .Pa secvol on Linux: .Bd -ragged -offset indent .Sy losetup Cm /dev/loop1 Cm secvol .Ed .Bd -ragged -offset indent .Nm Fl -map Ns = Ns Cm secv .Fl -device Ns = Ns Cm /dev/loop1 .Ed .Bd -ragged -offset indent .Sy mount Cm /dev/mapper/secv Cm /mnt .Ed .Pp Similarly on .Dx : .Bd -ragged -offset indent .Sy vnconfig Cm vn1 Cm secvol .Ed .Bd -ragged -offset indent .Nm Fl -map Ns = Ns Cm secv .Fl -device Ns = Ns Cm /dev/vn1 .Ed .Bd -ragged -offset indent .Sy mount Cm /dev/mapper/secv Cm /mnt .Ed .Pp Unmapping the volume .Sy truecrypt2 on both Linux and .Dx after unmounting: .Bd -ragged -offset indent .Sy dmsetup Cm remove Cm truecrypt2 .Ed .Pp Or alternatively: .Bd -ragged -offset indent .Nm Fl -unmap Ns = Ns Cm truecrypt2 .Ed .Pp A hidden volume whose existance can be plausibly denied and its outer volume can for example be created with .Bd -ragged -offset indent .Nm Fl -create .Fl -hidden .Fl -device Ns = Ns Cm /dev/loop0 .Fl -cipher Ns = Ns Cm TWOFISH-256-XTS,AES-256-XTS .Fl -pbkdf-prf Ns = Ns Cm whirlpool .Fl -keyfile Ns = Ns Cm one.key .Fl -cipher-hidden Ns = Ns Cm AES-256-XTS .Fl -pbkdf-prf-hidden Ns = Ns Cm whirlpool .Fl -keyfile-hidden Ns = Ns Cm hidden.key .Ed .Pp .Nm will prompt the user for the passphrase for both the outer and hidden volume as well as the size of the hidden volume inside the outer volume. The hidden volume will be created inside the area spanned by the outer volume. The hidden volume can optionally use a different cipher and prf function as specified by the .Fl -cipher-hidden and .Fl -pbkdf-prf-hidden options. Which volume is later accessed depends only on which passphrase and keyfile(s) are being used, so that the existance of the hidden volume remains unknown without knowledge of the passphrase and keyfile it is protected by since it is located within the outer volume. To map the outer volume without potentially damaging the hidden volume, the passphrase and keyfile(s) of the hidden volume must be known and provided alongside the .Fl -protect-hidden option. .Pp A disk encrypted using full disk encryption can be mapped using .Bd -ragged -offset indent .Nm Fl -map Ns = Ns Cm tcplay_sdb .Fl -device Ns = Ns Cm /dev/sdb .Fl -fde .Ed .Pp To access individual partitions on the now mapped disk, the following command will generate mappings for each individual partition on the encrypted disk: .Bd -ragged -offset indent .Sy kpartx Fl -av Cm /dev/mapper/tcplay_sdb .Ed .Pp To restore the main volume header from the backup header, the following command can be used: .Bd -ragged -offset indent .Nm Fl -modify .Fl -device Ns = Ns Cm /dev/sdb .Fl -restore-from-backup-hdr .Ed .Pp As with most other commands, which header is saved (used as source) depends on the passphrase and keyfiles used. .Pp To save a backup copy of a header, the following command can be used: .Bd -ragged -offset indent .Nm Fl -modify .Fl -device Ns = Ns Cm /dev/sdb .Fl -save-hdr-backup Ns = Ns Cm /tmp/sdb_backup_header.hdr .Ed .Pp As with most other commands, which header is saved (used as source) depends on the passphrase and keyfiles used. .Pp To restore a header from a backup header file, the following command can be used: .Bd -ragged -offset indent .Nm Fl -modify .Nm -use-hdr-file Ns = Ns Cm /tmp/sdb_backup_header.hdr .Ed .Pp Similarly, to restore a hidden header from a backup header file: .Bd -ragged -offset indent .Nm Fl -modify .Nm -use-hidden-hdr-file Ns = Ns Cm /tmp/sdb_backup_hidden_header.hdr .Ed .Pp Which header is used as the source of the operation will still depend on the passphrase and keyfiles used. Even if you use the .Fl -use-hidden-hdr-file option, if you specify the passphrase and keyfiles for the main header, the main header will be used instead. .Sh SEE ALSO .Xr crypttab 5 , .Xr cryptsetup 8 , .Xr dmsetup 8 , .Xr kpartx 8 .Sh HISTORY The .Nm utility appeared in .Dx 2.11 . .Sh AUTHORS .An Alex Hornung zuluCrypt-6.2.0/external_libraries/tcplay/tcplay.c000066400000000000000000001444121425361753700223750ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define _BSD_SOURCE #include #include #if defined(__DragonFly__) #include #endif #include #include #include #include #include #include #include #include #include #if defined(__linux__) #include #include #elif defined(__DragonFly__) #include #include #endif #include #include "crc32.h" #include "tcplay.h" #include "humanize.h" /* XXX TODO: * - LRW-benbi support? needs further work in dm-crypt and even opencrypto * - secure buffer review (i.e: is everything that needs it using secure mem?) * - mlockall? (at least MCL_FUTURE, which is the only one we support) */ summary_fn_t summary_fn = NULL; int tc_internal_verbose = 1; char tc_internal_log_buffer[LOG_BUFFER_SZ]; int tc_internal_state = STATE_UNKNOWN; extern int zuluCryptIterationCount ; int zuluCryptIterationCount = 0 ; void tc_log(int is_err, const char *fmt, ...) { va_list ap; FILE *fp; if (is_err) fp = stderr; else fp = stdout; va_start(ap, fmt); vsnprintf(tc_internal_log_buffer, LOG_BUFFER_SZ, fmt, ap); va_end(ap); if (tc_internal_verbose) fprintf(fp, "%s", tc_internal_log_buffer); } /* Supported algorithms */ struct pbkdf_prf_algo pbkdf_prf_algos[] = { { "RIPEMD160", "RIPEMD160", 2000, TC_SIG, 0}, { "RIPEMD160", "RIPEMD160", 1000, TC_SIG, 1}, { "SHA512", "SHA512", 1000, TC_SIG, 0}, { "whirlpool", "whirlpool", 1000, TC_SIG, 0}, { "RIPEMD160-VC", "RIPEMD160", 655331, VC_SIG, 0}, { "RIPEMD160-VC", "RIPEMD160", 327661, VC_SIG, 1}, { "SHA512-VC", "SHA512", 500000, VC_SIG, 0}, { "whirlpool-VC", "whirlpool", 500000, VC_SIG, 0}, { "SHA256-VC", "SHA256", 500000, VC_SIG, 0}, { "SHA256-VC", "SHA256", 200000, VC_SIG, 1}, { NULL, NULL, 0, NULL, 0} }; struct tc_crypto_algo tc_crypto_algos[] = { #if 0 /* XXX: turns out TC doesn't support AES-128-XTS */ { "AES-128-XTS", "aes-xts-plain", 32, 8 }, { "TWOFISH-128-XTS", "twofish-xts-plain", 32, 8 }, { "SERPENT-128-XTS", "serpent-xts-plain", 32, 8 }, #endif { "AES-256-XTS", "aes-xts-plain64", 64, 8 }, { "TWOFISH-256-XTS", "twofish-xts-plain64", 64, 8 }, { "SERPENT-256-XTS", "serpent-xts-plain64", 64, 8 }, { NULL, NULL, 0, 0 } }; const char *valid_cipher_chains[][MAX_CIPHER_CHAINS] = { { "AES-256-XTS", NULL }, { "TWOFISH-256-XTS", NULL }, { "SERPENT-256-XTS", NULL }, { "AES-256-XTS", "TWOFISH-256-XTS", "SERPENT-256-XTS", NULL }, { "SERPENT-256-XTS", "TWOFISH-256-XTS", "AES-256-XTS", NULL }, #if 0 /* It seems that all the two-way cascades are the other way round... */ { "AES-256-XTS", "TWOFISH-256-XTS", NULL }, { "SERPENT-256-XTS", "AES-256-XTS", NULL }, { "TWOFISH-256-XTS", "SERPENT-256-XTS", NULL }, #endif { "TWOFISH-256-XTS", "AES-256-XTS", NULL }, { "AES-256-XTS", "SERPENT-256-XTS", NULL }, { "SERPENT-256-XTS", "TWOFISH-256-XTS", NULL }, { NULL } }; struct tc_cipher_chain *tc_cipher_chains[MAX_CIPHER_CHAINS]; static int tc_build_cipher_chains(void) { struct tc_cipher_chain *chain, *elem, *prev; int i = 0; int k; while (valid_cipher_chains[i][0] != NULL) { chain = NULL; prev = NULL; k = 0; while (valid_cipher_chains[i][k] != NULL) { if ((elem = alloc_safe_mem(sizeof(*elem))) == NULL) { tc_log(1, "Error allocating memory for " "cipher chain\n"); return -1; } /* Initialize first element of chain */ if (chain == NULL) { chain = elem; elem->prev = NULL; } /* Populate previous element */ if (prev != NULL) { prev->next = elem; elem->prev = prev; } /* Assume we are the last element in the chain */ elem->next = NULL; /* Initialize other fields */ elem->cipher = check_cipher(valid_cipher_chains[i][k], 0); if (elem->cipher == NULL) return -1; elem->key = NULL; prev = elem; ++k; } /* Store cipher chain */ tc_cipher_chains[i++] = chain; /* Integrity check */ if (i >= MAX_CIPHER_CHAINS) { tc_log(1, "FATAL: tc_cipher_chains is full!!\n"); return -1; } /* Make sure array is NULL terminated */ tc_cipher_chains[i] = NULL; } return 0; } static struct tc_cipher_chain * tc_dup_cipher_chain(struct tc_cipher_chain *src) { struct tc_cipher_chain *first = NULL, *prev = NULL, *elem; for (; src != NULL; src = src->next) { if ((elem = alloc_safe_mem(sizeof(*elem))) == NULL) { tc_log(1, "Error allocating memory for " "duplicate cipher chain\n"); return NULL; } memcpy(elem, src, sizeof(*elem)); if (src->key != NULL) { if ((elem->key = alloc_safe_mem(src->cipher->klen)) == NULL) { tc_log(1, "Error allocating memory for " "duplicate key in cipher chain\n"); return NULL; } memcpy(elem->key, src->key, src->cipher->klen); } if (first == NULL) first = elem; elem->next = NULL; elem->prev = prev; if (prev != NULL) prev->next = elem; prev = elem; } return first; } static int tc_free_cipher_chain(struct tc_cipher_chain *chain) { struct tc_cipher_chain *next = chain; while ((chain = next) != NULL) { next = chain->next; if (chain->key != NULL) free_safe_mem(chain->key); free_safe_mem(chain); } return 0; } int tc_cipher_chain_length(struct tc_cipher_chain *chain) { int len = 0; for (; chain != NULL; chain = chain->next) ++len; return len; } int tc_cipher_chain_klen(struct tc_cipher_chain *chain) { int klen_bytes = 0; for (; chain != NULL; chain = chain->next) { klen_bytes += chain->cipher->klen; } return klen_bytes; } char * tc_cipher_chain_sprint(char *buf, size_t bufsz, struct tc_cipher_chain *chain) { static char sbuf[256]; int n = 0; if (buf == NULL) { buf = sbuf; bufsz = sizeof(sbuf); } for (; chain != NULL; chain = chain->next) { n += snprintf(buf+n, bufsz-n, "%s%s", chain->cipher->name, (chain->next != NULL) ? "," : "\0"); } return buf; } #ifdef DEBUG static void print_hex(unsigned char *buf, off_t start, size_t len) { size_t i; for (i = start; i < start+len; i++) printf("%02x", buf[i]); printf("\n"); } #endif void print_info(struct tcplay_info *info) { printf("Device:\t\t\t%s\n", info->dev); if (info->pbkdf_prf != NULL) { printf("PBKDF2 PRF:\t\t%s\n", info->pbkdf_prf->name); printf("PBKDF2 iterations:\t%d\n", info->pbkdf_prf->iteration_count); } printf("Cipher:\t\t\t%s\n", tc_cipher_chain_sprint(NULL, 0, info->cipher_chain)); printf("Key Length:\t\t%d bits\n", 8*tc_cipher_chain_klen(info->cipher_chain)); if (info->hdr != NULL) { printf("CRC Key Data:\t\t%#x\n", info->hdr->crc_keys); printf("Sector size:\t\t%d\n", info->hdr->sec_sz); printf("Signature:\t\t%c%c%c%c\n", info->hdr->tc_str[0], info->hdr->tc_str[1], info->hdr->tc_str[2], info->hdr->tc_str[3]); } else { printf("Sector size:\t\t512\n"); } printf("Volume size:\t\t%"DISKSZ_FMT" sectors\n", info->size); #if 0 /* Don't print this; it's always 0 and is rather confusing */ printf("Volume offset:\t\t%"PRIu64"\n", (uint64_t)info->start); #endif #ifdef DEBUG printf("Vol Flags:\t\t%d\n", info->volflags); #endif printf("IV offset:\t\t%"PRIu64" sectors\n", (uint64_t)info->skip); printf("Block offset:\t\t%"PRIu64" sectors\n", (uint64_t)info->offset); } static struct tcplay_info * new_info(const char *dev, int flags, struct tc_cipher_chain *cipher_chain, struct pbkdf_prf_algo *prf, struct tchdr_dec *hdr, off_t start) { struct tc_cipher_chain *chain_start; struct tcplay_info *info; int i; int error; chain_start = cipher_chain; if ((info = (struct tcplay_info *)alloc_safe_mem(sizeof(*info))) == NULL) { tc_log(1, "could not allocate safe info memory\n"); return NULL; } strncpy(info->dev, dev, sizeof(info->dev)); info->cipher_chain = cipher_chain; info->pbkdf_prf = prf; info->start = start; info->hdr = hdr; info->blk_sz = hdr->sec_sz; info->size = hdr->sz_mk_scope / hdr->sec_sz; /* volume size */ info->skip = hdr->off_mk_scope / hdr->sec_sz; /* iv skip */ info->volflags = hdr->flags; info->flags = flags; if (TC_FLAG_SET(flags, SYS)) info->offset = 0; /* offset is 0 for system volumes */ else info->offset = hdr->off_mk_scope / hdr->sec_sz; /* block offset */ /* Associate a key out of the key pool with each cipher in the chain */ error = tc_cipher_chain_populate_keys(cipher_chain, hdr->keys); if (error) { tc_log(1, "could not populate keys in cipher chain\n"); return NULL; } for (; cipher_chain != NULL; cipher_chain = cipher_chain->next) { for (i = 0; i < cipher_chain->cipher->klen; i++) sprintf(&cipher_chain->dm_key[i*2], "%02x", cipher_chain->key[i]); } tc_cipher_chain_free_keys(chain_start); return info; } int free_info(struct tcplay_info *info) { if (info->cipher_chain) tc_free_cipher_chain(info->cipher_chain); if (info->hdr) free_safe_mem(info->hdr); free_safe_mem(info); return 0; } int adjust_info(struct tcplay_info *info, struct tcplay_info *hinfo) { if (hinfo->hdr->sz_hidvol == 0) return 1; info->size -= hinfo->hdr->sz_hidvol / hinfo->hdr->sec_sz; return 0; } int process_hdr(const char *dev, int iteration_count,int flags, unsigned char *pass, int passlen, struct tchdr_enc *ehdr, struct tcplay_info **pinfo) { struct tchdr_dec *dhdr; struct tcplay_info *info; struct tc_cipher_chain *cipher_chain = NULL; unsigned char *key; int i, j, found, error; *pinfo = NULL; if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) { tc_log(1, "could not allocate safe key memory\n"); return ENOMEM; } /* Start search for correct algorithm combination */ found = 0; for (i = 0; !found && pbkdf_prf_algos[i].name != NULL; i++) { #ifdef DEBUG printf("\nTrying PRF algo %s (%d)\n", pbkdf_prf_algos[i].name, pbkdf_prf_algos[i].iteration_count); printf("Salt: "); print_hex(ehdr->salt, 0, sizeof(ehdr->salt)); #endif error = pbkdf2(&pbkdf_prf_algos[i], (char *)pass, passlen, ehdr->salt, sizeof(ehdr->salt), MAX_KEYSZ, iteration_count,key); if (error) { tc_log(1, "pbkdf failed for algorithm %s\n", pbkdf_prf_algos[i].name); free_safe_mem(key); return EINVAL; } #if 0 printf("Derived Key: "); print_hex(key, 0, MAX_KEYSZ); #endif for (j = 0; !found && tc_cipher_chains[j] != NULL; j++) { cipher_chain = tc_dup_cipher_chain(tc_cipher_chains[j]); #ifdef DEBUG printf("\nTrying cipher chain %d\n", j); #endif dhdr = decrypt_hdr(ehdr, cipher_chain, key); if (dhdr == NULL) { tc_log(1, "hdr decryption failed for cipher " "chain %d\n", j); free_safe_mem(key); return EINVAL; } if (verify_hdr(dhdr, &pbkdf_prf_algos[i])) { #ifdef DEBUG printf("tc_str: %.4s, tc_ver: %d, tc_min_ver: %d, " "crc_keys: %d, sz_vol: %"PRIu64", " "off_mk_scope: %"PRIu64", sz_mk_scope: %"PRIu64", " "flags: %d, sec_sz: %d crc_dhdr: %d\n", dhdr->tc_str, dhdr->tc_ver, dhdr->tc_min_ver, dhdr->crc_keys, dhdr->sz_vol, dhdr->off_mk_scope, dhdr->sz_mk_scope, dhdr->flags, dhdr->sec_sz, dhdr->crc_dhdr); #endif found = 1; } else { free_safe_mem(dhdr); tc_free_cipher_chain(cipher_chain); } } } free_safe_mem(key); if (!found) return EINVAL; if ((info = new_info(dev, flags, cipher_chain, &pbkdf_prf_algos[i-1], dhdr, 0)) == NULL) { free_safe_mem(dhdr); return ENOMEM; } *pinfo = info; return 0; } int create_volume(struct tcplay_opts *opts) { char *pass, *pass_again; char *h_pass = NULL; char buf[1024]; disksz_t blocks, hidden_blocks = 0; size_t blksz; struct tchdr_enc *ehdr, *hehdr; struct tchdr_enc *ehdr_backup, *hehdr_backup; uint64_t tmp; int error, r, ret; pass = h_pass = pass_again = NULL; ehdr = hehdr = NULL; ehdr_backup = hehdr_backup = NULL; ret = -1; /* Default to returning error */ if (opts->cipher_chain == NULL) opts->cipher_chain = tc_cipher_chains[0]; if (opts->prf_algo == NULL) opts->prf_algo = &pbkdf_prf_algos[DEFAULT_PRF_ALGO_IDX]; if (opts->h_cipher_chain == NULL) opts->h_cipher_chain = opts->cipher_chain; if (opts->h_prf_algo == NULL) opts->h_prf_algo = opts->prf_algo; if ((error = get_disk_info(opts->dev, &blocks, &blksz)) != 0) { tc_log(1, "could not get disk info\n"); return -1; } if ((blocks*blksz) <= MIN_VOL_BYTES) { tc_log(1, "Cannot create volumes on devices with less " "than %d bytes\n", MIN_VOL_BYTES); return -1; } if (opts->interactive) { if (((pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) || ((pass_again = alloc_safe_mem(PASS_BUFSZ)) == NULL)) { tc_log(1, "could not allocate safe passphrase memory\n"); goto out; } if ((error = read_passphrase("Passphrase: ", pass, MAX_PASSSZ, PASS_BUFSZ, 0) || (read_passphrase("Repeat passphrase: ", pass_again, MAX_PASSSZ, PASS_BUFSZ, 0)))) { tc_log(1, "could not read passphrase\n"); goto out; } if (strcmp(pass, pass_again) != 0) { tc_log(1, "Passphrases don't match\n"); goto out; } free_safe_mem(pass_again); pass_again = NULL; } else { /* In batch mode, use provided passphrase */ if ((pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) { tc_log(1, "could not allocate safe " "passphrase memory"); goto out; } if (opts->passphrase != NULL) { strncpy(pass, opts->passphrase, MAX_PASSSZ); pass[MAX_PASSSZ] = '\0'; } } if (opts->nkeyfiles > 0) { /* Apply keyfiles to 'pass' */ if ((error = apply_keyfiles((unsigned char *)pass, PASS_BUFSZ, opts->keyfiles, opts->nkeyfiles))) { tc_log(1, "could not apply keyfiles\n"); goto out; } } if (opts->hidden) { if (opts->interactive) { if (((h_pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) || ((pass_again = alloc_safe_mem(PASS_BUFSZ)) == NULL)) { tc_log(1, "could not allocate safe " "passphrase memory\n"); goto out; } if ((error = read_passphrase("Passphrase for hidden volume: ", h_pass, MAX_PASSSZ, PASS_BUFSZ, 0) || (read_passphrase("Repeat passphrase: ", pass_again, MAX_PASSSZ, PASS_BUFSZ, 0)))) { tc_log(1, "could not read passphrase\n"); goto out; } if (strcmp(h_pass, pass_again) != 0) { tc_log(1, "Passphrases for hidden volume don't " "match\n"); goto out; } free_safe_mem(pass_again); pass_again = NULL; } else { /* In batch mode, use provided passphrase */ if ((h_pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) { tc_log(1, "could not allocate safe " "passphrase memory"); goto out; } if (opts->h_passphrase != NULL) { strncpy(h_pass, opts->h_passphrase, MAX_PASSSZ); h_pass[MAX_PASSSZ] = '\0'; } } if (opts->n_hkeyfiles > 0) { /* Apply keyfiles to 'h_pass' */ if ((error = apply_keyfiles((unsigned char *)h_pass, PASS_BUFSZ, opts->h_keyfiles, opts->n_hkeyfiles))) { tc_log(1, "could not apply keyfiles\n"); goto out; } } if (opts->interactive) { hidden_blocks = 0; } else { hidden_blocks = opts->hidden_size_bytes/blksz; if (hidden_blocks == 0) { tc_log(1, "hidden_blocks to create volume " "cannot be zero!\n"); goto out; } if (opts->hidden_size_bytes >= (blocks*blksz) - MIN_VOL_BYTES) { tc_log(1, "Hidden volume needs to be " "smaller than the outer volume\n"); goto out; } } /* This only happens in interactive mode */ while (hidden_blocks == 0) { if ((r = _humanize_number(buf, sizeof(buf), (uint64_t)(blocks * blksz))) < 0) { sprintf(buf, "%"DISKSZ_FMT" bytes", (blocks * blksz)); } printf("The total volume size of %s is %s (bytes)\n", opts->dev, buf); memset(buf, 0, sizeof(buf)); printf("Size of hidden volume (e.g. 127M): "); fflush(stdout); if ((fgets(buf, sizeof(buf), stdin)) == NULL) { tc_log(1, "Could not read from stdin\n"); goto out; } /* get rid of trailing newline */ buf[strlen(buf)-1] = '\0'; if ((error = _dehumanize_number(buf, &tmp)) != 0) { tc_log(1, "Could not interpret input: %s\n", buf); continue; } if (tmp >= (blocks*blksz) - MIN_VOL_BYTES) { tc_log(1, "Hidden volume needs to be " "smaller than the outer volume\n"); hidden_blocks = 0; continue; } hidden_blocks = (size_t)tmp; hidden_blocks /= blksz; } } if (opts->interactive) { /* Show summary and ask for confirmation */ printf("Summary of actions:\n"); if (opts->secure_erase) printf(" - Completely erase *EVERYTHING* on %s\n", opts->dev); printf(" - Create %svolume on %s\n", opts->hidden?("outer "):"", opts->dev); if (opts->hidden) { printf(" - Create hidden volume of %"DISKSZ_FMT" bytes at end of " "outer volume\n", hidden_blocks * blksz); } printf("\n Are you sure you want to proceed? (y/n) "); fflush(stdout); if ((fgets(buf, sizeof(buf), stdin)) == NULL) { tc_log(1, "Could not read from stdin\n"); goto out; } if ((buf[0] != 'y') && (buf[0] != 'Y')) { tc_log(1, "User cancelled action(s)\n"); goto out; } } /* erase volume */ if (opts->secure_erase) { tc_log(0, "Securely erasing the volume...\nThis process may take " "some time depending on the size of the volume\n"); if (opts->state_change_fn) opts->state_change_fn(opts->api_ctx, "secure_erase", 1); if ((error = secure_erase(opts->dev, blocks * blksz, blksz)) != 0) { tc_log(1, "could not securely erase device %s\n", opts->dev); goto out; } if (opts->state_change_fn) opts->state_change_fn(opts->api_ctx, "secure_erase", 0); } tc_log(0, "Creating volume headers...\nDepending on your system, this " "process may take a few minutes as it uses true random data which " "might take a while to refill\n"); if (opts->weak_keys_and_salt) { tc_log(0, "WARNING: Using a weak random generator to get " "entropy for the key material. Odds are this is NOT " "what you want.\n"); } if (opts->state_change_fn) opts->state_change_fn(opts->api_ctx, "create_header", 1); /* create encrypted headers */ ehdr = create_hdr(opts->iteration_count, (unsigned char *)pass, (opts->nkeyfiles > 0)?MAX_PASSSZ:strlen(pass), opts->prf_algo, opts->cipher_chain, blksz, blocks, VOL_RSVD_BYTES_START/blksz, blocks - (MIN_VOL_BYTES/blksz), 0, opts->weak_keys_and_salt, &ehdr_backup); if (ehdr == NULL) { tc_log(1, "Could not create header\n"); goto out; } if (opts->hidden) { hehdr = create_hdr(opts->iteration_count, (unsigned char *)h_pass, (opts->n_hkeyfiles > 0)?MAX_PASSSZ:strlen(h_pass), opts->h_prf_algo, opts->h_cipher_chain, blksz, blocks, blocks - (VOL_RSVD_BYTES_END/blksz) - hidden_blocks, hidden_blocks, 1, opts->weak_keys_and_salt, &hehdr_backup); if (hehdr == NULL) { tc_log(1, "Could not create hidden volume header\n"); goto out; } } if (opts->state_change_fn) opts->state_change_fn(opts->api_ctx, "create_header", 0); tc_log(0, "Writing volume headers to disk...\n"); if ((error = write_to_disk(opts->dev, 0, blksz, ehdr, sizeof(*ehdr))) != 0) { tc_log(1, "Could not write volume header to device\n"); goto out; } /* Write backup header; it's offset is relative to the end */ if ((error = write_to_disk(opts->dev, (blocks*blksz - BACKUP_HDR_OFFSET_END), blksz, ehdr_backup, sizeof(*ehdr_backup))) != 0) { tc_log(1, "Could not write backup volume header to device\n"); goto out; } if (opts->hidden) { if ((error = write_to_disk(opts->dev, HDR_OFFSET_HIDDEN, blksz, hehdr, sizeof(*hehdr))) != 0) { tc_log(1, "Could not write hidden volume header to " "device\n"); goto out; } /* Write backup hidden header; offset is relative to end */ if ((error = write_to_disk(opts->dev, (blocks*blksz - BACKUP_HDR_HIDDEN_OFFSET_END), blksz, hehdr_backup, sizeof(*hehdr_backup))) != 0) { tc_log(1, "Could not write backup hidden volume " "header to device\n"); goto out; } } /* Everything went ok */ tc_log(0, "All done!\n"); ret = 0; out: if (pass) free_safe_mem(pass); if (h_pass) free_safe_mem(h_pass); if (pass_again) free_safe_mem(pass_again); if (ehdr) free_safe_mem(ehdr); if (hehdr) free_safe_mem(hehdr); if (ehdr_backup) free_safe_mem(ehdr_backup); if (hehdr_backup) free_safe_mem(hehdr_backup); return ret; } struct tcplay_info * info_map_common(struct tcplay_opts *opts, char *passphrase_out) { struct tchdr_enc *ehdr, *hehdr = NULL; struct tcplay_info *info, *hinfo = NULL; char *pass; char *h_pass; int error, error2 = 0; size_t sz; size_t blksz; disksz_t blocks; int is_hidden = 0; int try_empty = 0; int retries; if ((error = get_disk_info(opts->dev, &blocks, &blksz)) != 0) { tc_log(1, "could not get disk information\n"); return NULL; } if (opts->retries < 1) retries = 1; else retries = opts->retries; /* * Add one retry so we can do a first try without asking for * a password if keyfiles are passed in. */ if (opts->interactive && !opts->prompt_passphrase && (opts->nkeyfiles > 0)) { try_empty = 1; ++retries; } info = NULL; ehdr = NULL; pass = h_pass = NULL; while ((info == NULL) && retries-- > 0) { pass = h_pass = NULL; ehdr = hehdr = NULL; info = hinfo = NULL; if ((pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) { tc_log(1, "could not allocate safe passphrase memory\n"); goto out; } if (try_empty) { pass[0] = '\0'; } else if (opts->interactive) { if ((error = read_passphrase("Passphrase: ", pass, MAX_PASSSZ, PASS_BUFSZ, opts->timeout))) { tc_log(1, "could not read passphrase\n"); /* XXX: handle timeout differently? */ goto out; } pass[MAX_PASSSZ] = '\0'; } else { /* In batch mode, use provided passphrase */ if (opts->passphrase != NULL) { strncpy(pass, opts->passphrase, MAX_PASSSZ); pass[MAX_PASSSZ] = '\0'; } } if (passphrase_out != NULL) { strcpy(passphrase_out, pass); } if (opts->nkeyfiles > 0) { /* Apply keyfiles to 'pass' */ if ((error = apply_keyfiles((unsigned char *)pass, PASS_BUFSZ, opts->keyfiles, opts->nkeyfiles))) { tc_log(1, "could not apply keyfiles"); goto out; } } if (opts->protect_hidden) { if ((h_pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) { tc_log(1, "could not allocate safe passphrase memory\n"); goto out; } if (opts->interactive) { if ((error = read_passphrase( "Passphrase for hidden volume: ", h_pass, MAX_PASSSZ, PASS_BUFSZ, opts->timeout))) { tc_log(1, "could not read passphrase\n"); goto out; } h_pass[MAX_PASSSZ] = '\0'; } else { /* In batch mode, use provided passphrase */ if (opts->h_passphrase != NULL) { strncpy(h_pass, opts->h_passphrase, MAX_PASSSZ); h_pass[MAX_PASSSZ] = '\0'; } } if (opts->n_hkeyfiles > 0) { /* Apply keyfiles to 'pass' */ if ((error = apply_keyfiles((unsigned char *)h_pass, PASS_BUFSZ, opts->h_keyfiles, opts->n_hkeyfiles))) { tc_log(1, "could not apply keyfiles"); goto out; } } } /* Always read blksz-sized chunks */ sz = blksz; if (TC_FLAG_SET(opts->flags, HDR_FROM_FILE)) { ehdr = (struct tchdr_enc *)read_to_safe_mem( opts->hdr_file_in, 0, &sz); if (ehdr == NULL) { tc_log(1, "error read hdr_enc: %s", opts->hdr_file_in); goto out; } } else { ehdr = (struct tchdr_enc *)read_to_safe_mem( (TC_FLAG_SET(opts->flags, SYS)) ? opts->sys_dev : opts->dev, (TC_FLAG_SET(opts->flags, SYS) || TC_FLAG_SET(opts->flags, FDE)) ? HDR_OFFSET_SYS : (!TC_FLAG_SET(opts->flags, BACKUP)) ? 0 : -BACKUP_HDR_OFFSET_END, &sz); if (ehdr == NULL) { tc_log(1, "error read hdr_enc: %s", opts->dev); goto out; } } if (!TC_FLAG_SET(opts->flags, SYS)) { /* Always read blksz-sized chunks */ sz = blksz; if (TC_FLAG_SET(opts->flags, H_HDR_FROM_FILE)) { hehdr = (struct tchdr_enc *)read_to_safe_mem( opts->h_hdr_file_in, 0, &sz); if (hehdr == NULL) { tc_log(1, "error read hdr_enc: %s", opts->h_hdr_file_in); goto out; } } else { hehdr = (struct tchdr_enc *)read_to_safe_mem(opts->dev, (!TC_FLAG_SET(opts->flags, BACKUP)) ? HDR_OFFSET_HIDDEN : -BACKUP_HDR_HIDDEN_OFFSET_END, &sz); if (hehdr == NULL) { tc_log(1, "error read hdr_enc: %s", opts->dev); goto out; } } } else { hehdr = NULL; } error = process_hdr(opts->dev, opts->iteration_count,opts->flags, (unsigned char *)pass, (opts->nkeyfiles > 0)?MAX_PASSSZ:strlen(pass), ehdr, &info); /* * Try to process hidden header if we have to protect the hidden * volume, or the decryption/verification of the main header * failed. */ if (hehdr && (error || opts->protect_hidden)) { if (error) { error2 = process_hdr(opts->dev, opts->iteration_count, opts->flags, (unsigned char *)pass, (opts->nkeyfiles > 0)?MAX_PASSSZ:strlen(pass), hehdr, &info); is_hidden = !error2; } else if (opts->protect_hidden) { error2 = process_hdr(opts->dev, opts->iteration_count, opts->flags, (unsigned char *)h_pass, (opts->n_hkeyfiles > 0)?MAX_PASSSZ:strlen(h_pass), hehdr, &hinfo); } } /* We need both to protect a hidden volume */ if ((opts->protect_hidden && (error || error2)) || (error && error2)) { if (!try_empty) tc_log(1, "Incorrect password or not a TrueCrypt volume\n"); if (info) { free_info(info); info = NULL; } if (hinfo) { free_info(hinfo); hinfo = NULL; } /* Try again (or finish) */ free_safe_mem(pass); pass = NULL; if (h_pass) { free_safe_mem(h_pass); h_pass = NULL; } if (ehdr) { free_safe_mem(ehdr); ehdr = NULL; } if (hehdr) { free_safe_mem(hehdr); hehdr = NULL; } try_empty = 0; continue; } if (opts->protect_hidden) { if (adjust_info(info, hinfo) != 0) { tc_log(1, "Could not protect hidden volume\n"); if (info) free_info(info); info = NULL; if (hinfo) free_info(hinfo); hinfo = NULL; goto out; } if (hinfo) { free_info(hinfo); hinfo = NULL; } } try_empty = 0; } out: if (hinfo) free_info(hinfo); if (pass) free_safe_mem(pass); if (h_pass) free_safe_mem(h_pass); if (ehdr) free_safe_mem(ehdr); if (hehdr) free_safe_mem(hehdr); if (info != NULL) info->hidden = is_hidden; return info; } int info_mapped_volume(struct tcplay_opts *opts) { struct tcplay_info *info; info = dm_info_map(opts->map_name); if (info != NULL) { if (opts->interactive) print_info(info); free_info(info); return 0; /* NOT REACHED */ } else if (opts->interactive) { tc_log(1, "Could not retrieve information about mapped " "volume %s. Does it exist?\n", opts->map_name); } return -1; } int info_volume(struct tcplay_opts *opts) { struct tcplay_info *info; info = info_map_common(opts, NULL); if (info != NULL) { if (opts->interactive) print_info(info); free_info(info); return 0; /* NOT REACHED */ } return -1; } int map_volume(struct tcplay_opts *opts) { struct tcplay_info *info; int error; info = info_map_common(opts, NULL); if (info == NULL) return -1; if ((error = dm_setup(opts->map_name, info)) != 0) { tc_log(1, "Could not set up mapping %s\n", opts->map_name); free_info(info); return -1; } if (opts->interactive) printf("All ok!\n"); free_info(info); return 0; } int modify_volume(struct tcplay_opts *opts) { struct tcplay_info *info; struct tchdr_enc *ehdr, *ehdr_backup; const char *new_passphrase = opts->new_passphrase; const char **new_keyfiles = opts->new_keyfiles; struct pbkdf_prf_algo *new_prf_algo = opts->new_prf_algo; int n_newkeyfiles = opts->n_newkeyfiles; char *pass, *pass_again; int ret = -1; off_t offset, offset_backup = 0; const char *dev; size_t blksz; disksz_t blocks; int error; ehdr = ehdr_backup = NULL; pass = pass_again = NULL; info = NULL; if (TC_FLAG_SET(opts->flags, ONLY_RESTORE)) { if (opts->interactive) { if ((pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) { tc_log(1, "could not allocate safe " "passphrase memory"); goto out; } } else { new_passphrase = opts->passphrase; } new_keyfiles = opts->keyfiles; n_newkeyfiles = opts->nkeyfiles; new_prf_algo = NULL; } info = info_map_common(opts, pass); if (info == NULL) goto out; if (opts->interactive && !TC_FLAG_SET(opts->flags, ONLY_RESTORE)) { if (((pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) || ((pass_again = alloc_safe_mem(PASS_BUFSZ)) == NULL)) { tc_log(1, "could not allocate safe passphrase memory\n"); goto out; } if ((error = read_passphrase("New passphrase: ", pass, MAX_PASSSZ, PASS_BUFSZ, 0) || (read_passphrase("Repeat passphrase: ", pass_again, MAX_PASSSZ, PASS_BUFSZ, 0)))) { tc_log(1, "could not read passphrase\n"); goto out; } if (strcmp(pass, pass_again) != 0) { tc_log(1, "Passphrases don't match\n"); goto out; } free_safe_mem(pass_again); pass_again = NULL; } else if (!opts->interactive) { /* In batch mode, use provided passphrase */ if ((pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) { tc_log(1, "could not allocate safe " "passphrase memory"); goto out; } if (new_passphrase != NULL) { strncpy(pass, new_passphrase, MAX_PASSSZ); pass[MAX_PASSSZ] = '\0'; } } if (n_newkeyfiles > 0) { /* Apply keyfiles to 'pass' */ if ((error = apply_keyfiles((unsigned char *)pass, PASS_BUFSZ, new_keyfiles, n_newkeyfiles))) { tc_log(1, "could not apply keyfiles\n"); goto out; } } ehdr = copy_reencrypt_hdr(opts->iteration_count, (unsigned char *)pass, (opts->n_newkeyfiles > 0)?MAX_PASSSZ:strlen(pass), new_prf_algo, opts->weak_keys_and_salt, info, &ehdr_backup); if (ehdr == NULL) { tc_log(1, "Could not create header\n"); goto out; } dev = (TC_FLAG_SET(opts->flags, SYS)) ? opts->sys_dev : opts->dev; if (TC_FLAG_SET(opts->flags, SYS) || TC_FLAG_SET(opts->flags, FDE)) { /* SYS and FDE don't have backup headers (as far as I understand) */ if (info->hidden) { offset = HDR_OFFSET_HIDDEN; } else { offset = HDR_OFFSET_SYS; } } else { if (info->hidden) { offset = HDR_OFFSET_HIDDEN; offset_backup = -BACKUP_HDR_HIDDEN_OFFSET_END; } else { offset = 0; offset_backup = -BACKUP_HDR_OFFSET_END; } } if ((error = get_disk_info(dev, &blocks, &blksz)) != 0) { tc_log(1, "could not get disk information\n"); goto out; } tc_log(0, "Writing new volume headers to disk/file...\n"); if (TC_FLAG_SET(opts->flags, SAVE_TO_FILE)) { if ((error = write_to_file(opts->hdr_file_out, ehdr, sizeof(*ehdr))) != 0) { tc_log(1, "Could not write volume header to file\n"); goto out; } } else { if ((error = write_to_disk(dev, offset, blksz, ehdr, sizeof(*ehdr))) != 0) { tc_log(1, "Could not write volume header to device\n"); goto out; } if (!TC_FLAG_SET(opts->flags, SYS) && !TC_FLAG_SET(opts->flags, FDE)) { if ((error = write_to_disk(dev, offset_backup, blksz, ehdr_backup, sizeof(*ehdr_backup))) != 0) { tc_log(1, "Could not write backup volume header to device\n"); goto out; } } } /* Everything went ok */ tc_log(0, "All done!\n"); ret = 0; out: if (pass) free_safe_mem(pass); if (pass_again) free_safe_mem(pass_again); if (ehdr) free_safe_mem(ehdr); if (ehdr_backup) free_safe_mem(ehdr_backup); if (info) free_safe_mem(info); return ret; } static int dm_get_info(const char *name, struct dm_info *dmi) { struct dm_task *dmt = NULL; int error = -1; if ((dmt = dm_task_create(DM_DEVICE_INFO)) == NULL) goto out; if ((dm_task_set_name(dmt, name)) == 0) goto out; if ((dm_task_run(dmt)) == 0) goto out; if ((dm_task_get_info(dmt, dmi)) == 0) goto out; error = 0; out: if (dmt) dm_task_destroy(dmt); return error; } #if defined(__DragonFly__) static int xlate_maj_min(const char *start_path __unused, int max_depth __unused, char *buf, size_t bufsz, uint32_t maj, uint32_t min) { dev_t dev = makedev(maj, min); snprintf(buf, bufsz, "/dev/%s", devname(dev, S_IFCHR)); return 1; } #else static int xlate_maj_min(const char *start_path, int max_depth, char *buf, size_t bufsz, uint32_t maj, uint32_t min) { dev_t dev = makedev(maj, min); char path[PATH_MAX]; struct stat sb; struct dirent *ent; DIR *dirp; int found = 0; if (max_depth <= 0) return -1; if ((dirp = opendir(start_path)) == NULL) return -1; while ((ent = readdir(dirp)) != NULL) { /* d_name, d_type, DT_BLK, DT_CHR, DT_DIR, DT_LNK */ if (ent->d_name[0] == '.') continue; /* Linux' /dev is littered with junk, so skip over it */ /* * The dm- devices seem to be the raw DM devices * things in mapper/ link to. */ if (((strcmp(ent->d_name, "block")) == 0) || ((strcmp(ent->d_name, "fd")) == 0) || (((strncmp(ent->d_name, "dm-", 3) == 0) && strlen(ent->d_name) <= 5))) continue; snprintf(path, PATH_MAX, "%s/%s", start_path, ent->d_name); if ((stat(path, &sb)) < 0) continue; if (S_ISDIR(sb.st_mode)) { found = !xlate_maj_min(path, max_depth-1, buf, bufsz, maj, min); if (found) break; } if (!S_ISBLK(sb.st_mode)) continue; if (sb.st_rdev != dev) continue; snprintf(buf, bufsz, "%s", path); found = 1; break; } if (dirp) closedir(dirp); return found ? 0 : -ENOENT; } #endif static struct tcplay_dm_table * dm_get_table(const char *name) { struct tcplay_dm_table *tc_table; struct dm_task *dmt = NULL; void *next = NULL; uint64_t start, length; char *target_type; char *params; char *p1; int c = 0; uint32_t maj, min; if ((tc_table = (struct tcplay_dm_table *)alloc_safe_mem(sizeof(*tc_table))) == NULL) { tc_log(1, "could not allocate safe tc_table memory\n"); return NULL; } if ((dmt = dm_task_create(DM_DEVICE_TABLE)) == NULL) goto error; if ((dm_task_set_name(dmt, name)) == 0) goto error; if ((dm_task_run(dmt)) == 0) goto error; tc_table->start = (off_t)0; tc_table->size = (size_t)0; do { next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); tc_table->size += (size_t)length; strncpy(tc_table->target, target_type, sizeof(tc_table->target)); /* Skip any leading whitespace */ while (params && *params == ' ') params++; if (strcmp(target_type, "crypt") == 0) { while ((p1 = strsep(¶ms, " ")) != NULL) { /* Skip any whitespace before the next strsep */ while (params && *params == ' ') params++; /* Process p1 */ if (c == 0) { /* cipher */ strncpy(tc_table->cipher, p1, sizeof(tc_table->cipher)); } else if (c == 2) { /* iv offset */ tc_table->skip = (off_t)strtoll(p1, NULL, 10); } else if (c == 3) { /* major:minor */ maj = strtoul(p1, NULL, 10); while (*p1 != ':' && *p1 != '\0') p1++; min = strtoul(++p1, NULL, 10); if ((xlate_maj_min("/dev", 2, tc_table->device, sizeof(tc_table->device), maj, min)) != 0) snprintf(tc_table->device, sizeof(tc_table->device), "%u:%u", maj, min); } else if (c == 4) { /* block offset */ tc_table->offset = (off_t)strtoll(p1, NULL, 10); } ++c; } if (c < 5) { tc_log(1, "could not get all the info required from " "the table\n"); goto error; } } } while (next != NULL); if (dmt) dm_task_destroy(dmt); #ifdef DEBUG printf("device: %s\n", tc_table->device); printf("target: %s\n", tc_table->target); printf("cipher: %s\n", tc_table->cipher); printf("size: %ju\n", tc_table->size); printf("offset: %"PRId64"\n", tc_table->offset); printf("skip: %"PRId64"\n", tc_table->skip); #endif return tc_table; error: if (dmt) dm_task_destroy(dmt); if (tc_table) free_safe_mem(tc_table); return NULL; } struct tcplay_info * dm_info_map(const char *map_name) { struct dm_task *dmt = NULL; struct dm_info dmi[3]; struct tcplay_dm_table *dm_table[3]; struct tc_crypto_algo *crypto_algo; struct tcplay_info *info; char map[PATH_MAX]; char ciphers[512]; int i, outermost = -1; memset(dm_table, 0, sizeof(dm_table)); if ((info = (struct tcplay_info *)alloc_safe_mem(sizeof(*info))) == NULL) { tc_log(1, "could not allocate safe info memory\n"); return NULL; } strncpy(map, map_name, PATH_MAX); for (i = 0; i < 3; i++) { if ((dm_get_info(map, &dmi[i])) != 0) goto error; if (dmi[i].exists) dm_table[i] = dm_get_table(map); snprintf(map, PATH_MAX, "%s.%d", map_name, i); } if (dmt) dm_task_destroy(dmt); if (dm_table[0] == NULL) goto error; /* * Process our dmi, dm_table fun into the info structure. */ /* First find which cipher chain we are using */ ciphers[0] = '\0'; for (i = 0; i < 3; i++) { if (dm_table[i] == NULL) continue; if (outermost < i) outermost = i; crypto_algo = &tc_crypto_algos[0]; while ((crypto_algo != NULL) && (strcmp(dm_table[i]->cipher, crypto_algo->dm_crypt_str) != 0)) ++crypto_algo; if (crypto_algo == NULL) { tc_log(1, "could not find corresponding cipher\n"); goto error; } strcat(ciphers, crypto_algo->name); strcat(ciphers, ","); } ciphers[strlen(ciphers)-1] = '\0'; info->cipher_chain = check_cipher_chain(ciphers, 1); if (info->cipher_chain == NULL) { tc_log(1, "could not find cipher chain\n"); goto error; } info->cipher_chain = tc_dup_cipher_chain(info->cipher_chain); if (info->cipher_chain == NULL) { tc_log(1, "could not dup cipher chain\n"); goto error; } /* Copy over the name */ strncpy(info->dev, dm_table[outermost]->device, sizeof(info->dev)); /* Other fields */ info->hdr = NULL; info->pbkdf_prf = NULL; info->start = dm_table[outermost]->start; info->size = dm_table[0]->size; info->skip = dm_table[outermost]->skip; info->offset = dm_table[outermost]->offset; info->blk_sz = 512; for (i = 0; i < 3; i++) if (dm_table[i] != NULL) free_safe_mem(dm_table[i]); return info; error: if (dmt) dm_task_destroy(dmt); if (info) free_safe_mem(info); for (i = 0; i < 3; i++) if (dm_table[i] != NULL) free_safe_mem(dm_table[i]); return NULL; } static int dm_exists_device(const char *name) { struct dm_info dmi; int exists = 0; if (dm_get_info(name, &dmi) != 0) goto out; exists = dmi.exists; out: return exists; } static int dm_remove_device(const char *name) { struct dm_task *dmt = NULL; int ret = EINVAL; if ((dmt = dm_task_create(DM_DEVICE_REMOVE)) == NULL) goto out; if ((dm_task_set_name(dmt, name)) == 0) goto out; if ((dm_task_run(dmt)) == 0) goto out; ret = 0; out: if (dmt) dm_task_destroy(dmt); return ret; } int dm_setup(const char *mapname, struct tcplay_info *info) { struct tc_cipher_chain *cipher_chain; struct dm_task *dmt = NULL; struct dm_info dmi; char *params = NULL; char *uu; char *uu_temp=NULL; char *uu_stack[64]; int uu_stack_idx; #if defined(__DragonFly__) uint32_t status; #endif int r, ret = 0; int j, len; off_t start, offset; char dev[PATH_MAX]; char map[PATH_MAX]; uint32_t cookie; dm_udev_set_sync_support(1); if ((params = alloc_safe_mem(512)) == NULL) { tc_log(1, "could not allocate safe parameters memory"); return ENOMEM; } strcpy(dev, info->dev); /* * Device Mapper blocks are always 512-byte blocks, so convert * from the "native" block size to the dm block size here. */ start = INFO_TO_DM_BLOCKS(info, start); offset = INFO_TO_DM_BLOCKS(info, offset); uu_stack_idx = 0; /* * Find length of cipher chain. Could use the for below, but doesn't * really matter. */ len = tc_cipher_chain_length(info->cipher_chain); /* Get to the end of the chain */ for (cipher_chain = info->cipher_chain; cipher_chain->next != NULL; cipher_chain = cipher_chain->next) ; /* * Start j at len-2, as we want to use .0, and the final one has no * suffix. */ for (j = len-2; cipher_chain != NULL; cipher_chain = cipher_chain->prev, j--) { cookie = 0; if ((dmt = dm_task_create(DM_DEVICE_CREATE)) == NULL) { tc_log(1, "dm_task_create failed\n"); ret = -1; goto out; } /* * If this is the last element in the cipher chain, use the * final map name. Otherwise pick a secondary name... */ if (cipher_chain->prev == NULL) strcpy(map, mapname); else sprintf(map, "%s.%d", mapname, j); if ((dm_task_set_name(dmt, map)) == 0) { tc_log(1, "dm_task_set_name failed\n"); ret = -1; goto out; } #if defined(__linux__) #if TCPLAY_USE_OSSP_UUID uuid_t *uu; uuid_create(&uu) ; uuid_make(uu, UUID_MAKE_V1); size_t s ; uuid_export(uu, UUID_FMT_STR, &uu_temp, &s); s = sizeof(info->uuid); uuid_export(uu, UUID_FMT_BIN, &info->uuid, &s); uuid_destroy(uu); #else uuid_generate(info->uuid); if ((uu_temp = malloc(1024)) == NULL) { tc_log(1, "uuid_unparse memory failed\n"); ret = -1; goto out; } uuid_unparse(info->uuid, uu_temp); #endif #elif defined(__DragonFly__) uuid_create(&info->uuid, &status); if (status != uuid_s_ok) { tc_log(1, "uuid_create failed\n"); ret = -1; goto out; } uuid_to_string(&info->uuid, &uu_temp, &status); if (uu_temp == NULL) { tc_log(1, "uuid_to_string failed\n"); ret = -1; goto out; } #endif if ((uu = malloc(1024)) == NULL) { free(uu_temp); tc_log(1, "uuid second malloc failed\n"); ret = -1; goto out; } snprintf(uu, 1024, "CRYPT-TCPLAY-%s", uu_temp); free(uu_temp); if ((dm_task_set_uuid(dmt, uu)) == 0) { free(uu); tc_log(1, "dm_task_set_uuid failed\n"); ret = -1; goto out; } free(uu); if (TC_FLAG_SET(info->flags, FDE)) { /* * When the full disk encryption (FDE) flag is set, * we map the first N sectors using a linear target * as they aren't encrypted. */ /* /dev/ad0s0a 0 */ /* dev---^ block off --^ */ snprintf(params, 512, "%s 0", dev); if ((dm_task_add_target(dmt, 0, INFO_TO_DM_BLOCKS(info, offset), "linear", params)) == 0) { tc_log(1, "dm_task_add_target failed\n"); ret = -1; goto out; } start = INFO_TO_DM_BLOCKS(info, offset); } /* aes-cbc-essiv:sha256 7997f8af... 0 /dev/ad0s0a 8 */ /* iv off---^ block off--^ */ snprintf(params, 512, "%s %s %"PRIu64 " %s %"PRIu64 " %s", cipher_chain->cipher->dm_crypt_str, cipher_chain->dm_key, (uint64_t)INFO_TO_DM_BLOCKS(info, skip), dev, (uint64_t)offset, TC_FLAG_SET(info->flags, ALLOW_TRIM) ? "1 allow_discards" : ""); #ifdef DEBUG printf("Params: %s\n", params); #endif if ((dm_task_add_target(dmt, start, INFO_TO_DM_BLOCKS(info, size), "crypt", params)) == 0) { tc_log(1, "dm_task_add_target failed\n"); ret = -1; goto out; } if ((dm_task_set_cookie(dmt, &cookie, 0)) == 0) { tc_log(1, "dm_task_set_cookie failed\n"); ret = -1; goto out; } if ((dm_task_run(dmt)) == 0) { dm_udev_wait(cookie); tc_log(1, "dm_task_run failed\n"); ret = -1; goto out; } if ((dm_task_get_info(dmt, &dmi)) == 0) { dm_udev_wait(cookie); tc_log(1, "dm_task_get info failed\n"); ret = -1; goto out; } dm_udev_wait(cookie); if ((r = asprintf(&uu_stack[uu_stack_idx++], "%s", map)) < 0) tc_log(1, "warning, asprintf failed. won't be able to " "unroll changes\n"); offset = 0; start = 0; sprintf(dev, "/dev/mapper/%s.%d", mapname, j); dm_task_destroy(dmt); dm_task_update_nodes(); } out: /* * If an error occured, try to unroll changes made before it * happened. */ if (ret) { j = uu_stack_idx; while (j > 0) { #ifdef DEBUG printf("Unrolling dm changes! j = %d (%s)\n", j-1, uu_stack[j-1]); #endif if ((uu_stack[j-1] == NULL) || ((r = dm_remove_device(uu_stack[--j])) != 0)) { tc_log(1, "Tried to unroll dm changes, " "giving up.\n"); break; } } } while (uu_stack_idx > 0) free(uu_stack[--uu_stack_idx]); free_safe_mem(params); return ret; } int dm_teardown(const char *mapname, const char *device __unused) { #if 0 struct dm_task *dmt = NULL; struct dm_info dmi; #endif char map[PATH_MAX]; int i, error; if ((error = dm_remove_device(mapname)) != 0) { tc_log(1, "Could not remove mapping %s\n", mapname); return error; } /* Try to remove other cascade devices */ for (i = 0; i < 2; i++) { sprintf(map, "%s.%d", mapname, i); if (dm_exists_device(map)) dm_remove_device(map); } return 0; } struct tc_crypto_algo * check_cipher(const char *cipher, int quiet) { int i, found = 0; for (i = 0; tc_crypto_algos[i].name != NULL; i++) { if (strcmp(cipher, tc_crypto_algos[i].name) == 0) { found = 1; break; } } if (!found && !quiet) { fprintf(stderr, "Valid ciphers are: "); for (i = 0; tc_crypto_algos[i].name != NULL; i++) fprintf(stderr, "%s ", tc_crypto_algos[i].name); fprintf(stderr, "\n"); return NULL; } return &tc_crypto_algos[i]; } struct tc_cipher_chain * check_cipher_chain(const char *cipher_chain, int quiet) { struct tc_cipher_chain *cipher = NULL; int i,k, nciphers = 0, mismatch = 0; char *ciphers[8]; char *tmp_chain, *tmp_chain_free; char *token; if ((tmp_chain = strdup(cipher_chain)) == NULL) { tc_log(1, "Could not allocate strdup memory\n"); return NULL; } tmp_chain_free = tmp_chain; while ((token = strsep(&tmp_chain, ",")) != NULL) ciphers[nciphers++] = token; cipher = NULL; for (i = 0; valid_cipher_chains[i][0] != NULL; i++) { mismatch = 0; for (k = 0; (valid_cipher_chains[i][k] != NULL); k++) { /* * If there are more ciphers in the chain than in the * ciphers[] variable this is not the right chain. */ if (k == nciphers) { mismatch = 1; break; } if (strcmp(ciphers[k], valid_cipher_chains[i][k]) != 0) mismatch = 1; } /* * If all ciphers matched and there are exactly nciphers, * then we found the right cipher chain. */ if ((k == nciphers) && !mismatch) { cipher = tc_cipher_chains[i]; break; } } if (cipher == NULL) { tc_log(1, "Invalid cipher: %s\n", cipher_chain); if (!quiet) { fprintf(stderr, "Valid cipher chains are:\n"); for (i = 0; valid_cipher_chains[i][0] != NULL; i++) { for (k = 0; valid_cipher_chains[i][k] != NULL; k++) { fprintf(stderr, "%s%c", valid_cipher_chains[i][k], (valid_cipher_chains[i][k+1] != NULL) ? ',' : '\0'); } fprintf(stderr, "\n"); } } } free(tmp_chain_free); return cipher; } struct pbkdf_prf_algo * check_prf_algo(const char *algo, int sys, int quiet) { int i, found = 0; for (i = 0; pbkdf_prf_algos[i].name != NULL; i++) { if (sys != pbkdf_prf_algos[i].sys) continue; if (strcmp(algo, pbkdf_prf_algos[i].name) == 0) { found = 1; break; } } if (!found && !quiet) { fprintf(stderr, "Valid PBKDF PRF algorithms are: "); for (i = 0; pbkdf_prf_algos[i].name != NULL; i++) { if (sys != pbkdf_prf_algos[i].sys) continue; fprintf(stderr, "%s ", pbkdf_prf_algos[i].name); } fprintf(stderr, "\n"); return NULL; } return &pbkdf_prf_algos[i]; } int tc_play_init(void) { int error; if ((error = tc_build_cipher_chains()) != 0) return error; if ((error = tc_crypto_init()) != 0) return error; return 0; } struct tcplay_opts *opts_init(void) { struct tcplay_opts *opts; if ((opts = (struct tcplay_opts *)alloc_safe_mem(sizeof(*opts))) == NULL) { tc_log(1, "could not allocate safe opts memory\n"); return NULL; } memset(opts, 0, sizeof(*opts)); opts->retries = DEFAULT_RETRIES; opts->secure_erase = 1; return opts; } int opts_add_keyfile(struct tcplay_opts *opts, const char *keyfile) { const char *keyf; if (opts->nkeyfiles == MAX_KEYFILES) return -1; if ((keyf = strdup_safe_mem(keyfile)) == NULL) { return -1; } opts->keyfiles[opts->nkeyfiles++] = keyf; return 0; } int opts_add_keyfile_hidden(struct tcplay_opts *opts, const char *keyfile) { const char *keyf; if (opts->n_hkeyfiles == MAX_KEYFILES) return -1; if ((keyf = strdup_safe_mem(keyfile)) == NULL) { return -1; } opts->h_keyfiles[opts->n_hkeyfiles++] = keyf; return 0; } int opts_add_keyfile_new(struct tcplay_opts *opts, const char *keyfile) { const char *keyf; if (opts->n_newkeyfiles == MAX_KEYFILES) return -1; if ((keyf = strdup_safe_mem(keyfile)) == NULL) { return -1; } opts->new_keyfiles[opts->n_newkeyfiles++] = keyf; return 0; } void opts_clear_keyfile(struct tcplay_opts *opts) { int i; for (i = 0; i < opts->nkeyfiles; i++) { free_safe_mem(opts->keyfiles[i]); } opts->nkeyfiles = 0; } void opts_clear_keyfile_hidden(struct tcplay_opts *opts) { int i; for (i = 0; i < opts->n_hkeyfiles; i++) { free_safe_mem(opts->h_keyfiles[i]); } opts->n_hkeyfiles = 0; } void opts_clear_keyfile_new(struct tcplay_opts *opts) { int i; for (i = 0; i < opts->n_newkeyfiles; i++) { free_safe_mem(opts->new_keyfiles[i]); } opts->n_newkeyfiles = 0; } void opts_free(struct tcplay_opts *opts) { int i; for (i = 0; i < opts->nkeyfiles; i++) { free_safe_mem(opts->keyfiles[i]); } for (i = 0; i < opts->n_hkeyfiles; i++) { free_safe_mem(opts->h_keyfiles[i]); } for (i = 0; i < opts->n_newkeyfiles; i++) { free_safe_mem(opts->new_keyfiles[i]); } if (opts->dev) free_safe_mem(opts->dev); if (opts->passphrase) free_safe_mem(opts->passphrase); if (opts->h_passphrase) free_safe_mem(opts->h_passphrase); if (opts->new_passphrase) free_safe_mem(opts->new_passphrase); if (opts->map_name) free_safe_mem(opts->map_name); if (opts->sys_dev) free_safe_mem(opts->sys_dev); if (opts->hdr_file_in) free_safe_mem(opts->hdr_file_in); if (opts->h_hdr_file_in) free_safe_mem(opts->h_hdr_file_in); if (opts->hdr_file_out) free_safe_mem(opts->hdr_file_out); free_safe_mem(opts); } zuluCrypt-6.2.0/external_libraries/tcplay/tcplay.h000066400000000000000000000272441425361753700224050ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Version of tcplay specified during build (CMakeLists.txt, Makefile.classic) */ #ifndef _TCPLAY_H #define _TCPLAY_H #define MAX_BLKSZ 4096 #define MAX_KEYSZ 192 #define HDRSZ 512 #define HDR_OFFSET_SYS 31744 /* 512 * (63 -1) */ #define TC_SIG "TRUE" #define VC_SIG "VERA" #define MAX_PASSSZ 64 #define PASS_BUFSZ 256 #define KPOOL_SZ 64 #define MAX_KFILE_SZ 1048576 /* 1 MB */ #define MAX_KEYFILES 256 #define HDR_OFFSET_HIDDEN 65536 #define BACKUP_HDR_HIDDEN_OFFSET_END 65536 #define BACKUP_HDR_OFFSET_END 131072 #define SALT_LEN 64 #define VOL_RSVD_BYTES_START (256*512) /* Reserved bytes at vol. start */ #define VOL_RSVD_BYTES_END (256*512) /* Reserved bytes at vol. end */ #define MIN_VOL_BYTES (VOL_RSVD_BYTES_START + VOL_RSVD_BYTES_END) #define MAX_CIPHER_CHAINS 64 #define DEFAULT_RETRIES 3 #define ERASE_BUFFER_SIZE 4*1024*1024 /* 4 MB */ /* TrueCrypt Volume flags */ #define TC_VOLFLAG_SYSTEM 0x01 /* system encryption */ #define TC_VOLFLAG_INPLACE 0x02 /* non-system in-place-encrypted volume */ #define TC_VOLFLAG_SET(f, x) ((f & TC_VOLFLAG_##x) == TC_VOLFLAG_##x) #define LOG_BUFFER_SZ 1024 #if 0 #define DEBUG 1 #endif #define TC_FLAG_SYS 0x0001 #define TC_FLAG_FDE 0x0002 #define TC_FLAG_BACKUP 0x0004 #define TC_FLAG_ONLY_RESTORE 0x0008 #define TC_FLAG_ALLOW_TRIM 0x0010 #define TC_FLAG_SAVE_TO_FILE 0x0020 #define TC_FLAG_HDR_FROM_FILE 0x0040 #define TC_FLAG_H_HDR_FROM_FILE 0x0080 #define TC_FLAG_SET(f, x) ((f & TC_FLAG_##x) == TC_FLAG_##x) #include #include #include "uuid_source.h" #if defined(__DragonFly__) #include #elif defined(__linux__) #include #if TCPLAY_USE_OSSP_UUID #include #else #include #endif #endif typedef uint64_t disksz_t; #define DISKSZ_FMT PRIu64 struct pbkdf_prf_algo { const char *name; const char *algo; int iteration_count; const char *sig; int sys; }; #define DEFAULT_PRF_ALGO_IDX 6 struct tc_crypto_algo { const char *name; const char *dm_crypt_str; int klen; int ivlen; }; struct tc_cipher_chain { struct tc_crypto_algo *cipher; unsigned char *key; char dm_key[MAX_KEYSZ*2 + 1]; struct tc_cipher_chain *prev; struct tc_cipher_chain *next; }; struct tchdr_enc { unsigned char salt[SALT_LEN]; /* Salt for PBKDF */ unsigned char enc[448]; /* Encrypted part of the header */ } __attribute__((__packed__)); struct tchdr_dec { char tc_str[4]; /* ASCII string "TRUE" */ uint16_t tc_ver; /* Volume header format version */ uint16_t tc_min_ver; uint32_t crc_keys; /* CRC32 of the key section */ uint64_t vol_ctime; /* Volume creation time */ uint64_t hdr_ctime; /* Header creation time */ uint64_t sz_hidvol; /* Size of hidden volume (set to zero in non-hidden volumes) */ uint64_t sz_vol; /* Size of volume */ uint64_t off_mk_scope; /* Byte offset of the start of the master key scope */ uint64_t sz_mk_scope; /* Size of the encrypted area within the master key scope */ uint32_t flags; /* Flag bits (bit 0: system encryption; bit 1: non-system in-place-encrypted volume; bits 2–31 are reserved) */ uint32_t sec_sz; /* Sector size (in bytes) */ unsigned char unused3[120]; uint32_t crc_dhdr; /* CRC32 of dec. header (except keys) */ unsigned char keys[256]; } __attribute__((__packed__)); struct tcplay_info { char dev[PATH_MAX]; struct tchdr_dec *hdr; struct tc_cipher_chain *cipher_chain; struct pbkdf_prf_algo *pbkdf_prf; char key[MAX_KEYSZ*2 + 1]; int flags; int volflags; uint32_t blk_sz; off_t start; /* Logical volume offset in table (in blk_sz blocks) */ disksz_t size; /* Volume size (in blk_sz blocks) */ off_t skip; /* IV offset (in blk_sz blocks) */ off_t offset; /* Block offset (in blk_sz blocks) */ #if TCPLAY_USE_OSSP_UUID /* Populated by dm_setup */ unsigned char uuid[16]; #else /* Populated by dm_setup */ uuid_t uuid; #endif int hidden; }; #define INFO_TO_DM_BLOCKS(info, memb) \ (((info)->memb * (uint64_t)((info)->blk_sz))/512) struct tcplay_dm_table { char device[PATH_MAX]; /* Underlying device */ char target[256]; /* DM Target type */ off_t start; /* Logical volume offset in table */ disksz_t size; /* Volume size */ char cipher[256]; /* Cipher */ off_t skip; /* IV offset */ off_t offset; /* Block offset */ }; typedef int (*tc_state_change_fn)(void *, const char *, int); struct tcplay_opts { /* (Mostly) common options */ const char *dev; const char *keyfiles[MAX_KEYFILES]; int nkeyfiles; const char *h_keyfiles[MAX_KEYFILES]; int n_hkeyfiles; struct pbkdf_prf_algo *prf_algo; struct tc_cipher_chain *cipher_chain; struct pbkdf_prf_algo *h_prf_algo; struct tc_cipher_chain *h_cipher_chain; const char *passphrase; const char *h_passphrase; int interactive; int weak_keys_and_salt; int iteration_count; /* Options for create */ int hidden; disksz_t hidden_size_bytes; int secure_erase; /* XXX: default to 1! */ /* Options for map, info_mapped */ const char *map_name; /* Options for info, map, modify */ int flags; const char *sys_dev; int protect_hidden; int retries; /* XXX: default to DEFAULT_RETRIES */ time_t timeout; int prompt_passphrase; const char *hdr_file_in; const char *h_hdr_file_in; /* Options for modify only */ struct pbkdf_prf_algo *new_prf_algo; const char *new_passphrase; const char *hdr_file_out; const char *new_keyfiles[MAX_KEYFILES]; int n_newkeyfiles; void *api_ctx; tc_state_change_fn state_change_fn; }; struct tcplay_opts *opts_init(void); int opts_add_keyfile(struct tcplay_opts *opts, const char *keyfile); int opts_add_keyfile_hidden(struct tcplay_opts *opts, const char *keyfile); int opts_add_keyfile_new(struct tcplay_opts *opts, const char *keyfile); void opts_free(struct tcplay_opts *opts); void opts_clear_keyfile(struct tcplay_opts *opts); void opts_clear_keyfile_hidden(struct tcplay_opts *opts); void opts_clear_keyfile_new(struct tcplay_opts *opts); void *read_to_safe_mem(const char *file, off_t offset, size_t *sz); int get_random(unsigned char *buf, size_t len, int weak); int secure_erase(const char *dev, disksz_t bytes, size_t blksz); int get_disk_info(const char *dev, disksz_t *blocks, size_t *bsize); int write_to_disk(const char *dev, off_t offset, size_t blksz, void *mem, size_t bytes); int write_to_file(const char *file, void *mem, size_t bytes); int read_passphrase(const char *prompt, char *pass, size_t passlen, size_t bufsz, time_t timeout); float get_random_read_progress(void); float get_secure_erase_progress(void); int tc_crypto_init(void); int tc_cipher_chain_populate_keys(struct tc_cipher_chain *cipher_chain, unsigned char *key); int tc_cipher_chain_free_keys(struct tc_cipher_chain *cipher_chain); int tc_encrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key, unsigned char *iv, unsigned char *in, int in_len, unsigned char *out); int tc_decrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key, unsigned char *iv, unsigned char *in, int in_len, unsigned char *out); /* The following two are platform dependent */ int syscrypt(struct tc_crypto_algo *cipher, unsigned char *key, size_t klen, unsigned char *iv, unsigned char *in, unsigned char *out, size_t len, int do_encrypt); int pbkdf2(struct pbkdf_prf_algo *hash, const char *pass, int passlen, const unsigned char *salt, int saltlen, int keylen, int iteration_count, unsigned char *out); int apply_keyfiles(unsigned char *pass, size_t pass_memsz, const char *keyfiles[], int nkeyfiles); struct tchdr_enc *create_hdr(int iteration_count, unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo, struct tc_cipher_chain *cipher_chain, size_t sec_sz, disksz_t total_blocks, off_t offset, disksz_t blocks, int hidden, int weak, struct tchdr_enc **backup_hdr); struct tchdr_dec *decrypt_hdr(struct tchdr_enc *ehdr, struct tc_cipher_chain *cipher_chain, unsigned char *key); int verify_hdr(struct tchdr_dec *hdr, struct pbkdf_prf_algo *prf_algo); struct tchdr_enc *copy_reencrypt_hdr(int iteration_count,unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo, int weak, struct tcplay_info *info, struct tchdr_enc **backup_hdr); void *_alloc_safe_mem(size_t req_sz, const char *file, int line); void *_strdup_safe_mem(const char *in, const char *file, int line); void _free_safe_mem(void *mem, const char *file, int line); void check_and_purge_safe_mem(void); struct tc_crypto_algo *check_cipher(const char *cipher, int quiet); struct tc_cipher_chain *check_cipher_chain(const char *cipher_chain, int quiet); struct pbkdf_prf_algo *check_prf_algo(const char *algo, int sys, int quiet); int tc_play_init(void); void tc_log(int err, const char *fmt, ...); int tc_cipher_chain_klen(struct tc_cipher_chain *chain); int tc_cipher_chain_length(struct tc_cipher_chain *chain); char *tc_cipher_chain_sprint(char *buf, size_t bufsz, struct tc_cipher_chain *chain); int free_info(struct tcplay_info *info); void print_info(struct tcplay_info *info); int adjust_info(struct tcplay_info *info, struct tcplay_info *hinfo); int process_hdr(const char *dev, int iteration_count,int flags, unsigned char *pass, int passlen, struct tchdr_enc *ehdr, struct tcplay_info **pinfo); int create_volume(struct tcplay_opts *opts); struct tcplay_info *info_map_common(struct tcplay_opts *opts, char *passphrase_out); int info_mapped_volume(struct tcplay_opts *opts); int info_volume(struct tcplay_opts *opts); int map_volume(struct tcplay_opts *opts); int modify_volume(struct tcplay_opts *opts); int dm_setup(const char *mapname, struct tcplay_info *info); int dm_teardown(const char *mapname, const char *device); struct tcplay_info *dm_info_map(const char *map_name); typedef void(*summary_fn_t)(void); extern int tc_internal_verbose; extern char tc_internal_log_buffer[]; extern summary_fn_t summary_fn; extern struct pbkdf_prf_algo pbkdf_prf_algos[]; extern struct tc_cipher_chain *tc_cipher_chains[MAX_CIPHER_CHAINS]; #define STATE_UNKNOWN 0 #define STATE_GET_RANDOM 1 #define STATE_ERASE 2 extern int tc_internal_state; #ifndef __DECONST #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) #endif #define alloc_safe_mem(x) \ _alloc_safe_mem(x, __FILE__, __LINE__) #define strdup_safe_mem(x) \ _strdup_safe_mem(x, __FILE__, __LINE__) #define free_safe_mem(x) \ _free_safe_mem(__DECONST(void *, x), __FILE__, __LINE__) #define __unused __attribute__((__unused__)) #endif zuluCrypt-6.2.0/external_libraries/tcplay/tcplay.map000066400000000000000000000003221425361753700227170ustar00rootroot00000000000000{ global: tc_api_init; tc_api_uninit; tc_api_has; tc_api_cipher_iterate; tc_api_prf_iterate; tc_api_task_init; tc_api_task_uninit; tc_api_task_set; tc_api_task_do; tc_api_task_info_get; local: *; }; zuluCrypt-6.2.0/external_libraries/tcplay/tcplay_api.c000066400000000000000000000402431425361753700232230ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "tcplay.h" #include "tcplay_api.h" #include "tcplay_api_internal.h" int tc_api_init(int verbose) { int error; tc_internal_verbose = verbose; if ((error = tc_play_init()) != 0) return TC_ERR; else return TC_OK; } int tc_api_uninit(void) { check_and_purge_safe_mem(); return TC_OK; } static const char *_caps[] = { "trim", NULL }; int tc_api_has(const char *feature) { const char *cap; int i; for (cap = _caps[0], i = 0; cap != NULL; cap = _caps[++i]) { if ((strcmp(cap, feature)) == 0) return TC_OK; } return TC_ERR_UNIMPL; } int tc_api_cipher_iterate(tc_api_cipher_iterator_fn fn, void *priv) { int i; struct tc_cipher_chain *chain; int klen; int length; char buf[1024]; if (fn == NULL) { errno = EFAULT; return TC_ERR; } for (i = 0, chain = tc_cipher_chains[0]; chain != NULL; chain = tc_cipher_chains[++i]) { tc_cipher_chain_sprint(buf, sizeof(buf), chain); klen = tc_cipher_chain_klen(chain); length = tc_cipher_chain_length(chain); if ((fn(priv, buf, klen, length)) < 0) break; } return TC_OK; } int tc_api_prf_iterate(tc_api_prf_iterator_fn fn, void *priv) { int i; if (fn == NULL) { errno = EFAULT; return TC_ERR; } for (i = 0; pbkdf_prf_algos[i].name != NULL; i++) { /* Skip over sys PRFs */ if (pbkdf_prf_algos[i].sys) continue; if ((fn(priv, pbkdf_prf_algos[i].name)) < 0) break; } return TC_OK; } const char * tc_api_task_get_error(tc_api_task task __unused) { return tc_internal_log_buffer; } #define _match(k, v) (strcmp(k, v) == 0) tc_api_task tc_api_task_init(const char *op) { tc_api_task task = NULL; int fail = 1; if ((task = alloc_safe_mem(sizeof(*task))) == NULL) { errno = ENOMEM; goto out; } if ((task->opts = opts_init()) == NULL) { errno = ENOMEM; goto out; } if (_match(op, "create")) { task->op = TC_OP_CREATE; } else if (_match(op, "map")) { task->op = TC_OP_MAP; } else if (_match(op, "unmap")) { task->op = TC_OP_UNMAP; } else if (_match(op, "info")) { task->op = TC_OP_INFO; } else if (_match(op, "info_mapped")) { task->op = TC_OP_INFO_MAPPED; } else if (_match(op, "modify")) { task->op = TC_OP_MODIFY; } else if (_match(op, "restore")) { task->op = TC_OP_RESTORE; } else { errno = EINVAL; goto out; } fail = 0; out: if (fail && task != NULL) { if (task->opts != NULL) opts_free(task->opts); free_safe_mem(task); } return fail ? NULL : task; } int tc_api_task_uninit(tc_api_task task) { if (task->last_info != NULL) free_info(task->last_info); opts_free(task->opts); free_safe_mem(task); return TC_OK; } #define _set_str(k) \ do { \ if ((opts->k = strdup_safe_mem(s)) == NULL) { \ errno = ENOMEM; \ r = TC_ERR; \ goto out; \ } \ } while (0) #define _clr_str(k) \ do { \ if (opts->k) \ free_safe_mem(opts->k); \ opts->k = NULL; \ } while (0) int tc_api_task_set(tc_api_task task, const char *key, ...) { struct tcplay_opts *opts; va_list ap; const char *s; int64_t i64; int i; tc_api_state_change_fn sc_fn; void *vp; int r = TC_OK; if (task == NULL || key == NULL || ((opts = task->opts) == NULL)) { errno = EFAULT; return TC_ERR; } va_start(ap, key); if (_match(key, "interactive")) { i = va_arg(ap, int); opts->interactive = i; } else if (_match(key, "weak_keys_and_salt")) { i = va_arg(ap, int); opts->weak_keys_and_salt = i; } else if (_match(key, "secure_erase")) { i = va_arg(ap, int); opts->secure_erase = i; } else if (_match(key, "protect_hidden")) { i = va_arg(ap, int); opts->protect_hidden = i; } else if (_match(key, "fde")) { i = va_arg(ap, int); if (i) opts->flags |= TC_FLAG_FDE; else opts->flags &= ~TC_FLAG_FDE; } else if (_match(key, "use_backup_header")) { i = va_arg(ap, int); if (i) opts->flags |= TC_FLAG_BACKUP; else opts->flags &= ~TC_FLAG_BACKUP; } else if (_match(key, "allow_trim")) { i = va_arg(ap, int); if (i) opts->flags |= TC_FLAG_ALLOW_TRIM; else opts->flags &= ~TC_FLAG_ALLOW_TRIM; } else if (_match(key, "hidden_size_bytes")) { i64 = va_arg(ap, int64_t); opts->hidden_size_bytes = (disksz_t)i64; opts->hidden = (i64 > 0); } else if (_match(key, "retries")) { i = va_arg(ap, int); opts->retries = i; } else if (_match(key, "timeout")) { i = va_arg(ap, int); opts->timeout = (time_t)i; } else if (_match(key, "save_header_to_file")) { s = va_arg(ap, const char *); if (s != NULL) { _set_str(hdr_file_out); opts->flags |= TC_FLAG_SAVE_TO_FILE; } else { _clr_str(hdr_file_out); opts->flags &= ~TC_FLAG_SAVE_TO_FILE; } } else if (_match(key, "header_from_file")) { s = va_arg(ap, const char *); if (s != NULL) { _set_str(hdr_file_in); opts->flags |= TC_FLAG_HDR_FROM_FILE; } else { _clr_str(hdr_file_in); opts->flags &= ~TC_FLAG_HDR_FROM_FILE; } } else if (_match(key, "hidden_header_from_file")) { s = va_arg(ap, const char *); if (s != NULL) { _set_str(h_hdr_file_in); opts->flags |= TC_FLAG_H_HDR_FROM_FILE; } else { _clr_str(h_hdr_file_in); opts->flags &= ~TC_FLAG_H_HDR_FROM_FILE; } } else if (_match(key, "sys")) { s = va_arg(ap, const char *); if (s != NULL) { _set_str(sys_dev); opts->flags |= TC_FLAG_SYS; } else { _clr_str(sys_dev); opts->flags &= ~TC_FLAG_SYS; } } else if (_match(key, "passphrase")) { s = va_arg(ap, const char *); if (s != NULL) { _set_str(passphrase); } else { _clr_str(passphrase); } } else if (_match(key, "h_passphrase")) { s = va_arg(ap, const char *); if (s != NULL) { _set_str(h_passphrase); } else { _clr_str(h_passphrase); } } else if (_match(key, "new_passphrase")) { s = va_arg(ap, const char *); if (s != NULL) { _set_str(new_passphrase); } else { _clr_str(new_passphrase); } } else if (_match(key, "dev")) { s = va_arg(ap, const char *); if (s != NULL) { _set_str(dev); } else { _clr_str(dev); } } else if (_match(key, "map_name")) { s = va_arg(ap, const char *); if (s != NULL) { _set_str(map_name); } else { _clr_str(map_name); } } else if (_match(key, "keyfiles")) { s = va_arg(ap, const char *); if (s != NULL) { opts_add_keyfile(opts, s); } else { opts_clear_keyfile(opts); } } else if (_match(key, "h_keyfiles")) { s = va_arg(ap, const char *); if (s != NULL) { opts_add_keyfile_hidden(opts, s); } else { opts_clear_keyfile_hidden(opts); } } else if (_match(key, "new_keyfiles")) { s = va_arg(ap, const char *); if (s != NULL) { opts_add_keyfile_new(opts, s); } else { opts_clear_keyfile_new(opts); } } else if (_match(key, "prf_algo")) { s = va_arg(ap, const char *); if (s != NULL) { if ((opts->prf_algo = check_prf_algo(s, 0, 1)) == NULL) { errno = ENOENT; r = TC_ERR; goto out; } } else { opts->prf_algo = NULL; } } else if (_match(key, "h_prf_algo")) { s = va_arg(ap, const char *); if (s != NULL) { if ((opts->h_prf_algo = check_prf_algo(s, 0, 1)) == NULL) { errno = ENOENT; r = TC_ERR; goto out; } } else { opts->h_prf_algo = NULL; } } else if (_match(key, "new_prf_algo")) { s = va_arg(ap, const char *); if (s != NULL) { if ((opts->new_prf_algo = check_prf_algo(s, 0, 1)) == NULL) { errno = ENOENT; r = TC_ERR; goto out; } } else { opts->new_prf_algo = NULL; } } else if (_match(key, "cipher_chain")) { s = va_arg(ap, const char *); if (s != NULL) { if ((opts->cipher_chain = check_cipher_chain(s, 1)) == NULL) { errno = ENOENT; r = TC_ERR; goto out; } } else { opts->cipher_chain = NULL; } } else if (_match(key, "h_cipher_chain")) { s = va_arg(ap, const char *); if (s != NULL) { if ((opts->h_cipher_chain = check_cipher_chain(s, 1)) == NULL) { errno = ENOENT; r = TC_ERR; goto out; } } else { opts->h_cipher_chain = NULL; } } else if (_match(key, "state_change_fn")) { sc_fn = va_arg(ap, tc_api_state_change_fn); opts->state_change_fn = sc_fn; vp = va_arg(ap, void *); opts->api_ctx = vp; } else if (_match(key, "iteration_count")) { opts->iteration_count = va_arg(ap, int); } else { r = TC_ERR_UNIMPL; } out: va_end(ap); return r; } #define _not_null(x) \ if (opts->x == NULL) { \ return -1; \ } #define _null(x) \ if (opts->x != NULL) { \ return -1; \ } #define _zero(x) \ if (opts->x != 0) { \ return -1; \ } #define _not_set(x) \ if (TC_FLAG_SET(opts->flags, x)) { \ return -1; \ } static int _opts_check_create(struct tcplay_opts *opts) { _not_null(dev); _not_set(SYS); _not_set(FDE); _not_set(BACKUP); _not_set(ONLY_RESTORE); _not_set(ALLOW_TRIM); _not_set(SAVE_TO_FILE); _not_set(HDR_FROM_FILE); _not_set(H_HDR_FROM_FILE); _null(map_name); _zero(protect_hidden); _null(new_passphrase); _null(new_prf_algo); _zero(n_newkeyfiles); if (opts->hidden_size_bytes && !opts->hidden) { return -1; } return 0; } static int _opts_check_map(struct tcplay_opts *opts) { _not_null(dev); _not_null(map_name); _not_set(ONLY_RESTORE); _not_set(SAVE_TO_FILE); _zero(hidden); _zero(hidden_size_bytes); _null(new_passphrase); _null(new_prf_algo); _zero(n_newkeyfiles); _null(prf_algo); _null(h_prf_algo); _null(cipher_chain); _null(h_cipher_chain); if (!opts->protect_hidden) { _zero(n_hkeyfiles); //_null(h_passphrase); } return 0; } static int _opts_check_unmap(struct tcplay_opts *opts) { _not_null(map_name); /* XXX: _not_null(dev); ? */ _zero(nkeyfiles); _zero(n_hkeyfiles); _null(prf_algo); _null(cipher_chain); _null(h_prf_algo); _null(h_cipher_chain); _null(passphrase); _null(h_passphrase); _zero(hidden); _zero(protect_hidden); _null(new_prf_algo); _null(new_passphrase); _zero(n_newkeyfiles); _not_set(SYS); _not_set(FDE); _not_set(BACKUP); _not_set(ONLY_RESTORE); _not_set(ALLOW_TRIM); _not_set(SAVE_TO_FILE); _not_set(HDR_FROM_FILE); _not_set(H_HDR_FROM_FILE); return 0; } static int _opts_check_info(struct tcplay_opts *opts) { _not_null(dev); _null(map_name); _not_set(ONLY_RESTORE); _not_set(SAVE_TO_FILE); _zero(hidden); _zero(hidden_size_bytes); _null(new_passphrase); _null(new_prf_algo); _zero(n_newkeyfiles); _null(prf_algo); _null(h_prf_algo); _null(cipher_chain); _null(h_cipher_chain); if (!opts->protect_hidden) { _zero(n_hkeyfiles); //_null(h_passphrase); } return 0; } static int _opts_check_info_mapped(struct tcplay_opts *opts) { _not_null(map_name); /* XXX: _not_null(dev); ? */ _zero(nkeyfiles); _zero(n_hkeyfiles); _null(prf_algo); _null(cipher_chain); _null(h_prf_algo); _null(h_cipher_chain); _null(passphrase); _null(h_passphrase); _zero(hidden); _zero(protect_hidden); _null(new_prf_algo); _null(new_passphrase); _zero(n_newkeyfiles); _not_set(SYS); _not_set(FDE); _not_set(BACKUP); _not_set(ONLY_RESTORE); _not_set(ALLOW_TRIM); _not_set(SAVE_TO_FILE); _not_set(HDR_FROM_FILE); _not_set(H_HDR_FROM_FILE); return 0; } static int _opts_check_modify(struct tcplay_opts *opts) { _not_null(dev); _null(map_name); _zero(hidden); _zero(hidden_size_bytes); _null(prf_algo); _null(h_prf_algo); _null(cipher_chain); _null(h_cipher_chain); if (!opts->protect_hidden) { _zero(n_hkeyfiles); _null(h_passphrase); } return 0; } static int _opts_check_restore(struct tcplay_opts *opts) { if ((_opts_check_modify(opts)) < 0) return -1; _null(new_prf_algo); _zero(n_newkeyfiles); _null(new_passphrase); return 0; } int tc_api_task_do(tc_api_task task) { struct tcplay_opts *opts; int r = TC_OK; if (task == NULL || ((opts = task->opts) == NULL)) { errno = EFAULT; return TC_ERR; } if (task->last_info != NULL) { free_info(task->last_info); } switch (task->op) { case TC_OP_CREATE: if ((r = _opts_check_create(task->opts)) != 0) { errno = EINVAL; return r; } r = create_volume(opts); break; case TC_OP_MAP: if ((r = _opts_check_map(task->opts)) != 0) { errno = EINVAL; return r; } r = map_volume(opts); break; case TC_OP_UNMAP: if ((r = _opts_check_unmap(task->opts)) != 0) { errno = EINVAL; return r; } r = dm_teardown(opts->map_name, opts->dev); break; case TC_OP_INFO: if ((r = _opts_check_info(task->opts)) != 0) { errno = EINVAL; return r; } if ((task->last_info = info_map_common(opts, NULL)) == NULL) { r = TC_ERR; } break; case TC_OP_INFO_MAPPED: if ((r = _opts_check_info_mapped(task->opts)) != 0) { errno = EINVAL; return r; } if ((task->last_info = dm_info_map(opts->map_name)) == NULL) { r = TC_ERR; } break; case TC_OP_MODIFY: if ((r = _opts_check_modify(task->opts)) != 0) { errno = EINVAL; return r; } r = modify_volume(opts); break; case TC_OP_RESTORE: if ((r = _opts_check_restore(task->opts)) != 0) { errno = EINVAL; return r; } opts->flags |= TC_FLAG_ONLY_RESTORE; r = modify_volume(opts); opts->flags &= ~TC_FLAG_ONLY_RESTORE; break; } return r; } int tc_api_task_info_get(tc_api_task task, const char *key, ...) { char buf[1024]; va_list ap; struct tcplay_info *info; char *s; int *ip; int64_t *i64p; int r = TC_OK; size_t sz; if (task == NULL || ((info = task->last_info) == NULL)) { errno = EFAULT; return TC_ERR; } va_start(ap, key); sz = va_arg(ap, size_t); if (sz < 1) { errno = EINVAL; r = TC_ERR; goto out; } if (_match(key, "device")) { s = va_arg(ap, char *); strncpy(s, info->dev, sz); s[sz-1] = '\0'; } else if (_match(key, "cipher")) { s = va_arg(ap, char *); tc_cipher_chain_sprint(buf, sizeof(buf), info->cipher_chain); strncpy(s, buf, sz); s[sz-1] = '\0'; } else if (_match(key, "prf")) { s = va_arg(ap, char *); if (info->pbkdf_prf) strncpy(s, info->pbkdf_prf->name, sz); else strncpy(s, "(unknown)", sz); s[sz-1] = '\0'; } else if (_match(key, "key_bits")) { if (sz != sizeof(int)) { errno = EFAULT; r = TC_ERR; goto out; } ip = va_arg(ap, int *); *ip = 8*tc_cipher_chain_klen(info->cipher_chain); } else if (_match(key, "size")) { if (sz != sizeof(int64_t)) { errno = EFAULT; r = TC_ERR; goto out; } i64p = va_arg(ap, int64_t *); if (info->hdr) *i64p = (int64_t)info->size * (int64_t)info->hdr->sec_sz; else *i64p = (int64_t)info->size * (int64_t)info->blk_sz; } else if (_match(key, "iv_offset")) { if (sz != sizeof(int64_t)) { errno = EFAULT; r = TC_ERR; goto out; } i64p = va_arg(ap, int64_t *); if (info->hdr) *i64p = (int64_t)info->skip * (int64_t)info->hdr->sec_sz; else *i64p = (int64_t)info->skip * (int64_t)info->blk_sz; } else if (_match(key, "block_offset")) { if (sz != sizeof(int64_t)) { errno = EFAULT; r = TC_ERR; goto out; } i64p = va_arg(ap, int64_t *); if (info->hdr) *i64p = (int64_t)info->offset * (int64_t)info->hdr->sec_sz; else *i64p = (int64_t)info->offset * (int64_t)info->blk_sz; } else { r = TC_ERR_UNIMPL; } out: va_end(ap); return r; } zuluCrypt-6.2.0/external_libraries/tcplay/tcplay_api.h000066400000000000000000000046761425361753700232420ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _TCPLAY_API_H #define _TCPLAY_API_H #include #define TC_OK 0 #define TC_ERR -1 #define TC_ERR_UNIMPL -255 #define TC_STATE_ENTER 1 #define TC_STATE_EXIT 0 struct _tc_api_task; typedef struct _tc_api_task *tc_api_task; typedef int (*tc_api_cipher_iterator_fn)(void *, const char *, int /* klen */, int /* length */); typedef int (*tc_api_prf_iterator_fn)(void *, const char *); typedef int (*tc_api_state_change_fn)(void *, const char *, int); #ifdef __cplusplus extern "C" { #endif int tc_api_init(int verbose); int tc_api_uninit(void); int tc_api_has(const char *feature); int tc_api_cipher_iterate(tc_api_cipher_iterator_fn fn, void *priv); int tc_api_prf_iterate(tc_api_prf_iterator_fn fn, void *priv); tc_api_task tc_api_task_init(const char *op); int tc_api_task_uninit(tc_api_task task); int tc_api_task_set(tc_api_task task, const char *key, ...); int tc_api_task_do(tc_api_task task); int tc_api_task_info_get(tc_api_task task, const char *key, ...); const char *tc_api_task_get_error(tc_api_task task); #ifdef __cplusplus } #endif #endif zuluCrypt-6.2.0/external_libraries/tcplay/tcplay_api_internal.h000066400000000000000000000033461425361753700251270ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _TCPLAY_API_INTERNAL_H #define _TCPLAY_API_INTERNAL_H #include #include "tcplay.h" typedef enum tc_api_op { TC_OP_CREATE, TC_OP_MAP, TC_OP_UNMAP, TC_OP_INFO, TC_OP_INFO_MAPPED, TC_OP_MODIFY, TC_OP_RESTORE } tc_api_op; struct _tc_api_task { tc_api_op op; struct tcplay_opts *opts; struct tcplay_info *last_info; }; #endif zuluCrypt-6.2.0/external_libraries/tcplay/tcplay_api_test.c000066400000000000000000000025351425361753700242640ustar00rootroot00000000000000#include #include #include #include #include "tcplay_api.h" int main(void) { tc_api_opts api_opts; int error; error = tc_api_init(/* verbose */1); assert(error == 0); memset(&api_opts, 0, sizeof(api_opts)); api_opts.tc_device = "/dev/vn1s0"; api_opts.tc_passphrase = "apitest2"; api_opts.tc_keyfiles = NULL; api_opts.tc_keyfiles_hidden = NULL; api_opts.tc_size_hidden_in_bytes = 12000*512; api_opts.tc_passphrase_hidden = "apihidden"; api_opts.tc_cipher = "AES-256-XTS,TWOFISH-256-XTS,SERPENT-256-XTS"; api_opts.tc_cipher_hidden = "SERPENT-256-XTS,TWOFISH-256-XTS"; api_opts.tc_prf_hash = "whirlpool"; api_opts.tc_prf_hash_hidden = "RIPEMD160"; error = tc_api_create_volume(&api_opts); if (error) printf("API ERROR: %s\n", tc_api_get_error_msg()); assert(error == 0); error = tc_api_uninit(); assert(error == 0); error = tc_api_init(/*verbose */ 1); assert(error == 0); api_opts.tc_passphrase = NULL; api_opts.tc_map_name = "dragonfly-test"; api_opts.tc_password_retries = 5; api_opts.tc_interactive_prompt = 1; api_opts.tc_prompt_timeout = 5; error = tc_api_map_volume(&api_opts); if (error) printf("API MAP ERROR: %s\n", tc_api_get_error_msg()); assert(error == 0); system("dmsetup ls"); tc_api_unmap_volume(&api_opts); error = tc_api_uninit(); assert(error == 0); return 0; } zuluCrypt-6.2.0/external_libraries/tcplay/zuluplay_api.h000066400000000000000000000046761425361753700236330ustar00rootroot00000000000000/* * Copyright (c) 2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _TCPLAY_API_H #define _TCPLAY_API_H #include #define TC_OK 0 #define TC_ERR -1 #define TC_ERR_UNIMPL -255 #define TC_STATE_ENTER 1 #define TC_STATE_EXIT 0 struct _tc_api_task; typedef struct _tc_api_task *tc_api_task; typedef int (*tc_api_cipher_iterator_fn)(void *, const char *, int /* klen */, int /* length */); typedef int (*tc_api_prf_iterator_fn)(void *, const char *); typedef int (*tc_api_state_change_fn)(void *, const char *, int); #ifdef __cplusplus extern "C" { #endif int tc_api_init(int verbose); int tc_api_uninit(void); int tc_api_has(const char *feature); int tc_api_cipher_iterate(tc_api_cipher_iterator_fn fn, void *priv); int tc_api_prf_iterate(tc_api_prf_iterator_fn fn, void *priv); tc_api_task tc_api_task_init(const char *op); int tc_api_task_uninit(tc_api_task task); int tc_api_task_set(tc_api_task task, const char *key, ...); int tc_api_task_do(tc_api_task task); int tc_api_task_info_get(tc_api_task task, const char *key, ...); const char *tc_api_task_get_error(tc_api_task task); #ifdef __cplusplus } #endif #endif zuluCrypt-6.2.0/images/000077500000000000000000000000001425361753700150225ustar00rootroot00000000000000zuluCrypt-6.2.0/images/Screenshot_20190912_121900.png000066400000000000000000003021051425361753700214510ustar00rootroot00000000000000‰PNG  IHDR‘ýìâ pHYsÄÄ•+ IDATx^̽[‚ÛH¬,A{w/w‘³ßiÅ|€D>HIeû̉n«’H$Þù K%ñÿüßÿ ’ å’Úy]$€‹|#Ç| € Ákí7‡_ ”b!ÄÒ _Ú5Ì&IàQÚ °t£+ä/@Ý!ÉB ÀKÆÂHä–ž¯[mà—cå —8ê/ÀŠJÓnØ$ãõzEËv—å*"%ÇHÉ&:ÌÉ !vŒÈ–̈e‘ë¥0IÂu"éV%©ú¦v —¥]Ž Œá–3Ã9ú¾Ê(‘¬ xˆ^/†y¯d1^ˆòsÎCŽôl£¼¢ÎS³¹aAɪƈäœ5s.´/½®„Š3ÅðÊ IQèŽQ¦@®ÆÜÃÑ CsC“kˆÙò¥^B .€~5¢gz›ƒc% §Ms²â’ñú12¥då·Ý/k‰nNjöÆ‚`º¹ã25êöÑ[—jËܺI¶¤«õJêÙÙÍ8CÀØŒYLÐ.H¤³¬CB¶<ÄÿûÄ\´g‚‡Ò*r‡ºø+i—lÞ%Šˆè S¾˜+°gçèª%¢R&©–_V% U^ƒAé“(—ÐàóÜAr¢lsò[—0Ï©0×Wíc`BpÅ'Õ6%í“…uXªH댪ðLdÛêƒS°G4¼èÀ_f*!ÎeÎèRdÖ_åHÊO¹É_ˆ#GMò]b KÖ VßÕÌ'Ig È^(f„¬àz¥!ò¢Òºd*;‡†‘Dúrƒýrpè¥j^OºÚ“4o—|µã´ìc#û¶D¸p±"ðÛÆ÷Ý™º\‘ù^·ö†n_ƒ,eZ7\1*HS†‘‚wî¢Ûñ¢‡VpÜnv„–¼ÚRëK<×L¹¾…ö(´25–XH®•¦²PUÙ¬‹)]Ÿ, ,¹ ޾ÖÔ%xqéùä/аzͺ$ "©—€ˆdÙQÍ[1‡Q!æHÞQ:$e¾æÜ4â…<ˆ8Æ_xy²öÑchÚ‰(2NœÒc/a_ÝvÌõpòÄXƒ´ò•S‚M;‹Ajô㿤ىuÄï}òeµûŒƒÐHID>CÊ…lÑ™HþºK#ë”;ÖÚM„‚8lôÑ%£lðÿrW——“B,á‰>Š–D‰öI’"]¶’ Å5À8¾®®±—±­˜¿æ›ò²pìÿU½ŽÐ{(à Ï2ÀÜÒõŽ H±ÿV€Yô‹œìªøÛ” ÑÇÈtäu.ÅI#òšÁÊ Rƒ[“oy®…_/RR#ŽFŒÏ(øÊ©¼*úžµ-·Äg¤FÝШ_¯:ë…×eóÀùèæÞÛ´Ù»zyFFŠè¯.°6ô°Ö£Áf‚O¼Ê N·JÀByàÙŽ4ìàÞœX± øÂ¨ùp¶â õ ¶¸'ÆÌ‡ë0{údÜÁš@ ¤)E‡wk¤(Á¾FäòérhëQ !ÃØ±°Íò\!麼òlš•ÌY].j¿¦CÌÌ„ðéÔÁ¶2VtáÓ<ß ˆ¤¢–^’E;ózX‘RÜ?w„Ÿeibu“„jÎ,£o°iqèšÚv²öBÂØîQÊAÍa¹T­AìF Q»Ž»Êð„õΉR½á¸ðý@ ɇݖŸ¯¹{šD3â˜]-:mOWJº{¾J¿p©ÔàˆŒD õ–‰`RÞ”Maîa Ò©°õ÷ÄyƒÝ™†µâD톺JC”hs¶»'â°bJÌÕ]õÞ{jÀU[o_»µŒIóºÁËŠ°ùøª8ÅÀ™Ò?WÉfŠÌo^Æ!’À™¢nq§cµF•ñþ0—k¯“úÚy¢3M±5ËRóÊø À/4[ãÉ΄°.åuAWl³’Û0­¸ LMªxª`÷(1é]á\¨7Ø+Ž*–Üí @ô==òÕH)c]šƒ´­qÄøg¬¬sêŽ.åˆâœÖv¿FÒgX–àýlª j"ïøW†-ùµm˜rwÀ‡QŽ _qHÇQþ"\LhUíáYlðM_$<²6+%bÅöß/·Äٚ˚IVXÝq‡ŒOXá”`(´GpïM—aQ;i;e9O«QE­žHHñ²ËÃùÁ1Ø+Âî âtØ`D°³Ìr %UŒÌЂƤÍ;zI¤aMUTD·¶ƒ’ñα¨,Îm Ý/‹7`é$YgÖ.ú{ìÂÇAÑé 5ÿ™ùL$ÆOiêÀlóÚû)†­ÄKâ á‹Q7ÍÌ縅±SA–ã²®æ<†©ñŒNɪ5Àl³t.ä]Óǘ•.V磆|"’ ß1Åá½²¹vdöUº’>?ú« Ù˜2)ümEó jÁ‹ÜpÇaßï.W‚Žõu$.ø„g…Ò¾ÝįáöZl(Œt#Ûy)Ìú/p½5íyfmX˜¿×3ìË£c\%þ²vÊ<ÍÇ%ÎÌÐæi²ÇY@¦8è"b•xA¸rGÉŸKŽ+B"ȱ;næ¯6ÅBÓÉîQXÖPê1Ý”\ŸØ…`äQí=©ø^ÈwKg›·³£;½Èçxe‡’$‘#Œ?Ãqøº*b ô>j§ò^-ѹÛ7±Ï&…î#ÀÜOæ½»’õ]NHÂ7-Žyzi‚Yà˜½«?ø=âÀìrÄÂÝ'S€ÙÒwPSo^™QJR $‰ÌxˆHÌraèî|Devö£ç¬ïІEmžÞi1]' )&¦ÓÍ/ºÿ‹IYw,ÂQñ:ªa8µ,y’Àæ˜^[v1ç(m!¸Ñ øG´¿@˜p€š³V ÑSty071{Ô'rÄn|OãŽö™óÐë€mDEôÎÑØ~ W=Om®v6`¡—¨jtú~Î0JÈ.0¼»®ËºáåhÅ‘¸‰ºÇÊ9™9§5*¼÷k¬ù¼-üÍÿÿvQ·¿Ä;Ç·Wóªµ'ëáP;ö²õKJ[ÝlgÔ}¾ò›b«Þ$<*ÍCí.4økÁ5Ÿ_ŸÁ^l!ê'–n‰¼•ç‚–å8ÝB ìä‚WîDu3–Ëu³í¼‚-NýE,ÆÜee%­ƒ_׌Êf—ÐØX÷ÿA˜gV_ö®»ðlV{©/úú[²…oÁâAY~Çàñ¤¹ çxä*JvÖ]Ÿg6úeÁ.&. "~t üÐøWYOjÊ­*ñkOÀ]c¨û;%Ș½*uH?²ó¾í©o)Å¥ì:ÁCmÃò¬Ô¸3»ûÞy,ä#ô¹*ü'¡æÏÜåËH0}kô-jر8ÎÝ€åT±plxÔ“àGDàÛe RÜBPÜt @`]€d˜º[P„áä·Y¸AÌè,‰H‘cpCçlíØj6cNÈ8Ûë i˜fÛsQ£œåžúBÄg^HM fhÃ-vÀ²Vs7tÅ“w/ý"_À!›)tþÕË '¥‡TŠª.Ií× ¯õ±JG yƒR~?âÈQ[ÐŽ5Ùë¾e`hÕÊŒÍÄ{ÔØe®ò}àšË¶xBÙQh# €Ÿ#ô&'ÅßîXú6-‚÷UAôï®ê¥ñ(1¼~ÖPLV{€H¶Ì0ø‚Õ'Kä¸M¦+„ä7P®t¶)S™þ#ƒ\9ŽÆÃqÉóÌÒô\Ô{ é þÒ|ÿe[±«'Ù€wâ1ãn­¹C÷qÏxV!oؾòÑÝ6"0D¥ëyy‘ð_ÊÚþ&ã,,§OªF2*‰7¸íLzó>Y1)„Ú‹ÃÐxX_Ô<®Y²ß0Ã9½‘—ê³2MYIJ'ò°3b}![ê¢BPgÌxÛý ) ÎÉ‚’>³HÀï|L²Fc™]7“Àk‰‰gM…W’ç«$ “yíQB®ðR| ‘×¶p´1ø‡â v4ãmƒ3X˜6¼=6ÓøÎzc½8Ê M~äA ‘'Õ9—˜a¹»•F°©Íš%‡õ2Ãé³a{„B»­\ãy‚܉Ôú"@€ô‚Z†ºp¶½{T£‘Äð7õŒÎjÕ¨ÝB©tð;uÙA²~å׋!Û^’$¯Æp–¤Z6¥®Û¿"â³’Ï6R,9rJ³‰Œ~)ä>ï0ÉšœžgƒÓ{I¡Öb 쯅ƒÝʣ͎¡ñ^õ†&ª[?èDì]Õ¥³t˰Ñ× >ߨWëË¨Ó °´ØÇÆÈ©UH„4±–$ém-F½ò#ÝÜ €y]‚«-BlÚJºo „þ4’d-%É@’ð§ ćÌY ] „ÿ^ÿ‘ôGª>­†9 á´°ÆVm$-+L¿´U%$·´è•”;zk˜]ß’(ŒuL™YÐáºGöÃê*ꌱÌNuÔºñ÷,óauOÝ ç)Úa—¤$[µÖkü°u5Xã1Ë­M9€C|\«¼ÁÚ©›0îÅêÖjò•…ÜØ9 ‘¾¢ó'ó<ÖÆúÀ#çÎm÷c× ,î£@`üÝY†õV§DÔOÖj½•ÚŸ›š™Ý(¢ÏCk>??+\{åu•K€/€ùÒ·8‡ûAûêyõîCp<Gù&½rï©Ç_±e4qÃ"")øSlŒÕ'IÀEFКG~×—Š'éAB*òk‹J¢érröUÍ!Î|-ÓÍ1ÿÛÎô'©Ÿ1ììÔ„‚¡qɬí#¡ŠB †öèCâl1!‚86îÐéAõX=ÖÌ" éâŸ3!I9û†BÁ;ÍEØZZŒX(ÀùÙç Æ àÒÛÏÓt†cXíŽÕ#´à"Q·Ðw"ºÚ!ÓyH¾øŒØ'B_#åICœ~`‚c–9¤Ù)×,}À@s­†€Ýû8g‚Ó4¾C„Q>·É«‹ƒkL é8 aùÄÀC:Ò°r¶Jû”rûÎ’(ž xÊ…{bšˆI(€P8 `™[ò£Ù=¤kxc! z ¨xn­vfMçú®µ­Óù­®É‘$ùì¼2ô(;·á:Ö6ìn6Äš²’ Ý(;å¿Út¯œÑžU"¹{‚¤ÿÄõkAž¤¥ˆî‘-™!À3ýǰ2 & áô !¨mÙXrùj[ Š«ä“1’­JÑøMÜð„&ßb#¤6ìÇÞ ºüÏFU´KBÊìˆÞÿdtòæ˜ÀK º2§å"=Ž{ç 0¶ësveãñºHê«úG°#çt»––./Äó’ðƒî›iG!+߉%kØWìCÒ™1l “6c}i ¡º,?‡a€‡œvÇÈ¥qÑê¿h§ÂÅ|ô@Xh”–€´aHW:E`|°@î”,Ð*/*(Ñwù‡¡ J[6ÈâX‹Ó”û&†©iFzÑ%=˜û„ºA?žºýŠ«]!€0’Seÿ‹û¬‹$—µÚŒÅ~£Ë¸wá`e”YŠöÌž›Èz˜»âþá4 ±G5½Y¥Š­keüD;¶äYq8Õ 8»>ÇûdÒ›Dæñ{pÁ64Ñ]Ko éf§äÿò›2~KñBÄ`M•©ŽÊJVÿDïÞ½#eåäôsÜ1§×JW´ØCš{­\d—ZkŠÏX˜ú¤¨(PEL€Ðî} Bþ˜Ãàœ Îƒl/´I9ƒ¡ ð’:ÝÈtÌEÐǼ`ÙÊ“^[šDJ·1”¿L¥ܶQ¢_Ì< 2]ËåždÎZ‚Ì÷yôr„§"Dßì¾ò»§XX7÷nÁˆ†ê.–ñN=Pɨ«ª*»#Ķ=T¥›A3ñ߉ŽPä ¡L™Ê'jYQõûÛJl®'Aœ#TŸß¼Øâ²ïSî}Ãu@Ä-m:¤#îu'~ŸÊÚkFržòÃü/ljF©{L}ö£ ,sy̯"ø’i<&ºu“ãtÌÐ$G°üJ¥¶–ÅG„=3‘¶Ç ½ÞJW]Ê*sp"§ƒ y-›ØN'Å ;ÉžtÊí⟈ÀæR)L¡ùJ噆gìZ¨\!œ ǹœ$-¡Ïè£kÅÐ{~õÃ)å“…SÜå…ïׂÔo6Ú¨ ßëŸ~½I¥ÅÊ;ƒp BÖÂ0«þ'†˜ c›nÀ%û%«€‘ž"ڜM ÞœCO#á·'”àµ`ñöTšÃ½Cˆ³1í†)šŒ˜ãuFp?‘KCÍ: ¢ñI·ÙÈ9(úÆ¢yëÑ[y”ÙUI$(I‘a%ˆÎž‡ juS¦àE˜@âx˜CŠ Vº§yðLÓI@ÿ$qŸé·rùªŽ¥=+¬‹4­³¸@CFˆèÁi½ǨÌÁ|df<û ¬&‘âÛvR‘‘.¿n!¡9¶†ñ“iG¤—.ÁµwÂ-°îðsìH¢Eª²ê†½]#>sH-k °Q" Hwp : KŽÑ·»mUlÅrÀÕ<Пü(;·!…ª3MrìÅéâG C`KÓâæÞÞÁbÈU„1w¹R̼ÒoÒFZ²™$IòÖò¼ÌPÝ©\À/’c¶xLž¦;ôeïªöh“BÔ %Tr_°aôDã0GÀN 2¢ý Ë-ç([QÔeðÐ š¹ë2‚4u²É,ì“i wf{¥³È)oéª%xê~å;L/Pûè·p^ÕS³Öm…ã:i)¯M΀i-`ñc,HGœ ¶ ³¼ ¿ÆõçXL˜%­nO` ÁÄc›î™'¬¯] ãMð¢Ãè=ƒÉ{Ï#¦OˆíÆf¯sñËDh¼‹®Ÿ¥Äֈ쒌ÓU7¯´·o® ¦» µçF3ÞØßÊ.%ȇõf"ã0BRcãtˆâ_pMÖ¼È ÇiM<‰Ø¸*hkع»Ã(Ék-> Täˆ%¶sXÆ“dìwID„Y8ùÃÒeâEDNä½×€-Y섨ÿá$)¤‡Šn^ÌT(uleÙ2:?AâØ´3lXÁ¦¾ùüø…–/êw~L½[¨¯}Ôšˆ p9ÿkÇËÇ(ž‡ŸP"Ì\n~8ü€1e®ofâŽ(Px³È=kŽ‚ÈáÙQŒ‘K.,0S% áäŒ÷¸ ÐO98L2;ü…ÒįèN‰qŠ$[²²Dyš/ÄæŸ[ãNõ_žšà¶ðîæ±'†–ÿ¼»ýˆÕìÂVüKéó('eìÂÓÓD9â`²+…q6ºX]Á;‰"q:E XÊæðÁÛGù¸õ0­–ü¨l¤W8ö³ÝÝáèç¸,oAý1&€x€ @Óƒ}¼¶C—eù½ëOš„¼¡A )Õ¸—”,¶?j)«-Ž v,ÈÚrhÕ¦AÉð«\Ü'ÉB©ÈôÝ¡xŠø¨¿˜¨I:ïÿ´ê÷uè L’õ÷åŽd]‚Qê5ί“½RuµŒç ßK”žŒ€ëƒ¢^¼`V‚Ò¶£^WRn88y³¹V yIÿ!o`¿X|G©‚ÄZ¥ê ¤1SŠ ªYRò{su´]¯J€ÖÆ¥t“Ò’»ø ORO ì×:Ù&-äºdD&®±“˜{Øaù…E0ÕOcà\·G¿ÞŽšAà`¼õC×|Ji~G{:ÞôÕ¥M=o?ƒ ðu¨¶M†¯.”4CrðHºœƒÒÌ@nX%:,‘9®®*m´öÕIcì3qê=2® †{E„Š"М¨÷P؈À“…ƒÔ•– 7'Žì½QYqš¥/ÇxÒe)€¼,r¬‰¥6jRžR› €‰épgóŽcîÑØmJ I³Í¤b½‰Ïÿ\QdA÷w~ØåªÈÖïx+aPð’®ë"ç„mŸº‡ùǨ¨:ÐbtêüÌr¹gbd#ëÉ’Ç’cmJ¢øï ^þd €ŒOük¾ÄRw¡”œ ·7Ž ¹8R˜GkbZÑ-$0B´ÏnÍÔÿlK[è4gñ«+y^É„üqÍ©Z@YÄ9z½^9m MQR¢·Û,—Í~‹¬Ñ•¾“³“;WÄ0ÙT”]Þ„è¼2€ˆX?#") M$ ×a¨v¡–FÒ1¿UÑ:¬e¿!.×ìò4³¹þ381Ä^¿àéG–©*7ï @S•|ƒG¢ÜذV‡as‰N†ÔtðªÂ¨Ê ö}~’‘ߤ5Â[°R[™EÄ49P¿F¼¼‹¶4]~ÐN Š¸CÛ‚¼_¸[Y KÃŽ9Ó'ˆO3%·Å_ø ã Œ®X "´@*Kr’Ý11W‘¢’èé ô €ÿþ{áòÓ£4.ÆÛæM—û‘ü‹L3z Â›”ƒgöåºÌf칃¡%î¦ôOð›ÊzÒý¡Œ/ù H½$¸è÷ Ÿ¦€Ýo[[vd&‡ƒ¦²Åeh+¶¹dbžìw¡uãnÆÔ«k°ç—¿Jô%à Ñ`øRËöxÛî.zz„…»ï’ÿ¡>§¿SÖ5i ÇI™£üí¾q2Sü{‚ì§MHÍ3&«{ÇâÅI}"´ÓÍ'ÎÜÙqÁ°<µ•#K=Šø}]$µO–+ñOñ‘hоiÎI´©g973®PnŽzXÓx–s€$ÆiuíÈl”à·³§ ŒÈ1§ê¼5äåÊõ<ÑhS'y³Æ3ØN¥zäìØLÚà~»jsÏI”Õ’0·–'<Óå1§…£ü•޼â6}Œ..‚0g9‘ˆ!Ôçı—Oî¿Þ Ê%g ÍÊ«èýD¼Yì˜t—ßà†³léFÛ‰êFi:°Ãfu"9àh|  YضQ™YÙºa†+Lþ=fFBF…³˜ûÀ°rÞÚà®×"¶3DË_¸JBòÙf`ôù7?@jf@l;1á ÉâUøl[çA&±É—Ê1Ÿp4ûobÑû?Š£k7ßÝêÅc•ü˜ÿ÷ËÏáë¸#±%¾dœÌÏ÷+ ÚÚáð]%€kKÉëK;;ÐËá4=ZEÖóÐè%¥GeĨ»;”cBÆ|9AŠÛ)½è€¹Ðòö³|qƒׄ˜ÿd„(Ã6I³ IÈ2kýЯ>´DÈ"ô•$:–!¤ÂÞÛC|¥5 Á¶Õ©÷DÚæbÚ7¤›¿| øÿ¯À7‡ª2éÉ8„ßËê3Àö:§ uRGúâ9Xíb 4¾Îç„ ž[I¶ÐQ9}„#°Èy¦Äanhúg&Úôõ¹ÕQå©Ù2&Ž…¦¥ûXw×£Ÿí–ñ”øB<’šÄ¬±ã9 f³ŠyP|[3I'¢z;ÅÛÌØ.`]¥P¬„ÎPÒWÄ ¶’88“s UÇ.Ÿê0¶±Õ@<°#€ö¨£—´Þëþ!%¹[žæ9«nÕÛ[öcq˜MQ½ Þº I óI×Á¤^BƒäŸM¸qµ^ìŽät,ÞäuéT½”¹n̉uU0lÌÏ¿»¯´ê ~KB Ÿ,‹I»e÷{¾ÑR²¢tW_·gIÌ ] Ie¼Ðçµ[‹×E<«XÐÃBN7ëîJ“Ex®†ØÇh×@Eɳ_³ŒX”[<)I©KÐŽñ¯öh K/Ã&ì>Þ%îc°ËèE»°üØ{=xöõD IDAT»¬&= R0$/N§ê$TûŽ…Ë u{2ow*Qă’¥“ |ÿò4žöpO\?ƈ!†ÌÑ&Õ¶sŽ€Ñ#½Fï#ý<Ô<ýK˜ŒÿÂB/\”·L#$_âã¤Ï˜-%qŽ4Ew ï…ZÌ{)º¨’ǔ؀Š7èÉQ^‚Ñ‹g<¼àî/I‚~oIv† ±Œz•8&GÒ0lÒ}Ä1 '¨ iëXÑ½Û <$4ÝühÆÀÃéAçóôšQŒk|OسDß°/JÇ3”è¦Ø­…gr;îPF»zVTϲG´öÓplNQ Ì1‰ ó=@cŽ"|ûWá°ØœÌ0Ó1CHþ7ý ësÖEè:æç"ÆÙð¯jlöRU¦T|õÚ±ð?yªFîæÍ ìÈœš;H¼I×á\²mm#@³ŸäuxÇ_‘Çs,²žóLõÇuÛ«sC1DÊzî~ǪÚãý‡ŠátLîÁPšRWn9Š#AÏè)F>«‹lº´ŽŠg  cŽÃ>Ãý3’N Ó:}ö‹°uÇ?m|œwðOòõ˜²Ò˜?’LÀ•&©WÃ<}ƒ·«ñD¿Ð¨H¢Ý[J‚ÏÊÞ§°QñÀ%¯I^=HŽe$ë©jÞß§ÊɆå%mËÉ|»á·˜†ôO>þ’&Õù¦‡›±HqÉ‘#¹KgsÔ7–À¯áä «ËųšªmÝaó±—ÇO’Yàº]"CêdetËfazp±GX\ª·ö÷±ÿÍþKu%Ò°iàoÿŽO«Y! üûõƒã†Qœ†Ñé µMîgè2U·Âñz÷Šw.aÒÀmM$jMÉõ4»Õ÷Êkg¬ÞÅãË8½Ú§r¶_ÁXl´£ï~Ëãi=Fôû÷¶2Ï\ÖËú¾‡_öY^u^źˆÇÅm²Eq‘æt~Îw4ƒ'’M¯ ·ÊÓÇáD-=A$èLÞ‰`+Ÿ¤ûü®(|ÙÒR:¢!M_`q€Š~Ïòhè‚Hp{ÛuÄ7¼@(˜Ñ»f|UOeÿ=\ù™ñú?©­çUGYBT ‘W–Ìœä}­YÁ·ï4w²ùÐj—ħག¾yàñ¼ Ëk’ÌG¤5јt!$,Îa3$´òÄÉÕ$Å?4EÁ¥@’µå8rŸÜ¶Õn 6ø3ØÎˆ·4¼RÞùg-¦ùâŸ"µ9x•©†Ê{„'NÎŒ®rTôíL^ÚA; ÷³}ÞôÄ9ûu©­ë#A6âÂ=²X*(sîT„™~ƒ¨Š1ÊXǺZΉÀí:Îúƒ¼$ôÞ]QCxœ…78Ø ¸õ9]2óú²k¤qnˆÐÍPÛRX­¢h¨(f›6ˆµÌÊ I‚Õ\ÚZ6—MR¶ m„Dš¹×_yxD!œCsÔ" ÈËSéJí÷âé©ÃVœ±Hh—K¼3¡ ÓØÖõ”Õ#BÀl›Ûc°;oã8àÞ¶Ü€§cãœ&ÅÇ+þ)vš Ͻý‚»ã[}=7‰I“*Âd|œs¿å³ä5 u¢ý PŸ©œ<À›ÏˆÓ–ÛSO€d³ C’zæÒ ò$½Kh=Í@%äÖ¸˜[Œf]«e¬%œŽf^2Âf"ü ¥·Dpg\Dá¦iá‘¡a*¡»-_,׺ùÌ€úÒ·’¬æ‚’š†0‹ ñÌ¥’X™ZÏ`óq´;õ#ÝÊø9ò“©ŸLrŒ#3 ÏS︄[¿h•G»kÈÚ·©( N)?l¸Š%"”#H3*/ÈÔôÎl¬†=â<ªç}™3ÞëÚìüåo×N@$$Ië{ © “=˜ºA$9·áÁÀû'[3‚ý¦¤ln¯*¦²Ú8Âοz4ê»ò|y‡œ€uld` å$ˆtæ9}­‹/=CÜo ´k /õ u}K™6HDÎö³µD€¤,ú·Úír€HÉJœ˜Ž°±gÄ@ÿ+Q‚ÊQ’ˆÍ ¤â8Ç”LÕû’.»skjÊ!´Õ>G‡S¤ƒº€œÿ°‰ñ€ô’z…œ! /Ûw6ؤ÷°õn<`øþCxìÎo\íþ]î7Ý7ºgæá+HŠCÑ](ÞßÜaÌÕRI—¯;&‡Ú…Ü6DÖSLú³øãr•íà טB¼(Ѭr*!LQØŸðXgÇèéeôU;™£íÿ—{¦åY"šËað°g9³v59û0óiÈ~ºÝ¨åpŸËéävöÔ¥íi‡ù©K­=ƒyl-Êri·}mcÛF¸#ÞóLé†9+S@ÀJ¨Ÿ[‡ìI_"“]M‹ÆeN‹¤Ë§† ©Èjá°œ¼XÔ¥ä¾X%oî–1As‚åõ.í<ÒtŠ^ð×°ª–$¼GÎ\J±À¬FÌ(áÄ5Úa¤—“š LëЀ@މ/K žÂ8ÓøÓ#Œ±!4*T’ v̱îùÙùÜîp²ÆÕ¹ÑÝÜî8l&;O÷=±kÝÜ„$ÛYnªl]¡¬©Ìî嬪—ö6Y‰íé¾ï»1ò?Ÿ¶t¥Þ ’¾vœˆËu›ŽÇ lã~М@­<ñÒöÖÄ`ÞŒ ܨPç_x8Ìx™ê&‡ß†—ÛŽ`9µà¤•)o$ÎØåÑxîâ€]óžñt¶fL#,ꌜŒgÄ÷`uü¡¾$øðú$xêó’× x4ì¡ëÓMÛÒ×n2ã¬9…QõŸØøØŒZ%Íu/kVV¬,[ûÊ(«à¨Ê±ÙdbdìLÁ=ÏŠÁì<ÍÃÝþ 2]¤ “œ.a2¯gßvš(½*žNz çÎ8ãh³$‹}3<ìyeÌï9F!&¦¨†ÒA¼ôsTÄór5¸.ˆ£j›TF±ÿ"7Ò>Áqà‘ø)“Ù¥;?A½%éIHXòÄbäÆºÞX*/I€>De&[Ÿ×µØŒzíS k’è_ã $B™ÉÆÌçtÈCÌýëT†ÀÉ6œ\½ƒÈ }q¯­Ï!Lll%é %í üShû7` Èõ=buƒÉH©Q|´¢b‚WsæÙëV{ày½â>DYõ`ºZc@’…ލÖ\šõ )D¢+H€˜ƒ7ÌF¦™°Ãˆ•?.Úaºf[´†SiJ”!@zRgš#Mû§·ƒÖAq-ÉZáÔÌL#äƒ&mA*žnÅH÷Ž4ñlôt2¥õþ)ÍF~ ç´Lê9 l„Ÿ¡$KÈpí1ÄÏÔ¹:‘j žœÛ•¶µ±#æZ܇–äž²LŽIë§_b`G1\—K.#nÁôãÄ&‚yY$I½Š]°¥?þ"ž™Ñ&K^Ó5ø-ù~­Ð€/`8+é>îåîÒjºóÈ´¶C7‡œ¨…~ qcRmÑTKIbxÍÌZöŒó`°ÁýÍænæËõŒQ]>•¨;ׯãí@Ør‘ØC´'è‹=õùðÝ’ˆàNÁ˜†Ü0tÚôÞ€#´ 9>'o… Øe£€ÜÜÌÙ<'Fo*Û¥Ü.RòSÈ-"jÀo«õÎïv¬vo~oŽk4²ñ›Ü9Rv+Klãn½ÕL×LøUê @²oÚ3J¶†ô±Þ=ž~[ñÈ“÷%°ULÒ! h+~q…ëqMšŽeû6#ÜÆââ{²['¡Î>yM -lÌç+/äór1䬳tØãÜ9‡FöSŠa.@R|EÉ©Êó› Ê—‘÷¤"‚å+£8Ý­_  ¶®•‡Ñ'9¬HŒ°ð=ȘE}VÑ0Ãcú¥hðPfoP|eTé2eup Nwf'~‹ÝJì0òA° â—­þk<´J…‰ÄXTm³«Ù+þʃm!š§ÿÞÜãÿ€f™Îv@®E*^곿÷@:“ÙŽØÆÖñò¿¬^RÈÉB"þ³^?7{@[’±¥)fn¸Vˆ¶å)Ü™ð@û…~~×ùèmú@ W`û§œ|@  €¯öÌ5ò‘ª¡£2Ñ[2ŠžÅ†#x®sPü^!?yöªÕ¥sË®WÕ…¼°YòÉ`0lÈåVð-/ÕÐ$Òæ]€0žýZÓWïa DñŸ¼;aa°íµ¸ÙÊ]ˆí”÷eáe]ÃF—L7:LŒ¶¨S€Q-Ý¥Ó@æËÞÛúî~ ²O@&,µƒÌçÿk’ÕD˜câo fgVÉÛ Ðlõœœ~÷ E3ÚkQ ¿ ¾ãÀ1~BY8cÁÊ¢ÿ N1g:Ò® è$¹ /ÔK(G¢H2ÙKN&Œ8Ïtr2»Gi$'û%É/Gø©m^I€SBár.©ðLBÅdXFJpè$¯cup‘¸¹Ø7¼!9vƒÝé‘ÈdT×€-èáªV¸R]'”Dë 9ŽÒö‰Š †êñ#›–ÓVÎ]Gä78šùš6¹+®¦b>zXËŠ@¢bÏ:“¤nF/hf ˆ˜U“ÓÑ[à²+ ) Å”=ÄžlHCvvyvùrFÓ˜Ù´‹êÁP­Ú\XQáJ†ÍÆv— ¤Yh/”AÎy<³& 8ÎQ±Ç&ø; @Ô§ÉQ™IÀÅëšßtH² "èÝa$Ùbr5!‰ø †)\R¯ôâ|BŠ·&J¼_=š,Iu- ²¹ œÓ3u*³ŸI»?Ò $c%èé5%Ç­÷Î7éøD†]ñÔÖ¢æ`R²Áz¯ÎËMšÄ:€ œì¬¸˜>£y:d©ìü"ø;Ék\“‚(¡œ#lÆ÷a˜'[å9P m °ê.R/Ï‹šÅU—½}1n³ß£3…8µˆWK_ØÄ½Üuþk¶ÕâX1ÒD*NUæA/לax’ÚA@“À gZI@69Ž8ó*4éP‘ˆžâ „pH×@ØBŒ=Lʤ¾U ¸Ø±Zí|™¶Ys±å vQa§™žOOäÙl¨¹åÆ.#(cñéðżºÍ“ˆ s(rT‰œUÆÙ?†Dƒ¾šv{G½  Lz¨U¹:e¨ˆž½=>„‡-–ݪ˜!¸úß`•¡ rZ±øÏŒÉXœœ´E®ŒsíW¸±ÐÄXâÜŽŽÆŸ¶z¾€fŒÉŒÓ{Ü5'0Ú§pӼܟbnìozNHQ¦š·µ('Ž"9=­žGô ®kLCIªFS6ãVÆŠ1ú!ÜJ¯¤EYVÉbó;®w³=NÛ™H£î³ X="zÑQî“C«)iICùÚ©Õ®(_Ü,¬«ÎÎ)À3¹ãÖÔ‰H4ȱ뤿+²mýÏμùGsáXΖ@à¿bÈîÙ­ö¾µÐN6OFmÀÉ´Qmô•/CQW5aÜ=¶ó#‚â)5Û¶Ì#^ógÀq£{AÖ6è¥êîVY"^bÿ’Žêf]¶XmjËŽL—œ 8©5þi`R Éÿ7Á´-bàÌÈ‹bs;9’TLu*eºç€v úŸ07³¾FÊï÷Ë0?©ƒ¾ LúˆDtUiŒ§d=ZщYü &RZ^ËRz ž—KTôŠp³? ÆÕ¦#b’#J<‚@ß;On I$<‘î û!šãß`e÷ÝNŒ%x¹¢õ}ÝH–@v~‡¨ÿMZGW½^†qñÒLÍï3Wh‰ü‘Ì'/øPò¤?ÐWab6™³›ŠßàŒ®îÚÎ_ ÑîÔeŠÙ=ÿÜH†Ýþ¸¼~wù–t|‹aT¦`ÌäG±’Ò§3[óKÙg»…‘joÓ o»¶I:¯: ÷†ÚóŠ"Ÿšyw8Ø0;ñ$Ǧ¹·%`L8؃º U3%¿·ûïú#fÛÌ…]rûW{›ð¹À:–R©7ãýÛ”zGÊa3a§ÜJÐ\î–ûíR>_ì<¡ePðJ”—Öò“« •ÁÝÀúà-žêü…(Å#×V'Ó*÷ýd™-qµ˜eã:W?NMš½ û±K«ÊŒnψªÿ´Àù}É6A"걯¦™öJ™_{ŠÕÙbâÐ4Úc.8"×»zèÆúÀ„ë3«ÚH‚±ÑB°q[K$}Ù7ûÂ' } |‡.ê"¢z=ðu£ÉOs×3ô>“Ô<ì³Èz8 ïF!bþ~Û"_°­¿f·L´žíÙ}ç¸÷ºâ Ò„ÏÃ[ƒoL°³)#„×"L7cŠ¡oBÒb¹|€€Ùñ;§èÊcmž`çµ)‚ï°DÕO¶ÎVŒTœý}I9ëÍÆV k3¶ätg¿E{¾´—Û\ká¨Q©bp¬P·µÚpº3u?âúŸXûOÑâz‡ÚØÚÀø÷/Ñ3%åÜ5Ï”âæ ViÕå¤7JôëpâFøN‘×| ÿœõÝ¡AŒßî¸<Ó8–=¬‰×å¾aÆn¨:…ý.°uí’3á±´žJ€EõµÜýšÓå×íéICìá½½cü±'6N Pü•pw“ óš«#_b‹aÁZ"PÅæÆˆ)½¸•ÊK‚^ºy¢I– ŠÇïЃ³‚#©†Mô ?ƒñÞßЇûá"ÁÜÊüYÅÔÕ}BÞø•ˆ˜ÇÄ>‡´aqp0ËUUªIÊ&îãÜ\[ëáëð >Ï0fÈ;ž%K ÑN–ðÐ&à„ûòlR›ùÁsD&6Œ’¨ðä‘vø™HÒ‘S’–Ó]@v`ém÷HÖ®èOb »À«G,"ÙÄÐ/›ý2†ydükáõî—!&×*¦ÇÿÊáý?FZB:‡S9eä2±® ““¤PÛ£Í)°R¬Å‹† ר%¼ÛÎ0ÀÍçñuD^ššÇø9Iög‘¤¶Â}/ À'Êëxm#ãxZ»ÉW|oêÅéÖŠu©âà›7qÆ•Ï%ÿ´:¦ãð èeGèIJ^ù¶fóäð6ĘC\ Ãã¢u@|'ðêïiNÞ}ÌÍ_]Ý –½÷Yqq%º#Ó`û^a6©ÞIáª6’Œ{?œlcH÷5ia­ðTžTªV Æ&ˆsÉs¨ÿ>ì΄æ ýô¼gÓÍ3Î]¬| ãKþßb`žçü÷,þA8ÿ½ŽŸ7»!ÉØ‚~€ ê¸ýÜ€[¬K·M'ïœßÖ£Ö–Ç*7_’)ð óÊ>Äæýî¬ñVXŒíö’,;­¤èÑð†Æ¿j*;g™F¬ù^¼¶˜­¢ ÷î5\€¤"ÎÂÃo{ïARR,Ù>ÿ hr¤ ˜×òhèÒ®Mø2°÷~nÆ#æYJ²UZE`9ñW»ÌYY×à/àpÅÇ¢ö ÛÚ1eHjúß IÎÉô>Ú\}?, ÏÐþ¤C)?("c"np¿ðÂ8k°9ªy *$úW’‰e" }”îš^|ä]à [×ßÇ¢gœsõ5†Ò,…¼j÷3±Í݉«Ï=ï¦Ç4Š~™%ÑÖžÅϸ°žáPhùËÍ"òº/ôô-ÓloZˆ@”e'&ç× ›ê–” ”1iCr|ž sš‚ïϬš[ÄÇx[MTØäå€$ù®è2| CYV˜…¯*Öë'tÞ§QˆnèÇGñlÿ½ÊÏœ™§QGÔ)vm1©)ú3ôéÑ,œ ®Ô'¥¼ë?šäôlÇ?C¿5VÒº%½hë„RÙ%àE0>z’0;û)üȪ“b ÌD6þ >ö¢å™— IDAT".ÿñ ˆ}4gRWÚ)í¿²ÒÄ’²äkó}Ò%l¹[B7#{ršwfbZ‡Ý\=ÛÒ'€KdÊæœ2”/±qo°07:Ñ =µFW’ÕÆ=y $Ñr&ƒÞçéåˆÙ-Iðí2Ï.[¾âß(Ç#˜t-äþ©ý¯pŠ[é]Í'øˆ‡®[¬.ÞJX…{Õ«®Jœ9‚y+Ó3A™x ìÎ/«È`>Àâ[Ì4ØÂ•Dá÷.üt- 9Ïg€O0æzÙcѬê<=x_ Œ_¦Ë;W~|fe³/ZnM¤LÖ@q[LÀù½Rü^égHÉgióJ¡­J.ÌÙ2úu_¼f×>Üs½«[ö5J'/&xl¦|í5H¶ïÌä¾áþ'Onm„²ý­#€×Ž̳.K‚ߢw;€=dîλµE¹ Y,c›FïVó#XJ=&É /á½{o«þ b·h¹eÜØ,ÕØ&ãÏs=O&¾ÔxVðví'Øztwfuâ]IËŒZËë)\'(þHŠÈ[ gÚ_îú€umº…‡ˆÔ…_ý†ôx—8Qëðéoöµõ3[¶si<ÖÚâžÌÒ«'¿”ÇnÅâ¹8aù±úîÝwp0º Ð ºòÈX]–üIpš «û+Tç¾ Ewþ,† ‡®~†§d‹”F¢˜{Ü"ô.à…pˆˆâ‹~2–ÜÜz•ñã¾o‘µ¢°<±q ¥–PzÇþ!";χïÝÔ<Þçhܵ8ó->É9ˆ¹0Ã7-ÙEé5ŠwGÎVAíO€Ë£ÿ‡k,} ÅÜ0GbʯEõš­" ‘3O{q{¶`HÙp·ÄÄÙ.‹¨£¦‚¥:¼‹ÇÃj€x‰ }‹Xî2YüC-Þø$Dìs1&Aæ Ðøæ¨/ÚÃ3å¢ü%,«cQ]ÞÄöô‹ÿ›©Cpì'†°±'Âv—ÓµV¾iÕ™8IŽ‚DÎtÀUåMä§\–Ù–œ[—ß åTiµõªÈ¡K^ —Èl0×åíé¢lœØ@ÓZšÅ§ö h›õ@æákÄÀ»‘‹O Gœ¾ç!ð[gS†ÝŒøB| “€ÌP›â³aÞ!>1# F0"*.äå¿äK#^B®/KÑT8—UõCXZ zÉ'Ë!Qä¤ùÍ›õ ØIc' Zt—Íë{MSR]Mž=AiçS)S–ˆŒç$éNºŒžA(N°QÀ5übÚ@ÂÛ PëQ‹óGÛŽØ%”íì[Õ’ˆg°ƒ†¸ìî¿Ì¦Ï¬¡8§zi– Ôl:ÈÙ)«_ à]%§§}îcœ<²œ^X»ò '›#¤™Ze»À’ÖÝ9›»¢¿ŠÚ’£žW +nÄ&¦ï„‹ƒù¿šËˆâõä^*%¤&†muü0k h¤µ—¹Âïe”œ¤;C­‡ ÝMåßÚQ—¾Ã>ÙÓ¸ªÈ£äâòw•ÅØ°Ä5ÐèŒxÕ•¬ÒijùŸ` æŠé¬²â®ëŽ ;ù†ë#@' HŠS¦‰ç¨Lá¢W3g˜Ž µÈÓß•·‚^½h×6õÌIB. Í?‰Ðö’&‚>=€ó©¨öËK¯/ƒ“á}­©Ð×>d±Yoµ³3ù¥pk•$Ä_†L¿Y[‡tüÆÖï`®„DøÇŽKü\ŽQÈ}ä˜?'h½˜Æ©,SØâÓ /?Ȉ¸}y‡ˆÛ=!Zr5HÖT ÒãuáHµÙH”æ¿ö`ÐjeH~ÿã(pˆq¾†Ä\YáOû#¡J _,ô´XJó6– Y²“4Âá¯Cui›79Á±¦÷6’3,£ÆÙžE¬*$IÈm¸¡[§;¾L¯i§–±DNl”ÁXj‹áEòÎ)´0E„í €éÄ$ f/ªOàDûÖ ¯—ÂiNíé‹|¤1gÊ쮹í_s\¶äQJË<8½½Áfc–æÊ mlY©(!e-»Åê‡åå›M>0ñŒýôƧÙHGŒÈydÇþ çâQ³Fö¨{ Ϩ ¼ e‘tÎD\§S“sx˜büYˆЗ‘u« pÜ[¸®„gåÊ*þ%»–¬Z†î.“f‹}­œªª#±Ú `ì^Ì‚BíÅ A0u€¹™TÚ§a‰õúÆÚ*²oÕeRµ‹. B²víuµAˆb𳃤ªLx2zþµy W ]ó|ZõM²/Ç 5i%¿ƒ5ð–ÓÂ0o/ãw‡Šª‹0·Ïxä8©J莇œíàAm¢î"¨㟅¹Ò(7/B\kÎN:r¢ßb“€Q¨€;iŠfWJ¨œðEŽ#5Ú} …> [ìf+üm¬»|Wˆ¬<[ÊܵŠ×Àj߀M™§Dï½Gô× áœDÁHÒtŠ9Ù±Æô¢ƒfsº±˜[RÄ¡x›÷ äØ%wXƒ†bÖxr$A.d Óí_P“#ö‡>&ѽs§…¬8¬>3¶yzµí™µmR6°¸Ö±iIùЛC*˾:Ä¢@Úæ…’ÐHÊÉðöSÇ$ºWc ê<ÎÂð€´!Ül=w°.R)]wÌ^ï½ ìãd„[w‰ën³­æ¯5ûmù €äq[w [gBŠ(ye»s´©x¹‹taß›W ÝËOã©Ç®¥ÕÐC1vÔfq_5>D æ)®¬—$Dz€1sÎöQŘƑ#žÑWÜk"‚èÿ§®a‰/·$ë |@[™gÂ51ÓÓPÃe“­³÷˜p¾¬@/¦ùòÌŽ¦X̸©›°R½ÙFZU¿>gÿç÷³.Ëk®"f›Iˆ¶<‘^É×Ä@}•­æZ!ã×vç5ÈýyXÒ †ZûiJˆâß0d‰b°ë GKëÜff3}±+! ðâüõéˆ}¿‘Ÿ6L¨Þ®ªÚf—ò.y)$㓚™x* @ž{Ø hÌŒÿPB~*µ)ð Ýåd¸YÝíÍ©çCdö;§(‚¿ù]É ’ŽÓ6ôpïxîý uÓÜŒs¿eÛ lMr¿NLÒŠØòžsÿÒ3æÓ”0Þ]—ýÇvBÞ8nÄı\', œ–RËä¹* o…¾G.ÖÏ,ŽPý< aëéÆœiAé#ïZmÁ@ øS +\m7Cà];ý½êu¾leðŒT»/å@õ.áù c]¥ï£¿ÇX©êå=Òtâ8Ä)&oObóòøG!è`Fš>‹!?S͵7|¨ñ-Û[†¿ Ž­Óó÷Þódnqß³üGû.°ômñæ×„9:RA@òC8éõb‰/{@¶òj—Óê¤lð¶îJ²éà!)ÃQ#ØÔ<å.`¥oØ"È—ÀÞ¶œN_%û%8{yÀŸ\é‚ÇŒ €ûäôÕ·Ö~ö >Ϥ–ÃØVã'ZÌÊæB5¤!Ð?Nxèú‹xÖ²Õ§X¦çCݓт4Í´œø°17õ`âkAíñª/˜°Ö›¯Ìâ; 3/(=« žfÝŽÅêÆ÷¿‰UE^íÓóë™Ô2„80±Ô€Ò(Aˆ_Úf†1$[FÜî”1|¹~ŠD£Ý¨8ᓼ=Ò½ë¥ ÞnÖ,Ÿqàaê¹ràú߈½€½¤QVƒÖP£zÄ$-Ä]xÒ os±¨n=ÿÿãüœuAÍâ^ß·µùS8¹DÐß—m…-~uÍé[aGˆ™ìõ@n8I€Ä¯í@8ô0>7¦è«ãçé㬔@ñµÔ†šîn/4œŸceWíMçÔµJ-FÅÅ@Óûˆ’Ç‹ Òa$ ŇA„ÍŠ·´ÄÖ~˜BáàŽ#@ ¹0ÞXä ˆÔÏÏ,Þf³¢vB¸`}ÏPÀ1¡Õ~cëlØrSÓÓLo!â åAýÕ=ìc~¦W›)…ˆýúØ&¯Íî1ý‹ †Ñ÷‘XQBfM·èûh3oy†ó¹~@À‹yd5)R”9/-)µîåîðÖ)Zv¦š¼´ ¤lÝ`yÄÎ4Þ£'}Šçˆ9°•ßösøÝ Ì2–kù–?’Öì$P+˜=и?ü9™b¤ÖG³£(2b=G-§«æ×(}¯9Fü8_Y}~‡m~` €ÔH×ßÀ©lÌmâ‚× 0Cuó8öBOt!Si¹¶ÈßÞ•%—çˆa~¸|BÎb$j‡¹͈ÔÜ»>¨’m»±m(§Üý,ÓéˆpmXÇzŽ,ÄÀÍò~cä3ˆ¼ C¤€Hçœ3Á ?Ðò)>:³îà¿ïúg¸>F•øMCË…„VpYL V‹ä~ŽiÁ^R›~Ò?)ßÉSô€…Èxà‹‹!FÓµ{”sÅ«<º¤¡E@yd)A%.(N/pÙ à¨ÀÌ„ v!ÓQÌ$_>²FâÝ L’û„”Ý=&‚$IÁ_þ²¿³ÓÅ"ÄZvÉ©}ô}Fõ.Ýí:œ¤‘ƒD>Jš|G‹½‰MÈ‹ÒK`ì©ôí_’D·! r•EÓcmª]0{üøœ™Ã˜GtžÍàjÕü}‹=á–VÔz@™Pw•ƒ÷ nˆÂ+yÍß´z"2†„übtKz–—’p³Ô1$Â,ÈÅÃ×XÉVNæ‹îxþemœµê÷í!§†nJsxš‡´{ñ®ãÞ¯ÒAßY×p¢78ìN¥)ná){n´1‚¶wçšíž# ²ÒÐî~àíŒÒ6“ãÿ(yw&ÜÑqו3ŒrØ`3c ÌcÂp¦Á5à|Qÿ°áëäS€/¤m«Žã0Ûõ¢qçµ€¡›!"­:‰kõö÷q8³V¼nN}ÕÙȹ=$zÂ#_ë"ʧEÕE`³+À¶×ÌZÚù7‡N"HÜÄßȘ0§Õª áÍ*÷ˆqOìµ¾x6™]Èg^ÐÁŒ®}ëi²ÎŒp ü© Ó}Æx«“cÛæ6@ß–ÝßàI‹šüÕ‡Ó õ„ðÛAõj2d]EÌG§‡–Yÿmø1îZR’Ê|âBúýÖeå0*Ç—Þº¬6 ?t„-ÒÎÈî °XÑWf^åË3怣ó7¼÷¨U¥É³³¨eUy\dŒd°üºŠTþ‚Üý cD€ø•ÂH2>{UÊZRûÿˆ^~6l·&P¿TBŠ;Tê!$›Ö ^Þ]{ z¨zí%, hfÖ™»aدžÆuNŽ°ÛŒ›fÚß „ÌT8¹Æìà‭T6ñ˨µ6oó½°“ÕfD~4…ö¤Ã bŸ>Õ®Ë+Ó2™øœ,xÑ¢:º–Ýf°Ÿë‹ &L8y}‚SÚ=ñÕn¹ `º¼Çè-ΖyȔı§ÖÆF8Z±4÷ùË8^î¾ ¿yÚœÖù[hš«Ëç¥ !Mxòú-b…éÎ$¦öéAã[Ì«Ü9AE:œY7A²\(ËäNµá • ,ûš`ÎL†¼Ää>ëè% (-!àÜwž…®Ò_›w0mñ2¯DD~<Â`\Q“0´sC“Bæ“‘¥vŠq¯ÍbêN{bœÅßËXàõ¨Êû^õgcÉõÿÇÞyÇIQ¤}ü÷ôÎî’AÒT0`ˆ€É *"z§žñTA89s@”׌YÏìzzæˆDDf” ’³»,aêý㩪®N³3»‹®ú|?³»ÝO=õT˜îÙßTWWs‰æ¿²éÅ×&ôÐÝKPŠï¯rËïKè=""ÅíÓ5ŽyxW†QÆÆ9žÿvÚàt…ëîÄ 7U× öSÏxs¶ˆ{2¦º0̬ÿƒÜ-GcwÈÙ µ?ÚIÕ‹zHþ¨Š)Q»)ýã’[ó‹À™upA9„Ò*'0fDfHþàäµ§R ¬2¤ÓÊ>ãÞ¯5ÓFÒ-‘â2âÔàNVÚn´9Ћ:‚²£Mˆ€³[yؼ¦&Iï2Á_¬ ¦õ³5G\v倸˜6)69ž¤tDN Ì"þì¡ØÿÓÖ¦þQG¦QNø˜®´» !‚=ã~¼BUâ:“I²‰ ÛBMÙÿo~ŠÙ° ÏT°âÿ¡|4jÅVúˆˆù gL à 7;ö BŒ‰mÄŠ©ЀE[mà@A  áat‰úcJGÓÆøŠ–ALI6ŠÎnG¾:ï«kM&Ü[A8-u"ý‡!þ~&”Ýö{\‹xÎè@$¶†ø”ÖpA'[os›…ûÇ‚¿ñ¡ Z/ëRàjé¾`Kø‹¸‹-U){dQ|ÏtÁhsüÙj˜êWH§˜"8Á¶TwE¹‰­¬ º(¥ô„WíKáÏÜ+dŽ@)˜w—ÍÊ(•ùM°‡™mP!qÁÖÁ—í÷â•Ü€Šžéå†qPð½ã2¬çŒÓµÎ¡ÎׯÐ~|ÚP¹}»ùwìÁS\‡h5Üw·Ù‡Û7ü7.]¿¥Jä¬DáBA©<å?€rf<¹ßÕí$"ý.)Ä5$ÜŽulÆ-8à P ü™« 9*xR%O½H¤Ï*˜æJÕ Nq–Xb4‡HïG ˆü¯«lÊ”±Ü¸GZ´˜„ú”GÈ2e8†ßg|\Yøx±Ø7=„ïŸNÑ6 ka#)•VPÆÙlckÉL®þÙPÖ!¨‰¾¹¬cbº¶¼¤‚ #‚n[[è}CÂåR–CBª´|ØÂõFÆÊ„Ktú„w]«m›>Äüó >Tý™«ô€Rzx†‚"ý¼.ýu3Z÷0ÑÈG§ÙoÈú°ÌDB•ÿ{Ö¹C§œîÃP`ó…2÷C(ð¡©øHM$ý ø5Wñ»ûÁfÜxC{˜oI˜Öšã§\]—y¦FñÁ ÎñïR~bû ÍŒu¶Ÿõ±otl–²áHÑ.Qžûv±‡Œú["v"{Úò»ÊQÒ€²·XêC…tÿ‘RÊó*á è%¾ð(¥ü 8ØSOW›ÜÂIJîØ•œÿó¼Á­(ß‘¬gR¯*8`”Rœh;àGÒ5ä-6êöB)sˆ…:§LÌ{Ím8§VöXÒF¢ÈXšÛ‡™el+bz«¬œ¿’®µlˆÜSB)לM+îeð·ï9}BDü¦×2£ÐED;Îà†Kt6G 7YÛ¢naü® Z‰ÿËÊüOÔõ°éöLèÈ á{š¿™ý· Z°æöîdÀ™ ô¯øØú=óÛœè‰ Œùn¨°# ™j?6 $z ÛîOx4™S!îàÊ@6Î!Ÿœ‡ÅAþ¬tþño|ÀŽ f£bYû†þáÇ|ËSo˜A‘JP üE(-:bP«ÚÚ2ëXCŒù}G8éûå­›AA„8Ì›SZR ÖqÄ¢Õ(¸8%öZ ´à`yB„xáf¬Ie%ÙtuRI…ìÅ­4»À\T8L!›+ÎܯS³-Üš’â!‹ ‚ ‚ßKçb}Òà ôP,0Ó‘lÁ´°Ás ˆŒÎÝ—¥L”aÝ€lÑ•ÍX©(¬ccضM. ‚ ‚ ä˪°¸Ì ‹;›'f(1;B³œs…sf¥YUð.ï(‰³¢8Í3XͺysiiIɶm[­K–äå¥ «U+(¬VñáAAþôT\`T<‚k̬â‚Ä+KEÎr8fÛÁU³<†.‘(íÈÖpj™âÜ¡¢2aFUmÆœz"‘Pã“Cª´ž?Pº©¤ °°f­†……A—Ll.-ݸa}ié¦üü‚ŠG§ ‚ ‚ð§§â£â ¾h Zؘ }ç_Û'_ Ã…”[XÔá,f1Þ‰qðaÏT¸®e—R5©U.kD6 鿝oNÀÄß¶u[­úuò bëœDAA!Õ¢•+–¨âÂi‚ ‚ ü驸À¨x„pZDäe!5îêfAÙZ87ˆH™»¦"·X[Ú¹™k XMúDZkتð*t¹ åwèL«ð­å–g¤3¿°€ˆ¨2"‚ ‚ „¨¸À¨x„a™çî‡Ó"…Öfá$bHÀ¯®id”6– f-³0–‘Éq¥HßõŸzàÖT@™ÇñSL4~OÃÖìà>ªxAA„4… K4Õ¬:£ÀT¾Ý!ã#X˜Øveu? JOM%3E@´<½¯€`'ú~ Úž©¸8œŒJ$?®;懲Råñ@T *ÀÍ×_3þýÉãߟNAáwMÅFÅ#”õqUŸ›1¬y´ÕßuR²X ¡J*M@Ð2’õoΡBP™A:`¿Ë.úθwŸyæéÕkÖ4n\tx‡#Ú|ÐÔ>»–Ê ‚ 99 Qà«‘¬s2K£åôf×ñsÀD ×6+t]³È¿>«~¸—ŽàV¥¬jé”2nŸÊeB¸Ïõ²áH¿£a¶lX“_»~f#QB„ÓÏ¿ð©‡X¶k(&Gp9è€ý®ºt¸k¹þ¦Û¾úfæÃ÷Ýq߃~õÍL êïðнwœyÞàÅÅìÃAb}ŠKJœ}ÆÄIŸzúŠ<Z°héÂgŸSDoôM×Ïøü˽öhµë.-?ühz«Ýw~ÙÕ³i“¢»o»qðE—®\µzôM×Ïøâ«}öÜ£E‹–-[þØO?{ÎEÚm—–CÎ?gÈùçÌ™;ïŠkGqFAA*N¬ÀÈ’ 5âã8G%Š#òfq'-`8«˜úÒ-ájà °#óúVaTp}V³t÷”¶ÇÊÚxº;ÿDç ¸-n±A2 ÆÚ]£ùþáŒó/|ò¡€`-ˆ"ÑCé‹/¿´_€úŸpBÛƒž3wnÐ%7š7kÚ¸QÉLMS[H™m]:u¼ý®»˜;'UPí¡ûïÙkVßÏž {×£¾þúë•«Vq£{v=jôwÏÿq^÷îݯºô¢ÁÃ/»çž{›]?vì¸I“'+(߯A¡‚$ ŒlÈ,Qbˆ9!Fl¤¡(=;Sô6ï;™¢„e…ŸËêær¥c̶ãïànëù¬nQÊÊo¯ƒc{Á`–0û¶íIð×3m×ý €ÜejKÖÚˆ’ÃÇÚ#‘~Åy>ùÐ=vûÙgž>ãü¡N¢Ag÷QÈÛJyŽêØ¡S§N×\;²¤t‹ö±Îî.p‚D|êÔ­`õÚŸCYÆŽ÷ýÜy ù›7o›üÁ”Ý:?gn~~ªó‘G<üèãЋ…áÝñï}óýlïÕ7ÞêÔ±ã!í~wÂ$€Ò^j«—ÃÓ5AAÈŠ‘Z$$Eˆ5"`·ŠÂ1é¿ZÒ)Ý{c׊8ѽΉÐÀnåÎ=°õ€»…@L¸;l¯¿X¦ƒF¿&:0M2Í$"OW€«PV±á·#\q V;hêJXKl^ì×ú´“Oºù–[Wÿ²1œ–#ëù@ýúá!^ËŠ5ë”9žÆŽŸpXû¶µkÕ:¬}»ô¶ô§ŸiÝ–­\ÍniÊ[¾beƒä€‚ ‚ Tœ$‘ $J–Dó²®2zŠÕyFxÙ Ä ®&H–pö ¼ÑÃʆqã%n³Š®@RHƒ|aëÔÌsÔw26CYŽ wS–X×h®3κyýj39`t-ø‰F Ö3ÎÊ–'º'4ÚªßÛ -[ìþøws~´×åÌ_°°ó‘G|7kNÕÿvÊI@&¯ÙˆõQä=úø.þM¥¥&}°fÍÚÆqø¡ þ4uú'8@ãÆO8ûÌÓëÔ®ý¯‡qëÖ£Kç/¿žùãüÝ»tjP‡?ý DëÖ­k±óNy©¼mÛÊwä‚ ‚O’Àˆ%V`ÄFʹ¸ÎQ‰’=1¥qÖ'M„ÈYµÊª6âî \:J©T¤äÌÃoì›a~C¥ V3s€L®H^nq„3+ýeUÐqóC’lÞÂ: £Æ€s$dû¶mêï°Ãð ³–Q7ßþÕ·3Ÿþßs ðн·/_±rÜ»ã÷o½“I“äóù×3G^?ªß ýo¼öª‚‚üeËWLþpÚg3fsk¦úùYgœöíÌ™KW軯˜÷&L8å¤Zî¼Ó²åËo¹õ¶Ÿ7lèõ7Þ<ÿ¼szwï6oþü+GÞà„A¡b$ Œ"£â¶”)ˆÍ8£¾8O@ÒÊ«9(C"*:âÀ\Yçrs2~wpD/iÉKdS¸ŒÅ ƒ_>WʈV¥Poÿöh}ÀÆõ¿pzqñ†šhçY½rYµ*ÁµÚJé­®EyŠ<@yé-Pi)JQzK:¯/½YQžY ÞTšÔVR P R”§(ÀK—*J¹Ëä§RÝ{ÇcÿyâÃéŸYãm7Œ|ãÍ·§Lù* òÒ”ÒcÀ*í¥· 䥽ë/‚ B©¸À¨xÞ^µryiIq÷ÏÀ Ò÷³(èËõ‰GLe`9¨ô_þ ÌWx]£vec8¼öäg G”#®‘úùa#»îo»Ä·¸ äôw¬öÍ^›G "VÃᄬá®EQ¾òb¢tž{¾òôbטä”§í6_Ôˆ¨g÷®›·lžþéŒHż`YÊK{¾ÞA¡²¨¸À¨x„°€V,êx@š‚™)Ò~›ÑÅqVÖ#6;xÚ%­E: ¸Z ˆ+þ|V&Ö%וÀ”KþD¸C–¶nÛ’JÅÊÄLlݺÅß®p„*Âýׯââzxkä AáW¦â£â²ÃSå¼'Šâ%™+åᄾƵp–¤Œv<ÏËxW&=JÎýF¹Ê•Xl[ܾðív+ÏKm.ÙäU§T~—¶·lÙ\ZR’çåQeD¨:œ~æY©¼|rf ¸ìŠ+•— AAØ~T\`TùßgfÎünë¶m-vÞùÄŽïÞ­KØé7e;5|àà¡Ç÷=¶Wîá„Jâêk¯¯Y³Æ—^ì‡_ryË;rkü½sÙ•×|òégv·]Ûƒo¹q”“^™ÜÏv{{¿ƒ(ÇYª­Ûߜˮ¼fçv<è|k<ô¢öíÚžyúß/A„ߣV•2‚*vÊ¥;€‡Zcݲ‡Ç5ƒU}9 [œ½£IÏg¥Ü%al\—øXÝkA[æÒ¹½•ÁÇŸ|vÍÈëûõ=vàyç4jÔpÉÒeïMxÚGÓêÔ1ìš Ó?þdÄuÿwêɹø¢aÕª~4ý“{î`é²egœvjØõ7b;5üWàØ>½GŽºá ÕªU“-‹/ùò«¯‡8ÊàCÿ~}]ÅóǦêŸ5‚ 0X‘Üýc /m•JPm*>Œõfý‡qþHqÜŠ¸*ÄCÁI·q…RHŠšÍp!:oL6™>çËÄÇŸ|vùU׸–Ûn¾¡ÍAÞuÏ}½{õ8à\6îҲŹ?Ëu+J©»ïýWŸÞ=íhJî]É£[GßÙ³{·¢¢Æç rHû¶_óí?ÌkÞ¼Ù…ƒíÛz%%%ýûÉ)S§nÜX¼ß¾­‡ ¹ ¨¨1€ó9ìÐöß|;söì9õÔ:xPÛƒÛ¸%æŠR*CÃÏ8äÐCÚ}óíÌÙsæþ󢡇Ò>¶VW^3ò£éQQãÆG÷îñ·SN&¢Q7Ü<{ÎÜ[Gßyëè;÷ÞkÏûï¹3©Qå¦}»¶uëÖ}wü{ýŽ?Ž-cÞz{ï½÷Úu×]¬[·î¾ž1ãsµowðàj×®ÈüåÔÓ/»xøÁm°rÕª¿žzÆë/¿P«VÍó9èÀfÍž=gîE]zñð¯¿ùöÅ—_)..é|ԑÇ]È'jR‹^~õµ_zuíºu{´Ú}Èç·Ú}÷P¹•Bl·¿úÚo½3öáîcŸ¥Ë–væ9O?ùx“¢¢¤ ½Ë/½üêѽ{õéÝ3ûw°rÛ[¾³&ZÛÁC/↠ù`H:¡*·Ee’Ô±.±­ù‚ ” -Wõ8«¹LÐ^Š7Hùž¬ÙŠHBØÙìiÅ¥cD g†xÒ¯«ÅaéÏ|HzY·àM]d_ÄsgÝ\~¢ ¼<ì|ùÍ¡Œó¢´owð„qoñë¬3Nkµûîûì½×Â…?-[¾¼G·®aïŠÁa»Ãví|}:ãsÞ}cÌ[gŸyúóÿ{ê¨NG^~Õˆu?ÿ à¦[o_´xñ£oyîé'vÞiÇײ£ßãÆ¿7àܳ_zþ™ݺÞxËè ®óUfÃß;îÜ¿ŸõÆ+/t9ªSR­n5r¸·Þ}û뮽zì¸÷&¼? À5W]¾G«Ý/½ø¢ ãÞâ«´IÙË õéÝëÍ·ßáÝ­[·Ž7þ˜£{ñîuÿwÓÆyð¾ï¿{ÅŠ•7Þ2ÚÏ™S>œ:xÐù/=÷ôÞ{ïuÉeWþ´hÑcýëÁûï™öÑôÉLaŸØ-Z´øÁ‡»òòK^{é¹óÏ;ç½÷'W±ÝÞµkç šûÃ<ö;nüìߤ¨;Ä}—­1Ëw°ÒÛ[¾³&Z[— mžP•Þ¢2‰íذS\«Ã‚ åAøxE W_—™—}5\¿”öt_¤X6²ÈcOÎeeq^N@ Oo–”ò@…`¤¢±Äz%»G‰k†Îïv]yûîø±ãÆßô×U¯^?ý6lvª±a=Ï«_‡uëÖñî±Ç}àûרQ㔿žÔ¨aƒ)N]¹jÕ”§^2|XÓ&MjÔ¨qþyç,^²ôÇù Ø¿¿ã÷ÚsϾdznÝºÕ«×ø¡s'¶†.Çwlë}öö{ïô­;ï¼SQQãwÇ¿·÷^{Zã{ïOL§ÓmÛÄ»ü‹Yºtéá‡RÔ¸ˆˆ^yáuêÔ±IÛ‰²nº<©Vk×®uã-#G\Õæ «W«öò+¯M˜8‰“È·KÊ^qŽísôÈQ7ß÷Ø/¾üjÈÙØ¸Q£mÛ¶­X±²qãF/Y  QD—nÞ¼™·í^–dhÑa‡rØ¡‡(¥ÆOxØðK_zîiVÒ•H†no×¶MAAþ´¦OùpZ—£:ñúetHÜ ‹¬ßÁÊmoùÎkëRFÛã¨Üe&Cdžˆmµ BIøƒUk”Ë#HbsPÚ ”2ÏIt"‡…hr™þ?2¯ !ºôʈ[®©A¯ÈÅSTy;‰ I™X¾|Å•×\û¡CÜá@"úÇÐ!o½3î‘Çþ½hñ’ÒÒÒù <öï'&NúÀÉš3D4tð 1o½óÄSO¯X¹rýúõpÏ}œvêÉö‹×ǼõåW_—”<ÿÂK+W®:¢Ãá7êpØ¡·ÜvÇ¢E‹KKKgÍš=bä¨-[¶cWÙ7<©V¥›K•RµjÖÌO¥¾ûîû^~ÅfiP¿þ¼yó·mÛ–!»_@yi×öàºu댼þ†}öÞk—–-ØØ´i“ý÷Û÷î{ï_½fÍŠ•+ï½ÿöíÚFYwßm׷Ǿ»aÃÆåËW<üè¿C©™IjÑg3>ôñÿ,^²dëÖ­étzóæÍétäYr&C·Qn]_~õõÉS>ìÝK/ü”e‡„Èæ¬ôö–ï¬A°¶.¹¶½Ò[”™¤Ž û%´Z¡‚„uaÄB75š«bè¨as„$˜Rìs`IoˆŒ“FÆA]A®ïk(d’ºº¤H×!úä®l˜òáÔU«VuƒµÜvó ·9¨}»ƒïºý–§ž~vðЋ6o.mÞ¬Y·®];´¢#‡zÈè[n|êéÿ=ÿâË[·nmÙbçÁƒ¸ ^Ó§÷cÿ~â‡y?6oÖô¦®ã £—_vñ“ÿ}沫®Y»vÝ.-[œzò_óóóý •Jö ­U“¢¢óÏýû¨o^¿~ívïxD‡™3¿cÿ“ÿrâè;î~åµ×÷hµûý÷Ü›=XBy ¢>½{=þŸ'Ï8=°Òˆ«®ø×ƒŸ{þj×öà pS™çþýæÛî8é”Óš5mÒ÷Øc>3·ødIl‹Ø¿9s¸üÊ«V¯Ú±ùŽ#®¾¢zõêáœ&C·èÕ³Ç3Ï>ß²E‹½öô‡*³éÙ¼ƒÛ£½å;kBµõÃåØöíÑ¢ÌÄvlØ)¡Õ‚ %NMQײ3§Æ¡ÝÃeqAF‡Wðñ%hˆu| Ä+gÐŒŒÕ„5«…(î“JñÃdy 7 ‘(¥;.'¼¯ø >u~¹sÖ”o,)ÞøÚóO»IU™óùËI'tïÚ%œ BγæÏÙjA¶'Ÿ5ÀŠeKJKŠ™?H)¨ÈʬÑKLz QûAñJZÆQÙ¿ É/ÅN°«¤f˜ràŧ@D¤Ÿ)ã0±Z ˈÜT€Yè €Gf -NàŽá’­“E™èv'¦V‚ ‚ Bå–˜"¨ušŒv&#è¬TÕA”2¿È—¯4¡_eâ°6$)XMPœ‘Zú¥G±µŒäб$F•­Ð5 ¤ ‚ ‚ å‚(ðÜTkÔfZ}CËdVJê=½ûÊZLp½Åe˜TsÛ–C@[¦Ò!C¦ê±C¤ÙCà9.,¥]£¯]ÿ<ò ~^‘ Yòç®úŒ-À5Æ:Ð]fŸ†LrAA!|÷F§ò!‹«4ËV& À”;´Xùx0Å›ÅâqëJ¨UÔbŸÎÊÓ†·Ë_ùÏWÐ=£ë¯Áɶ¿ÔþŒ[´J‚ ‚ B–¸ËÊ*Õ¢ÓåEZîÑ‚ŒNKH7híçŽÚ:à®´ÑгR±#¬q‘€<¥x ðا²>àª#ÔzP>òÊÀÕ0Ë DV]±+‚ ‚ d ´úÒÏSÕB0fý{ú¦åÔ )3A ¬ÑŠþ2Y±¢³ù™•Þa¹ÈW÷9#ûðô[½|’ç³RByGeÆ @¶`/š‘Õ*oGS5+‚ ‚ dƒû3jŠåbPé%è>—LbŒãGÃܼ\<ﯺ#*£ÉŒËfЬŽÜt¸HeÄqÈÀˆxRŠ—9ˆÈs  ÜÕaÙÃÞËFð‚Kb ‚ ‚ YbJåë8c% ­…™€Ẇò@¡åùc•žE±š3ÿ(½ xñJœhÃj×ÃÚ ÄC¥IšŠˆ;ñjñ$5Àí@·EOˆÉBз¯ùUXÝzÁAAr *½ˆG ò`žßò£ÖcY+°ˆcÈ`ë`f¸*1ƒÒLÞT´ˆÎÅBZóf‡öŒ-ËIåmBÐ36 ‚ ‚;€X&ï|ɲK g9¬² ‰ÔdõFDÑ«çÉî>‰ã¬”-^A?W€ì“¢ÅA­"CœÁ€G*ø°† 9AA„ ñ"ù¤  À÷6ŽÎ#¾¼¯@ZÅŠôÍ÷®æ‹ÓÙ£ÀÓå‡Cùc±€ÈU€ )6Åã&ø3!øo¦|LçDëÅŽBke¬x×½¡­ì ‚ ‚ B,D¡_(÷e•j|Ë‘Y·Ô(<bG[Ãû€ë—…øS9£™¤#Y"aRÑÇ p¥ƒGภ®{À&Òºf‚‚•òNIª3¥Ü¨™†hAA„Œ¤€<çN(–Œæn"c„R*^F\*-6ƒ ¬Z·8ÝfòkQ€ˆ ìe|–Ï®ÂLEã*¿TÇD=Q¶|ßS7?’Ý zúÊɨ{ÑÉo6AA„¬a ¥üM‹Qp¾9YoYuqW¨rSý, 0óJyPÓEË=+…ýúêú’îÁÊL( —L‘@džzå¦sÚº‡B^4)'Š·¦¯þbËÜ_Bý"‚ ‚ð»d·:ÞÍòü¹£ôó@¬#Ã¥„¼EjôšÝ'žê[O:,± °\ôüIÎ@e´2\U@”ñ¬ä#E3“E)Ed4­‚ ctsŽ)-¼_&W¾åŽv…ak.Ì]_ö ‚ T: æÍm±ëîa« Dä|ÏÀ‚ys»°GÈøÏO6ßÞ® dÌ @PFÆBòÌçX޲ÂS!%æËBrdjPºYÜZ7;û1XV†)«œ­´Dà »ìãi¹u´ÕñK±°—ú}QÏ]AW&£í ’¸ æ®/G&AA„ªËœÜÔœaG–žJJ¥áyJé'•²#=WÕÊ9yø©UŽvÈf™TÐã«D~<hqHà¤R\s+™;ªêTܯ¶Ôíä%ˆì#Ìœë %{D ‚ ‚ ¹BGÍÙ+ÚF’¦XÈ‚ÙE¾lÕb•-&Éwƒ¿ëKÙ —5páŽ=AOH麺µ ÃwJkÄÛ¶ ‚ S0™87/*ÊýŒJ;EB ‚ ‚ 9`Ô”;ÚHÏÞ4>ñð+ x1t£?g!(‚§Çfõµt!¥kQ€2ÑQ}|+T\+ü¢sm˘ϚA2r’3bJÖ˜®s\)¬Ê£UAAÊÆj(W_ü«þfK!”æç X^²Ú#–žä܃°.MÐiqföÞ7ÖÈ– =“f ^ÄÎñ¢ž€ö %¹+ÏÃÄeAAr†õ/Éo„§‚¿­!â馮ò׿²(ó-(÷)œ%Û¯eFþ#1ìô¿–o [»í~Õ­w…­\¾¬­Ÿ±Ê"P<}•Ì¢ûÆŸH«»ÈÅpËWˆqdLŒÇf±n!(w>+WÊO&< 7N8jýŽHÛÀnP°š¿Á{­,±F¡räQç »8lýqD·ž³¾ýú›Ÿþ²nmz;ØT\üùô©:vëö®bð»³lÉ¢Ñ×\ñê3Omøå—¿œ}^ØIøU3¥Š3iì[GŸpRµ5~Y·nÚûï…“#Êq ~ì¿aS(GþTÜýÔs¼qÓåÿüqάv:ž7ü² ËŸžªè‹ûF‰@Ú™TêëD+ÈV´é@žÝàNK…Ä&ÊX«òà$šïŒù•Ð8#EÖ Ïgµ{z!.ÏãZ«ß¤Lpñìl5«S¥ŽØ'\I¡Â\|Îi¿¬[׫ßI çÍ7{Vš5úœxJÇî=oÜøÎ+/|1ý£µ«W5Ýi§“Î<§Õ>ûÚ,Ýë·ð‡¹ó˜³c‹]~˜õÝ¡ºü}èp ~˜sÃ¥åå¥F?öÔµÿô˺u=ûö_0oîü¹svhÐà„ÓÎ: Ý!#ÿqÁ’Ÿxÿí1ï¿=¦fíÚwþçÅ6Œyá_}úñºµk4j|D·ž]ûLJÙÊeKŸzð¾ùsg7l\tDòÿÔ6‡þ¿ÇjoØ0mÒ„ž}ûøøÃÉ[6oÎ/(hß±€Ö¿ñüÿ¾ù쓵kVïРáAíësâ_«Õ¨Š3ð¤ãÒéô…W^»ßÁíÖ®^uÙ€³\σMšïxÑY§l\¿þèþóÝ· ~˜Ó°qÑIgûõŒO?šøˆÚrøi‡p34'MšíxÐ!‡NûöÇS&óÿ;‚’——jXTtd÷^Ýë ¶9È’… ïºþšÐ»)T9SªÈ™R¯~ýukÖLûV¯~'Žóê–-›Ùb2T>C…“Þߨ·À–%z g¨ú÷aÿ<ôÈÎÛ¯òR&ßsÇG“&ätn"÷C·*A(¾oÞÑ`DžRÛ´Ìb[Ps)¥´8T 3" ðØeZ)EŽÎŒÌsukŒW€|}AÞïeÛ"ò¬(%òˆ¼XG"qí}‹»«l­ÉÍîo³¿ÍEDvJ+bº@¨¾˜>íŒ †vþkV­zúáûY·nÛ¶­£¯¹ìW^lÞ²åý",~6uÊÆ ë|èyÞ O<6㣩¢}h³DßM›$ThßÊ™ò+Ÿ)íŽèT§^½ñc^[ÿóºIcßnTÔ„“Uå“+}£oA8O·¨¬êãPé€|†dAçÞÇ Çs³‡nÁÑX¤‡>ùÆ|N…#Îì’£àO½¥Õ®‰æGÁ L¿ +çLiz#Œv#À8ÙB"—Öǹ¾­ÊiB |÷”mL0ÍÕ̘{°|×8Á#E”Òº¡·•RJ?l`­,”‡é“'ò=úó¹I»÷¬ß°á¾µN§W-_öíç3-˜àÔóÕ®[¯¨Yó~;ÓÍÒ©×ÑÍwn`—V{´Ü½Õ–-›§Mœ ”úlêéÔÙzvèÒ½~Æ{´Þw}öM§ÓSÞg“,ß~>cñ‚ùyy©cN:¥zš]Ž>À¤qoo*.žõÍ×Ë—,Уï 5jÖä‚$:vï`颟~œ3kÙâE|÷ 8}ûÅŒ%?-$¢^ýN¬^£fÏãO0oö÷?|ÿ]0†Æ~K‹rèQ]jשÛr÷=QçÞÇÔ©W¯I³pU34')Ìò%‹¿øø#í8ÒµQ£¢&ûp€/?ùÈMŠ}7ÃBFäL©ÊgJ~~A—£ûeÝÚ»G][R¼±Gß+q…gÕ¥è=ÓR®Ÿ¿ݶ.ÚÈ¿9“ ]|@õš¤èõ^µn'âúþB.d˜¥W»^=yfÂ~:^½r€ÂÂjµëÔu=-uw¨o·;÷>öß÷ÞñÁ»ï´Ü½ÕšU«ªU¯áŽ|ð„9uêÖ°fÕJ›dáâ¶mÛ:ø”¬1½mÛêU+×®^  °°ZõêêÔÕÑbÙ±EË»µZðÜ'Œ¯^£€&Ívlµwkk¸EÕªVP§^=βfÕ `?DÔªSßßP­zT~¾MJ§ÓÈØ–/Q¦Ož8}òÄüü‚wî݇ÿ·)¥Æ¾úâ´‰ï¯Yµ¢tÓ&ö\»zu g„è»HÊBÎTá3ÀQ½ú¼óÊ ü¡vÝz‡wéöâÛ¤ V>úþ’3{ çZŸJ¯€|†dI®çfùݪ€]A5e•˜k$Pš”3Èê¤P °³[5iìã^XZ©a1Ékg±‡ùÍûl–€RDüU•Àáì bº:òŒ™Ëе «I“ÑÄ p³Ú™û1¨ƒ¹í("ʬ&l4j  ´tÓú_~Núgliסã‹O<¶tÑOÏÿûvx~~MýeÝZ½ñó:õ6Bäh©ß¨1€ü‚‚{þû|^^à^ן׮°¹´tSIIµêÕùYGK¢c· ~˜óÉ”Éù:tëÎv.¢tSIié¦ÂÂjöj× ™¬ÏóÒéôÖ­[”ï¢X†æ$«“¾úì“—ÿûDaµjWÜ|GÓwzæ‘&}+ÞÆ©á3Nø-3åW>SÔ¨Y³c÷^ï¾þJ×>Ǻˆ²*_¾ gy¢ÅžÂ™ë“%©€|†dI®çfùݪ€gä§3ù4pÅœˆR*Màñ*Á#­Þ0zRñ>El"2¿tT:­3jøÐ³ù=Y=ÉÛqÇ'qt»2V0¬Þ·!ôFPYÆÕÑL@ý"—_¥”RJW@ç7µp2úÑ„íOëƒÚìØ¢%€gy`ýÏëV.[úâ“þ`FˆT~þÝz˜?w€CŽìì¦~8áÝ5«VÍ™ùÍì™ßQ‡.Ýð÷U+–§·m°ïAmšïÜbËæÍ/?õŸMÅÅkW¯š>yâ·Þ`Ï}÷kܤ)€q¯½\¼q㻯¿âÒ¾ãQ……ÕJŠ7þ²nm^^ê𣺲½õmšî¸“RêW^,)Þ8öÕìÒjÝ÷ v5k`æ—Ÿ—o÷úË¡ÔlÈМœØºe ÏËK¥RK~Z8cÚ‡nj¨…ß9S~“3å¤3Ïyø¥1G÷ÿkÈž¹òå«pEN´ÌõÉ’ŠT@>C²$×s³Ü‡nUÀ•Q°0³ÌIa‹¿rªñóç'ðh¤Vu!•fŒŒxi~-Crv.'à`Ë|KpËÕê¦-„íÈ(‘N WÈîú£§n=ÜY;o(¥¶à†õ}ܯB.ð•#Þ.óæÓ¼¼ÔÅ£nyç•>Ÿ>íŠAç4Ýq§“Î<7ìäЩgŸ±¯¾”N§ëÕo°ç¾û»I¶?ô±»Gÿôã›4í÷·3wl¹ €îÇõûiþ¼ï¾úbà_ú¶>°Í°k®¿dÔ-o½üü—ŸLŸ8ö­ºõvØsßýúžr:€¼¼ÔЫ¯{êÁûÞ}ã•Ϧ}xd^¶±T«^½m‡#>œ0ÀíÚ×®«/Æ¥R©KFÝòÆóÏ|ôs @ΔßÝ™bÉ\ùòU8ú„=’É\Ÿ,©Hä3${r=7+÷ÐýÕ "¥ˆ|¦¼2«"e—ÁŽ}2Áù!ZŸYEfÆG}¹È.J)ÏX9HÁ)f†€56|2Ô¬§þÒs.)P &"þg S(1F ";X[€‚Ÿ®Ú£õ%ÅKŠ7¾öüÓnj,ÇMØôz—jak.Ì]ÿÇŸÍSqn½úÒ¹ßÍìÙ·ÿ3Îf‹»’KÐW²bÁ¼¹-vÝ=lý#gŠ Äò›ŸïUùÜ\0on×ö³”7'Ÿ5ÀŠeKJKŠOùé2+«xT‘7yÀÐìº(/e”ji”´n0r‘}#•[˜1VŸÄBãæèQÐÀ3²#‹w9^ )´«›MƬ¸XÒ*Ýfâd"ènª+—/[4ÿÇT*õ‡_ÉO*‚œ)‚P5ùž›¬ •Òp4—@Ùeœ@ž“ªGñ<Î G˜'?ÞUÁ©J«\À±zà1Ìä㼈‹SŠ(úL§¬}‰© úGŒ€áèÆ üQTˆ&ø õµÂÅ ¿=÷ÞxÝ73>mШñ §ŸÕ¸i³p² äL„ªÊŸéÜtuÀW¼µ–t ZâAE¥”âYP0k;?ÿ‡=µÊ¬t#@g'=üÊΜè™õ  µ©घqVS‹Va+HéÑÑp.]ûùcÆ ãj3„ó U† ¯¼6lPÙO&„ß;r¦BÕäÏwn*–— ºJÁO¥‡K­#ceË‘…ž^ 6&qFð/_ê9죓t€€ê#îQ:N³2ÊüòÆÉG­<]‰š­Þ³#¶DAA!k|QX6•¦oŸR<£>•™à -=ö¢„3Ç×Ðcá37ÀÝ37Kñ/'!€–ÜdGH5”¬8£ÖpÞ¤œ‚ ‚ Bnîkg̘c@_:ê‹ÒîV–Eä<6¨u.}•Ÿ¦S¸¸@ '˜ßÙMàñXžbK)+9uº­9ñÔ[âø¡ð@@eÚí¨ôtwãä驳®-ì$‚ ‚ ”‹È¸§EJDJ雜l¢ÙÈ1Eæ$(À#Jç2ž ÀÒþlÕ˜ Ü«öD€™Æ H©!:±®“¿kI’§ÙìÝmåŽ&‚ ‚ d ³ÆŠHO¥ðúUD¤õ-Àc«RH³ v6œ˜¹ç…+CÖ à¬uÐôiJ)ÅS,™Ûå§*¥xt–»¸U†¤hÁ"ãk¬QAA(',º\êyžÝ%"Ötƒè ôJñêW¬T;¸‚š0˜2ó»ïß|í¥çžþ*/¬ðCŒQ%U†¸²bˆˆ<þíé «>íKÿµ2gbÉ“dÂjŸà FUfz>*ÇPD|s—Ò¾üÕ Ü/…³8Pîo0Õbrý—ñäqY›×Æ~_œð׿}ýÍ·akÅØ1™t:}÷}t?ú¸Ž]z^rùÕkÖ¬ {¹õö»ÚÞ©Ýá9¢s8Mª Ûï”).úßf…*¼ÑŸ#9ðHßúºN¥=B^@ˆqÌQ‰ø~Ÿëà;°—ÍkÛBŽ“ç¿¬¾d­Éy­#yžïOäñn°iìÈqŒF'!ëyçâßœàžûþÕ¥ÇÑ]zÝ­—|Òmw,\¸aý†ÖûìN¨Û#¦åßOþ÷Ý÷&üëž;^yá™Í[6_9bdØ#È¥ÿüÇ'S'ÝqÛMáA¨2l×S&3•U´³aÃÆ‚üüp² 9âjµ R< ¥ø·šFÈFÕk9­èÀyDhëŽBš[-µgóƒ—ž""¢QžïÌL~^@ÄÓôž¿ €ÝÈÞŒæŠrrä1¢uÛBf³ÈZ© rÁÐ!L›þñ5×^N*›¦LíÐá0ÏóV­^}ÃM·ÍøâË¢ÆNêßÏ:—”<ðà#'OÙ°qÃûïéÅ5mRôü‹/¿öÆ›O?ñû,Y²´ß_N}õ…ÿ5mÚÄiƒX³víwÝûñ'ŸÑa‡¶>lH:u2ØO=㜇úÅ—_ΞóÃN;6¿dø°ößÀK¯¼væi§¶Ú}wÿ¸pð_N=cÁÂ…-vÞ9É_ª>î)³`ÁOƒ†ücæ÷³6lpÉða‡¶o‡Œ§I»¶mf~÷ݬÙsš¸êò/¾úú™gŸ/..éÞµó—þ“cƞš¢Ï>oPßcûðÐשgœsä‡ùÕסjX6mÚtÕµ×oÛºí¦ÿ»®zõj6Î?/½rÊÔi^~õõ¿Ÿuú çfö¢‹/Ÿ2u5iRÔ÷Ø>?ótþï“ä¿qãÆ~lÒ”7¬ßЭk狆©^½Z†6 ¿-ó~\pÞ !¡Of{`\9âºï¾ŸuÝ 7_wÃÍû¶Þçß<àæM:òc›+t|&§žqÎýò«o¾ÿ~ÖUW\Ò£[Wá×'ùªºŸ¢|ÝE)¥¬ÖÓú-˜ìîÚdÞpÓܼ¤—p Ä ¬t`ë-žaaëî:‰ â½ôe«ùKF7+ÃIw×uð½…ß“§LíØá0W^=²  à•ž¹ã¶›ßp.Ó\{ý -zèþ»Ç¼òBË;_rùUétºWÏîóç/˜=g.û¼ñÖÛt V7¦ËWܰaãÓO>öäã/_¾bÄu7d¶xù•מwî[¯½Ø½[—aÿ¼líºu?ÿüËÊ•«ö1cB»´lQ­Zµ9s~Hò·¡¡*ãž2o¾=vÈçóJŸ^=¯½îþO“á4yÒäáÃ.|gÌ«û¶Þgð°.X°ðÙ§þýÔãðáÔ '³OìYÌI±g+ªÁ¬^½fÀC5lxÇm7Y¡Àqî}óIýûpüqŸL4hÀ¹6‹%6ì£oþdê¤>˜pÛMÿ÷æ[ïŒ}÷½Ìþ#®¿áûÙ³ï}Ëk/?·÷^{~:c2¶QømÉüÉ|ãõ×î½×ž×^uù'S'…+’üØc€‰ŸŽ×Ǽ5xàyï¿ûÖo+X³†V3½Âã¬6Éßµ;°#¬œÄ:Ѧú Aƒ[4Ï1ˆ† ÇЮk@xî +éÚ2z:xC8f´ˆ¨EøñËúõß}?ëÐöí-^òù—_]vÉEõwØaÇæÍ.¼à|vX±båÄI\}ť͚5­Y³æ…ƒ.Z¼dÞóëÔ®}ä‘G¼1æ-J©7ßzç¸cŽÅ´¥X¼dɌϿ¸ìâ‹5lXTÔøâáÃ>œöѪի“ìœë„~}ns`Íš5Ï<íÔÆNœôÁÆÔª©§Ê¨]«Ö†“ü­› TYB§ÌÉ9±õ>{W«VíÄþǯY»vÕª2N““Oê¿÷^{Ö¨^½Oï^%%%Ç]X§NvÚ±]ÛƒgÍšä³8Z´K´lŸ÷ã‚¿ŸA×.G]~Ép{-%CœIaxž·ç­þrRÿÉS>Ìà¿lùòÉ|8âª+vÙ¥eíZµúõ=¶c‡Ã3´QøÍ)÷'sÒ‘{ p–èñ™ùØøKÿößoßÐUÁ*‚¹æïÅB(ü"r4ž‹v`‰É××Ê#E|Íœyð83Å ú5+à”ÅŠ‘wÈyVŽX5ÑààV_+¥´›Ò`psDU)A™ÚÆ9¿¦N›~àþûÕ¨QãûY³«W¯V‡ؾcóæ¼±xéRG×ßf°té²ÝwÛõ¸>G_sݨ¡C}ñåWë7lè|Ô‘œjcºY–/_‘——gbwÚ±9KKKcí 4мYShÞ¬ÙŠ+kÖ¬ ÀŠTë7l°6êow¡Ê:eêׯÇÕ l*-]¹re†Ód‡´AaAµj…và³° `Si)2žÅ±g+­ï¾>æÍzuë¹Ó‡iBbÃŽŸ0ñ?OþwáO?•”làÎê‰ú¯ZµÊó¼›7³>ÈØF×"ü&”û“9éÇæÍ›£Ç=>3Mªö’€Nà+/À¤’‘a ðÇP#9©y”qv­žoç¶ø~)íGD (ÓRÊMŠŠŽ<¢ÃuÿwÓÂ…?mÚ´iæwß_rùÕ›·lày^ŸÞ½ž}á¥÷'M¶ܘ.Í›5;èÀn}תի—/_1úŽ»?ì† $Ù9×K¯¼>ãó/Š‹‹ÿûÌrÚì IDAT³ËW¬<ªSGýûõ}ê™gçÌ»zõš»î½¿ÍA¶Øyç þ‚P•I:e\2Ÿ&e’tgSt”¼TÞ¨‘Wï¶Û®ÿcÍڵȮ (--UJÕªU+•ŸÿÍ·3Ÿyö…°G&EE;>ꆛœ¿`Ư¾>惧&µ1œYø-(ó“¹aÃs~˜·mÛ¶=éÈ=8Kôøü½IJ)^ ØÙD€2sBÃ/""¿)Xêé ZÃjŧe v‹­—Îå¼j•~ñ£ <#@g«„‹Nÿùfê*<ÿ¥Š%4i €ãDzF¬Ÿw¹&ˆÎª6_|ùuãÆìe—›F,.)9þÄS.ºøò>½{Z·ëF\Ù¢ÅÎC‡_Ú£OßÛî¸û˜>½ìB6Çõé=ãó/š5mjÊ Åt¹iÔÈêÕ«ŸrúÙ§Ÿ}^£F®»æªÌv'ô=ö_=ÚûØÞûî]·ß²C½zÎ>ã´î]:ºð¢¾'žœŸÊ¿iÔÈÌþ¯¾>¦Ýá†_rE:æ…Z+þ|/A¨,2œ2.N“lˆ=‹³,:ŠçyW]~I»¶m ºbÅÊrÇaš6m2tðÀ«F\wT·ÞwÞ}Ÿe”믽z·Ýv½ð¢‹ûžxòwßÏjÛ¦ ÚÎ)üÄ~2»œñ·S¦Nû¨ÃQÝÏ>oP()éÈ=˜Ðñ‰ßí±' -Z˜P J©tÚ¿=‹^èYÔŽÒ£‡–ªÁJV‚®Ô¿Ôâø±z‹õ­ÎçÃÞ¾À (g×ÜÅ‹ÆrEÃÇD¤”"€‡v8ÎÄ ˜ØÝöÝà=ZPR¼±¤xãkÏ?íúÄrÜ„M¯wñ§°¼ùöØÛï¼Ûµ¼ò³ÑQýÕ«W·l¡Ø„rp×½÷çç x^8¡TbÌSÏ8çô¿ýµwÏá„rõ„ª@%ž2¹RYEWVAøÃÐùõÕ±ò&ÄÉg °bÙ’Ò’âÓæ_VvhÓŒØó=) Ø™:) F J©´µ)å ¿Ez ÔϦxÇHL§*Ä©Z*½$–^7€ˆ«ªeµ5QÀ)AMò @O($Æ„ÕßËX[$½èÓ»ç„qo¹¯¨`*NÒ7a{Ä„?0¿á)SYEWVAøSã0Mt¬”}_®þ“¾  ÌPXš!Y~YJÄôý çÕš‹þ«»ò»VЕ¨ •yukl;Ž8#£Š†%õFZùª›Ç5õÕÕ×Ð I×µP;úf «ã8Žã8Ž“ŒŒIŲÂÃ+ú­@3=ËX´¾ú؈ÑVûÓ~V‹áþš4´ÏÃÀíç`%SÛí?SG`K£Úú<Èì¹Ä‹¬¤ŽPoÇqÇqgK1ÙcÃ]‡¥kFál“«&ÓÓÆ ùFú°*gfFFgØ7@C‚ë@lšå`MQs‡ìr8evH¦¹9)^À|›rÇqÇqf†¨ƒ—Íc£ŽÎ v³öyƒÚ\c±ô³I\üèˆÆó@†ö H³P[± ij+7ÓvêQÇùd ݾYØšqÖöÇqÇqœ-‚ƒáÍv”3á¦! ²ž5®Ý…Q[_ÒÖäPœuxtMÉ´üfÈw&7m¦XùôXµF†«$ØdIÇqÇqg˜QÅü-ŠÒVRmdÖûúH­d9ŒqG“Q(MH9Y w<à¬$[óe­; ¶2êÊg“×ëµ—ÅÔµÝø@Á\Ì2fy©ÇqÇqœ¹£¦¡j¾%+IW]¬‘9#ÉEå5º 3l»‰–c% ežÏZÛb\òOsk¶µêH[EJŸA[™ÉAù´tEVc|©­v¼‰ sÇqÇq6M¼ï]/RÊkþMÃdo0kFšâ¥1©ã, 5:0‡6µ©Ö½µS–h¤ ·Y«7k‘¨ 6„—m_vÞî}xνŒ5kÖväcn¿ýŽvÆ ¦5šxjßÝÔ†NÒ›i¹Z"›Úi³yº9¥MN•é8ŽãÜó˜‹F8Žs×A’æÀ%…ŒÇ S ]“\¬IÖR"ÙžégöCH¾†üµÛ2ULɰÎ1Z‰uSK­«'kún3_í4V²)1+&5ZNi©—|!¤ñŒØ™²œ{&Oöó/ÿå¯Ú©[Æ]Ѧñ¾œvØ‘9ìÈÇ<ü‘kçb¾åçnç®ûølëúÓŸüØ_ó—í¼ùp7^‚sç_rÜëN|ìŸüäcžñÞ÷ŸºaÆv‰{¦Y«@f‹MçMka7ÖÓ |„Ês­QkKb™Üÿ (¨“(Ñhë¨Æý`g‚&Èþj]¦ã”•g4®3ï9P'¦¤ñ&…eêS[Ê¥—]þoúùWÏ|Ös_pÚ‡?²qãÆv gá¸îúëׯ[ðA¶3¶€»¢ÍÌ^ÿÚŸ^ðÃSO9¹1ó-ï8w/wéÇgvªë…jÇq6ƒO}æsÏî³Ïþê™ÿrúûqñe§œzz»Ä=„¦uµ–Ä7Õn.¨Ã¬)m¤^æ’#sGc¢ ,ZÝFÓή¬ „ÖšÚê-qZIzZch{qÒk¢Å*Y ÷V­ÿ…ãó_<ã9ýÌø€•«V½ã]ïùÐG>öÆ_ß.ä,çÁQG=BDV¯Yóî“OùÅ%—î²óNÏzÆÓrûø'ð£ó×oXÿà?ù“7üÃëvÛu—/ý÷ÿ|íëg᳟²2+VÜü´¿~ÞWÏüÏÝvÛµÙfnÀÚÛn;õ´_ôÓŸ“|ćŸpü±Ûm·Ý,éÏ{áKŽ:òˆK.½ôª«¯ÝkÏ=N<áøCþäAÍ[Ì·¼ãl4?>×]wÃ+}í¯såòåËN<áø#? ³~d{Ø¡¿¾âŠ+¯ºz×]vyë›ßxÉe—ñŒ/mÜ8ñÄ'<îŸÞðzksä'ºÕõ‹_úʧ>åh µ>ï…/yô#¼ô²Ë[ÃÈLNN¾ùmï¨úÕÉï:iÑ¢ñf;~û»ë^úÊc[ŸÊ×ýÃÏ¿àB’»îºËSŸrôßýí ìwÙ|û:ãÌ/ñŒ/ÝvÛí|Àþ¯íq|ÀÍÂÎ=Ž'?õoË›?ì¡V®\uô_=óûß9{Ûm¶ÉæòøÈé§Zá}öÞûiOýËÿüÒçê[9&\ùx:ÔFA1[Ë66T1=˜`àYoè3ŠÜ(šO1;¹+"Ñ“-FH´AÄ ¦ob”ÔFX€7UCË€Ð%@È’, vj%×rœêæN«žŽ·”SÞóî‡úÅ‹ÿÑýïô“Ÿtùå~ƒé.äGç_ð¨£àMoy{·ÛýÊ™_<õ”÷|ýìoæo{Ç»¯¿ñÆýÈéßøÊ™tÿûøÆ7‡žôçOüýﯻêêk¬Ì×ÏùæCò`Öf›Mþé-o_¿~Ã>÷©Ïýû'n½uå[Oz÷ìéþç+_{ÅKÿþœ¯ý÷ÿôñÇ¿þo»ýöœ5’ù–wœ­æÇçìo~ûØW½üÛßøÊÑOúó·ôn»6ËGæÜþè„ã_ó­o|õ>èÕÇ¿þºë®?ã?>ýÿþ‰ó~|Á÷ð#+3òmY#?¹˜aÆš5k_öªãvZ¾üÔSN6aÅ`;#?•|ÿ{~zÁÿï¼ïŸrò»Î>ç[ßþîÿæçÞ×õ×ßpú‡?úη½å¿õõãŽ}U³ç^Éf¼~~ñ%ì¿_;u«$«X>΂ÕHËÇ탖;ŽÄnѧõq7VšÚmº6c]šñî}tMÒú2qh Q%©”¸!™f,ˆ²P)€¥@ e¡R@A<&)@aó$’¿“Œ4Ø\MÅÚÃ_.½ìò}÷ݧê,w®[wÅo®<âðÃn¼iÅÅ—^ö'¾nÇvØsÝ_óª—[•+Wýà‡ç½åŸÞ°ûî»-Y²ä5¯~Å7­øíï~¿Ý¶Û>úÑüú7ΠªgŸó­cþòÉ­6s/nZ±â_òÿðº–/ße—ÿá„ã|áÿ­^³f¦t«õô§=õ¡‡>xÉ’%û7ÏÛy§å?øáyÍ6‡™oyÇÙÚh}|žó×Ï<ø ÇÇÇŸùŒ¿Z{Ûm«Woâ#óœg=ãÀ>`ñ¢EGÿÅ“&&&N8þ5Ûm·Ý^{íyØÃzå•WaæOôp×M†‡aé¿ýÝu÷òW=áñ}ã‰'äû*­vfùTŠÈØÿ¯ŸõŒÿãœ8÷¾Ê²ìtÊ%K–t»Ý|ÐñǾ27âÜûØŒ7Àùå_\|éñǾª•¾ubFPÌÞ’õ Ë é#ëCD!Û*~‘õ2$Ànº“)4 «O@šíi¤.Ô¾„(HóÃÆˆ¬h]™¢¶Œ7â™GËåcÄã4ü˜À8—6%)@I§‰µ Hÿšm¢ñoÜÜmì%Ö ò J._ùêY—^vùÇ>|Z;ÃY .¸ð'þ“-^¼ø7W^µhÑøŽ;ì`é{ÜtóÍž|Ì3r7ß|Ë~ûîsÌÑOþ'½ó¸c_yÉ¥—­[¿þq}´åæ6›Un½ueQ9»×ž{XâÔÔÔÈôåË–Øc÷Ýb}`Ýw_¹rU>É|Ë;ÎÖFëã³ãŽÛÛÁøØ€É©©U«VÍò‘Ùa‡X¾;ÖËϱnwrj ³~¢G~ráaØéYß8{û¥Û7§aèF~*¿÷ý|æsŸ¿þ†&&&4§ñ̽¯ÝwßíÝ'½íCÿò±Ûï¸c¿}÷y¹ÿ~÷Œˆš³Ì÷ ð_g~ùSŸþÜG?têž{ìž·f̱jKÖ7‚¦ƒfïk0(dYÿ€è‘€Æž˜úµª–Ö¨Ð<˜]0¦ç`Õƒ,£È$Mm j0U¥©3ˆé%¡ˆ> €Mâx1]×N€ÍvͪnÆrÖþ /ì–𕯞õ_øÏ÷¿÷Ÿwoü•ç,,çÁ£y$€wÞybbrím·™¶Þ¸b…Øm×]Dä;gméÒíš<üð‡u»Ýó|á¹?<ïÏþô ccc–žÛl²Ë.;WUuË­·îºË.n¸ñ&Kœšš™nµVÜ|sná¦+ý¨£òéHæ[Þq¶6F~|šÌôQj—›Y>Ñ›ìz˜×¼òåþä§ÇwÂi§¾o»m·µÄV;ßʵko{ó[Ozï?¿ãð‡=tÑ¢Eg|é¿¿ó½ïç231²¯G=òÈG=òÈ·¿û½—¾ò¸o}ýÆÇ£¦;÷DÆÇƦҿRÖÞv[3k^o€Ï|îógœùåä´}öÞ»ÙÈ=ƒ¦P«bdÊnÄÙùf¢½QÀ&ÉýdttÌÁ[2n›%£Z&“LC%@²°¹°©|³} ŒZ±ü½î°¦ÓÙð]¦*ÓVs`D»] ¾xÆ—¾pÆúþ÷ì¿ß¾íö +³ë.»<ú‘Gô®“¯¿þ†ÉÉÉ__ñ›ßø–é^€ˆýO:ãÌ/ŸûÃå‰Í6›ì±ûîyð!ï{ÿi«×¬¹õÖ•ï?õô#ñðåË–Í”nµ¾ü•³~qñ%7nüüϸuåªÇ>æQƒ­¶™oyÇÙª˜éãÓdöÌ&™é=—®‡)Êâo˾ûîóŠW¿Ö c¸áOåÔÔ”ªn³Í6e§óË_ýú‹gœY·83Ã}ý䢟}äãŸ¼áÆ›úUUUajj*ÌºŽ³õsÀþûŸuö9ëÖ¯¿ù–[?üÑ7³æþøè¿~òË_9ë“ýð=RXkÅj×_’&d$˜'جQ“´a†[7Ìà f¢±…öSËYŽG}(‘»²RÓ¥TäLƘk}š5\b¢`ÜjÀF–’è*ÛAlލ’ ±¨Ì¶ðl3øÔ§?ûÝÿýþi8åžÒ¿‡rÉ¥—ï¼óNù&ãÉï|û»Þó¾¿zæsm߀_ýú K?é­oúä¿ö¸Þ°ö¶µûî³Ï‹^øün§cYÇýŸùÜç÷Ù{IM«Í&'¿óí§žþ/Ï}Á‹ ñðÃO8þØÙÓ<ý©Oùè¿þÛÕW_³çž{œö÷î°ýö¾zÖ7ÞýžS¬ÀaG>ÀwÏ9kûí—nFyÇÙª˜åãÓd–Ì\ù‰þù/.™K×Èțßxâ?ô‘—½ò¸~èÔn¼©ÕΈOåö8îÕ¯xó[OZ·nýØÿq}ôwrmõuèC¹òª«?áÄ•«Vßo¯½N~×Û/ZÔ®ãÜ£xÍ«_~Ò;O~ò1ÏØc÷Ýžùô§]ôÓŸ7sçòØ81ñéÏ~ÀÓŸý|«Õít~üÃï5ÛÙ:1Ë*E³IF•l W3d8ØL+½FU£†š9&q5²56I{Eþž¨{äþϹ0É£5\Ÿ ‚dÚÀŠØø@æð§]ªý‚B’€ § ° Š´µoÏG°W2Ålã5‚q÷«€€Jl¸èé|ÈÄÆ 7|íK_ˆýÎÌ1ߟ<ëñíû8G?u`®U§ÓùöÙ_k¦kÖ¬ù£û߯êÌ™Ó>ü‘N§ûêW¼´±,`›Ï{áK^ðügÿÅŸÿY;cæ[Þq¶6ðã3_ªë…jÇqîÑ<î¬5Ãz3Ìs^ô2+oY15±ñ¥7œÄœµ™ÄtV£Ñ&‘œpX7ÛÄ)¢IC…TÚn­Pº®´^£†a]—(el²ÉZU¨Ý¸—ÔiÏ5`¥Ôâ«"é\E,]4b}Xc€¹«Ép,cS[c1²ÎØb-ZôýïœÓNuî~tþoË?µS·Œ»¢Mǹp7~|ªë…jÇqP©IMêìÚâfÅ Å-öídpcD*¸IN(š6j2™¢Šj-1vbiS¨E[If¥52p¹ 9·Ö˹LT‘B«4×Ô˜0Á¹ñ?ÿµéXø|¹+ÚtœûwãÇg¡º^¨vÇuѼ¬%[µÃAky³ót0²¢õ±•ÚFMnÕDÑþ…¢„Ø&ÿˆÅä”!$ Ñ sVmz‘l–dÜa€0CM²,6“5—‡(I•LBÛP °ønTÂfãTÒB¬ù#»îÓNš3¿[»öÅg­i§:Žs×sî1ËçŸ>ǹoàŸ÷Y8÷˜eí¤Í%ÙZ>o¦DCdÓSRM.6tµÝ¬¯[%‰´‡@.:0”úd ëÖP4íÏš2AKM„iãh›¤c¤`1 ´8j ’æ6S+Ñ€5LÏЊ¬°Œ-Å!€¦ÎZÍqÇqÇ™$-˜ã†öì€d–5G cËž‰ ²TbÅT…r<•Ôy«Dô¿ q ¹Û\¬Õ7ã¬öMÚÐm¯)Ð.•õ.]±0£nš®¦Ñ‘m‹’„4–`E«méJÐ’IQ±Ä]ÇqÇqœùµ+‘D‘Œþj¹Í2mó²¢é8NÞÌ9é| I³øBB1I•­ˆÚÌÒA–¹+Çx`WB…tD’TØ2gQ˜öS¥‚$Jµù°$ R Œób'ÄÀžV± ²Ð`UP2hôŽã8Žã8ΜV(ÖVHbXP›HÜGÊ䈸üÉ0'¬!ã|‹TBAdùm1ŽÊL;‚‚´©¦)ßþKûd˜†¦VÌú«Å4—É8? 6G’)TUã¬Bƒµ–Ñ/:.Ö"AhaA d4c@uô†aŽã8Žã8Î,4.¥ÔiÍã!,+ûØè’yu=jlaÊŒ[£Zf’È¦àæˆ/Ü#* ”diSi4½šò6GH0Æyïì+aÏÁj ’( …Eºû/Zß*D‘öH2/PRƒÈ4CÊÁYŽã8Žã8Î\¾YMš¦hê %¢Ø™“Z°Õ$¯ådŠ”•OT((lʪÙj]•ŒÑV…E5íÀ´2¯Æ-ŒÒšPÚÐÒ±CX2ÅÔ£IkÄ„5fÒ%vq}óN’`PU„† A‹B¤¤ˆJH|H{-m¸@P !4†ä8Žã8ŽãÌŸ4LáU³>Ö…šDùŠ9©B,ÜØó56WPQ: ¤ÌMJA3UƒqÖ;ÉéVF@ÉB q±• ™ =:•ñÑTµ¶j3UX϶ùªP@‚PZJÑ‚*PA(;èŽuºÝ²[ÝB¤`Q–EQBE¶*€ÂF“®?¨2Tá·‡Ú…ú IDATqüŽã8Žã8Î\1k4yC¼)oþi #oek®‘ÉñÄ!r†ªP(B€„†h®$©ÞLÅ @ŽlFh:%Bó¾–/‚¤Æ¹ $Óô±@DâÒ¨B¤ TƒP)Ѳ@G(º]Ùv›ÅK—.é–èt´,A@µBU¡ßg¯‡ªÒÉéªPõƒöû•VAª¡, BE´Óét;e§#ÅL¯’³pœ~øØW®ïÿà–ª±upW ïýë~gEõ Ù¦ãlUÜœd+Þ&ñ¿Cœ{¥H)aØÌÖè1]c Ñ&¡Pa»¥Úü¨­±¾ €"j(l¡ÔÀÍvä&PBêÀl̳š"ˆEQ‚ T ‘¢a€ö †nɱ®v:Úíbé6Û,Ý~ñØ"¡T@èMOOOóŽ;tý†jÃú‰ÉÉiU@ ö¢€Æhn¡AA Y*T @Eô„=±y¶Î½—ûÈßû÷‘ËtÃßð޳UÅk£Ò--ê$ ©Ñ>FÛ TUsSk€ ABLHK˜÷umSÖ:†²¬a¨müO˜ÜÂÒ«@j)Qh($Ë’cbÑxgÉ¢±m·Ûv‰E5=¦¦úw¬Ã6®»s¢ª4¨„`["c€T•b[ P éª’Ê **ÀBÈ‚T8ú5r„1vÚ½vêëú~6ÝΘ'ÖÎoîØªß'[~™Ž3wüsí8N=¬{öÕÿÞ|oû·IU[ÅMDc(‹+RÝdŸ °'MééÐ"¤v*P ƒIn¨éQVVGDD¨„j((… )KíJ+ºétËE‹ÝnB595µâV®»szÃÆ©ªÒJÀÀ1Ð¶Š²­•’*"‚äê&ƹPH{^‘ÓtÞ€{7¬ºõ–o|é?¯¸ì’Öo¿ÃŽ9âÈcžóüN§Û.wŸaÅ\ÒÁ•wÞ ¿ªë…jÇqî5ÜŠ…êz¡ÚqgØNj1ËŠ™¼³ÆRû¬ÉÙâÞûTX3€C™Ã«©ü€°Zšj>M½›þ’%A°H‹®HBâ>ìwJŒKƋŋ:ÝñN!!É~UéôtµnýôƉÉÉ©é**””,TEAØ|ZЃET û­F_µ+!‘ŠÛ´ÜA)ßbÎýæ7vÔ£žû’—¯¼åæžô–oõË¡ªžõ¢¿o—»Ïpøòâg«ƒ*챘ï~Hw¿ídí”~âªÞÅk€¥]¾tÿòŠŸ¯ Ÿºº¿®§N?|ì²Ûªý·•}¶•U“zú½ƒ¶—§îU,*xÞÊê£Wö¬Íñ/Ø·sÄrYRò×w„_Ù[9ÿ—æ®›÷O?|ì¢ÕÕAK¥5ŒÌXî ñ¾_NOVu;OÞ£xâîÅk/Š¡]ñGŒ½ô©•“:Ó%4ùôQc§]Ñ»tm°|Œÿ~ÔØs4¹¡¿—™i]æ\š]6ÆcØ9h{Y=©ß¼©ÿ²:sÞÔCƒwœ÷šÏµ*N?|ìçkªƒ–ÊÞÛÊÍÿ^տ⎀™Çpúác?[]¸½ì·­|ø7½í;xêýÊ¥^».|òêþµë6qù#ÇùÖCº[& ¬šÔﮨ¾ôû¾·ZŽÞsÆß‹K<ŸÎ×˒ç¯ Ÿºº7Y ¼aÎ[Y°¼æ'SVw÷ÅüèÃÇ^váÔÊIù><ñàÎ~ÛÊñÊñv®º3lù½…»sÐ&)9‚áƒԦ™}ÉÝb]¦§KY1Â4Ϧdì/“4Šü‘"`åSu „E‡EA)D ”KA·Ä¶‹‹w¿ÿ‹÷»ÿ6ûÞo‡åÛ—cEorbâÖU~{ýúß^¿îúëo]=yÇz˜îL‡nO»}v*U` •Ba_TÕ`'ÁPj V‚ª ©@P¨B PŠª@ -¨íY·[À_¿èïtèÃÆ/¾ß>ûîûÀÜxÝïÛ…îK¾\~º:þòxü®Åg¯í¿ðüÉso©N8¨cï—üãÎâ’Ç_4ýºŸMï4Æ×ÔÉu±SñoW÷_xþä•w†w>¤»ÇbwÑô ?›:|¹¹S|Þïëê쾈oºxúï.˜¼qCxÓƒ:ùãÐìºÉÈa;tyò¡Ý5Sú®Ëâ/6¤v~xKØk±ì³M\ÿø„]‹Ëoö;l–K˜ [x™31—fßðÇ}}ÙSï¼lú±»ÖPvœÙ¹×|®íøI{_ø]ÿÅ?žb§âÿéÝ:¡ûøôµý]Éý–p¸ë&Ãðôû-áûÚýñÊð±+{!ý+&·³¾¯?Y]=a÷ÇïV|ïæ Àì—0¶ä2ga“Í.•½ªGOo™ÐÏ]Ûo7á8£¸7}®íô[7U—ß6öñåëúk¦ôˆd–18ûÆê7w„ è+z+¸òÎðékúØÔß 3@Püv]øÆ ý×/ð¯$g™éwÁNã<|¹œ~Eï† º¡o¯¨ò?ŠòÆÞö±G #xÂnÅ·‹‡ß‡9k«g¿€:,j¨Ñˆ1P*Q'£ç/¡± "Oˆshßk=­=µQEFÔÕÒI‚e!¡”±±Î6‹e»%Üvñ¢²ÄôôÔÚÛ¦n_§ëÖ÷B%@ í0ÙqŠ¡ÆVI­†`'V"†U‘†¤q©WMPEÜ 6¾^Q¾í+µŸZX¾þ__üú—¾hÇ}ÄQ‡=ê1ƒù÷!ºL~}G˜HÉÛ§ãÛd:(€®`Ù+EþWæÍ `§qÞ6­îH7©§+LUÈ’^À˜À.‹à3GÅ À.ã¼n½¶ºn2< ãOw+îìáìÔ­ÙÎ÷n®^PçÓ×àॲMÉ VV–Ïz saK.³™Òb“Í.ãd…<à–‰ÙZsœÌ½ìsÁ7ÿ­“º|œ³ŒÀªti·Nèû5ýâý:Ûuðûõúõú¿[¯³ÿ0rœGí\<ëþÅî‹e¼›œàlµŒü]°ó8ƒŽþ‹4¿aœsSÿƒ‡}òêþC—I¥¸huýn~æÓ­ž9 µeh-ÌS‘µu¸tºõÏø_a·Ï³Ý™zZY’£M*mû€€€8 ÖÊÙ N‚B–Ë–v—ããEY–BTw¬ë­Û0µ~ÃÔtOƒ–ŠRµ4==ËnôÚtɤ{Ò%½õi:Y³‹×†é€Ã–ØI~tk5€9_ÂtÀXú%ºt>QXÌz™[š)/°]‡¦­».šß¨œû,›üpÍñC1³¼á7Ùõ0›ü\Ø¥!»Œó'«t–1 ý¢3.Z.Z=Mâ1»':ö·?žœïåoßå‰wÞóËÞ¥k§'+ò¤Ì­Õëœáß.QêÌͪjÍåc…­†dÐk5Ù¤y À¤­q~­5Ÿ+Yvþ)÷Ûc›í¶éjUmX¿qÕê;úßß4±r­n˜ëëâ€n¨$T¡_…*TU¨ªBª[·vR« ³NÀFÛì; …¤ñiHEÒc`Å®g±ªåhÁÝ|¤(ö¸ÿvÔ£\ùËËÛÙ÷ âÐe£gžen™Ð_Ý^q@g‡.—óet~¾&Ì=B¹jR²ºzí=s¬ÀþÛÉ›ÔéÈœº¦R¼ÿ×½ëÖë»íšV¶ÚQŹ·TOÙ«xÄNñfæ| ¿]ž°[±¤ÄÎã|Ѿe+wvfºL¯y`çÙÌ])nžÐßÜ^~@¹´Ã]ñ…ó•sßd.®9~(fb¦7ü\ºf“ŸkOÚ£øãíeQ§Ý¯\>Îÿ[fC‹ï(/Ü·ÜmKBˆ±œÿåw$6ôµ¯xÀRyê^>™ukgäï‚U“úÓÕá¸;{-áâ¶{qØ s<ι±zÆýŠ.•ÖîÂÃïC·Mã¶±}9·^š²f_9=åšÕ_æ¡D!ˆ÷ÃSµÖbª,¢ Õx³>ª¹nýÍ|¶®“kIåÊÕë7N„‰É~¿Òj(”P*”ª@P!€ÆÔmÜè4i;Õºg’ÈqÕv’é¬{ BEQˆÈý±võª/ÿǧŸø”§í¾×ýÖ®^õó ϰÿA·ËÝ78h{Y=Uß ›‰÷ý²÷÷û—~xW‹×„»z~³*?øëÞsö.ßvHwû.¯ßÎü}¿ð æÔõ0ªø—ßô^²ùžC»ÿïâéݳÕÎ÷n®žyÿòú zUc‹œ¹\Âg¯í`ç3Gß2©çÜØ?dÇÑ—ÍÄÈËÜrÞ÷«Þ±è|âȱ5SúÝÕÛIÿžñzçnã^ù¹þöŠêû–{o#+&Â;.¶Ù #ÇÐâ—·‡}¶•·?¸»lŒ7mÔ÷þ²gSæuù+'õ3×ôO<¸³MÉkׇ WULktœ­–‘¿ >ðëéîÛ9éîX¯ ÿ~Íè Œ/\U½ô€òòÛB+";ò}øåëú¯9°ó—{–×®Ûz÷ ˆV8ó·!¢-6S I9mVë¦iJ`žZš2`ƒ꤆GýÓ-UJ UÀBœ T ªB¨ iÄ}³°æk°-W&ª´gu%ìÐöÕB*ißí¹]všŠA…°,KPøËÏ>쀃™Ø¸abㆯ}é V~Žùþ䩇µã[ªzñO.øÞ7¾vãïGÊË–=øðGüÙSŸ¾xÉ’VÉÛ×®}ǵ۴ïeüÝ~e_q·¬ìY¨®ª{[&'ÜyÞâ&,÷bÎ=fÙãÎZÓNuæÆÝø¡X¨®[íÜÓŸïêÌÎVøyï>sÔØÇ¯êŸwký®»[އ糬<î¬5g=~¼:Äs^ô2+oY15±ñ57½· &¦3H¢=ˆµÁ€³6­ 5Œ‰IðŠf1Ô¡%Á¨Ì>ÝkÖ#$€²Æ¡™©ª%ìÖ~j É¨Õ4ÔfJó8™gB³©@cº@²]‚¤¢E)„…ÐÆ†z¦ÉC8êÐ#ŽjgÜ'9|yqw=&g¡º^¨v¶ZµKQ\¼¶Úuÿv¿Îy·Å‘g»ñC±P]/T;޳8zÏr:ÀVnÝ; JšÏš#œÚ܈÷ë›ú€¨`iq½ÝÙo)˜û"ÇSãÞ­Œt<Ø"Àž[Ÿ±¬”P%l.€µ×HE¡*¯Юm¤¡Ž<¶UÓUBÆ– ³æ”œÊRʲ,Ä&"  A ƒí; Å+þïn‹Ø-T× ÕÎVË%kÃ+(=°œ¬páªðÙîd9NænüP,T× ÕŽãlg>v|C_?tE¯¹úꞎ)” §ýQ(™ü5kºVãžæ±qã ªgÂÊXvJ¯s­¦¹´­¬’Òæ«Ä(ª*bÔ6n`ëjCfc¿Ö tË\õºß^ÓNš3K·ßqäó'ÇùàŸ>ǹïàŸ÷»‹6n–o ŒÂh–V£@#%z[7ëZ™í²¥ö{°I¦d~Þ€ÅdÓVTf™Âv÷Op›B­ödQeYÒ¶®"ì""Ê.Ó× b¶œ°Õ”æÍ×'r@;iάY³u=JÎqÇqg3Ðxc{suj€dpÍp#°±€Ý›âÄ’ÔÆn#Hòg“k6XVýiRT ! ‚1 KR¬‹†93Šij²–Re!RHQˆˆØeĪªI-Úxk*ް ¬hlÑ´uÇqÇqg¾$ÉÚæi)ï €¦jfŠYí¬¬EÇ”JÎ2–,¬$“F–РBJ’12*EIy¶AvV;·‘Q„€ØfRQE ‘ dÖöG© \¢¶Æ\k3¹i#AëUYŠÆr-ÇqÇqg>ÌÅ¢fÖà˜µç³šÍ2¤$‘Ö÷¼W?LÎeRX,@¡q‡+[sEAƒJ!QDEn¨¦c ‘²(DH±Y²ñbã„X’P…²×Ò«€Í»£!ÌJóTˆ¸Aªã8Žã8޳0F$KM+c‹ö} ,šÔU¢1TE ZhA›ajºgEêFêæ@Þ åÙWiŠu“jõ5ô5@… …eQ$))EQJ!"°Í«hÔö¥¢¹4  ¶ÝVtÙº£xdj{µÚ¹¨Š:V›ŸÒå8Žã8Žã̃†{%Ô³Ö°€är)¥¡Ÿ1òI²1 f¦uö©¤í:%±hÉøòÝ–M¬›¸cÍú0Ø2¿DÓ IP(@|–Émº*”ªZU¡R‹¥²èNÉ¢!S{)2JE¬K0-äŠCËý¨=µ fÆ«¨$„TÛ>–ÑSãu¤^ÇqÇqœ§©Žlk’öX*`2§ÉóHB!JÝv»%{ï³Çm«o߸nrjzºa«`!N›2ÚÌà@€3÷˲!Ç$­¥‚ªjš+RT{¡ `œÊjc5͛Ɋzúi2Íô`‚8 }OE¢°Z@íÕª 7†å8Žã8Žã,8QÙØµ f—¶~Œ[˜æYE*,Ô¸aÃÆë~ãÔÆ©ªê'Å‹=B>&ÆEùùÙ­õ$ÔT]ãÆDÜ   !ÔPõ§DÚäË3]EZ0¶©¨hmÐ ‹°¦«…jãÊmD3_’ã8Žã8޳¤¨åÑÐØÌ#IUÀü4§‚ê$⊨X‡$ÀÄú©×­‚¢?Ýgˆ¦`†ž¤ªÍ” J‰²™jzH€P’Œ+¬Š‚’6WP…*D«JC…ˆ!EJ¡Ø¬Tko ×tÖLTI³Ëç©«DªR¿ Žã8Žã8Î]ŒÅc@ÓÃaW’jˬ ñ}ŪHj4™1ϤMеJ©ÛR iÕ?@RÂîü‹Pµ¢ŠÝî"©P’ jÐ~¨Hˆ ! …õû1ïTë :/ÍÏ­I„]* yK„XÊqÇqÇ™?Q¶´¢Š*šxÖéÑb¡âýË5I‹Ë› CU ¤`¡ª% Bc/©#ö½2a5c¶I¨„–¦ª6 @$ÎP›AÀ4?uðÂ’c"éo¬jBUõC_DŠ¢ˆ¤ê{ ¢°ª*S€5‰yM³O+SŸ;Žã8Žã8 J6-3·vÀЂL‚ÉFh2™^Z%¥i!SH1HÕ`õÉ 9ÜÇÒ|-PXHQØ“°@Àf—¶Ué"÷gÃ$ã²/UŠ*„† }Q’¤…0&ãr+’ª°ØjÝ ]i£ñ”ì8Žã8Žã,›4¬(g QZ4Q`ÕƒÓTp"j^ôÎT{óÀÂNìF’Èf,e§ÓJCªÖ=‡;5R¨Ö†]“Ï¢w’ªªªP(T•а"ãÄöP!„v%Ii^÷е9Žã8Žã8se•"LÔ’Â5³hÕ°4mµ@*$VeµPLÓF«eóÀz2«u¯PE!°  ÊlÚÀ5EvYGÍzÍ_!i,VXCö„‚„j ÓfE(4A´R)©*”x °ii$ˆiБsÇqÇqœ-BMFë"NM5vç=+-Zœ5¹šä\›€lÁjÒhÌ,u¹ËFßC¨ª$B90L€iÆk=¶Ø½Ùä@ᨘ©"º-ãµi¥H—AûC „ @¯×«*’ `_mË,ªö šçø:Žã8Žã8 FŒAé["û'@uÜpÐ!`Þ% '¦‹–ÒØI qvA£u@iÛX©íÿš,Taš›ÇE…¢Ìi­‚RÕÜpKUX»´]¸ŠÔ´í%«!îc50:»t €†_+UíWAÜí5¾ŒVÏ6Ùx=ÇqÇqœ9bžÖðÅhYù\‹–YË¢Ù•@ܦÑî,ÚÚ¤–Iª­uRÛ…? ¨µxZ‡jƉ@°@œÕšJ˜¶ÆXksVªUˆXð65fy mÍú˜mJ€¦”ø2ä~šÊ›Nsã „HVÊ*ôEH…^ãŒÇqÇqçî!ä»ù DIÕ&tYÃÔ_³×M¢ƒ“#rbÃßSFuê8Žã8ŽãüÁa”´_«ó’[»"U9jA=G{¦B) )›‚ $‡T“F$Eœw«”±ÖÈŠs¢­ó<Èê8Žã8ŽóA‘ŒSØš*›,¿“šÔŒŠº…¡°í÷J[ä¤ÖˆÕ@i*;O=¥’¤@H$  ÊX+×T%sÕä­ª*"ª•‚öHª4|†º”ÕœZkVUµÑ~Nk¦Ð’‹ ÖpÇqÇq¶³A4Œ‹$À(y£Ã¢±hÛŒ†$!¶¾@”:ÛŸ 6‘Õô”Ö&Á< Öb¢$I ¨…”V>[&býøÝcçAûe)¡ €P¨ J†TQ”°™¶Ñ•SE ª°Måmik¤¾´Fšª ï°à8Žã8ŽãÌ“®†Œ1ºÖàZ"“E+£P@RùšX͈֖ëåä4? $UXyUƒRI !„°$HRDºÒé‹-*¡ µ¬1åŒ""DojJÉ‚EÐ``m΄µ—ÀNÓ &1g¤ª&ZÑÕU£¦Ü:Žã8Žã8ó†­ø`&y†ÖI B„`q[*i†©´jEQÚnY*J’$)ÇÊîXgñ’Åc‹ÇBú½þ†õ¥5ý˜Hž[HUûýéBÃâÅ݃X>5Ý¿öwë6Nõjî¬H³”qçÖ8?UíŠTaí¶^ŽL#Ç#ò “Žfªë8Žã8ŽãÌF²:»A'\ZbÖ°¼¸ˆ òsL9ZÁLñˆ0hI)IRMï¬5!AAAØäR‘’eYŽu»±±N·SRi5±~bjrº7Õ«¦ú%­¯…¡TBU-zÓIRƒöʪX…4‡5ŽÂŒ•xFBýª Ýîo¢ µþâËDa=4™m¢¯ã8Žã8Ž33ÑÆ’®æ §’”Í”Ï Œ™µµŽ-6”ŽŒqK3@(©wZÀ¤­¤Râà „BRˆtŠN§ìv;ccã"°ªª©‰Éé©éþt¯ª‚VŠ€€&Ψ¶')&À‰‰þ¿Y­é¾@%/ïjV{Ò+’I±ˆ±½qÒjʵ^’¥aUëWÉqÇqÇÙ<’x¶cˆ5 UUÀÖú[ P¨­§·¥W!F<´€%… DD *vÇÝž›%ÊEÑétÊ΢ñn·ì”%€ªWmÜ0Ñ›îU½^ÕÔ카ͱb/µ{ý„ùg=} ô €E`¡›ö«®;¡ª6§!¾NJ€¶€Ì²A@óK˜’8W–š$á8Žã8ŽãÌÁûöšl«ù}&H悪¦± Jò¸ø£@‚jq\¤@ dAÓ?±Ù¬aÑítÇ:Ý±îøøx  ˜îõ¦6Nõ&§û½*ôCiŒ!(ÔÜÑæ³š/æ1'}Œöšõ¹¨êBñÚUÕ¬Û2,dËxd+´b…‘ä°3ÀÜ6ÉBSÿgþ§€ã8Žã8Ž3˜¿%¡KêˆjTK$²’©"$=ÔZÔc¬f§d:H€²@·ÛíŽu;ÝNÙ)‹¢ !LLMö¦zýé^Õ룯¢°’E@0WT¢´^ìFBâ(IEêøq­iöT(jm¥Æé Mmi›¤‹˜Øj¹ùlV‚͘qê€ã8Žã8Ž3$Ó}uÚl»õïf ˜ÞŰ¥Ð\-Ú LüÒž/eUÕ² ÄJ) °(‹²(¥éH·3V¢ª½^zbzrrº7ݯú•†~­Àbëü++ ¶¨)î c×b¤eP1AÍ$Óµ$ã$ij]°6×F[€ 5\o;0вã8Žã8Ž3oÌ0aªe!CKi~·™Ÿ§t&³³ï&r Š(„-äR% ‰©¤ (¤(Ë¢[v:²(Š¢PhÕ«&¦&ûý~Õë‡~UõSJU !ÀW•ÕY?Sœ5‘‹@eP Hz›õ7B­-#7Ä ¨ã¦6åÌ3½Ä U[ ä2jÝ ŒÓqÇqÇ™#@m¿);‰Ù´$@+3hÅòÞM ³ºw™-Áv(D:Rv˲,ÊN§ì”ª¨ªª75Uõú½é^¯×× ªª4TA5 P€õ­øæmù2A³šh* ˆ› ^L­š°æsªÖs,œ<CmcƒPU€Ì ¿¬RŒTI—ÓÔÇqÇqg~ ­U/:VÎŽ‰Jd“U+¥ñ¹ £±©‹Ù£fteÙëvÆ;n‡$T«¾NOMMOM÷{} A+ •I&TU¨AP*µQDZ5dY2<_ˆ@ÜÀ¤q_¤Æ “TF÷5‡e:E¼Ûì Õ¨ÝY•HñZÚ7‹ÔÐ@éuqÇqÇqæ‹yTÒ²,À4´µDP‚f‚6¥5Š‹Œ¢â!¢(¤(ŠN·Sv;eYª0]õúÓ½ÞT¿êõCM¨€­¨QW“ –¤0+…Áù¬@3$6cIvdsWNYóª¦S…]•ÂZˆ? D|éì8‘:ŒgªšÏf;Žã8Žã8s‚ƘV±‘H38³-2Ú¨²~tEÌß„BRÊ¢( éŽuÊ¢”B´ßë÷§û½^¿_U¡ªB4˜þ) fwª´ØjÒL„BUQO;¢çÔ!gH@54¯Ìb¨(ì´‘ehŒæÒʦè©ÍS€ªªªˆX;LÎÛH¨‹ÈFâe¦ð°ã8Žã8Ž3/†Õ„Q[‰z–iH H*cX°(«E§,»c²Ó)ÊB(!„^¯_Môú½~è‡Ð× fœ U„tU ÒLýQXóþù;ÅJ _ Ik7¢ª 6çTódØúÚŒUb™8L3Õ(ÍvX—4uÔŒàÖ½¤{Ø‚ã8Žã8Ž3/šñÔˆ"é0®Ï"HsU@h_TÛðÔ¢ªeYv:n§[EÐÐï÷«~ÕŸêWýªê÷5(ãíq›« ¨Ú4ØØ³Ý¦•MB° 1›|¢U·Ï Èy$Cv *l-Žu#1°ª0#Méb É>ë®MIÍVí{m¨ƒ®š Q¾ÇqÇqœy0쬄Í÷Œnf?„T0©jY”ëvƺ¢cwÎ{½éééé©©éjº¢‚(»»4€b‘Õ**”̶Š*ÝEoÜKiN@”6é6ÖTE\W6xm¤m²Ú¾b 5iÙ (´ÄÇØ4ŒíW€P‘TÔž;ÊWcûƒa]ÇqÇqgnX@3Û’4¹2  …t j[€eÙév»n)…Ô¦¦zýé^¯7]U•V¶†Šª}UUU{Ü*‚"é_@Ð`z +mr›¼f­ª T$ó ä}2ªIw­¥(—$¯WcÐ5—±ˆ©f¿Tš7,°@Õü€]“¦fòÜVK‰!â:·>vÇqÇqæ…E:ëS0ªã}üBl“¨8…µ)ËNÙ-;e§!©ªÓS½~¯_MWZøT…ÚÝp»A¯”hnfu©ç4€è‡LIjí £P@‘&˜³æ;ûˆ§ñXH˜p’Q‰S3±°)6jÞYQã‹¢ytylö-U£;Žã8Žã8w9¤Éh}! ­z¹¥tì±UeYE!zU¿ßïõz½é¾VÁî÷D‚" q3_“…ªÂ<4Ûݲ9Wµ‰¹f<@¬Z¡gÍžÚlD©·«²ì–\ªÍQà@Åhí…2 rÐ@JžNâkþnæÊ5NÕ¡C×å8Žã8ŽãÌ•ë$!"2( EQEÁ²ïv»Ý²,Cý^obbrzº§}Õ TT†  ÛZ5FG5KØít6¼³™­°m¥äy €©kÔÎh‚QtÖ`™;Ú¡}ÅñÌ.ÊTUa¯Ò5¦P…ùhVP»ÚÐ`ʼn¨¨³÷ç8Žã8ŽãÌ•B ³,‚`ŒJÐN§Óí–e·S”¥ˆˆHÕ¯&§&«^zzºêÛÖª ªjˆ;(I>šÂšöS©* 3:æä¨vV¸µF)5$m’ÄRK‹nÆb7h”T¤R14Žë¤fC="wdòÝhldüöÞn7–œÉ²\›ʯ1Ýïÿ 4ª¾T÷\l#ÒÉ<滮 [y$¹Óùç~µÒÜHgU:fØ4MÓ4MÓüŒ¡Q"•Xë÷q»ßo||||ÜÇiüxþçŸÿùçŸÇçÃ6ÓHc'úT¢hþÁáluzùZšï«o§Aõ˜ß‚Äe©o $í —^³ßw‰\Y=ï®zÉÿ‹æ@]r<*»à—zjÿ";·iš¦iš¦ùK4$i Ýïc}àvƒéÏÏÏÇ<O?™Óó9÷«q挀°‘4ƒ]x­®‡ØÚ ù§nßËéVÊ«$µ·õ]¨»$Ï™™HbÙáÑ=ÌÕ`%ªžÓÊHŽ §‡}iUØ%oœÂú•…}{MÓ4MÓ4Íoðñ¯ûÇýãþqû¸ß4Æœ~|>>ÿüôãñùùð,­óÌþÙ˜ªÖ[ÂØö•üI¥sÚ1Áð÷Æö+ñûJR_S;ù¬ÚD=³UAJ’øp]7 !{–æ’«°úxQÏ£ÂWŽŠ¯m›¦iš¦išßçÿù_ÿó6xÎùùŸ>>ÏÇÓOóœ®mª¦…mŒ´B‹}v.!¨ß—þ—ïß ä–M¨ dê•7 K%u©iBµ»‹:\ªk$T½Uç%°»ÚÙµÃ@Ó4MÓ4Móß‚ŸŸÏçççãñxîÀª„P½ÅJ¿çrÂÿ?xÙëʶ4®*âúp°mqMÕJBÀº¿’Ò%¼Ähëð:­®0mc‘_sikžÝW§nš¦iš¦i~“ÿýÿþï™Uçd®¨áÒ+Žt]›hãï£#'õÿ÷Ú´Ëãœrì1™-ZÁ®Ë°œ2À9Xâ*-MƒDY¯Àêá¦J Z9ýê©ÿgCÓ4MÓ4Íÿ¥<þ|@©ñËXÙ²+I%Þk§Þùbg/,m½Tñ•]ø—½üš|¹ $“äÕ¬í 2|J£åiðBlu’}g+›7•—¹;ÚúòˆÈ·ÂJ€Ój“'x–4MÓ4MÓ4?bxȃ%†”âu‘$dËŒèÛ»zÚýKÛÊî¾ðMAüØßXjœ™¼ §L#MÌØË)×}+lj8'â–•æ·wÃ7iÏÞ2ÒiÓ4MÓ4MóSì K‚É*+9¯Ñ•ëTŠ&P±ËרaÉæÖ¿]]ûÚf½ ØÙ&6W¿ 'öÛzüTòù¬š›Ë'¿ pFIkšJòR?ÚRÕ4Ü#¾½è/mŸ¬mV5ïÜòMf~"MÓ4MÓ4ÍïPiÌ™™½­^äñ‹þ½ ÄwÜrvµŠ·%ÛóâxÛüò»ª•úm2/¼|»Ø­Þ‹‹ì‡ðmogaŽÏ’š™¤tRÛÜ=‘ÞÜ G‹aœµX:Û4MÓ4MÓüÕÖÿ†+x ó«8d.g­¨Û{³â½x¹ì{·«Ì»,®¹ÑºpüÝš§oøu•¨è~›ÿåKEA{¬í¬ç¡r'‡„¯¢ÿã‹Ñš¦iš¦iþ¯DJŒrFË–bÅY²¥m¤K¾vÕ+ÕóM¯*ßpihøËÊTý·R |g½x¹±_£Üu¬(i?'•Ï5x7×õ \°•ÄZÛO!,Vh¶iš¦iš¦ù)Šsj 9/éqíP6‘ì¹ ®4®¼vmÑÿª…¹ök¶ßE•|×Á×,ËåÝ¿ µ¾‹çÒ¯™¬ä õÓ\××®$ˆ`› Ôæ4c l,†¼‰¦iš¦išæGܹ&ƒ&¶M% $´Zë®nÌœŠyùã%²¯Nyšâ [Ýêò%æÛX¤í¨ã;²æÎåˆGÿ¡"Á×R²*>äu/9ûK\i©•NqÍÛ6žFç½Ô¥‰$¯%\ßÝDÓ4MÓ4Mó7ܸM¼þq7S¿”ˆ!Â`4"‡¯vh–~e—n•ûZ²ø¾‡¿b%&$Î*¨PkL–K›÷Á©\ó¨[Yoÿ¿E•“zùî¾VŽÿ~_ÚóK$¹iš¦iš¦ù]þÿzæCXÌÉS2ù– ßÀÓSÆ®´WÁ8¢ÎÏ««Õ™"–ÿeSÓ/?¦%ò¬unOWÆCÌÒf0çL€ôM[ ±ðŸñ׫ÎòÑU'ŽZ5—#+£%]bOiiô¯n iš¦iš¦ùþçÇÿšóù˜ç|>ý˜~Zù “g¼m0JÏ*b8¡[to"<J `)ªÑå²;¸ ïwým›Þ›Ffšit8k rú·ñp2WÊ&¾r”ƒcÖ¥¤ØæZnUçLI‡sM`ÛÛhª“±ßo¡iš¦iš¦ù{nãã6>îöœÏ9“Çç|>ý”ŸsòäIœUFI{OFñTa1$Ï+ÉUžÆ"Ëæ×—Æþ­»-ÌŸ­ðâ}å…Ǿ—@Œ˜²øÕ¨5µ­ÿû7°–N™ê3ÕJieM!âk kÉìöJ.Ù]» 4MÓ4MÓ4¿Ë¿ÿqÓÇ·Ûí~7üqÓó9Óχ?ó15’§<·òÁè¢oÄØæ@Tö@R`˜60b€x›è¯¨åÞ ,ï›V5ù>§¥—H¬$Ž`§+ ¯Õ®«JƒÅ»¶°v XE»Î®°ËÙy¶uaÝ?ºÜ4MÓ4MÓ\üÇçÜôy»Ýïcܸ ÆmÜn·›=?|Ìçs>§çä©ù[žàä³**6Ið #NCü­²~algéá©WqéâºòÚ‹{œòf?‰z ÌU´ÞØG8W"Á{´uÚÃHš2¶<4$½mppYñŠÝ¾]ð±ßBÓ4MÓ4Mó›|òï§zhH·q»s¿ûà6¤›>n·Û<ü°ŸŸó1çÓó)= 6ÆJpR+ާ]_Økµ–‘É%¤ìXêÄ%WprˆSó®P&¤ñy&0wØï÷kÄ3^uúVm¥èZ\é·§°‚ÓƒÁ^áâlllëÍHfwR—Á.é;tÜ4MÓ4MÓü„'3…Œ<Ÿ?Æsܸ Ýï·Û·›ÆmÜnÜŒ?ìùü|øñ˜çóáÒ±g¨dÕ8"97V VxEd#™©6°Œ—a~Ý¢µê×É©¦¸ÏYÕ]©.®ù,4çÔX/ý]–­Ød”Á\ÂZØ\52LÏ4I‡¹ójxHéêa‚$U¼¹iš¦iš¦ù9VÄÎO0–æ4OnƒçcŽ»oƒ1”l×û} t»ûùœ‡ÓÏéùðsú<ý@ùîÀd‚Oƒ×z¤QNh/]L8vÙ^ÜïÜHëRÛ«d­Ãs¯«Â¦Âš•ѰÆÇÓsúñ˜ÇsL?Ÿ–5chËè¤q“”G&O—ïÙb•nmuéå÷¶W*xÿ.ÈZœE.“Õ×þ*ôKŒU’>H¹šGu†‚÷¦BÉdÕØÎ­^u«Ó¦iš¦išæ'˜9W¤3M!×[þ¹ÞÖ?ŸÏÇsþ{<ï·ñqÓí®1Æ]Ì۸ßuÎÏç|>õœÓÓÓHà‰±‡dO3©wé€Á':™y{Žùe£‰—ªZ¾Qκ٧K3«äj™¬Óš‰¯ª¶¤$¹†xç(­ãoý8—V¶šTý¸ü7“oš¦iš¦iþã í-aR4Ü’‘ì9ð©ùï›î7î·q¿kÜn7i|Üÿøð=Óz<µÛÓL<duu…×6®ÂÖLf‚4왯̲ɑ`­fÊW<û$7à;‰Ü~¹l2ƒÖE•Ÿçl7‚$#Ì<€­µçú­c6‹2㪌]J.åÿš¦iš¦išB¶¬ŠÇ%¾(4-Á@O âZõ‚ÐÓOñy{Ž·Ûóv÷ñq·ÛívÃ÷ññx>óm­‡ŸO?Ì´gÞü Ϙ]bŽÆž%›öTR_c©dH“„ˆú~¥òYã”’°—…&¾Éê€iFiìWÙfÚÛgØõ¬Å’Գؙ³ûêÝo<·iš¦iš¦ù;fíÿÏr¼hÕZI´dkûŸ Ká͘þ|ú&?îóqÓív»Ýuc|Ü><>î~Î9?ŸŸŸóÓ~XÓžsÌ‘|àÔШX¯IHu¸¯ÔoM¬¶}ÝÕØßÁŠGnE½ÚÕ­Õi|ÑÖÝŠôýê¢ìÞ^9•w_^Gýxÿ9jÓ4MÓ4MóÛÔ+k6‰)V¼uZð”åþËÅÌÔaÊžžbÜ}Ÿãy÷ý¦»”ø+÷ÛÇýñçs~N?Ÿ~<ýxV/3šõYÉ0…H¬§ç#ßÐZœ]Jx×…;`#­Ðæjf›|»•Øjñ%½N•'ñruT‰mÈ?"»o:ûµd=º¦iš¦išæR+üK\ccL<2‡ÀÚ& ˜™!c1ðóùü¼ÏûM÷¡ûív»ë&éû‡¹Íç|ÌÇs>žzš9ý˜îÓ3×Çü|ÌÇÓO3‡¦5‘§m?'n+îjŒG"²±XƒelÖ÷S“àäÆÚõ Wc~mŒ+zZŠ™ i8Œ3Ó˜1êl>»[Ùð7ÕK[súµBÓ4MÓ4Mó&ˆ¬;"ÁTÄ^|4\~7Ué§©:óS14Ñð€õôcÌÛç¸Ýu»i|ŒÛ¸kŒ»nwÿëÃÏçüü|þùœÇüs‚ÂS yÎiîOžâ6˜fÎ|5ÕÈš û‰™+ÚZù¬QDÕF¯€öâ­œ¬Ãb ¥¶¤æä½ÎÑ2 ¬ß¥¤ß¶mš¦iš¦iþûÉz{;<‚„TI+´Y4kt?×PÕ¬s&8ä²®%Ž›ª²º ¼„N«l‰­¡®¦MuøÖUÓ4MÓ4MóHÀ°)ŒU9w‘²½ZWDo™àà6yfkUIÒÍN~*â9æãéÇÏ»î7߇Æm܆Æ÷?žóñx|~Îϧ?§§™OæÓŒkž"›·‚ç@ææ¬ÝÂò‘Ϻ'¶™¶Œä¥äìjZ]®ò ”æÜöÒß« WWZn\þžÝáïØmÓ4MÓ4Mó…mQÖeqKF·ä].·ôîÀkEþT^ÙãÆØk¡$ݸMæÓŸ~þ;Ÿ$øã>Æí¦Û·?þ¸ýñœÏ?~>ÿýä!ž2OFB­kwlú4ÖZ†%ß=§2ùøåJQ%¦ÖÚ& ¦ŽØ¨I2•IpÝ¡óÌĆZ!¶b³’$Ùµ¹ i%Œ›§V]¬î¾{|MÓ4MÓ4ÍßQáU–ç-oËkïU© °~›‰ Äap8Ëú<õY€1Œ²+ÈOjŽOû¼ ßþ¸ýëãöÇM÷»>î·çý_?þ|üû1?žþœ<ž€¦É’'Ùžv¤‘ä³dƒÖ ÿÌŠä̪¯RµJÜtŸ-Õ\EašZy @BÖ‰§J+Õ"Ó1Únß4MÓ4MÓü„r³$˜z^Þgוë;ƘÉ+QSå‚UäiIh¬dê ¦õ°äñçü÷ýñ¯?nÿú¸}Üu¿Ûü1t›~>çãs~>žþéÏ9ŸŒi=̓§g…t“Yv÷×àù½nBqØ_bçŽHœÔdÝI}¨nÊd¯[ÌQ E$ºÎS§¼5Ç/O·iš¦iš¦ù º\U埗— Äñ½¬\YÖ¨k™+Àþ¡œoÈ Æµk©%yz~òü÷óßóãc||Œûø¸qËñÇüã1þuüûÏçÎçsj€-ßn~ÌÇô|÷Z2¥¨çVÌs‹Ê¼Tvú VÝ9WÄtu»¯¥û9§bà¬XíÕs®TË·)5MÓ4MÓ4¿‡†ò*]|)ß{µ27¿^ÝÇÖ‘$`9N(iò”5¤¼É7L²Í)2CChÜnb>žÏéÇçóÏçÇ]÷;Üï÷ñqCú¸éö1>¦Ïùxøóñ|Ì9oTõ¬ ɾÜÀ²f²Vk„Ê«>’œ= v¶@<´êľs³ƒìŠÈJ•1[þ¾OjZc6MÓ4MÓ4¿‹t¾1¯Øcî° ¼/EÒPåpðÌ›yX«Òêl‰A)f¾ž%K“ç°f- Lûùä1|»ëÏñy»ë–˜ëMããö!þÀ~>??ççƒÏO>y™z%¹VçïþiÙbÊaÅ\«Ž³Æ>ß ÀX26–îúÜ>t»‡þ¸×¨±Rö2¢‘œ8ç¥Ë©u;7»u3qÓêöµ¤pW>K£È€ÐœÖÑtlÓ4MÓ4Mó3t#/"æ*ˆ¹JD6“Ô™C;ë÷ËA!Õ Y¸åòÞIâ”’êÓT¥°FñZ©ò ,¯ä[ÜÖàó¦Û'ã_wîw݆n÷qÏ7.‡4FÈOÉ¥5b’ܯۼsýº0«ÓÔÇ)<Î]Z|WduõÀ[…¦iš¦išæ77%ÀŠ+ÈY*¨Z¦i×[ýˆ+$AtšÄ1¯bÔ7]l7<4Ñæ{‹U¦Ë„y…@“§Ò-ÃXÒ“ç}úósþyóíÆýc|Üõ±r2` ³ïŹ´©©:ºK$Uû=å’ÍÕW;M(öªF¦ÇW9]îÌ‹hš¦iš¦i~—1ò\kªŸ,ë´Q}6 ÊSeªÞy;«Œ¶¦¥4%KóÒM.Ç…]õ²BÖ -`æ8V»¯bäÇ“ÏÁÐ÷y¿égÅv©°¼ÜOÓj-­ªéul¹L Tªè©3¬Öm]•È¬ß c¼™|.kéïKx¶iš¦iš¦ù!qÖ%{PÂZáB1\2f=íe¡NvEOËÑf.—Ú!|]—ümsL”•xi.¬}`MÞä f•ÑN$4ncú!sÏWYËHeJ*¯ «“ŸZ3XŠ ØªÚªûÉÐd,ò ª“ÜæªáН›árÓ=\†€ãZÓ4MÓ4MóC¤è©ÀXeé‘•€‚ã¬8&ãä·Ú%më«T¶•¦¶^-m«AWÿûtŸÉ&þX2YWJ^5#~éÆÈ"ýûRÅê- l û%"º*Õ„×ùÈ_mW@}áš\*U‰§!ÙëzTuïrê7MÓ4MÓ4ÿˆ8"±ÓXØ!¬’³Á¾²ZjI ð´Æ3wðÒ¯ $êa{΄U¯ë/M!Vx!eCd9Þ¨ºæœhTjÌ F¾)``Só%Ø9dx Y“ÃZ»«J"Ÿ™úÆÒZ8ÆÝ§9~+ß%MÓ4MÓ4Í?$áÕ¥TÊëõ˜$H ßbŠÑ±ì|öôMòHú)2.W\­©¯N ,çüLpo‰e¢²™(ûÔ&›'1RI`Íûœ×®¨vhðúª¬êe½û«ë—€ÚçL"kB¡Fñå¦aX£\üR¡­µiš¦išæŸ ˆ[´.ñÇè"HØÒ}meU/æAf‚Œ!ƒg^Ö›iOOÝ3ÙWߎ›¦iš¦išŸâD7ßJÊÙ*“51XÊÝ,®0£* ZשtVôôL˜g­ú 2¢…m¤z–‡9^ÓK ‰½[Kõ&Í =äfêmþn¿®PÊy:e±5ìa¹Û]ÉcÉÃúµŒÚ =_›¦iš¦išß%ŸW•v¬02GY%ìtT3ëJ²ªæÊèêÜñ>1!!ÑÝÛ‹âe4¡ØïhÚ*±´_IÕ¢Z¦ñÄÜË8nûª’lÏù$)•^;ÝOáðÍC”7g×$©à:3¼Œ¾ûÌ䚦iš¦išÆœÛGßd¯ñ¿uPŠh,FR]·es*«²6cŒ˜›ÅÍŽ7r©_ÒcS8„Çõ4ã´€Õ©™óÍþ¬ð$jˆç|f iHšv8˜$Æb¼KÒ–uÓÃà•,°nZH™Ã¡Ÿ†\÷³{1×UÓõÓ4MÓ4MÓü2°à¿‘ªÃ³Q€$ÛâÒ¿–Tv=ºÉfXÎ -ψl´TQ:DGIô1==^bœÉ;P½ò¯cYgÝ•s¼…Ó¶+1@9]æ›Õá‹­³¯¿b›jÖŒ¶°6MÓ4MÓ4ÿ½8nw–€ 2z–¿p bÇØ¦×åJhåx8z'‘_à‚-ähßJ„Mÿ§§·U8«’ïùB×¶F16ìà+NtiçÀ@Ú:‡ iÕºÆ׆û©•³ïú¿f]=o¨iš¦iš¦ùM^Dë¿¿@ÈùxTi»iÀܯôM>ÆZ•ˆ$jØ%}q9­/¶þe†§bÀâ^_>pÒ4kOVÙûse«ÕÊI,XÁQ;†Ks"´'·ESû6ߟÚy¾µþ¿¿Ë¦iš¦išæ öŠužkŠxó³Å«’¹Jb&P™¼ÕÒÊÕǰ&·]b»rw¥˯|5@ ÍïfVz™½†nQÑskª}/uìµ&ÌTœUx峪R<² -8ê˜FIí—8뎿îÂÔigmš¦iš¦ù'˜Zœ¿bˆ¥a‡ãÕ»ýäÖÓÓr”µP`¨eX&‚až ±ÄmÖ»ik ^µøWÂ3¼_*i¨¼»šÍøç#SÎ júX®1k˜W½´wbËu¾=‹PÛƒ}­æÔ4MÓ4MÓü3ìSǼ…ÔŽÍžª¶¨ZUŽS‚K½ÖG‰!%áIŠFzþ…È}`žÄ{B£ÆJ+>ü0bZ© ¾Ò`F¦ýÍÍG1KI—Iÿb&û\ÂúíŒkoƒ¦iš¦i𿇨³—¾Ÿ×¤õ^]ËÂÊÄŽ%OÎʤo%m‡Œõ‰Õ‹$;{l½Tû–¨cFy‹l‚îsN‰¼ÞÛS"‰¬ÔôIr»5/Ñ®î^»¾tç¶žuN¡Ök7Y‡’Òä­¼iš¦iš¦ù]âtÞ~v°¬´Ž¯Uó”;Ú. t•¼IïfÛ*({»JûÞå¾u¼Ósp·Ÿv‰ãº\ÖR±ÏjæLãûŒ^¥n’×Ù}ÓnxŒWÍKmפš¦iš¦iš`£k]|¡w1sOߌTÒ«Í}eÀS:XžM)ÃiÚÞ]}u°G/t Ü;¬ƒUÉSZµù·9K=Óu®/¿þžo…u×·½+ì«MÓ4MÓ4ÍOxM']Ò—²|XÙ ë’¤z¿äñ—d%Vùš+4;ÀëZ—CžÊ÷õøÆg›ûu˜¹erÑV°}»Õ†¬™†ÐÚ®5½¾=ƒßò˯=F¿j|Sþ~µiš¦iš¦ùËÛ]T­W’²ßéuÍ`|&¤~µµÅ¨êEU+‡[©ž¿bxÍJ­RÛ÷kWz-+—Á–¤çó)%Å´„Ð^¡2‚‘N¶dO^úÁ‰_‚-–Ë®ŠP91f$BÍÕ“½?«‰x:óqX—;~F›µñ¬ò¹[R¾0+é ëö„ŒýšÕýš†^ë´03ñß/hš¦iš¦i~‡igS'à Õò®³ÚÒÐ}Z׿âUärl.—Û•w5- -+­]ªÔë´„QW¢èËôî©’ám—5Úž×·<Í>¹æT ÐVó´Œ·ŠžbÖLù=`uŠ!k²V]€˜îNhš¦iš¦i~„òÊZ¥“ª–út³Öú¥ÃãàòÀ})*x”TÝ!ÙN"A)áºø¢…¾æR3L”g-‘” ÏT²¥º/ý¤’YƒRÉ´¶Ç‘qºödd cM¢³™ìlךú¹p«Ê{뀦iš¦išDmŽºÎ»"•gaøj\¶£g 4­ 9[ž& û)IÛ+S£ÞÚ²–Ië;®T¬òÒ¾:M÷×,êè^ƒ+‰a©ê¾"2V©hýP1ÓX;']µêx2‡>ØcÕY훿ÊYs8cÀMÓ4MÓ4ÍϘ3_O]øõ×ëûz¿½ì+žZî¹/nÍs½žO6*^ #»¶a.mm¦°Úæ`ÍÈëMþ./ÊYKXž0"Š<±P*lctë bÊÀ BÎ’ÌÐ6à(6¦*¤²€€ñöêÝÄeú-¬MÓ4MÓ4ÿŒéË/£V/ »8<ò‘ ‚D2óR_x‚͈—‚åaÛ®ÅSåxÌYqS;biÖþﶪ«ð b^ùvëšw]3•Xºï§ê8±_°Ÿ0`e`%»ûu¿%a«6ª%5; œ©T¢íÛÃ[·uUûîá6MÓ4MÓ4ÍJ$@1¯CÿvÍèœÑ—Kz™¯&d{¬ôµš§ÛÕà¸ho¼8%õ:ze›ëÝžùAX/â'²IìõZÀµIÐtf9µŽå—‰B[?'n»n{Ga1V’ì• û­žî7MÓ4MÓ4?!*™CSZµ‚§e–µ¶¦T{=§G¥‡‡¹~´üì·í» ˜X«j9àNF•í|ë×êë¿Hâµo@ÕK©ÅÒP¥§=™å”Õ‘“×›ÖÎTØ3óˆ}N{}| 1M 8Ó:šàÜáê8lš¦iš¦i~›hÕ>Y¡Â}1ÇÉyõi‹s?/5 §^Äå®K®Eõ½K%íŒ~Õ«†ìÈiÕ|#ßHãê,,cÙBŒoŸk¼B%•×Ù  MO$ת±„p_l4“Ô:\§oã6MÓ4MÓ4¿ËÞ.ªN'Ëý8ELRíÜ”ˆ¥]V/µ‹RÚò¹1àµ5¿!¦÷ÍŸHó!Õ%ÍpžÒÖ*®Ji›K÷£|Ùâ%àªS™@é륓_ÖW¥á«Ó S’ZEØÙdŒ°±420~Û “aÎ[lš¦iš¦i~‹Y/Àsüí…KmkÿRg ªsSÊ]y—c+U´&‡ÈE0WãÒÊ}ïž®î«Ò=óKðkU1qË-ŽKVgNbP‘YY©zí’¶³fò5ƬI |Ý7trÜNÓ4MÓ4Mó3¬m¨Ê¯+¶¸üðö¾„+tŠ9’DSw]z-$¿w”³Ê¯º""É\ÉÕÃõJq‹3èy_âÒȬ©²XS¦"¥çW¯ª¯£Sç† st…ˆ…ì—ñÖä®?«Ü`%öºÖ¬åvvÀµiš¦iš¦ù)sP…,ïÃådk³§àCUe|Úm*\‡—à]…N@\óµ~ˆ^¯ÖÐå>vâ®8«%N¤S•1k1ó²þŠ­:ÓÙÛ¯&ÁA)ß {-ÆÂxØ–¢£iQcS;’›>Lê× MÓ4MÓ4ÍÏ™µ}ê &rĆY‹ø/¶LÖñ™êùÊ’Ý8ë—mY¯F»Ò¼·ÞÎ(g°½Jœ5X×0WÀ÷ˆn/­ŠkÿLuUÛuAYl,tÆ?ãîæ–]vGKgͺQ•¤ p² Ž&MÓ4MÓ4ÍïóœOD¹J¨òç0Ä\òw—ÖéÄ£Š#j)=uñ86˜ŒƒÆcS¾jd‚‰Ÿ’:Žñ®J/ÎöÅ-¦שW’€Wªk”·n¸Švmœ=üt>Fð&Ô6cÝRíöºäõíÑ5MÓ4MÓ4Ï£*Ç)¯7á€hâ³|‰WWÝØäázÎJ—Á-ÍÛ–úª‡‹êÔ¶,VÀRu©úºË†üË•±¤‘´É€è R‰Qw‚S¶oIõRb°4 qÓfðþÄ\O*M”.Ø×WkÖ¬š¦iš¦išßÆiý‰¯]›¦Î3:¹â¬9!Zw:6žLM—ŽnæL¢‘G{ <—ûLI°l{¬o· Ö‹ýô„©Ô×ÍP àÐÍQoüO%ÅÔëe%iV sÝý3%ûÉ¢l°k6MÓ4MÓ4?Âöò´’Δ+kãÁ¶£\vŒ0ê%$‹`ÚxoîÄudg½0Ó~µÈƒuÁ™Lj¯"ÃÓ&+ǘp'³-Ý ú¬òUáµ| ŽK‚¤Ã®òÌÆ‚•‘ 5›:Q"µõα*+WŠ-¶¯þ›¦iš¦išpØ_yž¯sG«#¶e„Ž5EŽ>ÊÛÂêˆÞ_Ø…çïub¶%2…{¾dÅÜ1Ü^!Ù ëRnU7©‘+tÃÙÂ@ÓO)=`§OÁÒPÈÔ€DÝ–œ™h5Ì(/÷Ð4MÓ4MÓüf®wßλ~É¥‘Æ2v¶¬*#“i fÌÕXs뫜õ#î:çsG së,’x\|9°9¢%D–ã+κ:ÐZ U¡ÒÔ^¾Å<'ÀN‡u®¦¦ÒÞ`»¦b#ÌvEd:—GvW'kFxõÖ4MÓ4MÓüŒò¬òµò*l1â]¼¦´VÃT\V¸eq i&Ï¡á¹=úU¡Ï/É«Óë\rõ¿†[¬jyÅîråûªgê=¾@v‰vÙ£TKÉv/W<ØIt€a*ÂêYɯu›†,¯G™‹öIsZZû³V ,ÒHJòiš¦iš¦ùMl{-4’¼^ªÛ—\ ¥NÕ¯—âedq¸%v‡>ŸOÈûr ·t°¥ëC[e¸ÖF¹L3ù¤)Øžx•cƒ¯ýYáòÜÌ ¨4€ª³GT2 *,Zu&•Zuª·Ø±‡À;ú[sHJ_v"µå°ïº¡¦iš¦išæ§”P1$osªVñznSQ×e‚1øÝ%¤$é)”Pæ–ǪÎRG® кöåXõ«ªÉ›cÖaÙ³m›¬köÙË0×–X•ÀUyHÔª¯+@«z ë4Æ*áˆûÕ À°­4›À·ÉMÓ4MÓ4Í_cž—€™Ø¨e]&ÛùæSY_Z+Dz¦«žÞ™ƒé‰žBë |XÝnÿCìQRcÿ‚ˆ×i.Ù^k°BM|Íé ® ØÐMôtÂ-aܼÅÇù˜×\j¤FÝ3‘"¬ò¶Ñ<œz¦¹·z^²VEÓ4MÓ4Mó& b­,©2³ìSïµ/ß4‰¿²,ðºðrV¶F¾MÀ(0·ÛcfxG2«5¤£CY3áÝÐ_Ö`횥©éKW¹'ŒÝ"©¯àÌ £Õùñ9A¼ú”ç};6ØJv=ºÝ£~Ó4MÓ4MóS^ãž@¢™rŽËÑ*¹UzQ6A¢“\*÷œ)ýÓ[ß Òð[’ã‘éj@ü8UuãZƒUݸT3ŸKfe½Žë^¶»½AAâÁµSBl¥BúÈœ”°+Ll¤Ä_­Uùåa7MÓ4MÓ4¿‹÷皀eÝ’i®¯¢f;ÖVÔZ¥'ŒêåÒ…$ƒÖâªóZå%bÙ^Ù"âêΕ~æºã†\©5Xñßêñ{Î)îcgǯÕ;6:—„&»êÝ~2òo}Á¶²gįmWWÆ"þŠG–¢5MÓ4MÓ4¿O>Y{Ûoí—ðE ë"IåâcoàYæºzXds§}¹*—b&Ñ´”V3QÒª› ”Œ’‚5¥üÉüóíÖˆ2×Êpï2Ñk !1ÖU¤±Â·ù²kÍò÷|:«xùîQ’ ¢Ò^ê7MÓ4MÓ4¿Ã„˜ œ6˜ß¢ä/Žš¥Y©ñ¦^ H–9J±¢¶f.É{ѹÒ`±f•*:è ¾Š³¸Z¦c—÷&Ÿõ gÇK·VÖé!š>ûq-Û¢vUXÁâ­Ó»Ú:„µ;Á›¹ž“8Š›¦iš¦išßÂËÌDÖ¾›eˆñ·K²Œë|å°úÐ?¯úy‰Å,Ó å®mtÆëL-pM`‰ñ*V¶y]h\Ÿé÷$¤ÊÔge‚cY¦‹-ËT¤8]t%(ĉEÆVþK%ÖcZ§¹™uŽU ¸¹žâYÚ4MÓ4MÓüÆ{±Ó2­Hã®¢Ê X¹®J;ò–ý¬F^•êÏ‹ÃM&Ù´l1–¯nõS x‡/±³Ó?¾—CÓuÜÑÇ=‰•›®r>LeØJj«f~ ,á1ý€ÁHy¬Y¥3Õ#‚™tQ\ãºñ¦iš¦išæ·ñÌ·¯c2ÍÁ„ §~˜m¾Ê6¬5ë;¦eu’·³ž/Ö 8#ž+¶ ˜DHñJ|=§aßqI+¥µcËY9FÆß­ÄJHÈ rŽé´®ßc—[dé&¾*ä)S¹« Æ” º]%ÕEJ*¼iAÖ`qº¯©®jIX•DF£*5”VKZÏBZ]Û^5ÓÕãA »2Î PßjÔš¦ "®v"°þ iš¦iš¦ùs%ˆ‘«1*F9·Ë:?‚‰„§Åsù䳜c•†ZJUaÕ¹Ä-uRkQ /Ö¤Ç^2 Û,q¹qÚ›gìn"Ãy_ %µ+κ3tD^‹ª‰Öc9k&9UÄ 37ìÌHÄ×ʳ[÷Þ4MÓ4MÓüŒ8,—›ózõ¿/Q¾ecÅÙª ¶Ïª—ìPå˜ñ<ÀžFÙÆËM_0¸-^S0Êþ¬‘ÅÕ¸,ò’Äón2°ƒ½ÇªS±’fwìC§fÒ|s r"аúOMiÉ®Ž˜vÓ4MÓ4MóÛ¼âÿ<¯lsÛZhÎïÛ_©’ñwš@LõèðäkgxMÏ&QÝ|ãà^w1Ÿ(Ò Ä¤ E–£–ÕOõæô¶2ps`ðê皇”Óu7T¹³u,Ž « «ÇjuÚ.kš¦iš¦i~ÂtmDE9^ŽNS ;€yº—a›œ¹ÞÌÿ{…K¯áj«ïx JTKýrö Xò½ƒ¦INGîfY+°¶HX½Œ {Õñ3>*‘ÁÏä až5ÊÞd`;¸´f³þÍjš¦iš¦i¾eg|U²+¢ør¥L1f+½zøÒÉEZ8ÌÔ‹FdsyZUÎT„*¿œ°þÞ%&|X IDATaÏÕUgKÉ&¸†bŸHé/1WsÏÜà’×=³ÂW†îÈüßA\~µù[§oš¦iš¦i¾aI×71ÄÓ´Þ­ñ´²†œžf&¤Y’x4ºt-…YJEt5¶H¬ïrÔ\F@öÛªZ«—²m׬S /¹´½¶ÊIµ{“ÃWÀ¹†„é|ùjõ¶|Vçñz‚3Ç.U jÂ×§Ü4MÓ4MÓüË£.7–w]jí[¹›+Æ [gs°O¨lÐI»ôw •C×Ò®e°¥…À™!PE¯ÑJ¯}^Ë!ÁÚ¾*+{ \õÓtG‰9 O£½®l_Y uÔÏòòU±: SI…C©›¦iš¦iš0™ùÐ*%¢"§ØÑ¶²ºñb\®Ÿãü«7žqÖRÃü¾Šslb«WaŽÕª¶/gq÷JM8b¥©é­˜Ë4suÝR4q wͱpe`VíîNÙKËF{‰ÖÌ|-„’[g/7Ñ4MÓ4MÓü.Î ú切ðåÅý¥Yu\z¦ªþ&gï¢YÕvQ‰@Þû¯:U£”ò4ÙͲ¦ëû[Ó˜h"^AÓm´Ób ¢^ð/Y¯~WCƒä ãXÒ•Š“\´"¼‘ï·"3ít"¶jmš¦iš¦ù9±3–ááÚ–iï·¿•/gË÷åu ¨jG‘–鮲r]Ȉ«îKWΟ‹c±ÐuÕ÷¬“JEö]Ù(·“‘C”J¦¼†4/ ¾t\ãˆiýd×±!û,Ó¯BˆÑòMÓ4MÓ4ÍψáÅ±êØŽ˜%1€+·ÔUi»ØnE¬®ÕÕeEO…'¨Yk–^ îêôõlY/>¹.`áûµqÕYA¨¦KUð«^ågtC‰®‘Ѻ‹‘{Y&¾$ÛF’rz# ×P»–’PâÛ4MÓ4MÓühÕuz\¶·ÒRcwÂWÑI‚ˆG]²á‘ÐjypÊWÝ—)¼vqr n9ÁRq·÷f«™CDÒf ù%—¯·lJ7cªi[ýOrÃu¾,¾z®y¬y¹R Öwö$VÍëk±MÓ4MÓ4Í0óRÁ"Šu©]öÌ_/ßû"•“˜œ´B’ìZéìÍN)A<ú¬Èäu=ÅëÒ Æ‰½Þ.ÖAuñÞX…祷õ[ç31Ìs}-ÿZ‚=¤½ÇÂîÐ ñ¾Öoš¦iš¦iþ1‘±÷¢S$¿Ø#TãBlô»š'_MôUí¾^=qÚߣ‹G+ãÊ<Ø¿Œ•plÝÉÞCKUk›v ºÅ{õk@+)7³u‹ZdaÉ”@ël­àjš¦iš¦i~ˆ¿³Ê¸š`íä?€éç:ö²º},’¶I]™Ñµ_ñ–•°™èZQõÆÎ,}Ó¿;®9UC8Õžõqë6&¼*%&Zù²éDÂs_Ÿ«| \'5ÕÕgæ óÌÙšV¾ ÛÎÚ4MÓ4Móß‚íJóÞ]àicMHj€©—ÿÎq™Ú!|¹•ÑùÂRÕü¾JJWªÀ·Úꨩ’:«ZÃw3Ï]RyhìmÿòÔu5%×w öLì! æ1•lR+v“•q%­Fv 6G4×G lÓ4MÓ4Mó#^l2Q8#ê{g½r`wdx½¤«­Ú|Ê•È``/¤ª ªœòñ9+ÆœHìuÅB¯…ëà%y iš¦iš¦ùßxTéÝqíWûÊ7]½°õíKÍ*1v­÷ÚÖºþ>:Ž‹ÆY µNßµ?”î–µ ÀÞÍ ÀÊ…e«¾>£Pzå3¨·™ôÅ_µãm½›ôðVØ4MÓ4MÓüç;wÅÄŽ e®½™Ö—×ô›xã_‘·çïÜz».¯_”ù ð•a*Jüœj¦ü–»+t\õ2¥ü9†]×z‰‰ñ¾EjÀïucÞ÷¹íVUe­ÀR ÞIU¥iš¦iš¦ùmlm+cìnUØÇëB¹Ө䌔§™Ólg„¾‹à¹²¾ß»]¯œõTQØL‰L!s®i-Ý|7Ñ_à¿©)ö‹æ¿ŒÞ4MÓ4MÓü˜­Rµ×¨Ê:¿TX¦÷Zú^¾mîÌ[=ƒ¦ßÚÞòÞx—µîýYË w'—)úue¨»D>f»&!È­I¨#žžUØi¬À5¡ô…mš¦iš¦i~Ê´/—Ò-ó[ªŸ.'|)øRˆnÖ’,jéT¥Î¾òš] œ‚Yåù–à|×/Øöiª÷âPcƒjÆësP±ƒ›ñÊÙ•êàüJ_¢B¹$×ÕªnÙ_àÊømš¦iš¦i~Â%o‡NIÇZ¦wŒ ‹6ïE±Æ+'`æ¥y´SuVJ™lÚZ¿tdТ‰µVzíúQÉ 0×ý8£‘ÍAã”oÙ¨^Ó0”>³«VJãÓ»W-W…ÕóZ¥U»k_ì»iš¦iš¦ùm¾W¨ ëøåW… =¯ ‹½”þ±S`C)jŽëߎº–#ªÖ%”9fÛúêü2ÀÏzÎ`µâÌ%­Øçi¬À1Esíë1(šŠaF[«ÓÓ€™]º|^»›¦iš¦išßækþè‹o½ð.„oø‹ ìyV–Î7ô«Aùè—rX‰¤ûâ·sð=}á}‚³ý¸B©5ºö±Ê ó Ö®CFQõn•Ëko…Ó•Óö›§Ö4MÓ4MÓü-“y|•À/¢Uœ’÷Usg ’>œø«2®×ýWÛ³—çqüF”¸‘PCÒ®®Žh¨—Pnvµó’—h¾4Vg»B®±²iÏ&›ó¦š¦iš¦išŸðÕ­ÞBž¬•GÏ{­j§ È+7ôðÍ$<«Ëo÷º:†S~–Jje#¼ˆlØÒÉÌg¸ØI­Õ‡HQV}MP­·ºF¬cÕ&µ_jš¦iš¦i~ŸÊ5­uðÎñºª¥gä{ªQ²+ÄxZå«àUÇGq(gLRê’¯V·ãš{«¨=p*§÷û¯c¿Wд&CýYYï ¥-í±R¼¢Åvš WC­â”—§ò1,Ùëjß4MÓ4MÓüÛG±Êµ"’uõ¬»~*„ZÞöµV´ò%@»œ 7¯¼™dN·¶^,o½ÛO–†"V¦)OWÁ9b:d/—ºÆßC_ŠlÉ£z˜@}Lx)¼nÖÉ®8ïgÝ4oiMÓ4MÓ4ÍI„5GQ·DV…­­®ÅN§WêR‰clo_Úº8м?fº´n·zá­d \. ÷dʈiÂ!¡U÷øóf¾ ýÒÆk•9kmÞ*—ã«*½Üã[ïpÙìË•¦iš¦išæ÷pöŸ¶ö¶<é]þ§™}±Ì´xkg×Ï‘!úM[x)¼b®®Ÿëlq·-dWˆXi%ì¡ š÷ù—à®n’ ±ºÜ´î]OŒi}kZ‚)€qÌh€VjÁ¾×@qÓ4MÓ4MóXOŽÕQbÀLP±¼ëõxù¬¿ÂÄÔÊ¿^\oê—FdóezçA¸Ò Nù»I­þëG0K=·ùjPe•'û5ó`Õ¨RsJW§G5³d߆JØóÞ5WAÓ4MÓ4MóÛįÖÙùª^U¾Þƒ¯$ÍËºÞ ï䥟:XË™v†ÀN%}•ÑÙ+ \º^Ì_µî5ÞÖD öZªú“÷ü«M†×y—×îÊ)Ç ½–ë˜Ó‘e`ƒ–÷&éµ.äÏêð¢iš¦iš¦ù—_m§ªýr¬å`/fù[þõRi‰àF^Dq_/—Ž¡9jÅï`.㎟Õx¹zÙ'bå\îJ*k^»’h½æõ Æ®ž7õü^Æhš¦iš¦i~›Ëº¶âíEEðê}¯>Yeù³¢uvýùÒèuW:êÅ[ý/ÎWÆY½æ' É_Ýe¬O[e?Õa}¾¨³*!U]Z‡Áöfy@®,BÕÛ„ŒmùÚ%`;ôûý7MÓ4MÓ4¿Á›&.µ2Â95ë×;_ µ^ý›RW¢p×(G£¯íßÊÊs H_Sc1N‹ìϺªh7b¥4\êš[•Ðèñ”[ß]åzÍåx@W•ÌXëäè°Z¼6MÓ4MÓ4?àMØ^Ýò4¶7Û¼8Ø6Åý‚|K\ê}U7­!r|²ÄÒ9N¿ð:_ ¾ƒe«~P ƒ8kû±Áƒˆ{²^óSåHµ¡×rwà¬o»æ"qXÿRåõ€D[+ðœõkMÓ4MÓ4ÍϘ%UѹK¾d§ ¨öË×­¯ëì%sûxŸéêÂÎq‰¤l<Žªß‘àïÑÝqíq„×I:¿êsV«hÿ^yÇ×¶´GÞƒ¨Ƀ¸:Ù6›³ªe`¾Ìºiš¦iš¦ù]¢]µ¿iLl½0/;eR‡’.%û;4éìmµò'rW3xÕÐßaOòž¨a/ïT=:ãJÊʲsô8'+‡ &z•­?^É©_g»ŸERq&¦»«4MÓ4MÓ4¿]škcü—Eï×ñ6®+†ø·8¿êOš]ʵ/Õ_±rDÁeÍWàWw{"%z¦£ž÷±zɲ^JʉsM^, •Jï köÑcéúd€MîâEs¯I×cú6,Ý4MÓ4MÓü‘´ò±q«ÜŒ9ŽzÕ;øúÔVÇÒÅÕ›(uL':>úz>Yæú­òí¢U{å˜îißÍ”G¼>‘pˆý­2k]áVþ¿öÞ]g–f‰ZÑgksÁs„Ð <à#Þ‹à!ÀáÍp0pi ìq0‘v-Œ‘—îþöùÏ P.í¯wVddÜ2++*;«:Ô›å®Þ ²y;ªáP’Fg~Z_/:ïÅÅÅÅÅÅÅÅÅ× ˜[AaÄØ®‰²uSÙ¤Ê*dÎFßìªæ%çÌàœ©èçcËêëµ>RB•éqªšJ[š&+« J. %à;\={.9hý™-Ðú‚…FBMWçtÑRo1îâââââââââ;| ”Q„'20zÎêÉ#ÝŠ¡ä«db%I#`žË)W›ÉHéz‚ËrB>ƒe^©üQg„£jÊ wýï3›'¼“³¸ûaØ‹‹‹‹‹‹‹‹‹Ÿ ¦X£œdO%†$øcN´I=õ$?€™o³7 XV™¿È±óÀÌ&†øVÞ"ã.UÓ1ôk­ÂìµÃ¥©™½vFÿŽ »uúâââââââââ ~ÏiÖ>·újp`Gl)íwP6øÛ\ÂËQ½ŸµaÍkÁØéZ7!ô‡Í “Vâ*mÅy1•€‘ôm1´.ihù%cç뜡•¥L­-nÁHO ß"7è7‚ ‚0–Ûp3[Líáõ…ËWI ˆŸ`€8:s߂ٽë}ÕÕÅÅÅÅÅÅÅÅ_‡’Y•‡¯jŽIÃú={äj‘áé@‘èÇåYû^™/ïàë—ã ÄCÀ`¿H婨{Wý›zíE0½é`Æúm¾·€~\ieìl^¦zUªº.µšie—.ÅòâââââââââÇXs¶‘«•Œë˜z¥4OW°ÔMO×{™0OiÇ È¿"Kögù#•T1’L°ïÀ-nÔïô3"N|H(}–´pòY’dbï¬gßô?PBŽÑ»¸¸¸¸¸¸¸¸Øc›³n·e2“¹uO@ÀÌ”2 µ Oûœž @<ãk~™©òwËwúVÒ>µâ¯ #S$‘AtÅ ½'kâ1_4ŒT.Ge°„Òå¨f :”:_\\\\\\\\üÓJ¦R4RIJ‚×2:ÏËb( Å‘B ÀoÀêzí¬å"tæj‡¿ëÊßTO½ôøUî8}ÜçqÉJ\Ú§¼À@Â`¦µU¹ðFÿ֟лÁÜ65| fÀ|u–vqqqqqqqqñ#Ôý£‘t1ÓS%f¯(g¾õ0¼´[0ƒQ =ñ{FögZý|¤‘ä«'u%¶Ý.YxûJªìù!ø~V‡•AûNú^þ“­ÁYvú<¤z[Õf-Egixq¸’BHq^\\\\\\\\üE ‘ÈåQü@iÉ•­Eq°f®Êò°•èûX•sÆê¤y"ê‚w¨T56ÿÃ/`´üáVS¾ #ž¬tXMé«¡ã¡©)µôC­šÕ DX0ÙªŠrµ6…OZ.........>#²¬A`°¾Þ©¼K¨ü,¥¶æßÅ;Rˆgzz:©Ìþ¬’µ†¤âLU•çøåyd1hX,ÿÑQ %ÑJ“ Ä“Ua9§åKRœ`uffÎ&žh+Ñà çâââââââââ3êò&<ÅÒ:èKN¹H É‘Ã%[Õ3’¼Š•’UQŠŒ¿"%íï©‚‰¢ÒÌ÷›Æ×ú‘’à F€úòñUÒ]F˜H¼œGl^ä¢t‰ h/ï$ðâââââââââ3ò‘¨L³Ž k©ˆ…Å {VXèþ(}€®ÄË!†.ÿÝZ«¿+ªZg]›6ÛÆ…  æûYóËýI#³¯léWÙ]@UÆ£]I\E^\\\\\\\\| íׄ'¯™fµÿDÕþ@_¯-˜—* 'ä*lÝF€Cz·à—?¿¿0,KžÜ"Ï/áZõP “HÄžTú_´Z”›N iˆ7|Åók³Ÿ©•Žùíõ6iL_A5À*°¦©Ä{§<á³±ƒÀ³Ï‰d2Ÿ/ßϺ e“fV¼?áÖêýQ¹Á*?WÃÙ}SˆUîo²]\\\\\\\\|‰|ו!’­8PR¬–ÏeBIÿs”­«ghë)P¬”âyN9«¶’åw œ^¾ÄÇä$¬ΣŠ)@SC–lUÿ’þÆÎ‹‹‹‹‹‹‹‹‹=Æ&U¹at¤`Û”ÌQÓ¯ÌÒ>ã[>|›à~Ñ_àªã|Ÿ@|¹ßà‰£A²Ü’4èI)Ì`4ã ¼|ë-Ó‹»­WÙÙK°|ÔÐÌÿÃÅÅÅÅÅÅÅÅÅ@é”¶]F"ëÙ—iˆ”Ë”ÃyÊçå–¼A/bõ²mËñÎýHëšÒ`,ÏþÒa”åwŸe}— /EÄkìÐÕ®ÕO ¼`l¦0Ò¿rhÏ„V“¿uêââââââââbÉWþ`@y «çXYöü²¤z,µ4_Jôw (Ë †šfÙhB¼—`ÿ;Xïñ+òFæG”Ó¸D­ÎïýƒMž¹˜xVJ?jeæm,¹‚„Á¦·$@›rÏÄnÄÅÅÅÅÅÅÅÅÅgL?0V 7ð× ª<2=Z†ÍäM¹œsˆíÉ#Ër(4Sƒftaù¯·FWÌ ¶ ƒÈRvº²Ïú-aÈÝ À Ðnk«îâââââââââ§ÙØ úß±ž˜\Ì<ôÕšÎåiùÑbéGc 1¿Èß­Bé¥JmKëlÿ²îIäZ*”œjéô%9e¡TS¼Ff2žDŠ)Ú½sçââââââââb‹¿{åß•ƒ%ý2Œß£µ ÛFþÄSÌ_ç?’Ø5£ïgÝ£<ûÿ%ÈÆïŠrØŸ¬ôZÆ:ëÂpqqqqqqqqñSÊ¥„mÅ’ªí’/ƪªmjE0ûêuX\ ¬ˆš5g•%˜, Û¦_Òªkª ô­«S>*r+¯ÜD)£` ŸEàÅÅÅÅÅÅÅÅÅ—x€—?òïÙ¦)_ÛdW%[á k”\5Y, Ž É¿Óðù©¬_ožmÒWú3505¬Ë«­†h//4+—&é6ß 2ÞÈpqqqqqqqqñTÂÊïžÛ®7i W0=Õ“Ô7é%2Ó[ÅÏÇ ë:«ÀªÎ̆w„§Ñöi@] NµÀoðŠ÷µ:ËX|Þ0"òÞ‹‹‹‹‹‹‹‹‹-ø­$#·òÔ*7§f®åÿ#^Á¬4ï`4Â`¸˜‘TžG€ ^ZÙ5J©ô‘!Doˆ m©V4Öt3«&»Syd¯áÏäÛ½¬´ Aó%סc’Ì'¤™/!Z8-UoH@}dÆD^%’2Ä\’Ì”‹`,M>Û `þŽWÍ ÔQCWþçoÊ`JPý@ÍdJ¶4üŸÈ;•q¾@¶2ж›¢9 þê*úï`xð2fÃZ¼Ñ DåNÙ–Œæ‹¤³¬-ßœõââââââââ«„žV)'{0Ò+Æ¡B ¼ ã×üÆãI«ž;BP¤mþ*V¡ä„õÍFHà<µ @%‚Æ{Ô†˜FÈ85ÙîJ0SªJ2ÒVÀåH~=9ƒalÐa²ù¾ÝIçÖ„‹‹‹‹‹‹‹‹‹OèÉ`"rÐÌ7µpl–Uë3UMTËP¬š$kd~Žo³;Cy«4W¥Yõé»N“Ï(×"¯‰³oSÐßÏ P@ØLnBœÒÓ çÅÅÅÅÅÅÅÅÅ'ľÌ)µŒƒA4c![«ÛÁk7IÚD"jQá˜ßN ò(ûYÀ®me 32¹Œ¬|ÎA«µha¾#ÿö£z°Øyqqqqqqqqñó"è!©ò/ÏóР•ÉšÈm‚œÒ¶#'€VËšåЀ­Î5g51w£Gƒ”ÕÚ‡$œ€KʶtŠl{@ã+ý,:/........þ0ßþT°]gl%¬ýñ%@ÛF§%Æ’å%¶ ÝLä z„ ˆ—p™ÿÙn}×Õ,¹dlIÕc[æÇ½…)Ãe²‰*¶xRK‹;.........þ žBÙÚê$2SÛ™ïìT#-LD~èèycˆeà¹* @OUE~-.ZüE½X`¤™M&<dæË À¤Îây-µö¥W‰Ìß]°È¡#VjPbæOµ½âcð¼únÙ‹‹‹‹‹‹‹‹‹ïáyÔH3±rÈøÏÒFJ'2óÃi£aIˆ£ÍGdr—;üÝQ‰¦ð—[ULˆ²ùŸ›ÜAOC„•„[i¤[Õ]Ò‹˜¿õÊ<;šµ0«$–|PI±^]ûCü«±îʽ¸¸¸¸¸¸¸øÿ0þ³ÿàÇéÍHÕâë~ —FkX_ 5ÐÿžT‡† O(:A-‹È\[k”5~éMªZ2.Õ†àÖ›dó½^RíIPï¬òÅShmôU6¶V—˜ž*d±äúäöç&É4±.ý~ƒÿñ?ÿ'ÿýÿüÿïÿ×fÇwøgø_þíL»¸¸¸¸¸¸¸ø ÿé¿xýÿÅ?™©_!²QþåøšUfºåÛl¤¸2{Óp¬LÂб&¦Zµ b‚À+ÞÏêÛT„Û$Qfžû¾8öàJ¹ÙäzÔD_û[.¬:Çãµ€ïð¿ÕF7LØU¿Å¿÷7üOÿåŸõëÅÅÅÅÅÅÅÅÿùÁñå¼yƕߓ{!¿ò‡ŽœV*-„:—çYá«›‘8zS ävu»­L q&®§¼ŸYíIdˆLÑQ`©¤ -#… Ýa¬¼ZY=UÑG¼¢z*_\\\\\\\\ü#•jiœ§_^i¡£¿ ÊQŽÿý@)]ýŠžÐb­HSš •PélóÞˆ%Vg³ÅSš¶rÉ0Í}5ÿC žø]B¤¥$ÂîæÅÅÅÅÅÅÅÅÅß =#´…çs5;œàÙÏ( mêØ í8V/ñÄϦ"3EêÃÿ[˹¦[sÖ­MéÈH#kÃq°&/;éM›‹‹‹‹‹‹‹‹‹?CMºŽ˜˜”z.ä-zjèÛfijû•ò™[þ:¤Þmí6‘³¦M«­ FÙȯû¢)ý屦M¹mø½÷ôâââââââââ‡ø½¤¯È ÿ pÍkͰËܒ͠ܯVfÅLs¶íÞdRk#?­ÿ $a™*ô»¬€x•§Ž×]uˆc¦ÎXš]\\\\\\\\|òB' ó¼·8.—~ÊÙ–lq9žkzh–ǧœu¬zú¡x!+:E¬nÄ`êaæoŠ5ƒ§Ñù×Î|E¿;\/.......þÄ£ÅA†wÊ IDATâ¿ÍßxŒf° *Ç›žŽy#ç›2Ë’fª›‰œ²¾ÚļLþ¢ÚYj³ÌH9ëOzBê].«.2g± ©ôÊ–ÈG‘„~a å ?„™gXT¶Ï¬| räbñaÀx{ËÖéÉÀRV»h¸„vªåbã/ð7€%—’m/ÃË¡Ç5yäÃØc•uý5¼’^Çn9h³|qqqqqqqqñC4þ&2Å9˜g—TÖæùå+ó®ºjh¦µJ€¦W”Ü­~?¯ô1^ð€YSÆñ© ~ Œx^Ñ,×Y«¨&¶—uøD’©?1x"mÁò¬™'»:ª{BrfÃ3ŽÞ\\\\\\\\\|MšÔ¯¹=‹ó-ž¸Í0€‘°¢dyª˜G³˜þÔW“ŸoeÅÌ6Œ¬9ëTx_öç©ò°lÐÎÕÆ¹pk –˜ <ßéú7ƒ½¸¸¸¸¸¸¸ø1Fnê¯z"= ®eg«ò=,Ye‡)Mܰ´ý ¦ÜÐrý³¬ï> @³Wý¬†­'2]é)ÛϳFqÊ“=h­(ó[uO¤”ü ž0zíùXM=¾ixD¤…ô} …Øtz|k5è` ÃÍÊe³¡³¶^$­ê&Ôÿþ?ýgÿÍûßÂÅÅÅÅÅÅÅÅÅÐ@=ô[EÏljßÜP’çÍÉú³Yò!.þê¹æ[Æ©ÍɸI±3ùV×JÚÚ`…^Vq/........~€H£JªªD0ëÖLŽ=›°åwòÛ…HË,t[5¦yßæ¬2a¦Úç°®’zKø#ÿaBÄJŸÃfÃ!í=ãÿü7ÿÇLº¸¸¸¸¸¸¸¸þåò¯³œ?zé×fµQêDã.ù3«B´]66¬ï¤¢ñEöNðl†yÂèûYkV묋3¬*[gU5É&  dõ7¡Jöòÿö¿þ/…xqqqqqqqq±Áº´×²1m(¤±øÙÓ²5GSê8åñX=ɃrAǧ~Ô ðTÐ×@'Ñ@£í÷³@y/€S:"Ól5~@}ŸO¾`ô$•¯´Îô¡}ªôš#þÍ¿ýWÒìøƒ €çí¦%_¨×ÄÍ@ðŒ—Ô/¼Ðà± ¼ø@# F#{6?Ù%¾q„ó6©:1w_ÃN\í"Ív¢,ýí±õ€ÙV\2…dªã  ½&:Q8 #øB•>Œåš½nµüõhîã¨A˜-€òú·êa”£§€Ý %o­4ÆKft“òÞª!~¶OÕ2¦ÿº³ øSwȆô˜€ÆdÓ¾!±þäÆô >’4œüL/¢ ŒÉú’‘ˆ †aá~d&<ð•°ër¡ˆ« ’$ždžaÏž>`4tãÜ_;¼œèá²€±Î!Σê(šÐU«dGóÕ&¢Du¶Ãm`íǸ[zC£w‡˜ 0à!ÎÁÂlº*à#l„â8äv~EëЀþü̳&^{@ í?3À8´ø®<¦b s[r>!€—e™æ]¶T–× ‰_aUÀ;`d¹‚¢¹+=H«¨f7xfÉ üêIè¼"ŒØ«54Ðø2/â!i0XFrE™¯ºyöHŒfjlÌÞnøbkK’óWLʲê¦kAVí—†¯˜¨S常ÿÇŒl»Ì¯‹2LrZ™ /‚X†ß*¾ßà*bê68Ä#§Aô~báàDPåÑØ@²¸¼0k*‡½jg‰FH:¨×rÁÏt4ê­¹1?€åÐÓ}Œ7$€’xÍcÂð!Äi’^Ò•¬¶ŠèuÒ0sB–áY?älRÔ~ØC ‰zõºb´0ÉäHi‹ì7Ö  @Mתs¢£ªŽªæ£ˆ5Ú§¨Î’¹éñ¤"¸¥­é,@³;RN2§YÖa—¶‘½’ºL«”†~Vòà÷S" qåŠôh#109[åL +çV°´ ÌZüxÃ=0!( ñæl³›¦þR9Kwû´Dl.ГÁ4oMU«åíL/¨ö¸ƒî5IT©+f¤`Žd èkZ*5f‘hNÀh\UOåB†1©v4Ì>î&},ï0üºq'Ø0ÀäbG•ø±<ˆÌ’sÞ˜4¦ ÿf“Õ¶Gâ 4ö"S‹žê ¯wOKý[cÖ .‹*ÿû¶‘Í7]°Ó('· b *X…'rrPì(z¦#?‘MWóM1N­Fúa#MÞÎH³&êü³dk¶ˆHŒší8ðAï\dE˜d¿ {yw¶Œ¸ŒåÙ%Ç9ð”›C*Ùtÿ$¼@ª.ø¼M‹Ç8û„•åÔl•ÌÖ‹²CVQ³³YUõ.©~…Ÿ?Çd_µ ¶YN×¼ %ìÍ^4ä¬j$¶#' ö>Ìÿ²¦ ÝsûuhT§ûíªËxÆ ÌMÚßj Aø¿Á¶©Qº;øòÎr«¼‹æÌÀ‰;(³Ós&‹õ³è©wbŸ‡`]ð[f †©)ÐWh ,BÅfåßNFÐÖn'Gd v‘7ù#b&II_Qèš”Êt×q’°³Øñ¯bø¬ÈlÊ>˜ó‚ŸËY›Ø©N³'ûY)Ñp¶Ê¡(î~  €!ÌŠÿÇ4“³¾Vã½:ƒ¬¦òÑ$|œ…¼ÇnºfŽˆèæêgNà[$coÔ¼ªJ}¬¶DC+ÕËE“adާ˜r¼ØB¦Ö0D‡lxTÌÔæ3•‘e˜{©6Õà:Œ³,ù^.Ahc>9ÜŽM·.p–ê×(w iƒjàžP¦%–P9ªF«CžÇ%^HÀ`¾­*f?j,´± `òQ± Gl¸Ñ%W–Y娜Ê'H£|¬‰`$[« #ŒÓåžÚeDTÕÓ¬”ý$*Б®æŽ®Ö L,g¦ˆªùßñ7&ø©S;åœ$È%‡Ð! ˜ £þ£øtš®¾ÐÚ‚¢:Ò`$J"ámλ1BrÄStí0«³¶A0`HÕÔX+Üê˜W›qt±ƒ²¥›ƒÑY×µ9jKi?‚ˆÁ|Àìº NíÒûNýà É-ZaöLO uëp6ÿè 72 C­4V£†UY-æ 'mEk%hH4°¤Væ&B%;tÊÄüMÞƒGÿ-f8ÊA9pNPÉ×BQ“Z™j7¼B…\K9[ g")Õþéd<¢vîÔú0ÍO,z85è󧦗Z¡Ê]&³ÒåwfPrc¡ËX Úã4Øòª\°çüŒmw|ð{ÖubLû3 ±EÕ>0‘84X-G=F kwo¯DŽsÍŸ¡È“©ÕQtýC6*¾T?*f×pÉ.4ZüLi#g Ž$Yò“‰Årvr ÷V7V¿‰Ý$€61;¶­'†ÔWÓœvƒ„!c”&¦‡R\×béÀœž ¬h¸±HðË®øh?9o÷³ –’èÉŒìòe7ŒˆyþU²ó•|Ù_>l˜€¶— Û¼UØÉRȲ¿“Dûm›>x¹ÍfÀÃiÚ&à·Èyœ œþ¿6zûP¦Ó=³}g˜hjmpÕ><«_‘bÆÑjû +JøÐz°ë…pwhWÃXȤÿ ÃŽ!;M•pŽ"¼$™ø© ˆÅžs«_$˜yâpD@æÊ8Þ433óDpÔÑ w¬ý Æm—۶Ȧ’󌳿 ˆZ!"É)³9—ÍÖ‹"ðã°ÚÛ9G¶ÉM:¶ô5sCw¨pÕ®ÖíýS¬f8b6ߘjÀÎÚ#KNÄ¢,1-†#ì³#îi~y3w¡ðHueb—¶ñ.°VQŽ ¶ãjƃ”0™Ù%O>¦ðä‰c¹ÄV7Š:/Íÿ†+9ÕÏRM©3ýöãÅkb½Z?dw ²$3*èÉŠÄîâµ…Kå6Ÿà¶7áÞÀü¢™(èߊ.—ÀwU±xí#eæEÀ/bƒ‘n•´HéX~sˆÛÛÄŒgÁËŒíªVî§Ó–^0øu=µ@f¦ŽR¾þ—ö#*+üÞ./ìEÔ@5{Ëк ûŽÌrÖç~@.]¿Wíc¹T,@±VÌÙ ±&4l(% z¡Ó¸f!,µe ²´¿æ<šÿY|‚ù…ùEZ‰¤¼©]é+jLäK9aåîzB 3·âÍØ~€ÐV}nº„úíÊ;HMµØ:œSÿUç ê »ñH óNïx…~ôÊÄ &UòªeãËéjô$—ž[5î Ë5'æï»ôsp¼pg)¾óñ„UbXWpá‹D¡Å¶_—– I–ú×nMk@zû=â2÷‹bŒKÁ§Ü¨Hü ÈäãÏ„œ¡¯X_Ðp"¦àdŒl¨þžÍé!-1ž¾KœBכּ•»]TSnšªþò2aðoŠ í»Ÿ só „ý2´d{‹o¤£™–ÕìÆ Ûéþ$…þÂ_×ýþüžÐ·Ö¢¤o5 F¨-kSñ Özy”Á~¥š”o½|Ä3éþdØ5”]Š~™›åíÛ€Jû¢a–tÚíIÃãy5¡5ÔøkAq‚ç3p\Urº¨Gê!]M¦ìa3ÕC:FEX^KF«˜Ä %à,'MCÄ-ÞüÕDhÁÎà‰=öQ“Û/Ãá¨ûåv*²aæ/ Û!Dýv1³©±kùd×Äå¤Àµg¹\¨ò íò7`É̆Wˆ?># >¼‡a½+x¼v‹ê»u† kNÐÈšNíqTè{~ŒPØÍH5µ OæmñFrþS(fX!b^R}:r˜/5Slëd˜—¥ ñÏ«, ×r\,ôÊc¢cèfÏô‹µ8ž÷·*~`|Ã<˜gx­ùŠþý£ðÉ÷òÓ Wã §æKü‰_gÅ®a^免úÕ_4FO\¶à¹ z&4]3 ¤•¯þ÷ l²Ã8ÝÇVY¶¹Ör‚ºªn´³#Q§«jFئ.}˜šú“¾E¶bT¢¼³Åß:VáZQLJvŸ’­èJb½f<H€º9¨¿ (¼€ÑnLÌqØ=‹Ø`Ä2TP!L¿çŠ®ªH+×''`—ZÖìjºFz¿Y®Ì¹‡Œ0h >¢jÈ 6€ô 5Ý—t-m•Dµñ–! Í«aosÆÐVÔÌT»JÏã%¢$‚êy¸êžï• ¦aÍÔè‹j¶"™Vé¿Ü@9˜Í½ÌâÕ¡óøP™GîÕ¹¯‡ç y£˜<F²› ÃÔ’/f1¼à7âò"yü³¿•r£ÆNMâa~dU-õ†[HÚ¥¡Äø›F¼W˜Í¶­Y[ÙŠñx-§TC7û eŠÕ:ütPç¿x({‡‹Cu’Ì?š(˜Ë"THÖ©›V(Jx¢(Tƒ5Nôoºér†ÊÜkóp4,wxƒ3úÊËÙiÓðÚøâœ‹Hò†~¨ù8µg9'Ÿå­‚æú½Ñ›9yƒ>4F—Uç«åš–WBõù„4W+ê½”ÚëÅéåä)mžìmÞHÀ§Ú„äÇt;Os>zÒ¹¥î„1¥‘ÒAâô«Ý%6Žr«FF5Að¥#@åG¥”e›y{ÊÅziôìH6ˆþA‹³Ç€<‡î·ÁŸ•šY5u‹2Ã#\¥!Ëâæ-ZXP%¬ïºªÚO劑NчáCØËâÙIó²0“‡ÆW`2>©Ã•ÎϧKc— ë–Êï >Gw{]…›±uÇõe†ëRµ§òFž&Ї°Î«Dm0¤Tß8,4P¢"¥ÑÿTë‹ýP[• x€™¯kHz , d@‰ö@úT­«XÛˆ"i†ž¬Iµ ‡FM è¥*­üL²P†ªÎ9q¹¤ªÑ)CŒÌzxœ^ÝYM*sW¿ävÃÞB\­uoh²5ù¢à÷èˆt$«¾ÓÛ æ*¤ñUæYåþCö€Á67õMiñ³œ„ÎÇ2-ô€ÐÿâsH&P/’’rˆÿpÇ®)…$Éj•Ì!ÄõÈ;F ­Ùô^îBŒ[®lÍà«¢:6)QÓ#³‹¸jÌ #r|…!“À³i;¤"f‰Ãª g%©œ—•RS„4¼+S¤õ.ˆò–8à#×é1“†@R± ó¬×Nþlèéj”Ö Ê^ôo#¶Å<ðà lï¡N†Zwe¨"<]åFÀd‹¸.‡ §ªž¨¬#§°E¶Me§OÕ‹'‡hÍlX€¦;ÏjiËg°’¹ú¶õAÏ«<æ ·fTC<^n)|Ó`ñKšT@åà>ãËhS'5ÿù(&˜åQÎ)Œ§‹Î·Œ]‡ò@þî`hÉ¡9c#8À˜æ(ºÓU¡ ŒÅ /;Z@†×!U‰yXVäEw”ÃÂ`±q§‹xzL.„µ2€ßG¿¦F¤\u­’ÿ«¤FˆäÑ /{»ñ”¥G²«JÌ68†‘*v"´–Úµ´•õ-Hõ"Ë Á ´ÑÒh¼YÁ<æ­ŸŸ>Ž Þµ¥MnêBñ2À4UÁ6p÷’ÑÍAŸ¹æ1y0áÐY€ÁdDq-¼}Åzvëö‹™MÚ2X©jB§‡bïš–c™Aöë‹6­ñ²„ vr‹Y º´µ—¸òZDMƒ:fØ¥‚ÛÔË’˜üw¤[Tf‰hÜðô!Ó„‚èMÓ¼(çTðÉ’âÀ¼°o•þ(ã@Ì_ ˆÑ‘Þ6S ÀïI$Cl>Z‚s,ܪŒ¤•qt•¼85@Ð 3*='¿ë!ÑçyÛ•Õ”—ü$U:Ž3Æg0…ò ºHB< ú€yö˜" àìûŠy8åôN¸UY¯>òJÎ//‚Ô9fÉÞ!pû#cKvn¢˜Bà‘Á,Ð1õEs<†>þö·þ¯“ïQ•yVÙc4•ÃçcÁäåwœfÁÒÜZsÆ%aT¸ZñzþýF5õbñBC`P`Ê'³'C, ëm€˜j,jfÉN:ÔYêÓð¦€æÞ^e7țYUºÓ’8Ð}Æ›ÛÕY#S' ÅÕ°ˆžÍTtûËÁÒD‹Ùˆ,3ª€EØhP[¹À¢cñ15¼Ì¶§ÆÖ\núåp°IvÒ]vSM4üŒ? ”­a!?‡K¤ aÞ_î‹òµ$$cV´³óÜpV!P¦ž6礩*ï1´Tâ¼Ø ié+ŠÔ¥î3¢é;ÃŽ>Vl³·†÷w^5¾½•Žèg†¶ê2ó?EÌ*\¢tgç°ÌB?{f øÚðæ·[¿kC ÜÒzg悉‘=€V œþ^G¯ÝÚi@¹_áÆìzÜë¦Hw¢;›êbÿ(8‰M™ˆ›egŒ>Ðw-”ë˜üõÿâò¸íGÖ(-9-½b‹yW†QI–7êf?öv`ÞˆåV,dÄ+òo²vÜ ç].ê|Á+ýû…PäÕñ™‰‹Xµ§|T¼&«>™ø-¢³¬˜§¨Î&ÌÇAëÆˆù‡AûÔcMPMF¢ÄE'®¸ J ¸¤Ø’ýy6õ#²ùäâ<Ä édSO”,ä½Ð3mæGÕ…”VÃR1m%×™°~ICxUTÄ>;д¬;B f‹B¯Ì»†5!Ql (^{9&i¹ñé’fÝ0§Ž"óÔãäºz5ÍÊ©o'î„S@~Ž4øïC”í¹\æ±w0ïvïŠ8%J^UË­Sˆ>øœîè°•ˆëö6“O+Ç ãUø‡gtm±Ò©y›êŸ ôBbkÉ¿ œˆÁFÚö×ákôú|Bš*/ûЦ5ÈÆ`›c¼Lä»´­ü0T¦ÂßþöÏÿU9œa¥kg=`¤XãÜ\íÃÒ0æ\E£ÐçTå2Õ‰”ùS³•ˆÆMÐFÞBª¾«zi<$|Ô8}rdéǬÔ|±gˆšaÙ­3Z_é¿™X$âÞÅËh”öÅÞ¦Ôòã=ª~Üý€a€±æ*†¸ãœaÅ›d(œÍìŇü>£® ¥œç+’¸X¯KTG.2výC3U•Ãâú•æVà„Á-,¦~Fæƒy%•œÕ¬¶1ÀâwxN4†œ/J,qHô4uÍ›ÞB¯QíëÚ'†-óOQ}ÌÃ5¤?Ó55§>ªƒžEÖȆM{¸·<¸-ßcê­å``?yx}°íFÈPÂy0(ðQË”ÚYÿ(¾™^PªW=Ø4¯ƒãèNeJl„z’ìôêð§ùvàöo`adž†‘¨iÖ—HÎmè,þ•£Éó¥aO7èÿÃ0®õI?8Ë`ç IDATõó¥¿ ½)*Ôg°&œèh›½‰‘©¬FФ-§T{±”ì[ ¾Ç"ˆ_†CÅ/ç„_áXì·€áoµA³ÉÄ'(%°aÚf*£Þï^ØE¦eX£²Ê<:"è…Ü-#Lf€Ðb"3Ø í»ÔBÆ,o–î$½Eu;Lú}“œ²ð@¹Ih` C‘³R{(9– £RŸ|™ß»¥Wê¶õ´ÛéÎð=„nÊiÁNwªÂ¿~År•÷kÑûÅñlÄb Ýf³ÎîÏæ¹Ö›ìvqž®·Ù0<ç¥V;š>-L>fùÏ UÈpââhÌobU|>òôæÍHó õ-ÆüæöúüO¸eêšÖ†Œq;£Q%c'éi7 'ƒœ'eÔÜ}Q1‹öØ›¼`\_Êö}ð§2!~ÛpÆâ ±\¶²·Ä •çDx5cÐŽ9€¸7ìÆÚ{`š.ŒfúªÅPŸ¶‘¼iR±¯ùàfAøÔ›l…¶.Y¯÷[Tó€½ÁÀN©|£µ«qcUÕ¸ þ ÊNbÂjî¬ú^ÂµŽ» |qû;XóX®páôÇ_ÊJ0lð;+FŸÊ¥:] ¢Az¡~òÓÿ\UJ{¢mÚìßÐ,êÕ¶q¾L.¤A£½34ÂcfÓ9Á)˜ ¯•a) È»/çlØ¥MoÃÒˆ§Þ• È`Á°ZÙ R– 'lÓb‘9k€2¼Cv• ⌮ŀøàðîÄHÍͬ;"Ì–wLnlË{BAu‡…Ï u‘3á>!zÃ3iU7/<Ê4J@Ã(u÷™ñuÉÕ­/@ØÜÔ}Ô›Ó(b–óC _mÖ7ÛËÙÞÐ@Žl- ³!¦¾¼GrPÌÜ*a¢²Þ!fW4Ë 59€s¹\郰è:¡˜ÍòØ#\/ )< T~ÉŠ³Ý¯~#ÞµÙÃdh_¸¼—á˜W™BC‘2âšDýh\gxg[Zòª ƒµÝ¸EN¦ÔG½ö=<ábDeBFëàÒ&#üé\¬þg`M±Írð ”“q>G*ÒKU›7T¹u‡è ~Ñsqiü@­–µ6Ù£8l* >„ À"á$0=ÃÄí$y’–BN àn‡º!>J`R‡±¤ˆ¦O–NPλˆEÍ0U?4ÏY×ÐLü½6®.Õúî ` iô·Ræchºß¡ÔËCkE5¤¶1 Îþêó°Àšÿ ±õɾ*0j3’²×Hðå ´ø)NÀ  »GD§›•´h³lÆ£vŽBM« 4@׳¤¶ÌXùÉ%ÏQkàÄ3&+‰pv@×Î&¶[ ¿BóÇïé¤y+F"ÿžGæÌŸˆÛ½ÆÐã*¹Þé>Öd#Ìʲ[.!²3\wï Ðø*J²•®A„ÑËF€¡Œf0ÂråSéÎ ‹&nZŽ¹Î–§yr/ÁNúX͆Åò†UfîÃduÀd<I-õQlóÑq2¾å] ÂGHœ|IÏïj’Ç{ £ë‡@ø´Ù±R„™^.ÏÈ0Ø ;×®áãô¦œÆ_Æ ëøcìÃÜòëPòÀ(k`°v”ó­“?¿Gÿ"9…¿vÃ/¼êß ¯â¬kô‘ïã ìáTÎyP­ÀИE €‘¼Î¨SiAÆÊ+w<XÍSÖpæáauÁ5Ìä û©Ï@‚ñMl‡?³xx™ýåñŽƒ÷j•䓆„îæª}¥ ÊÙ°åð¥¨mÝq ;‚À½)ÄÅÃjPG£Ò§…zúTÔ5U,’ø¯ç“!E’GÎ Ôz?Ó_¦´£"C‘{22É LsuQ¤2w õ'CV8×(Õ.]pÝEóŽ2o±ÖtZˆ¼n<ÛRýãœg°Ü” u«Mµ[ê¥ØwÄÒ%[E”d/u„_³5=t.+ÒTðå$üu†d˜u b颼J!áä^´‹û—Õ/éü"ÒÔd =N B1€H.„C«öárµ °wPM4ôoë˜eXu mÂÒ Î¬Ë 8Uí<ÚâœÄ®BLƒ‹¿@dªjH¡~¤¨êsDㄵª0j=ï_n]bÝ„ì=bø[ºmÓfîÜ©¬ÃºžR£jZ›2¿‹Vpù´Õͨ3Û9küËðFÁnŽMЬ,Øý!Ö–û:¾5@Ÿú vVþ23Äo °÷Ó¶¼YÖ/*ʦ]/´¯¿wð¶m ˆ4M$¬֩¢ºÔºQïð\ÂÇp–ËÎÝÄ"ÓË['Ó‹ƒ ŠžªÂ‡Œž».¹[!ì(iÔ!I5œ\È1Sé ˆW^ 6ß ä~†Ã.…éÛ„4y_Áì;Œš8ž†Yó´Uy§ïRlÄÁ5(’ ˜ö®ÌÚw¨Q<•¿BZèÞÈë½1ÜŽSRý}ÕªM›òš¨£(¤©[óV/NØœ 3ÌXP•ÊŒjÒ¶ ‚^5VfƒÏ´ks©›vYQΚZ¨ «v@Þ¸ª­‰¾Î™Ÿ{¾-HæÔRX½ÒM"˜ÙGáH S9?šÔ¹ÞiaÄÔ°Ò{‹†¬z§@1¯6y#y‹Ï>tE1¿4¥¿TýAq°îƒ³§v|iè„ͪ§–§³`5ä“a !1KG?À,Çt™UÚ]÷„úáQ?™¿Gmö©Âü´ò²oz åqÉFMfBÓaÓêe™æŒ_g-&‰ÙÚrÌR'D5éø Qs_3 x/„a}˜8Ú>ƒõH`ú²Iuö ^…3Ì-k>:Òþ$ʵ¨Ã‡lˆfXË:|‹ê#Ñó¹E£˜ˆæ—¥ ú(bÚågÔEîªåäG@l5 ;Åü´‘Rì!€G¼S_Ëú”ÿÞD¿CÈ€è@'÷EÐSó ˆ{³š`îciØx6ׯÚ9ôé'ž„²{æ¡pÄAZA™‚>¡q÷‡UËgxHçŒá`mwñŠ5ró“×]?· k Ë0ó! `LÜ[|v¼Ÿ´s5¸[k­Lêj²ª{«Ýݱn—-»]¦. E'Ñeû„ÆÏ­Ú 9[­•ã°zôƼ¹ùJœ1†CR|ÂÚyÐàlaLÉ Î¨×Žö98Dw´¤ ò–«€Ï0^CŒÆ'v9;©UÍaM!¥â`Xõ‹'ô¶Um–»-™4 6gU[ËŒæŸþ«õëÂ\Á4key°V7²‰# ø‹'^AZ/aPŸðið•0tî‡Ó„ùD Øæ}D ”„Ù¯ÿè¿® ÂÁšÔ³­ýc˜šÅ·AÄk’cë£\ð<,ˆÛITµ2•Ç½Í¦é—øÿ¦ZwrÞ÷0ËŰ^]°Êö'|^?w™MÂV1E# /À-tû˜Åü²àë2z0ßJ$µ¡—•ñJogkË%4*ßôÑ ˆÑ0°±ü¸m¡¼Ÿ`±á#|0Zq{ùm˜ë)·¨ù” 挺•lÕ£Ô2AyÓ4vw À¿8ª&óB¦æÐ< ˜ºmÇ6­&9 õÚ_"´i¿‹¿‘m/Øu÷ˆvÙæT;K+,iîwà9I*>zä"7Ÿœ™Øx4ÉSË"*.ù«‡ NA\¯†J£ÆÃÖˆ?ÂìuïñýÈÚŠYη0_„›É4À˜“¡›•o‰üz0àÏš’M££’2o\Â[gpj»çÚcí¿RaÕΓÚw·M¦¨*¾N°Míüh€­f¨ ˜Å]Vš¼ò2tjØ…,hÔ8I+)ÿËojD UIÿ FêO0þÎuÖ,ª¯ûøÞ£6äÞòÔ_•úñÔ|¢Lxt©™!Øö1­ÇÔ±7x£ñ/ÁËß¡IÖW¢Ì‰þÔËTøRKz´=«1sŸ ;Ñ'T!oºP;í"36 ûë™ñÄi+É{¦Äÿ"•Êë:ÊóÍ8=éüѨø€ƒ¬Œv1`˺†cËÖ°Þ¾K6ÆÍÌ Ç$Ô…úÍøÞâ;.Œ8üc±Wq22Îî]e¥m˅غa'ìϱU Œ_è;_ÏB>àÈL€>ú¡é?Ǫѭµýo gÞÊ˰Íõ  ¬–Án´¹É‚m‚Ïîp5‹ 'Ì|ó1lþy¤…@ý*ãJ¦R·CZV27+Ýë &PïÖÁYã*°õ”¨_5j/M Ài)Ô[̲@ÑïÖþžB1ü6‚¢ÌªÍ¬_‰ .»"=¤f@ý¦Â3þ%}]ýmðöýZ–1/M5CÚš%‹ƒÙ\3ýðlh÷3±2¹,Ô¥ÄyYÀ†RFÈRYÃi‰U‹\4@RY‹~{B'󴌷*“Gò=x›¥¸Þû:˜Ï‚näçÅê[è·nʃè³e~#áSÓJ²gjB>«ãâ⻫|J?å<8˜v»¡,Æ ²bàloý7~uP*6A¬0Ñbš0~*Æ€—7GÔízb¥Ú 8Áü ? ²µöÑ“¸ÂœýµÑ¸bez¯7¡e©jBV‰ßáC;û‰ÅJFÉÌÌPT“ Væ‰;­½Çr,ˆ7 ïPôâ—F8’i×?ˆè˜˜ Xî=þݯï%»MÃ4ƒúìgeÄt¶˜B¨ÝSà·ë¬UóG+¸é¤Ñ«¢¼“€Õß…sÆŸµê¨^ÎØVôÓn7'¿§7S¬G¸Þ®Ù<‰q˲ø=\껀ÞË"©0åT±ƒ_ßhtä´R¬2WÊ3›3±ÚEýùeÏ@Az™„‰—ªý8! ßB¢rùp¶rÁ–øŸíP¯-ûŽÅˆ©¡‡õ–ðÞZòQ,²Ÿ¶T¿Òk¶=^tݶYÄ× @¿»â~ã -£h-Nv¬AÛªôÏïQTÎ8ÑÏaïà$©.nñ®¡â°c9™´¢9䬿ß´3Àçœu­ä*¯—³o6ôŸ(ùw€9ÿ ±ÿh<8þFèŠÕÇ•Ò0îá£HSCˆùóÛœ@ƒ•‰½h„iÅ#þ³Øç ü‡J†v#Ë ‹®FzMY =ÃëÝí8!bÞ¾n"ÕÖí†-#Šì'`N«h‡÷óNõ›²¢W#©ò+³‹®Só«×0ÕLWXÀÿÈåh €XT¦3ÿ‘?êÈÛÌÁ¨.;%*ÛEOtE*„­2©ÿÜ.âoöOÿã‰iE’]…O{‘1!¼ÏC€‚KÓí´Æ½Š2 à±!¥Ê‰V.n«iZ‘’ÂÿFÌr1Y$Û™—ZäÐb6–¨ÜQ…ýU`h¬”EÌ ¹Àü©RǦE í_üŒqVÕØÊaSe·KFã‡:ßßú¼5f‰ÕˆÄŽÖ±jÄѯ=÷D«–Dy6Cǃ*3W]ZÍGgx§ÌÿFÑÄ `ºXu¨@Ÿ~:Ѷ¾Ïh cž*ØyB3u¢›÷Û¨Ž~dNÃæqpYœ­ht‰³ »°ã<[°:/^rØSÇ*?”/Ø'´>ꉛ4êo+*‰Uˆ„_œèA®ž'Ÿ­äoÀüˆìª˜n{¥9Ö“@Ê*ŸIöÍæùègÁÀ>^½¼àðšÁ¿ê‹N(ÿMÅAˆx™»`°XèÒÑ(YŽþûEêÀ||¾G­|˸¢š3Ê„ ÷g”Ó§¦ŽU²Áò¸– ªÿQîÚÌÿ:qsFÀVæÑò¢h‘IÁ£êŽqv›‚ãp‚¹¸™*†H‡2ÂþöþW÷´8ŸŒxTï6…Ô€ÔòôDZ-^R%TåŸðƒµ„$A–xy‰Ù'-z.°¹P˜b8wGóqs3å \QjWès¢Lð†Í*€˜©Ül¯â¢!ê…8¥qjذæ÷jhZÃM{›š3Ýaþk+ÔJnè M™!d5@MòFåCxï\MìuÊá±Ù 1·ø¥f=‹fA$ 9d'ó: ¾ö&‹ÛíSì @ýnn§*eo¨#S?PBQ‡ýܰczº‹ñØH˜WíÁ§³GÄæ÷ OÛÂÜåo¥Íó†Øìì8¡ÞzU™ä<•f} ºëÒÔxðwˆî¨çÆÒƒÑkÓù½žG1™gA|÷owÁ7ˆ±^—òŠ7>þ&ÇFpŽÐïjÎ~ðL/lyðˆ®9ë…%r[x´Æ%Ð Ê{x,ÿR¬`Æ6ªÙkÔ8ü ú•ÔÏ øPûÅ shÌØFl^”RE¶;Oìëœã8Œ|33Œi¡î ¨æ­å‰N›,+á0?ŠÌ[3¦rEꫵµüQH= ‰!ñsÃÊ àÆ½pýìpZí¨MÐrÕÁt œÔ‘¶µ*ñ£ªYÁR˜tÕrm+[WÎm7‰ *Â@B·Y|оR¶™àz³¼b"FØç+úI#€rë0¸VÒhU.ÃS@Âe°:V7(¢4Ø\Œ†Ìd³ò¶T„ÇŸ´ ÄP4ƒf”I…МÒwCy¨f„åû.8©ØbUâ :±c–Ìñ6ó8át¶¿œM”•Z‰ý¨6œ\Ø[%j•   L–"!bSYÑkX®@£Ïú õdÏÐ¥ªq*ãÐ|‹½XSòB0ü9Ü›{}‰¢C•@ým°»‡ç è*¶b|ߊƺJûSÏ?##r ˆ=&f ³½ ”òμ)ÁW¦ˆS”º´×7øó¶j9äï‘Øáñ3@_aV‘¦Ö«¬Õ%*Xœ8øä}ìA­a8W v =g5Ô¼Á|Y0LeÉ~ÎÀãý!¡î¨·"³7¬P|\]Uš§·: Ih-Á_ª[ÿȆ€íÿ¦œ‡­L"î‹-³Ép¾>á‹9wE›ªâ½3‘W¡ùfìœNâ>©–‡À7xªUè:ž.Ô„ùóü-’Å2«¿Û¬B»UU•¹ ¤†Îl&ï‚•fƒihŒÕSY•¡°Ÿ>Žö ¢FCñ8yŸ±HÎd¨¿“P­•B+åÐB‰ûÅ.$C‘Wh1L1Q¹è*f6?qKLª€Õwø9`²Mg7^åæï®[dªâ¶©Ø©=îŠ_ª ëPªŸoN’«ý“/%’ù]àâlŽUÒ­”˜j8Ÿã@BocV€À¿ýúíã ; Ý-jF9sV±Ê}òå€!’~˜VÌå…ÁÇ5:3Ï‚/̬z³Ìæ!ø¨ñ  e¹KK׸*Yëfd¤i"N ¢6jÏÃø#YjBóSLVxú tï A¡ßÞøn@€Ô1¼wbnP/ïô×øh$ uó„ŸÔƜ⶙™/ ïß|@ÐÉ‹£Jào¯ºŸÕ‚ìG'w…7•ªj^&dJmüFЊ3ó±FÑäIåäð^ª”I S…¹ŒÓFàŽ&AqHq"¬hݹˆ Â\1;f›w}l@‰…i”­”ó8 îÒvÅÑÕ4±.eÃ]Õ̼X›.[NÑóBûwurg)e8dUl»Ô‘É€pcdÅL7`“|ò½Ìn•{n ˜Çå6©¡K˜šQ}J¯ñÖ-ž5 ü@®™”£–Û«ŠQ¥¹yñqA˜«Ó,©™ñ"ÙMm…¿¹&°1 tb)œ¬¤QƒèÒZƒ‡[åÎPk”ÿÍÂz¬¼¥wG˜×êðNšÃ¼µÂÜÎIŒÍ¬]¼âÐH?Àâc±¬ìÍpœ­;êˆÏâŽvM–Nžo[­¢Å2ïÑ5µbeZ)>¨\ÑgÆÌ ɤ”nñ¯ *k` og‰"aáÚó-¸÷æR¯‹Š‚¿Ã¶ŠœæÔò¢»˜†ÑÏ§ qìs0ÿ_¡3Ø.^ã¿`ñŠ[7kWÊÚd-¯&–$Xþ*íÌ‹â76t†žz ˲bòŠ+w¬¬9üþ6/º€¼©¶©¬*g ö ŽÖ$Åh@n0°¨pêÉ!ZÄ´v^¥¨†É;Â}©0è¦Ç] Ú\Ö¡D Uаa»  +#ÓgíÊBœ*~1¨˜Æ¬ðj¿y‰„ßᵆ=s4Ã_“&ËæÃ4”3«Vy’®Ö¶™Z°ˆ€ì d˜Æ¤ê`iC ‰FrDÀ”çUq_÷«ű"S°r¨»j ³! öªÇï {™—áZ¡½‰bĬ¥ZµC ¿A“âg™]–™,oçfW–s‹“Óå‚l1Ùy6ç”}šú8æs|u%s&ó?ÆAˆe)ŸÍø„ÑExOt†–¦æ­Îmûð¥—Â[Áì3L"-|Úd6„ûnÒå#›~Õ_ÂNÚŠ2ÈÛ¤PËYêgì¬d¶òÄ7PµLà¼ÀoÔPGH•B¤Y7åÏõ¬ zØ'~Y¶ñò+Ó—‚ůƒˆ/ë}|Ø&%ÿuùdðx!ÆŒeù¥*?/X,ýͨß!›ïµ[³BQË«r&<ÛS²Jx‡í=è ç*¿2„Q;ã:.γ=ô?ç’›³‹Be9_¢pUPQ»¬4*DóúÞ_Å–,Q’kKýØeæ…®6kïši¬Sß&ÙÓK)lãwÖí Ö{:­”‡æì`±/£0{pF•Ó§v­.’®ˆáE3ò8E8°†jFOg ¿;†©àãa¦å>Ÿm´KãbY&mµf-xyé¦Õ@¾2l:/†Gç®,×¾V}À$ÜPÏ'è׃Î<\&FÃ6œD×çèêP²i•c> QHS‡ÍÕ²*ëÜo«4°’ÿkãNéÖüdªÜc;gß¿E½oÀm6”Ý2L™v¦½wå3êð]ÊÐGx)Ÿï¦WûUÜÄö÷ú¸`–÷Æ¬Šœ×ßâ+a=¦Ÿ….˜š¼;<…o5t{w0õæ†Ã«f5&Õæ¢â׸ٞ›¼—IÀšó9úø›hÛ&Öé[žEä@VÎAOìÍ6Ì*æ™áýhao^·p½¶ ©ÉU—P4JxÉéE{kPQêlZÆB{ 3ÀE‹KJ À –“Ñ£ú98§è¸•³k^nˆŽunÇ>˜we€,4À‹9“1“ÆÙ¤`páüjgRBû¼7ÁC‘fÐíW¢vTq*6¸ƒ2¯ºSW«Eƾ \sA ,(¨‡‹#iÇb¨6÷®„ņŽU`@ÎôõŰ¿›º;#$vp.(qèD0­"Léi®¼Ê†‚YÎ߃꯱­L€~PÏžèå“jú_A®…`©:!Ù¦HÎÍ—1#ˆ¸j$ê)QÊ'oà³íÍ'm¥§0Tí Ú¨Vm_Jü}xg¿giªÂ{İÑHHOeaè†ð±”7`øÁÚÓŠlZûä]ÿxE‹N=¨ Ëeï‹«-;ó6zŽÒ¾56° ÚÌ‚¾¬ŠÔ—~W²IÆ,xvó*v𓲝Z¨“M`Û–:£ Šnm¹ÂXâ)Ÿþöú§ÿÒ ?ÆÞ¸Š7§nõ¡2âÎ `iº`‰=¬EÔi=G{gIDATÚQ©Yú‘óEjBT§Ü,3þÉ>˜{”øÖ» L¾Tþ¿(9à“À°Í26:$ ô%ƒc_7äv^_]— Æ‰X¸&«ýrÒ\úzm“Õ¥ó̯úo'wGF[ÃÙeÍ8QmðÇu<´LÿFUÜMÆ4ï ª oF*EHj q§ÍFó¹vªìâý¿EþÞÔÝ\'δVŠê?ä]AáAí×Xì™P%N™º§T¹ª¤É$ô̲"D鑯–äËPÓ•Q ókåò¼$¤Ú¦}˜÷A£ˆs:K“‡éT”cJ_tÝ̆>´ƒ—Ï(Nø&r5ëÐbÅêK4-nl˧«û#’žH†rlh-(†ÕéÕ`o^s#]m¯²Zúð꽘NV†C©õåu80Åû¨zà#Ã,÷(gAeŸÊy8Êšcu Œn‰B÷qø>V€º@%¶+ìf4ŒÛ¥F•Ùþ€-wNË@0ü*–Š–¨œdS¶gÙÆâƒSX£MÛ i€¡´k8ØBy_éé‘ t£å¸µÕ¯ ÆÝM/Ô&B½ªúgn*àÏek;A¨‰(†hõó°#‘½x?€éF }ìðâ ð³$òq} ß>ðä÷†j°À"ª9u‡õŽóÎucç vò9¢Ö·(–zu N>𴕇ÂòÇÛ†­*¨íì@Q̇É ^Pc¹Îd0“b ™Ý¢¦*•:tL5°AùùŽ/XBê\ú9ÀQ ™IEND®B`‚zuluCrypt-6.2.0/images/Screenshot_20190912_121934.png000066400000000000000000003365041425361753700214720ustar00rootroot00000000000000‰PNG  IHDR‘ýìâ pHYsÄÄ•+ IDATx^̽[‚ÛH¬,A{w/w‘³ßiÅ|€D>HIeû̉n«’H$Þù K%ñÿüßÿ ’ å’Úy]$€‹|#Ç| € Ákí7‡_ ”b!ÄÒ _Ú5Ì&IàQÚ °t£+ä/@Ý!ÉB ÀKÆÂHä–ž¯[mà—cå —8ê/ÀŠJÓnØ$ãõzEËv—å*"%ÇHÉ&:ÌÉ !vŒÈ–̈e‘ë¥0IÂu"éV%©ú¦v —¥]Ž Œá–3Ã9ú¾Ê(‘¬ xˆ^/†y¯d1^ˆòsÎCŽôl£¼¢ÎS³¹aAɪƈäœ5s.´/½®„Š3ÅðÊ IQèŽQ¦@®ÆÜÃÑ CsC“kˆÙò¥^B .€~5¢gz›ƒc% §Ms²â’ñú12¥då·Ý/k‰nNjöÆ‚`º¹ã25êöÑ[—jËܺI¶¤«õJêÙÙÍ8CÀØŒYLÐ.H¤³¬CB¶<ÄÿûÄ\´g‚‡Ò*r‡ºø+i—lÞ%Šˆè S¾˜+°gçèª%¢R&©–_V% U^ƒAé“(—ÐàóÜAr¢lsò[—0Ï©0×Wíc`BpÅ'Õ6%í“…uXªH댪ðLdÛêƒS°G4¼èÀ_f*!ÎeÎèRdÖ_åHÊO¹É_ˆ#GMò]b KÖ VßÕÌ'Ig È^(f„¬àz¥!ò¢Òºd*;‡†‘Dúrƒýrpè¥j^OºÚ“4o—|µã´ìc#û¶D¸p±"ðÛÆ÷Ý™º\‘ù^·ö†n_ƒ,eZ7\1*HS†‘‚wî¢Ûñ¢‡VpÜnv„–¼ÚRëK<×L¹¾…ö(´25–XH®•¦²PUÙ¬‹)]Ÿ, ,¹ ޾ÖÔ%xqéùä/аzͺ$ "©—€ˆdÙQÍ[1‡Q!æHÞQ:$e¾æÜ4â…<ˆ8Æ_xy²öÑchÚ‰(2NœÒc/a_ÝvÌõpòÄXƒ´ò•S‚M;‹Ajô㿤ىuÄï}òeµûŒƒÐHID>CÊ…lÑ™HþºK#ë”;ÖÚM„‚8lôÑ%£lðÿrW——“B,á‰>Š–D‰öI’"]¶’ Å5À8¾®®±—±­˜¿æ›ò²pìÿU½ŽÐ{(à Ï2ÀÜÒõŽ H±ÿV€Yô‹œìªøÛ” ÑÇÈtäu.ÅI#òšÁÊ Rƒ[“oy®…_/RR#ŽFŒÏ(øÊ©¼*úžµ-·Äg¤FÝШ_¯:ë…×eóÀùèæÞÛ´Ù»zyFFŠè¯.°6ô°Ö£Áf‚O¼Ê N·JÀByàÙŽ4ìàÞœX± øÂ¨ùp¶â õ ¶¸'ÆÌ‡ë0{údÜÁš@ ¤)E‡wk¤(Á¾FäòérhëQ !ÃØ±°Íò\!麼òlš•ÌY].j¿¦CÌÌ„ðéÔÁ¶2VtáÓ<ß ˆ¤¢–^’E;ózX‘RÜ?w„Ÿeibu“„jÎ,£o°iqèšÚv²öBÂØîQÊAÍa¹T­AìF Q»Ž»Êð„õΉR½á¸ðý@ ɇݖŸ¯¹{šD3â˜]-:mOWJº{¾J¿p©ÔàˆŒD õ–‰`RÞ”Maîa Ò©°õ÷ÄyƒÝ™†µâD톺JC”hs¶»'â°bJÌÕ]õÞ{jÀU[o_»µŒIóºÁËŠ°ùøª8ÅÀ™Ò?WÉfŠÌo^Æ!’À™¢nq§cµF•ñþ0—k¯“úÚy¢3M±5ËRóÊø À/4[ãÉ΄°.åuAWl³’Û0­¸ LMªxª`÷(1é]á\¨7Ø+Ž*–Üí @ô==òÕH)c]šƒ´­qÄøg¬¬sêŽ.åˆâœÖv¿FÒgX–àýlª j"ïøW†-ùµm˜rwÀ‡QŽ _qHÇQþ"\LhUíáYlðM_$<²6+%bÅöß/·Äٚ˚IVXÝq‡ŒOXá”`(´GpïM—aQ;i;e9O«QE­žHHñ²ËÃùÁ1Ø+Âî âtØ`D°³Ìr %UŒÌЂƤÍ;zI¤aMUTD·¶ƒ’ñα¨,Îm Ý/‹7`é$YgÖ.ú{ìÂÇAÑé 5ÿ™ùL$ÆOiêÀlóÚû)†­ÄKâ á‹Q7ÍÌ縅±SA–ã²®æ<†©ñŒNɪ5Àl³t.ä]Óǘ•.V磆|"’ ß1Åá½²¹vdöUº’>?ú« Ù˜2)ümEó jÁ‹ÜpÇaßï.W‚Žõu$.ø„g…Ò¾ÝįáöZl(Œt#Ûy)Ìú/p½5íyfmX˜¿×3ìË£c\%þ²vÊ<ÍÇ%ÎÌÐæi²ÇY@¦8è"b•xA¸rGÉŸKŽ+B"ȱ;næ¯6ÅBÓÉîQXÖPê1Ý”\ŸØ…`äQí=©ø^ÈwKg›·³£;½Èçxe‡’$‘#Œ?Ãqøº*b ô>j§ò^-ѹÛ7±Ï&…î#ÀÜOæ½»’õ]NHÂ7-Žyzi‚Yà˜½«?ø=âÀìrÄÂÝ'S€ÙÒwPSo^™QJR $‰ÌxˆHÌraèî|Devö£ç¬ïІEmžÞi1]' )&¦ÓÍ/ºÿ‹IYw,ÂQñ:ªa8µ,y’Àæ˜^[v1ç(m!¸Ñ øG´¿@˜p€š³V ÑSty071{Ô'rÄn|OãŽö™óÐë€mDEôÎÑØ~ W=Om®v6`¡—¨jtú~Î0JÈ.0¼»®ËºáåhÅ‘¸‰ºÇÊ9™9§5*¼÷k¬ù¼-üÍÿÿvQ·¿Ä;Ç·Wóªµ'ëáP;ö²õKJ[ÝlgÔ}¾ò›b«Þ$<*ÍCí.4økÁ5Ÿ_ŸÁ^l!ê'–n‰¼•ç‚–å8ÝB ìä‚WîDu3–Ëu³í¼‚-NýE,ÆÜee%­ƒ_׌Êf—ÐØX÷ÿA˜gV_ö®»ðlV{©/úú[²…oÁâAY~Çàñ¤¹ çxä*JvÖ]Ÿg6úeÁ.&. "~t üÐøWYOjÊ­*ñkOÀ]c¨û;%Ș½*uH?²ó¾í©o)Å¥ì:ÁCmÃò¬Ô¸3»ûÞy,ä#ô¹*ü'¡æÏÜåËH0}kô-jر8ÎÝ€åT±plxÔ“àGDàÛe RÜBPÜt @`]€d˜º[P„áä·Y¸AÌè,‰H‘cpCçlíØj6cNÈ8Ûë i˜fÛsQ£œåžúBÄg^HM fhÃ-vÀ²Vs7tÅ“w/ý"_À!›)tþÕË '¥‡TŠª.Ií× ¯õ±JG yƒR~?âÈQ[ÐŽ5Ùë¾e`hÕÊŒÍÄ{ÔØe®ò}àšË¶xBÙQh# €Ÿ#ô&'ÅßîXú6-‚÷UAôï®ê¥ñ(1¼~ÖPLV{€H¶Ì0ø‚Õ'Kä¸M¦+„ä7P®t¶)S™þ#ƒ\9ŽÆÃqÉóÌÒô\Ô{ é þÒ|ÿe[±«'Ù€wâ1ãn­¹C÷qÏxV!oؾòÑÝ6"0D¥ëyy‘ð_ÊÚþ&ã,,§OªF2*‰7¸íLzó>Y1)„Ú‹ÃÐxX_Ô<®Y²ß0Ã9½‘—ê³2MYIJ'ò°3b}![ê¢BPgÌxÛý ) ÎÉ‚’>³HÀï|L²Fc™]7“Àk‰‰gM…W’ç«$ “yíQB®ðR| ‘×¶p´1ø‡â v4ãmƒ3X˜6¼=6ÓøÎzc½8Ê M~äA ‘'Õ9—˜a¹»•F°©Íš%‡õ2Ãé³a{„B»­\ãy‚܉Ôú"@€ô‚Z†ºp¶½{T£‘Äð7õŒÎjÕ¨ÝB©tð;uÙA²~å׋!Û^’$¯Æp–¤Z6¥®Û¿"â³’Ï6R,9rJ³‰Œ~)ä>ï0ÉšœžgƒÓ{I¡Öb 쯅ƒÝʣ͎¡ñ^õ†&ª[?èDì]Õ¥³t˰Ñ× >ߨWëË¨Ó °´ØÇÆÈ©UH„4±–$ém-F½ò#ÝÜ €y]‚«-BlÚJºo „þ4’d-%É@’ð§ ćÌY ] „ÿ^ÿ‘ôGª>­†9 á´°ÆVm$-+L¿´U%$·´è•”;zk˜]ß’(ŒuL™YÐáºGöÃê*ꌱÌNuÔºñ÷,óauOÝ ç)Úa—¤$[µÖkü°u5Xã1Ë­M9€C|\«¼ÁÚ©›0îÅêÖjò•…ÜØ9 ‘¾¢ó'ó<ÖÆúÀ#çÎm÷c× ,î£@`üÝY†õV§DÔOÖj½•ÚŸ›š™Ý(¢ÏCk>??+\{åu•K€/€ùÒ·8‡ûAûêyõîCp<Gù&½rï©Ç_±e4qÃ"")øSlŒÕ'IÀEFКG~×—Š'éAB*òk‹J¢érröUÍ!Î|-ÓÍ1ÿÛÎô'©Ÿ1ììÔ„‚¡qɬí#¡ŠB †öèCâl1!‚86îÐéAõX=ÖÌ" éâŸ3!I9û†BÁ;ÍEØZZŒX(ÀùÙç Æ àÒÛÏÓt†cXíŽÕ#´à"Q·Ðw"ºÚ!ÓyH¾øŒØ'B_#åICœ~`‚c–9¤Ù)×,}À@s­†€Ýû8g‚Ó4¾C„Q>·É«‹ƒkL é8 aùÄÀC:Ò°r¶Jû”rûÎ’(ž xÊ…{bšˆI(€P8 `™[ò£Ù=¤kxc! z ¨xn­vfMçú®µ­Óù­®É‘$ùì¼2ô(;·á:Ö6ìn6Äš²’ Ý(;å¿Út¯œÑžU"¹{‚¤ÿÄõkAž¤¥ˆî‘-™!À3ýǰ2 & áô !¨mÙXrùj[ Š«ä“1’­JÑøMÜð„&ßb#¤6ìÇÞ ºüÏFU´KBÊìˆÞÿdtòæ˜ÀK º2§å"=Ž{ç 0¶ësveãñºHê«úG°#çt»––./Äó’ðƒî›iG!+߉%kØWìCÒ™1l “6c}i ¡º,?‡a€‡œvÇÈ¥qÑê¿h§ÂÅ|ô@Xh”–€´aHW:E`|°@î”,Ð*/*(Ñwù‡¡ J[6ÈâX‹Ó”û&†©iFzÑ%=˜û„ºA?žºýŠ«]!€0’Seÿ‹û¬‹$—µÚŒÅ~£Ë¸wá`e”YŠöÌž›Èz˜»âþá4 ±G5½Y¥Š­keüD;¶äYq8Õ 8»>ÇûdÒ›Dæñ{pÁ64Ñ]Ko éf§äÿò›2~KñBÄ`M•©ŽÊJVÿDïÞ½#eåäôsÜ1§×JW´ØCš{­\d—ZkŠÏX˜ú¤¨(PEL€Ðî} Bþ˜Ãàœ Îƒl/´I9ƒ¡ ð’:ÝÈtÌEÐǼ`ÙÊ“^[šDJ·1”¿L¥ܶQ¢_Ì< 2]ËåždÎZ‚Ì÷yôr„§"Dßì¾ò»§XX7÷nÁˆ†ê.–ñN=Pɨ«ª*»#Ķ=T¥›A3ñ߉ŽPä ¡L™Ê'jYQõûÛJl®'Aœ#TŸß¼Øâ²ïSî}Ãu@Ä-m:¤#îu'~ŸÊÚkFržòÃü/ljF©{L}ö£ ,sy̯"ø’i<&ºu“ãtÌÐ$G°üJ¥¶–ÅG„=3‘¶Ç ½ÞJW]Ê*sp"§ƒ y-›ØN'Å ;ÉžtÊí⟈ÀæR)L¡ùJ噆gìZ¨\!œ ǹœ$-¡Ïè£kÅÐ{~õÃ)å“…SÜå…ïׂÔo6Ú¨ ßëŸ~½I¥ÅÊ;ƒp BÖÂ0«þ'†˜ c›nÀ%û%«€‘ž"ڜM ÞœCO#á·'”àµ`ñöTšÃ½Cˆ³1í†)šŒ˜ãuFp?‘KCÍ: ¢ñI·ÙÈ9(úÆ¢yëÑ[y”ÙUI$(I‘a%ˆÎž‡ juS¦àE˜@âx˜CŠ Vº§yðLÓI@ÿ$qŸé·rùªŽ¥=+¬‹4­³¸@CFˆèÁi½ǨÌÁ|df<û ¬&‘âÛvR‘‘.¿n!¡9¶†ñ“iG¤—.ÁµwÂ-°îðsìH¢Eª²ê†½]#>sH-k °Q" Hwp : KŽÑ·»mUlÅrÀÕ<Пü(;·!…ª3MrìÅéâG C`KÓâæÞÞÁbÈU„1w¹R̼ÒoÒFZ²™$IòÖò¼ÌPÝ©\À/’c¶xLž¦;ôeïªöh“BÔ %Tr_°aôDã0GÀN 2¢ý Ë-ç([QÔeðÐ š¹ë2‚4u²É,ì“i wf{¥³È)oéª%xê~å;L/Pûè·p^ÕS³Öm…ã:i)¯M΀i-`ñc,HGœ ¶ ³¼ ¿ÆõçXL˜%­nO` ÁÄc›î™'¬¯] ãMð¢Ãè=ƒÉ{Ï#¦OˆíÆf¯sñËDh¼‹®Ÿ¥Äֈ쒌ÓU7¯´·o® ¦» µçF3ÞØßÊ.%ȇõf"ã0BRcãtˆâ_pMÖ¼È ÇiM<‰Ø¸*hkع»Ã(Ék-> Täˆ%¶sXÆ“dìwID„Y8ùÃÒeâEDNä½×€-Y섨ÿá$)¤‡Šn^ÌT(uleÙ2:?AâØ´3lXÁ¦¾ùüø…–/êw~L½[¨¯}Ôšˆ p9ÿkÇËÇ(ž‡ŸP"Ì\n~8ü€1e®ofâŽ(Px³È=kŽ‚ÈáÙQŒ‘K.,0S% áäŒ÷¸ ÐO98L2;ü…ÒįèN‰qŠ$[²²Dyš/ÄæŸ[ãNõ_žšà¶ðîæ±'†–ÿ¼»ýˆÕìÂVüKéó('eìÂÓÓD9â`²+…q6ºX]Á;‰"q:E XÊæðÁÛGù¸õ0­–ü¨l¤W8ö³ÝÝáèç¸,oAý1&€x€ @Óƒ}¼¶C—eù½ëOš„¼¡A )Õ¸—”,¶?j)«-Ž v,ÈÚrhÕ¦AÉð«\Ü'ÉB©ÈôÝ¡xŠø¨¿˜¨I:ïÿ´ê÷uè L’õ÷åŽd]‚Qê5ί“½RuµŒç ßK”žŒ€ëƒ¢^¼`V‚Ò¶£^WRn88y³¹V yIÿ!o`¿X|G©‚ÄZ¥ê ¤1SŠ ªYRò{su´]¯J€ÖÆ¥t“Ò’»ø ORO ì×:Ù&-äºdD&®±“˜{Øaù…E0ÕOcà\·G¿ÞŽšAà`¼õC×|Ji~G{:ÞôÕ¥M=o?ƒ ðu¨¶M†¯.”4CrðHºœƒÒÌ@nX%:,‘9®®*m´öÕIcì3qê=2® †{E„Š"М¨÷P؈À“…ƒÔ•– 7'Žì½QYqš¥/ÇxÒe)€¼,r¬‰¥6jRžR› €‰épgóŽcîÑØmJ I³Í¤b½‰Ïÿ\QdA÷w~ØåªÈÖïx+aPð’®ë"ç„mŸº‡ùǨ¨:ÐbtêüÌr¹gbd#ëÉ’Ç’cmJ¢øï ^þd €ŒOük¾ÄRw¡”œ ·7Ž ¹8R˜GkbZÑ-$0B´ÏnÍÔÿlK[è4gñ«+y^É„üqÍ©Z@YÄ9z½^9m MQR¢·Û,—Í~‹¬Ñ•¾“³“;WÄ0ÙT”]Þ„è¼2€ˆX?#") M$ ×a¨v¡–FÒ1¿UÑ:¬e¿!.×ìò4³¹þ381Ä^¿àéG–©*7ï @S•|ƒG¢ÜذV‡as‰N†ÔtðªÂ¨Ê ö}~’‘ߤ5Â[°R[™EÄ49P¿F¼¼‹¶4]~ÐN Š¸CÛ‚¼_¸[Y KÃŽ9Ó'ˆO3%·Å_ø ã Œ®X "´@*Kr’Ý11W‘¢’èé ô €ÿþ{áòÓ£4.ÆÛæM—û‘ü‹L3z Â›”ƒgöåºÌf칃¡%î¦ôOð›ÊzÒý¡Œ/ù H½$¸è÷ Ÿ¦€Ýo[[vd&‡ƒ¦²Åeh+¶¹dbžìw¡uãnÆÔ«k°ç—¿Jô%à Ñ`øRËöxÛî.zz„…»ï’ÿ¡>§¿SÖ5i ÇI™£üí¾q2Sü{‚ì§MHÍ3&«{ÇâÅI}"´ÓÍ'ÎÜÙqÁ°<µ•#K=Šø}]$µO–+ñOñ‘hоiÎI´©g973®PnŽzXÓx–s€$ÆiuíÈl”à·³§ ŒÈ1§ê¼5äåÊõ<ÑhS'y³Æ3ØN¥zäìØLÚà~»jsÏI”Õ’0·–'<Óå1§…£ü•޼â6}Œ..‚0g9‘ˆ!Ôçı—Oî¿Þ Ê%g ÍÊ«èýD¼Yì˜t—ßà†³léFÛ‰êFi:°Ãfu"9àh|  YضQ™YÙºa†+Lþ=fFBF…³˜ûÀ°rÞÚà®×"¶3DË_¸JBòÙf`ôù7?@jf@l;1á ÉâUøl[çA&±É—Ê1Ÿp4ûobÑû?Š£k7ßÝêÅc•ü˜ÿ÷ËÏáë¸#±%¾dœÌÏ÷+ ÚÚáð]%€kKÉëK;;ÐËá4=ZEÖóÐè%¥GeĨ»;”cBÆ|9AŠÛ)½è€¹Ðòö³|qƒׄ˜ÿd„(Ã6I³ IÈ2kýЯ>´DÈ"ô•$:–!¤ÂÞÛC|¥5 Á¶Õ©÷DÚæbÚ7¤›¿| øÿ¯À7‡ª2éÉ8„ßËê3Àö:§ uRGúâ9Xíb 4¾Îç„ ž[I¶ÐQ9}„#°Èy¦Äanhúg&Úôõ¹ÕQå©Ù2&Ž…¦¥ûXw×£Ÿí–ñ”øB<’šÄ¬±ã9 f³ŠyP|[3I'¢z;ÅÛÌØ.`]¥P¬„ÎPÒWÄ ¶’88“s UÇ.Ÿê0¶±Õ@<°#€ö¨£—´Þëþ!%¹[žæ9«nÕÛ[öcq˜MQ½ Þº I óI×Á¤^BƒäŸM¸qµ^ìŽät,ÞäuéT½”¹n̉uU0lÌÏ¿»¯´ê ~KB Ÿ,‹I»e÷{¾ÑR²¢tW_·gIÌ ] Ie¼Ðçµ[‹×E<«XÐÃBN7ëîJ“Ex®†ØÇh×@Eɳ_³ŒX”[<)I©KÐŽñ¯öh K/Ã&ì>Þ%îc°ËèE»°üØ{=xöõD IDAT»¬&= R0$/N§ê$TûŽ…Ë u{2ow*Qă’¥“ |ÿò4žöpO\?ƈ!†ÌÑ&Õ¶sŽ€Ñ#½Fï#ý<Ô<ýK˜ŒÿÂB/\”·L#$_âã¤Ï˜-%qŽ4Ew ï…ZÌ{)º¨’ǔ؀Š7èÉQ^‚Ñ‹g<¼àî/I‚~oIv† ±Œz•8&GÒ0lÒ}Ä1 '¨ iëXÑ½Û <$4ÝühÆÀÃéAçóôšQŒk|OسDß°/JÇ3”è¦Ø­…gr;îPF»zVTϲG´öÓplNQ Ì1‰ ó=@cŽ"|ûWá°ØœÌ0Ó1CHþ7ý ësÖEè:æç"ÆÙð¯jlöRU¦T|õÚ±ð?yªFîæÍ ìÈœš;H¼I×á\²mm#@³ŸäuxÇ_‘Çs,²žóLõÇuÛ«sC1DÊzî~ǪÚãý‡ŠátLîÁPšRWn9Š#AÏè)F>«‹lº´ŽŠg  cŽÃ>Ãý3’N Ó:}ö‹°uÇ?m|œwðOòõ˜²Ò˜?’LÀ•&©WÃ<}ƒ·«ñD¿Ð¨H¢Ý[J‚ÏÊÞ§°QñÀ%¯I^=HŽe$ë©jÞß§ÊɆå%mËÉ|»á·˜†ôO>þ’&Õù¦‡›±HqÉ‘#¹KgsÔ7–À¯áä «ËųšªmÝaó±—ÇO’Yàº]"CêdetËfazp±GX\ª·ö÷±ÿÍþKu%Ò°iàoÿŽO«Y! üûõƒã†Qœ†Ñé µMîgè2U·Âñz÷Šw.aÒÀmM$jMÉõ4»Õ÷Êkg¬ÞÅãË8½Ú§r¶_ÁXl´£ï~Ëãi=Fôû÷¶2Ï\ÖËú¾‡_öY^u^źˆÇÅm²Eq‘æt~Îw4ƒ'’M¯ ·ÊÓÇáD-=A$èLÞ‰`+Ÿ¤ûü®(|ÙÒR:¢!M_`q€Š~Ïòhè‚Hp{ÛuÄ7¼@(˜Ñ»f|UOeÿ=\ù™ñú?©­çUGYBT ‘W–Ìœä}­YÁ·ï4w²ùÐj—ħག¾yàñ¼ Ëk’ÌG¤5јt!$,Îa3$´òÄÉÕ$Å?4EÁ¥@’µå8rŸÜ¶Õn 6ø3ØÎˆ·4¼RÞùg-¦ùâŸ"µ9x•©†Ê{„'NÎŒ®rTôíL^ÚA; ÷³}ÞôÄ9ûu©­ë#A6âÂ=²X*(sîT„™~ƒ¨Š1ÊXǺZΉÀí:Îúƒ¼$ôÞ]QCxœ…78Ø ¸õ9]2óú²k¤qnˆÐÍPÛRX­¢h¨(f›6ˆµÌÊ I‚Õ\ÚZ6—MR¶ m„Dš¹×_yxD!œCsÔ" ÈËSéJí÷âé©ÃVœ±Hh—K¼3¡ ÓØÖõ”Õ#BÀl›Ûc°;oã8àÞ¶Ü€§cãœ&ÅÇ+þ)vš Ͻý‚»ã[}=7‰I“*Âd|œs¿å³ä5 u¢ý PŸ©œ<À›ÏˆÓ–ÛSO€d³ C’zæÒ ò$½Kh=Í@%äÖ¸˜[Œf]«e¬%œŽf^2Âf"ü ¥·Dpg\Dá¦iá‘¡a*¡»-_,׺ùÌ€úÒ·’¬æ‚’š†0‹ ñÌ¥’X™ZÏ`óq´;õ#ÝÊø9ò“©ŸLrŒ#3 ÏS︄[¿h•G»kÈÚ·©( N)?l¸Š%"”#H3*/ÈÔôÎl¬†=â<ªç}™3ÞëÚìüåo×N@$$Ië{ © “=˜ºA$9·áÁÀû'[3‚ý¦¤ln¯*¦²Ú8Âοz4ê»ò|y‡œ€uld` å$ˆtæ9}­‹/=CÜo ´k /õ u}K™6HDÎö³µD€¤,ú·Úír€HÉJœ˜Ž°±gÄ@ÿ+Q‚ÊQ’ˆÍ ¤â8Ç”LÕû’.»skjÊ!´Õ>G‡S¤ƒº€œÿ°‰ñ€ô’z…œ! /Ûw6ؤ÷°õn<`øþCxìÎo\íþ]î7Ý7ºgæá+HŠCÑ](ÞßÜaÌÕRI—¯;&‡Ú…Ü6DÖSLú³øãr•íà טB¼(Ѭr*!LQØŸðXgÇèéeôU;™£íÿ—{¦åY"šËað°g9³v59û0óiÈ~ºÝ¨åpŸËéävöÔ¥íi‡ù©K­=ƒyl-Êri·}mcÛF¸#ÞóLé†9+S@ÀJ¨Ÿ[‡ìI_"“]M‹ÆeN‹¤Ë§† ©Èjá°œ¼XÔ¥ä¾X%oî–1As‚åõ.í<ÒtŠ^ð×°ª–$¼GÎ\J±À¬FÌ(áÄ5Úa¤—“š LëЀ@މ/K žÂ8ÓøÓ#Œ±!4*T’ v̱îùÙùÜîp²ÆÕ¹ÑÝÜî8l&;O÷=±kÝÜ„$ÛYnªl]¡¬©Ìî嬪—ö6Y‰íé¾ï»1ò?Ÿ¶t¥Þ ’¾vœˆËu›ŽÇ lã~М@­<ñÒöÖÄ`ÞŒ ܨPç_x8Ìx™ê&‡ß†—ÛŽ`9µà¤•)o$ÎØåÑxîâ€]óžñt¶fL#,ꌜŒgÄ÷`uü¡¾$øðú$xêó’× x4ì¡ëÓMÛÒ×n2ã¬9…QõŸØøØŒZ%Íu/kVV¬,[ûÊ(«à¨Ê±ÙdbdìLÁ=ÏŠÁì<ÍÃÝþ 2]¤ “œ.a2¯gßvš(½*žNz çÎ8ãh³$‹}3<ìyeÌï9F!&¦¨†ÒA¼ôsTÄór5¸.ˆ£j›TF±ÿ"7Ò>Áqà‘ø)“Ù¥;?A½%éIHXòÄbäÆºÞX*/I€>De&[Ÿ×µØŒzíS k’è_ã $B™ÉÆÌçtÈCÌýëT†ÀÉ6œ\½ƒÈ }q¯­Ï!Lll%é %í üShû7` Èõ=buƒÉH©Q|´¢b‚WsæÙëV{ày½â>DYõ`ºZc@’…ލÖ\šõ )D¢+H€˜ƒ7ÌF¦™°Ãˆ•?.Úaºf[´†SiJ”!@zRgš#Mû§·ƒÖAq-ÉZáÔÌL#äƒ&mA*žnÅH÷Ž4ñlôt2¥õþ)ÍF~ ç´Lê9 l„Ÿ¡$KÈpí1ÄÏÔ¹:‘j žœÛ•¶µ±#æZ܇–äž²LŽIë§_b`G1\—K.#nÁôãÄ&‚yY$I½Š]°¥?þ"ž™Ñ&K^Ó5ø-ù~­Ð€/`8+é>îåîÒjºóÈ´¶C7‡œ¨…~ qcRmÑTKIbxÍÌZöŒó`°ÁýÍænæËõŒQ]>•¨;ׯãí@Ør‘ØC´'è‹=õùðÝ’ˆàNÁ˜†Ü0tÚôÞ€#´ 9>'o… Øe£€ÜÜÌÙ<'Fo*Û¥Ü.RòSÈ-"jÀo«õÎïv¬vo~oŽk4²ñ›Ü9Rv+Klãn½ÕL×LøUê @²oÚ3J¶†ô±Þ=ž~[ñÈ“÷%°ULÒ! h+~q…ëqMšŽeû6#ÜÆââ{²['¡Î>yM -lÌç+/äór1䬳tØãÜ9‡FöSŠa.@R|EÉ©Êó› Ê—‘÷¤"‚å+£8Ý­_  ¶®•‡Ñ'9¬HŒ°ð=ȘE}VÑ0Ãcú¥hðPfoP|eTé2eup Nwf'~‹ÝJì0òA° â—­þk<´J…‰ÄXTm³«Ù+þʃm!š§ÿÞÜãÿ€f™Îv@®E*^곿÷@:“ÙŽØÆÖñò¿¬^RÈÉB"þ³^?7{@[’±¥)fn¸Vˆ¶å)Ü™ð@û…~~×ùèmú@ W`û§œ|@  €¯öÌ5ò‘ª¡£2Ñ[2ŠžÅ†#x®sPü^!?yöªÕ¥sË®WÕ…¼°YòÉ`0lÈåVð-/ÕÐ$Òæ]€0žýZÓWïa DñŸ¼;aa°íµ¸ÙÊ]ˆí”÷eáe]ÃF—L7:LŒ¶¨S€Q-Ý¥Ó@æËÞÛúî~ ²O@&,µƒÌçÿk’ÕD˜câo fgVÉÛ Ðlõœœ~÷ E3ÚkQ ¿ ¾ãÀ1~BY8cÁÊ¢ÿ N1g:Ò® è$¹ /ÔK(G¢H2ÙKN&Œ8Ïtr2»Gi$'û%É/Gø©m^I€SBár.©ðLBÅdXFJpè$¯cup‘¸¹Ø7¼!9vƒÝé‘ÈdT×€-èáªV¸R]'”Dë 9ŽÒö‰Š †êñ#›–ÓVÎ]Gä78šùš6¹+®¦b>zXËŠ@¢bÏ:“¤nF/hf ˆ˜U“ÓÑ[à²+ ) Å”=ÄžlHCvvyvùrFÓ˜Ù´‹êÁP­Ú\XQáJ†ÍÆv— ¤Yh/”AÎy<³& 8ÎQ±Ç&ø; @Ô§ÉQ™IÀÅëšßtH² "èÝa$Ùbr5!‰ø †)\R¯ôâ|BŠ·&J¼_=š,Iu- ²¹ œÓ3u*³ŸI»?Ò $c%èé5%Ç­÷Î7éøD†]ñÔÖ¢æ`R²Áz¯ÎËMšÄ:€ œì¬¸˜>£y:d©ìü"ø;Ék\“‚(¡œ#lÆ÷a˜'[å9P m °ê.R/Ï‹šÅU—½}1n³ß£3…8µˆWK_ØÄ½Üuþk¶ÕâX1ÒD*NUæA/לax’ÚA@“À gZI@69Ž8ó*4éP‘ˆžâ „pH×@ØBŒ=Lʤ¾U ¸Ø±Zí|™¶Ys±å vQa§™žOOäÙl¨¹åÆ.#(cñéðżºÍ“ˆ s(rT‰œUÆÙ?†Dƒ¾šv{G½  Lz¨U¹:e¨ˆž½=>„‡-–ݪ˜!¸úß`•¡ rZ±øÏŒÉXœœ´E®ŒsíW¸±ÐÄXâÜŽŽÆŸ¶z¾€fŒÉŒÓ{Ü5'0Ú§pӼܟbnìozNHQ¦š·µ('Ž"9=­žGô ®kLCIªFS6ãVÆŠ1ú!ÜJ¯¤EYVÉbó;®w³=NÛ™H£î³ X="zÑQî“C«)iICùÚ©Õ®(_Ü,¬«ÎÎ)À3¹ãÖÔ‰H4ȱ뤿+²mýÏμùGsáXΖ@à¿bÈîÙ­ö¾µÐN6OFmÀÉ´Qmô•/CQW5aÜ=¶ó#‚â)5Û¶Ì#^ógÀq£{AÖ6è¥êîVY"^bÿ’Žêf]¶XmjËŽL—œ 8©5þi`R Éÿ7Á´-bàÌÈ‹bs;9’TLu*eºç€v úŸ07³¾FÊï÷Ë0?©ƒ¾ LúˆDtUiŒ§d=ZщYü &RZ^ËRz ž—KTôŠp³? ÆÕ¦#b’#J<‚@ß;On I$<‘î û!šãß`e÷ÝNŒ%x¹¢õ}ÝH–@v~‡¨ÿMZGW½^†qñÒLÍï3Wh‰ü‘Ì'/øPò¤?ÐWab6™³›ŠßàŒ®îÚÎ_ ÑîÔeŠÙ=ÿÜH†Ýþ¸¼~wù–t|‹aT¦`ÌäG±’Ò§3[óKÙg»…‘joÓ o»¶I:¯: ÷†ÚóŠ"Ÿšyw8Ø0;ñ$Ǧ¹·%`L8؃º U3%¿·ûïú#fÛÌ…]rûW{›ð¹À:–R©7ãýÛ”zGÊa3a§ÜJÐ\î–ûíR>_ì<¡ePðJ”—Öò“« •ÁÝÀúà-žêü…(Å#×V'Ó*÷ýd™-qµ˜eã:W?NMš½ û±K«ÊŒnψªÿ´Àù}É6A"걯¦™öJ™_{ŠÕÙbâÐ4Úc.8"×»zèÆúÀ„ë3«ÚH‚±ÑB°q[K$}Ù7ûÂ' } |‡.ê"¢z=ðu£ÉOs×3ô>“Ô<ì³Èz8 ïF!bþ~Û"_°­¿f·L´žíÙ}ç¸÷ºâ Ò„ÏÃ[ƒoL°³)#„×"L7cŠ¡oBÒb¹|€€Ùñ;§èÊcmž`çµ)‚ï°DÕO¶ÎVŒTœý}I9ëÍÆV k3¶ätg¿E{¾´—Û\ká¨Q©bp¬P·µÚpº3u?âúŸXûOÑâz‡ÚØÚÀø÷/Ñ3%åÜ5Ï”âæ ViÕå¤7JôëpâFøN‘×| ÿœõÝ¡AŒßî¸<Ó8–=¬‰×å¾aÆn¨:…ý.°uí’3á±´žJ€EõµÜýšÓå×íéICìá½½cü±'6N Pü•pw“ óš«#_b‹aÁZ"PÅæÆˆ)½¸•ÊK‚^ºy¢I– ŠÇïЃ³‚#©†Mô ?ƒñÞßЇûá"ÁÜÊüYÅÔÕ}BÞø•ˆ˜ÇÄ>‡´aqp0ËUUªIÊ&îãÜ\[ëáëð >Ï0fÈ;ž%K ÑN–ðÐ&à„ûòlR›ùÁsD&6Œ’¨ðä‘vø™HÒ‘S’–Ó]@v`ém÷HÖ®èOb »À«G,"ÙÄÐ/›ý2†ydükáõî—!&×*¦ÇÿÊáý?FZB:‡S9eä2±® ““¤PÛ£Í)°R¬Å‹† ר%¼ÛÎ0ÀÍçñuD^ššÇø9Iög‘¤¶Â}/ À'Êëxm#ãxZ»ÉW|oêÅéÖŠu©âà›7qÆ•Ï%ÿ´:¦ãð èeGèIJ^ù¶fóäð6ĘC\ Ãã¢u@|'ðêïiNÞ}ÌÍ_]Ý –½÷Yqq%º#Ó`û^a6©ÞIáª6’Œ{?œlcH÷5ia­ðTžTªV Æ&ˆsÉs¨ÿ>ì΄æ ýô¼gÓÍ3Î]¬| ãKþßb`žçü÷,þA8ÿ½ŽŸ7»!ÉØ‚~€ ê¸ýÜ€[¬K·M'ïœßÖ£Ö–Ç*7_’)ð óÊ>Äæýî¬ñVXŒíö’,;­¤èÑð†Æ¿j*;g™F¬ù^¼¶˜­¢ ÷î5\€¤"ÎÂÃo{ïARR,Ù>ÿ hr¤ ˜×òhèÒ®Mø2°÷~nÆ#æYJ²UZE`9ñW»ÌYY×à/àpÅÇ¢ö ÛÚ1eHjúß IÎÉô>Ú\}?, ÏÐþ¤C)?("c"np¿ðÂ8k°9ªy *$úW’‰e" }”îš^|ä]à [×ßÇ¢gœsõ5†Ò,…¼j÷3±Í݉«Ï=ï¦Ç4Š~™%ÑÖžÅϸ°žáPhùËÍ"òº/ôô-ÓloZˆ@”e'&ç× ›ê–” ”1iCr|ž sš‚ïϬš[ÄÇx[MTØäå€$ù®è2| CYV˜…¯*Öë'tÞ§QˆnèÇGñlÿ½ÊÏœ™§QGÔ)vm1©)ú3ôéÑ,œ ®Ô'¥¼ë?šäôlÇ?C¿5VÒº%½hë„RÙ%àE0>z’0;û)üȪ“b ÌD6þ >ö¢å™— IDAT".ÿñ ˆ}4gRWÚ)í¿²ÒÄ’²äkó}Ò%l¹[B7#{ršwfbZ‡Ý\=ÛÒ'€KdÊæœ2”/±qo°07:Ñ =µFW’ÕÆ=y $Ñr&ƒÞçéåˆÙ-Iðí2Ï.[¾âß(Ç#˜t-äþ©ý¯pŠ[é]Í'øˆ‡®[¬.ÞJX…{Õ«®Jœ9‚y+Ó3A™x ìÎ/«È`>Àâ[Ì4ØÂ•Dá÷.üt- 9Ïg€O0æzÙcѬê<=x_ Œ_¦Ë;W~|fe³/ZnM¤LÖ@q[LÀù½Rü^égHÉgióJ¡­J.ÌÙ2úu_¼f×>Üs½«[ö5J'/&xl¦|í5H¶ïÌä¾áþ'Onm„²ý­#€×Ž̳.K‚ߢw;€=dîλµE¹ Y,c›FïVó#XJ=&É /á½{o«þ b·h¹eÜØ,ÕØ&ãÏs=O&¾ÔxVðví'Øztwfuâ]IËŒZËë)\'(þHŠÈ[ gÚ_îú€umº…‡ˆÔ…_ý†ôx—8Qëðéoöµõ3[¶si<ÖÚâžÌÒ«'¿”ÇnÅâ¹8aù±úîÝwp0º Ð ºòÈX]–üIpš «û+Tç¾ Ewþ,† ‡®~†§d‹”F¢˜{Ü"ô.à…pˆˆâ‹~2–ÜÜz•ñã¾o‘µ¢°<±q ¥–PzÇþ!";χïÝÔ<Þçhܵ8ó->É9ˆ¹0Ã7-ÙEé5ŠwGÎVAíO€Ë£ÿ‡k,} ÅÜ0GbʯEõš­" ‘3O{q{¶`HÙp·ÄÄÙ.‹¨£¦‚¥:¼‹ÇÃj€x‰ }‹Xî2YüC-Þø$Dìs1&Aæ Ðøæ¨/ÚÃ3å¢ü%,«cQ]ÞÄöô‹ÿ›©Cpì'†°±'Âv—ÓµV¾iÕ™8IŽ‚DÎtÀUåMä§\–Ù–œ[—ß åTiµõªÈ¡K^ —Èl0×åíé¢lœØ@ÓZšÅ§ö h›õ@æákÄÀ»‘‹O Gœ¾ç!ð[gS†ÝŒøB| “€ÌP›â³aÞ!>1# F0"*.äå¿äK#^B®/KÑT8—UõCXZ zÉ'Ë!Qä¤ùÍ›õ ØIc' Zt—Íë{MSR]Mž=AiçS)S–ˆŒç$éNºŒžA(N°QÀ5übÚ@ÂÛ PëQ‹óGÛŽØ%”íì[Õ’ˆg°ƒ†¸ìî¿Ì¦Ï¬¡8§zi– Ôl:ÈÙ)«_ à]%§§}îcœ<²œ^X»ò '›#¤™Ze»À’ÖÝ9›»¢¿ŠÚ’£žW +nÄ&¦ï„‹ƒù¿šËˆâõä^*%¤&†muü0k h¤µ—¹Âïe”œ¤;C­‡ ÝMåßÚQ—¾Ã>ÙÓ¸ªÈ£äâòw•ÅØ°Ä5ÐèŒxÕ•¬ÒijùŸ` æŠé¬²â®ëŽ ;ù†ë#@' HŠS¦‰ç¨Lá¢W3g˜Ž µÈÓß•·‚^½h×6õÌIB. Í?‰Ðö’&‚>=€ó©¨öËK¯/ƒ“á}­©Ð×>d±Yoµ³3ù¥pk•$Ä_†L¿Y[‡tüÆÖï`®„DøÇŽKü\ŽQÈ}ä˜?'h½˜Æ©,SØâÓ /?Ȉ¸}y‡ˆÛ=!Zr5HÖT ÒãuáHµÙH”æ¿ö`ÐjeH~ÿã(pˆq¾†Ä\YáOû#¡J _,ô´XJó6– Y²“4Âá¯Cui›79Á±¦÷6’3,£ÆÙžE¬*$IÈm¸¡[§;¾L¯i§–±DNl”ÁXj‹áEòÎ)´0E„í €éÄ$ f/ªOàDûÖ ¯—ÂiNíé‹|¤1gÊ쮹í_s\¶äQJË<8½½Áfc–æÊ mlY©(!e-»Åê‡åå›M>0ñŒýôƧÙHGŒÈydÇþ çâQ³Fö¨{ Ϩ ¼ e‘tÎD\§S“sx˜büYˆЗ‘u« pÜ[¸®„gåÊ*þ%»–¬Z†î.“f‹}­œªª#±Ú `ì^Ì‚BíÅ A0u€¹™TÚ§a‰õúÆÚ*²oÕeRµ‹. B²víuµAˆb𳃤ªLx2zþµy W ]ó|ZõM²/Ç 5i%¿ƒ5ð–ÓÂ0o/ãw‡Šª‹0·Ïxä8©J莇œíàAm¢î"¨㟅¹Ò(7/B\kÎN:r¢ßb“€Q¨€;iŠfWJ¨œðEŽ#5Ú} …> [ìf+üm¬»|Wˆ¬<[ÊܵŠ×Àj߀M™§Dï½Gô× áœDÁHÒtŠ9Ù±Æô¢ƒfsº±˜[RÄ¡x›÷ äØ%wXƒ†bÖxr$A.d Óí_P“#ö‡>&ѽs§…¬8¬>3¶yzµí™µmR6°¸Ö±iIùЛC*˾:Ä¢@Úæ…’ÐHÊÉðöSÇ$ºWc ê<ÎÂð€´!Ül=w°.R)]wÌ^ï½ ìãd„[w‰ën³­æ¯5ûmù €äq[w [gBŠ(ye»s´©x¹‹taß›W ÝËOã©Ç®¥ÕÐC1vÔfq_5>D æ)®¬—$Dz€1sÎöQŘƑ#žÑWÜk"‚èÿ§®a‰/·$ë |@[™gÂ51ÓÓPÃe“­³÷˜p¾¬@/¦ùòÌŽ¦X̸©›°R½ÙFZU¿>gÿç÷³.Ëk®"f›Iˆ¶<‘^É×Ä@}•­æZ!ã×vç5ÈýyXÒ †ZûiJˆâß0d‰b°ë GKëÜff3}±+! ðâüõéˆ}¿‘Ÿ6L¨Þ®ªÚf—ò.y)$㓚™x* @ž{Ø hÌŒÿPB~*µ)ð Ýåd¸YÝíÍ©çCdö;§(‚¿ù]É ’ŽÓ6ôpïxîý uÓÜŒs¿eÛ lMr¿NLÒŠØòžsÿÒ3æÓ”0Þ]—ýÇvBÞ8nÄı\', œ–RËä¹* o…¾G.ÖÏ,ŽPý< aëéÆœiAé#ïZmÁ@ øS +\m7Cà];ý½êu¾leðŒT»/å@õ.áù c]¥ï£¿ÇX©êå=Òtâ8Ä)&oObóòøG!è`Fš>‹!?S͵7|¨ñ-Û[†¿ Ž­Óó÷Þódnqß³üGû.°ômñæ×„9:RA@òC8éõb‰/{@¶òj—Óê¤lð¶îJ²éà!)ÃQ#ØÔ<å.`¥oØ"È—ÀÞ¶œN_%û%8{yÀŸ\é‚ÇŒ €ûäôÕ·Ö~ö >Ϥ–ÃØVã'ZÌÊæB5¤!Ð?Nxèú‹xÖ²Õ§X¦çCݓт4Í´œø°17õ`âkAíñª/˜°Ö›¯Ìâ; 3/(=« žfÝŽÅêÆ÷¿‰UE^íÓóë™Ô2„80±Ô€Ò(Aˆ_Úf†1$[FÜî”1|¹~ŠD£Ý¨8ᓼ=Ò½ë¥ ÞnÖ,Ÿqàaê¹ràú߈½€½¤QVƒÖP£zÄ$-Ä]xÒ os±¨n=ÿÿãüœuAÍâ^ß·µùS8¹DÐß—m…-~uÍé[aGˆ™ìõ@n8I€Ä¯í@8ô0>7¦è«ãçé㬔@ñµÔ†šîn/4œŸceWíMçÔµJ-FÅÅ@Óûˆ’Ç‹ Òa$ ŇA„ÍŠ·´ÄÖ~˜BáàŽ#@ ¹0ÞXä ˆÔÏÏ,Þf³¢vB¸`}ÏPÀ1¡Õ~cëlØrSÓÓLo!â åAýÕ=ìc~¦W›)…ˆýúØ&¯Íî1ý‹ †Ñ÷‘XQBfM·èûh3oy†ó¹~@À‹yd5)R”9/-)µîåîðÖ)Zv¦š¼´ ¤lÝ`yÄÎ4Þ£'}Šçˆ9°•ßösøÝ Ì2–kù–?’Öì$P+˜=и?ü9™b¤ÖG³£(2b=G-§«æ×(}¯9Fü8_Y}~‡m~` €ÔH×ßÀ©lÌmâ‚× 0Cuó8öBOt!Si¹¶ÈßÞ•%—çˆa~¸|BÎb$j‡¹͈ÔÜ»>¨’m»±m(§Üý,ÓéˆpmXÇzŽ,ÄÀÍò~cä3ˆ¼ C¤€Hçœ3Á ?Ðò)>:³îà¿ïúg¸>F•øMCË…„VpYL V‹ä~ŽiÁ^R›~Ò?)ßÉSô€…Èxà‹‹!FÓµ{”sÅ«<º¤¡E@yd)A%.(N/pÙ à¨ÀÌ„ v!ÓQÌ$_>²FâÝ L’û„”Ý=&‚$IÁ_þ²¿³ÓÅ"ÄZvÉ©}ô}Fõ.Ýí:œ¤‘ƒD>Jš|G‹½‰MÈ‹ÒK`ì©ôí_’D·! r•EÓcmª]0{üøœ™Ã˜GtžÍàjÕü}‹=á–VÔz@™Pw•ƒ÷ nˆÂ+yÍß´z"2†„übtKz–—’p³Ô1$Â,ÈÅÃ×XÉVNæ‹îxþemœµê÷í!§†nJsxš‡´{ñ®ãÞ¯ÒAßY×p¢78ìN¥)ná){n´1‚¶wçšíž# ²ÒÐî~àíŒÒ6“ãÿ(yw&ÜÑqו3ŒrØ`3c ÌcÂp¦Á5à|Qÿ°áëäS€/¤m«Žã0Ûõ¢qçµ€¡›!"­:‰kõö÷q8³V¼nN}ÕÙȹ=$zÂ#_ë"ʧEÕE`³+À¶×ÌZÚù7‡N"HÜÄßȘ0§Õª áÍ*÷ˆqOìµ¾x6™]Èg^ÐÁŒ®}ëi²ÎŒp ü© Ó}Æx«“cÛæ6@ß–ÝßàI‹šüÕ‡Ó õ„ðÛAõj2d]EÌG§‡–Yÿmø1îZR’Ê|âBúýÖeå0*Ç—Þº¬6 ?t„-ÒÎÈî °XÑWf^åË3怣ó7¼÷¨U¥É³³¨eUy\dŒd°üºŠTþ‚Üý cD€ø•ÂH2>{UÊZRûÿˆ^~6l·&P¿TBŠ;Tê!$›Ö ^Þ]{ z¨zí%, hfÖ™»aدžÆuNŽ°ÛŒ›fÚß „ÌT8¹Æìà‭T6ñ˨µ6oó½°“ÕfD~4…ö¤Ã bŸ>Õ®Ë+Ó2™øœ,xÑ¢:º–Ýf°Ÿë‹ &L8y}‚SÚ=ñÕn¹ `º¼Çè-ΖyȔı§ÖÆF8Z±4÷ùË8^î¾ ¿yÚœÖù[hš«Ëç¥ !Mxòú-b…éÎ$¦öéAã[Ì«Ü9AE:œY7A²\(ËäNµá • ,ûš`ÎL†¼Ää>ëè% (-!àÜwž…®Ò_›w0mñ2¯DD~<Â`\Q“0´sC“Bæ“‘¥vŠq¯ÍbêN{bœÅßËXàõ¨Êû^õgcÉõÿÇÞyÇIQ¤}ü÷ôÎî’AÒT0`ˆ€É *"z§žñTA89s@”׌YÏìzzæˆDDf” ’³»,aêý㩪®N³3»‹®ú|?³»ÝO=õT˜îÙßTWWs‰æ¿²éÅ×&ôÐÝKPŠï¯rËïKè=""ÅíÓ5ŽyxW†QÆÆ9žÿvÚàt…ëîÄ 7U× öSÏxs¶ˆ{2¦º0̬ÿƒÜ-GcwÈÙ µ?ÚIÕ‹zHþ¨Š)Q»)ýã’[ó‹À™upA9„Ò*'0fDfHþàäµ§R ¬2¤ÓÊ>ãÞ¯5ÓFÒ-‘â2âÔàNVÚn´9Ћ:‚²£Mˆ€³[yؼ¦&Iï2Á_¬ ¦õ³5G\v倸˜6)69ž¤tDN Ì"þì¡ØÿÓÖ¦þQG¦QNø˜®´» !‚=ã~¼BUâ:“I²‰ ÛBMÙÿo~ŠÙ° ÏT°âÿ¡|4jÅVúˆˆù gL à 7;ö BŒ‰mÄŠ©ЀE[mà@A  áat‰úcJGÓÆøŠ–ALI6ŠÎnG¾:ï«kM&Ü[A8-u"ý‡!þ~&”Ýö{\‹xÎè@$¶†ø”ÖpA'[os›…ûÇ‚¿ñ¡ Z/ëRàjé¾`Kø‹¸‹-U){dQ|ÏtÁhsüÙj˜êWH§˜"8Á¶TwE¹‰­¬ º(¥ô„WíKáÏÜ+dŽ@)˜w—ÍÊ(•ùM°‡™mP!qÁÖÁ—í÷â•Ü€Šžéå†qPð½ã2¬çŒÓµÎ¡ÎׯÐ~|ÚP¹}»ùwìÁS\‡h5Üw·Ù‡Û7ü7.]¿¥Jä¬DáBA©<å?€rf<¹ßÕí$"ý.)Ä5$ÜŽulÆ-8à P ü™« 9*xR%O½H¤Ï*˜æJÕ Nq–Xb4‡HïG ˆü¯«lÊ”±Ü¸GZ´˜„ú”GÈ2e8†ßg|\Yøx±Ø7=„ïŸNÑ6 ka#)•VPÆÙlckÉL®þÙPÖ!¨‰¾¹¬cbº¶¼¤‚ #‚n[[è}CÂåR–CBª´|ØÂõFÆÊ„Ktú„w]«m›>Äüó >Tý™«ô€Rzx†‚"ý¼.ýu3Z÷0ÑÈG§ÙoÈú°ÌDB•ÿ{Ö¹C§œîÃP`ó…2÷C(ð¡©øHM$ý ø5Wñ»ûÁfÜxC{˜oI˜Öšã§\]—y¦FñÁ ÎñïR~bû ÍŒu¶Ÿõ±otl–²áHÑ.Qžûv±‡Œú["v"{Úò»ÊQÒ€²·XêC…tÿ‘RÊó*á è%¾ð(¥ü 8ØSOW›ÜÂIJîØ•œÿó¼Á­(ß‘¬gR¯*8`”Rœh;àGÒ5ä-6êöB)sˆ…:§LÌ{Ím8§VöXÒF¢ÈXšÛ‡™el+bz«¬œ¿’®µlˆÜSB)לM+îeð·ï9}BDü¦×2£ÐED;Îà†Kt6G 7YÛ¢naü® Z‰ÿËÊüOÔõ°éöLèÈ á{š¿™ý· Z°æöîdÀ™ ô¯øØú=óÛœè‰ Œùn¨°# ™j?6 $z ÛîOx4™S!îàÊ@6Î!Ÿœ‡ÅAþ¬tþño|ÀŽ f£bYû†þáÇ|ËSo˜A‘JP üE(-:bP«ÚÚ2ëXCŒù}G8éûå­›AA„8Ì›SZR ÖqÄ¢Õ(¸8%öZ ´à`yB„xáf¬Ie%ÙtuRI…ìÅ­4»À\T8L!›+ÎܯS³-Üš’â!‹ ‚ ‚ßKçb}Òà ôP,0Ó‘lÁ´°Ás ˆŒÎÝ—¥L”aÝ€lÑ•ÍX©(¬ccضM. ‚ ‚ ä˪°¸Ì ‹;›'f(1;B³œs…sf¥YUð.ï(‰³¢8Í3XͺysiiIɶm[­K–äå¥ «U+(¬VñáAAþôT\`T<‚k̬â‚Ä+KEÎr8fÛÁU³<†.‘(íÈÖpj™âÜ¡¢2aFUmÆœz"‘Pã“Cª´ž?Pº©¤ °°f­†……A—Ll.-ݸa}ié¦üü‚ŠG§ ‚ ‚ð§§â£â ¾h Zؘ }ç_Û'_ Ã…”[XÔá,f1Þ‰qðaÏT¸®e—R5©U.kD6 鿝oNÀÄß¶u[­úuò bëœDAA!Õ¢•+–¨âÂi‚ ‚ ü驸À¨x„pZDäe!5îêfAÙZ87ˆH™»¦"·X[Ú¹™k XMúDZkتð*t¹ åwèL«ð­å–g¤3¿°€ˆ¨2"‚ ‚ „¨¸À¨x„a™çî‡Ó"…Öfá$bHÀ¯®id”6– f-³0–‘Éq¥HßõŸzàÖT@™ÇñSL4~OÃÖìà>ªxAA„4… K4Õ¬:£ÀT¾Ý!ã#X˜Øveu? JOM%3E@´<½¯€`'ú~ Úž©¸8œŒJ$?®;懲Råñ@T *ÀÍ×_3þýÉãߟNAáwMÅFÅ#”õqUŸ›1¬y´ÕßuR²X ¡J*M@Ð2’õoΡBP™A:`¿Ë.úθwŸyæéÕkÖ4n\tx‡#Ú|ÐÔ>»–Ê ‚ 99 Qà«‘¬s2K£åôf×ñsÀD ×6+t]³È¿>«~¸—ŽàV¥¬jé”2nŸÊeB¸Ïõ²áH¿£a¶lX“_»~f#QB„ÓÏ¿ð©‡X¶k(&Gp9è€ý®ºt¸k¹þ¦Û¾úfæÃ÷Ýq߃~õÍL êïðнwœyÞàÅÅìÃAb}ŠKJœ}ÆÄIŸzúŠ<Z°héÂgŸSDoôM×Ïøü˽öhµë.-?ühz«Ýw~ÙÕ³i“¢»o»qðE—®\µzôM×Ïøâ«}öÜ£E‹–-[þØO?{ÎEÚm—–CÎ?gÈùçÌ™;ïŠkGqFAA*N¬ÀÈ’ 5âã8G%Š#òfq'-`8«˜úÒ-ájà °#óúVaTp}V³t÷”¶ÇÊÚxº;ÿDç ¸-n±A2 ÆÚ]£ùþáŒó/|ò¡€`-ˆ"ÑCé‹/¿´_€úŸpBÛƒž3wnÐ%7š7kÚ¸QÉLMS[H™m]:u¼ý®»˜;'UPí¡ûïÙkVßÏž {×£¾þúë•«Vq£{v=jôwÏÿq^÷îݯºô¢ÁÃ/»çž{›]?vì¸I“'+(߯A¡‚$ ŒlÈ,Qbˆ9!Fl¤¡(=;Sô6ï;™¢„e…ŸËêær¥c̶ãïànëù¬nQÊÊo¯ƒc{Á`–0û¶íIð×3m×ý €ÜejKÖÚˆ’ÃÇÚ#‘~Åy>ùÐ=vûÙgž>ãü¡N¢Ag÷QÈÛJyŽêØ¡S§N×\;²¤t‹ö±Îî.p‚D|êÔ­`õÚŸCYÆŽ÷ýÜy ù›7o›üÁ”Ý:?gn~~ªó‘G<üèãЋ…áÝñï}óýlïÕ7ÞêÔ±ã!í~wÂ$€Ò^j«—ÃÓ5AAÈŠ‘Z$$Eˆ5"`·ŠÂ1é¿ZÒ)Ý{c׊8ѽΉÐÀnåÎ=°õ€»…@L¸;l¯¿X¦ƒF¿&:0M2Í$"OW€«PV±á·#\q V;hêJXKl^ì×ú´“Oºù–[Wÿ²1œ–#ëù@ýúá!^ËŠ5ë”9žÆŽŸpXû¶µkÕ:¬}»ô¶ô§ŸiÝ–­\ÍniÊ[¾beƒä€‚ ‚ Tœ$‘ $J–Dó²®2zŠÕyFxÙ Ä ®&H–pö ¼ÑÃʆqã%n³Š®@RHƒ|aëÔÌsÔw26CYŽ wS–X×h®3κyýj39`t-ø‰F Ö3ÎÊ–'º'4ÚªßÛ -[ìþøws~´×åÌ_°°ó‘G|7kNÕÿvÊI@&¯ÙˆõQä=úø.þM¥¥&}°fÍÚÆqø¡ þ4uú'8@ãÆO8ûÌÓëÔ®ý¯‡qëÖ£Kç/¿žùãüÝ»tjP‡?ý DëÖ­k±óNy©¼mÛÊwä‚ ‚O’Àˆ%V`ÄFʹ¸ÎQ‰’=1¥qÖ'M„ÈYµÊª6âî \:J©T¤äÌÃoì›a~C¥ V3s€L®H^nq„3+ýeUÐqóC’lÞÂ: £Æ€s$dû¶mêï°Ãð ³–Q7ßþÕ·3Ÿþßs ðн·/_±rÜ»ã÷o½“I“äóù×3G^?ªß ýo¼öª‚‚üeËWLþpÚg3fsk¦úùYgœöíÌ™KW軯˜÷&L8å¤Zî¼Ó²åËo¹õ¶Ÿ7lèõ7Þ<ÿ¼szwï6oþü+GÞà„A¡b$ Œ"£â¶”)ˆÍ8£¾8O@ÒÊ«9(C"*:âÀ\Yçrs2~wpD/iÉKdS¸ŒÅ ƒ_>WʈV¥Poÿöh}ÀÆõ¿pzqñ†šhçY½rYµ*ÁµÚJé­®EyŠ<@yé-Pi)JQzK:¯/½YQžY ÞTšÔVR P R”§(ÀK—*J¹Ëä§RÝ{ÇcÿyâÃéŸYãm7Œ|ãÍ·§Lù* òÒ”ÒcÀ*í¥· 䥽ë/‚ B©¸À¨xÞ^µryiIq÷ÏÀ Ò÷³(èËõ‰GLe`9¨ô_þ ÌWx]£vec8¼öäg G”#®‘úùa#»îo»Ä·¸ äôw¬öÍ^›G "VÃᄬá®EQ¾òb¢tž{¾òôbטä”§í6_Ôˆ¨g÷®›·lžþéŒHż`YÊK{¾ÞA¡²¨¸À¨x„°€V,êx@š‚™)Ò~›ÑÅqVÖ#6;xÚ%­E: ¸Z ˆ+þ|V&Ö%וÀ”KþD¸C–¶nÛ’JÅÊÄLlݺÅß®p„*Âýׯââzxkä AáW¦â£â²ÃSå¼'Šâ%™+åᄾƵp–¤Œv<ÏËxW&=JÎýF¹Ê•Xl[ܾðív+ÏKm.ÙäU§T~—¶·lÙ\ZR’çåQeD¨:œ~æY©¼|rf ¸ìŠ+•— AAØ~T\`TùßgfÎünë¶m-vÞùÄŽïÞ­KØé7e;5|àà¡Ç÷=¶Wîá„Jâêk¯¯Y³Æ—^ì‡_ryË;rkü½sÙ•×|òégv·]Ûƒo¹q”“^™ÜÏv{{¿ƒ(ÇYª­Ûߜˮ¼fçv<è|k<ô¢öíÚžyúß/A„ߣV•2‚*vÊ¥;€‡Zcݲ‡Ç5ƒU}9 [œ½£IÏg¥Ü%al\—øXÝkA[æÒ¹½•ÁÇŸ|vÍÈëûõ=vàyç4jÔpÉÒeïMxÚGÓêÔ1ìš Ó?þdÄuÿwêɹø¢aÕª~4ý“{î`é²egœvjØõ7b;5üWàØ>½GŽºá ÕªU“-‹/ùò«¯‡8ÊàCÿ~}]ÅóǦêŸ5‚ 0X‘Üýc /m•JPm*>Œõfý‡qþHqÜŠ¸*ÄCÁI·q…RHŠšÍp!:oL6™>çËÄÇŸ|vùU׸–Ûn¾¡ÍAÞuÏ}½{õ8à\6îҲŹ?Ëu+J©»ïýWŸÞ=íhJî]É£[GßÙ³{·¢¢Æç rHû¶_óí?ÌkÞ¼Ù…ƒíÛz%%%ýûÉ)S§nÜX¼ß¾­‡ ¹ ¨¨1€ó9ìÐöß|;söì9õÔ:xPÛƒÛ¸%æŠR*CÃÏ8äÐCÚ}óíÌÙsæþ󢡇Ò>¶VW^3ò£éQQãÆG÷îñ·SN&¢Q7Ü<{ÎÜ[Gßyëè;÷ÞkÏûï¹3©Qå¦}»¶uëÖ}wü{ýŽ?Ž-cÞz{ï½÷Úu×]¬[·î¾ž1ãsµowðàj×®ÈüåÔÓ/»xøÁm°rÕª¿žzÆë/¿P«VÍó9èÀfÍž=gîE]zñð¯¿ùöÅ—_)..é|ԑÇ]È'jR‹^~õµ_zuíºu{´Ú}Èç·Ú}÷P¹•Bl·¿úÚo½3öáîcŸ¥Ë–væ9O?ùx“¢¢¤ ½Ë/½üêѽ{õéÝ3ûw°rÛ[¾³&ZÛÁC/↠ù`H:¡*·Ee’Ô±.±­ù‚ ” -Wõ8«¹LÐ^Š7Hùž¬ÙŠHBØÙìiÅ¥cD g†xÒ¯«ÅaéÏ|HzY·àM]d_ÄsgÝ\~¢ ¼<ì|ùÍ¡Œó¢´owð„qoñë¬3Nkµûîûì½×Â…?-[¾¼G·®aïŠÁa»Ãví|}:ãsÞ}cÌ[gŸyúóÿ{ê¨NG^~Õˆu?ÿ à¦[o_´xñ£oyîé'vÞiÇײ£ßãÆ¿7àܳ_zþ™ݺÞxËè ®óUfÃß;îÜ¿ŸõÆ+/t9ªSR­n5r¸·Þ}û뮽zì¸÷&¼? À5W]¾G«Ý/½ø¢ ãÞâ«´IÙË õéÝëÍ·ßáÝ­[·Ž7þ˜£{ñîuÿwÓÆyð¾ï¿{ÅŠ•7Þ2ÚÏ™S>œ:xÐù/=÷ôÞ{ïuÉeWþ´hÑcýëÁûï™öÑôÉLaŸØ-Z´øÁ‡»òòK^{é¹óÏ;ç½÷'W±ÝÞµkç šûÃ<ö;nüìߤ¨;Ä}—­1Ëw°ÒÛ[¾³&Z[— mžP•Þ¢2‰íذS\«Ã‚ åAøxE W_—™—}5\¿”öt_¤X6²ÈcOÎeeq^N@ Oo–”ò@…`¤¢±Äz%»G‰k†Îïv]yûîø±ãÆßô×U¯^?ý6lvª±a=Ï«_‡uëÖñî±Ç}àûרQ㔿žÔ¨aƒ)N]¹jÕ”§^2|XÓ&MjÔ¨qþyç,^²ôÇù Ø¿¿ã÷ÚsϾdznÝºÕ«×ø¡s'¶†.Çwlë}öö{ïô­;ï¼SQQãwÇ¿·÷^{Zã{ïOL§ÓmÛÄ»ü‹Yºtéá‡RÔ¸ˆˆ^yáuêÔ±IÛ‰²nº<©Vk×®uã-#G\Õæ «W«öò+¯M˜8‰“È·KÊ^qŽísôÈQ7ß÷Ø/¾üjÈÙØ¸Q£mÛ¶­X±²qãF/Y  QD—nÞ¼™·í^–dhÑa‡rØ¡‡(¥ÆOxØðK_zîiVÒ•H†no×¶MAAþ´¦OùpZ—£:ñúetHÜ ‹¬ßÁÊmoùÎkëRFÛã¨Üe&Cdžˆmµ BIøƒUk”Ë#HbsPÚ ”2ÏIt"‡…hr™þ?2¯ !ºôʈ[®©A¯ÈÅSTy;‰ I™X¾|Å•×\û¡CÜá@"úÇÐ!o½3î‘Çþ½hñ’ÒÒÒù <öï'&NúÀÉš3D4tð 1o½óÄSO¯X¹rýúõpÏ}œvêÉö‹×ǼõåW_—”<ÿÂK+W®:¢Ãá7êpØ¡·ÜvÇ¢E‹KKKgÍš=bä¨-[¶cWÙ7<©V¥›K•RµjÖÌO¥¾ûîû^~ÅfiP¿þ¼yó·mÛ–!»_@yi×öàºu댼þ†}öÞk—–-ØØ´i“ý÷Û÷î{ï_½fÍŠ•+ï½ÿöíÚFYwßm׷Ǿ»aÃÆåËW<üè¿C©™IjÑg3>ôñÿ,^²dëÖ­étzóæÍétäYr&C·Qn]_~õõÉS>ìÝK/ü”e‡„Èæ¬ôö–ï¬A°¶.¹¶½Ò[”™¤Ž û%´Z¡‚„uaÄB75š«bè¨as„$˜Rìs`IoˆŒ“FÆA]A®ïk(d’ºº¤H×!úä®l˜òáÔU«VuƒµÜvó ·9¨}»ƒïºý–§ž~vðЋ6o.mÞ¬Y·®];´¢#‡zÈè[n|êéÿ=ÿâË[·nmÙbçÁƒ¸ ^Ó§÷cÿ~â‡y?6oÖô¦®ã £—_vñ“ÿ}沫®Y»vÝ.-[œzò_óóóý •Jö ­U“¢¢óÏýû¨o^¿~ívïxD‡™3¿cÿ“ÿrâè;î~åµ×÷hµûý÷Ü›=XBy ¢>½{=þŸ'Ï8=°Òˆ«®ø×ƒŸ{þj×öà pS™çþýæÛî8é”Óš5mÒ÷Øc>3·ødIl‹Ø¿9s¸üÊ«V¯Ú±ùŽ#®¾¢zõêáœ&C·èÕ³Ç3Ï>ß²E‹½öô‡*³éÙ¼ƒÛ£½å;kBµõÃåØöíÑ¢ÌÄvlØ)¡Õ‚ %NMQײ3§Æ¡ÝÃeqAF‡Wðñ%hˆu| Ä+gÐŒŒÕ„5«…(î“JñÃdy 7 ‘(¥;.'¼¯ø >u~¹sÖ”o,)ÞøÚóO»IU™óùËI'tïÚ%œ BγæÏÙjA¶'Ÿ5ÀŠeKJKŠ™?H)¨ÈʬÑKLz QûAñJZÆQÙ¿ É/ÅN°«¤f˜ràŧ@D¤Ÿ)ã0±Z ˈÜT€Yè €Gf -NàŽá’­“E™èv'¦V‚ ‚ Bå–˜"¨ušŒv&#è¬TÕA”2¿È—¯4¡_eâ°6$)XMPœ‘Zú¥G±µŒäб$F•­Ð5 ¤ ‚ ‚ å‚(ðÜTkÔfZ}CËdVJê=½ûÊZLp½Åe˜TsÛ–C@[¦Ò!C¦ê±C¤ÙCà9.,¥]£¯]ÿ<ò ~^‘ Yòç®úŒ-À5Æ:Ð]fŸ†LrAA!|÷F§ò!‹«4ËV& À”;´Xùx0Å›ÅâqëJ¨UÔbŸÎÊÓ†·Ë_ùÏWÐ=£ë¯Áɶ¿ÔþŒ[´J‚ ‚ B–¸ËÊ*Õ¢ÓåEZîÑ‚ŒNKH7híçŽÚ:à®´ÑгR±#¬q‘€<¥x ðا²>àª#ÔzP>òÊÀÕ0Ë DV]±+‚ ‚ d ´úÒÏSÕB0fý{ú¦åÔ )3A ¬ÑŠþ2Y±¢³ù™•Þa¹ÈW÷9#ûðô[½|’ç³RByGeÆ @¶`/š‘Õ*oGS5+‚ ‚ dƒû3jŠåbPé%è>—LbŒãGÃܼ\<ﯺ#*£ÉŒËfЬŽÜt¸HeÄqÈÀˆxRŠ—9ˆÈs  ÜÕaÙÃÞËFð‚Kb ‚ ‚ YbJåë8c% ­…™€Ẇò@¡åùc•žE±š3ÿ(½ xñJœhÃj×ÃÚ ÄC¥IšŠˆ;ñjñ$5Àí@·EOˆÉBз¯ùUXÝzÁAAr *½ˆG ò`žßò£ÖcY+°ˆcÈ`ë`f¸*1ƒÒLÞT´ˆÎÅBZóf‡öŒ-ËIåmBÐ36 ‚ ‚;€X&ï|ɲK g9¬² ‰ÔdõFDÑ«çÉî>‰ã¬”-^A?W€ì“¢ÅA­"CœÁ€G*ø°† 9AA„ ñ"ù¤  À÷6ŽÎ#¾¼¯@ZÅŠôÍ÷®æ‹ÓÙ£ÀÓå‡Cùc±€ÈU€ )6Åã&ø3!øo¦|LçDëÅŽBke¬x×½¡­ì ‚ ‚ B,D¡_(÷e•j|Ë‘Y·Ô(<bG[Ãû€ë—…øS9£™¤#Y"aRÑÇ p¥ƒGภ®{À&Òºf‚‚•òNIª3¥Ü¨™†hAA„Œ¤€<çN(–Œæn"c„R*^F\*-6ƒ ¬Z·8ÝfòkQ€ˆ ìe|–Ï®ÂLEã*¿TÇD=Q¶|ßS7?’Ý zúÊɨ{ÑÉo6AA„¬a ¥üM‹Qp¾9YoYuqW¨rSý, 0óJyPÓEË=+…ýúêú’îÁÊL( —L‘@džzå¦sÚº‡B^4)'Š·¦¯þbËÜ_Bý"‚ ‚ð»d·:ÞÍòü¹£ôó@¬#Ã¥„¼EjôšÝ'žê[O:,± °\ôüIÎ@e´2\U@”ñ¬ä#E3“E)Ed4­‚ ctsŽ)-¼_&W¾åŽv…ak.Ì]_ö ‚ T: æÍm±ëîa« Dä|ÏÀ‚ys»°GÈøÏO6ßÞ® dÌ @PFÆBòÌçX޲ÂS!%æËBrdjPºYÜZ7;û1XV†)«œ­´Dà »ìãi¹u´ÕñK±°—ú}QÏ]AW&£í ’¸ æ®/G&AA„ªËœÜÔœaG–žJJ¥áyJé'•²#=WÕÊ9yø©UŽvÈf™TÐã«D~<hqHà¤R\s+™;ªêTܯ¶Ôíä%ˆì#Ìœë %{D ‚ ‚ ¹BGÍÙ+ÚF’¦XÈ‚ÙE¾lÕb•-&Éwƒ¿ëKÙ —5páŽ=AOH麺µ ÃwJkÄÛ¶ ‚ S0™87/*ÊýŒJ;EB ‚ ‚ 9`Ô”;ÚHÏÞ4>ñð+ x1t£?g!(‚§Çfõµt!¥kQ€2ÑQ}|+T\+ü¢sm˘ϚA2r’3bJÖ˜®s\)¬Ê£UAAÊÆj(W_ü«þfK!”æç X^²Ú#–žä܃°.MÐiqföÞ7ÖÈ– =“f ^ÄÎñ¢ž€ö %¹+ÏÃÄeAAr†õ/Éo„§‚¿­!â馮ò׿²(ó-(÷)œ%Û¯eFþ#1ìô¿–o [»í~Õ­w…­\¾¬­Ÿ±Ê"P<}•Ì¢ûÆŸH«»ÈÅpËWˆqdLŒÇf±n!(w>+WÊO&< 7N8jýŽHÛÀnP°š¿Á{­,±F¡räQç »8lýqD·ž³¾ýú›Ÿþ²nmz;ØT\üùô©:vëö®bð»³lÉ¢Ñ×\ñê3Omøå—¿œ}^ØIøU3¥Š3iì[GŸpRµ5~Y·nÚûï…“#Êq ~ì¿aS(GþTÜýÔs¼qÓåÿüqάv:ž7ü² ËŸžªè‹ûF‰@Ú™TêëD+ÈV´é@žÝàNK…Ä&ÊX«òà$šïŒù•Ð8#EÖ Ïgµ{z!.ÏãZ«ß¤Lpñìl5«S¥ŽØ'\I¡Â\|Îi¿¬[׫ßI çÍ7{Vš5úœxJÇî=oÜøÎ+/|1ý£µ«W5Ýi§“Î<§Õ>ûÚ,Ýë·ð‡¹ó˜³c‹]~˜õÝ¡ºü}èp ~˜sÃ¥åå¥F?öÔµÿô˺u=ûö_0oîü¹svhÐà„ÓÎ: Ý!#ÿqÁ’Ÿxÿí1ï¿=¦fíÚwþçÅ6Œyá_}úñºµk4j|D·ž]ûLJÙÊeKŸzð¾ùsg7l\tDòÿÔ6‡þ¿ÇjoØ0mÒ„ž}ûøøÃÉ[6oÎ/(hß±€Ö¿ñüÿ¾ù쓵kVïРáAíësâ_«Õ¨Š3ð¤ãÒéô…W^»ßÁíÖ®^uÙ€³\σMšïxÑY§l\¿þèþóÝ· ~˜Ó°qÑIgûõŒO?šøˆÚrøi‡p34'MšíxÐ!‡NûöÇS&óÿ;‚’——jXTtd÷^Ýë ¶9È’… ïºþšÐ»)T9SªÈ™R¯~ýukÖLûV¯~'Žóê–-›Ùb2T>C…“Þߨ·À–%z g¨ú÷aÿ<ôÈÎÛ¯òR&ßsÇG“&ätn"÷C·*A(¾oÞÑ`DžRÛ´Ìb[Ps)¥´8T 3" ðØeZ)EŽÎŒÌsukŒW€|}AÞïeÛ"ò¬(%òˆ¼XG"qí}‹»«l­ÉÍîo³¿ÍEDvJ+bº@¨¾˜>íŒ †vþkV­zúáûY·nÛ¶­£¯¹ìW^lÞ²åý",~6uÊÆ ë|èyÞ O<6㣩¢}h³DßM›$ThßÊ™ò+Ÿ)íŽèT§^½ñc^[ÿóºIcßnTÔ„“Uå“+}£oA8O·¨¬êãPé€|†dAçÞÇ Çs³‡nÁÑX¤‡>ùÆ|N…#Îì’£àO½¥Õ®‰æGÁ L¿ +çLiz#Œv#À8ÙB"—Öǹ¾­ÊiB |÷”mL0ÍÕ̘{°|×8Á#E”Òº¡·•RJ?l`­,”‡é“'ò=úó¹I»÷¬ß°á¾µN§W-_öíç3-˜àÔóÕ®[¯¨Yó~;ÓÍÒ©×ÑÍwn`—V{´Ü½Õ–-›§Mœ ”úlêéÔÙzvèÒ½~Æ{´Þw}öM§ÓSÞg“,ß~>cñ‚ùyy©cN:¥zš]Ž>À¤qoo*.žõÍ×Ë—,Уï 5jÖä‚$:vï`颟~œ3kÙâE|÷ 8}ûÅŒ%?-$¢^ýN¬^£fÏãO0oö÷?|ÿ]0†Æ~K‹rèQ]jשÛr÷=QçÞÇÔ©W¯I³pU34')Ìò%‹¿øø#í8ÒµQ£¢&ûp€/?ùÈMŠ}7ÃBFäL©ÊgJ~~A—£ûeÝÚ»G][R¼±Gß+q…gÕ¥è=ÓR®Ÿ¿ݶ.ÚÈ¿9“ ]|@õš¤èõ^µn'âúþB.d˜¥W»^=yfÂ~:^½r€ÂÂjµëÔu=-uw¨o·;÷>öß÷ÞñÁ»ï´Ü½ÕšU«ªU¯áŽ|ð„9uêÖ°fÕJ›dáâ¶mÛ:ø”¬1½mÛêU+×®^  °°ZõêêÔÕÑbÙ±EË»µZðÜ'Œ¯^£€&Ívlµwkk¸EÕªVP§^=βfÕ `?DÔªSßßP­zT~¾MJ§ÓÈØ–/Q¦Ož8}òÄüü‚wî݇ÿ·)¥Æ¾úâ´‰ï¯Yµ¢tÓ&ö\»zu g„è»HÊBÎTá3ÀQ½ú¼óÊ ü¡vÝz‡wéöâÛ¤ V>úþ’3{ çZŸJ¯€|†dI®çfùݪ€]A5e•˜k$Pš”3Èê¤P °³[5iìã^XZ©a1Ékg±‡ùÍûl–€RDüU•Àáì bº:òŒ™Ëе «I“ÑÄ p³Ú™û1¨ƒ¹í("ʬ&l4j  ´tÓú_~Núgliסã‹O<¶tÑOÏÿûvx~~MýeÝZ½ñó:õ6Bäh©ß¨1€ü‚‚{þû|^^à^ן׮°¹´tSIIµêÕùYGK¢c· ~˜óÉ”Éù:tëÎv.¢tSIié¦ÂÂjöj× ™¬ÏóÒéôÖ­[”ï¢X†æ$«“¾úì“—ÿûDaµjWÜ|GÓwzæ‘&}+ÞÆ©á3Nø-3åW>SÔ¨Y³c÷^ï¾þJ×>Ǻˆ²*_¾ gy¢ÅžÂ™ë“%©€|†dI®çfùݪ€gä§3ù4pÅœˆR*Màñ*Á#­Þ0zRñ>El"2¿tT:­3jøÐ³ù=Y=ÉÛqÇ'qt»2V0¬Þ·!ôFPYÆÕÑL@ý"—_¥”RJW@ç7µp2úÑ„íOëƒÚìØ¢%€gy`ýÏëV.[úâ“þ`FˆT~þÝz˜?w€CŽìì¦~8áÝ5«VÍ™ùÍì™ßQ‡.Ýð÷U+–§·m°ïAmšïÜbËæÍ/?õŸMÅÅkW¯š>yâ·Þ`Ï}÷kܤ)€q¯½\¼q㻯¿âÒ¾ãQ……ÕJŠ7þ²nm^^ê𣺲½õmšî¸“RêW^,)Þ8öÕìÒjÝ÷ v5k`æ—Ÿ—o÷úË¡ÔlÈМœØºe ÏËK¥RK~Z8cÚ‡nj¨…ß9S~“3å¤3Ïyø¥1G÷ÿkÈž¹òå«pEN´ÌõÉ’ŠT@>C²$×s³Ü‡nUÀ•Q°0³ÌIa‹¿rªñóç'ðh¤Vu!•fŒŒxi~-Crv.'à`Ë|KpËÕê¦-„íÈ(‘N WÈîú£§n=ÜY;o(¥¶à†õ}ܯB.ð•#Þ.óæÓ¼¼ÔÅ£nyç•>Ÿ>íŠAç4Ýq§“Î<7ìäЩgŸ±¯¾”N§ëÕo°ç¾û»I¶?ô±»Gÿôã›4í÷·3wl¹ €îÇõûiþ¼ï¾úbà_ú¶>°Í°k®¿dÔ-o½üü—ŸLŸ8ö­ºõvØsßýúžr:€¼¼ÔЫ¯{êÁûÞ}ã•Ϧ}xd^¶±T«^½m‡#>œ0ÀíÚ×®«/Æ¥R©KFÝòÆóÏ|ôs @ΔßÝ™bÉ\ùòU8ú„=’É\Ÿ,©Hä3${r=7+÷ÐýÕ "¥ˆ|¦¼2«"e—ÁŽ}2Áù!ZŸYEfÆG}¹È.J)ÏX9HÁ)f†€56|2Ô¬§þÒs.)P &"þg S(1F ";X[€‚Ÿ®Ú£õ%ÅKŠ7¾öüÓnj,ÇMØôz—jak.Ì]ÿÇŸÍSqn½úÒ¹ßÍìÙ·ÿ3Îf‹»’KÐW²bÁ¼¹-vÝ=lý#gŠ Äò›ŸïUùÜ\0on×ö³”7'Ÿ5ÀŠeKJKŠOùé2+«xT‘7yÀÐìº(/e”ji”´n0r‘}#•[˜1VŸÄBãæèQÐÀ3²#‹w9^ )´«›MƬ¸XÒ*Ýfâd"ènª+—/[4ÿÇT*õ‡_ÉO*‚œ)‚P5ùž›¬ •Òp4—@Ùeœ@ž“ªGñ<Î G˜'?ÞUÁ©J«\À±zà1Ìä㼈‹SŠ(úL§¬}‰© úGŒ€áèÆ üQTˆ&ø õµÂÅ ¿=÷ÞxÝ73>mШñ §ŸÕ¸i³p² äL„ªÊŸéÜtuÀW¼µ–t ZâAE¥”âYP0k;?ÿ‡=µÊ¬t#@g'=üÊΜè™õ  µ©घqVS‹Va+HéÑÑp.]ûùcÆ ãj3„ó U† ¯¼6lPÙO&„ß;r¦BÕäÏwn*–— ºJÁO¥‡K­#ceË‘…ž^ 6&qFð/_ê9죓t€€ê#îQ:N³2ÊüòÆÉG­<]‰š­Þ³#¶DAA!k|QX6•¦oŸR<£>•™à -=ö¢„3Ç×Ðcá37ÀÝ37Kñ/'!€–ÜdGH5”¬8£ÖpÞ¤œ‚ ‚ Bnîkg̘c@_:ê‹ÒîV–Eä<6¨u.}•Ÿ¦S¸¸@ '˜ßÙMàñXžbK)+9uº­9ñÔ[âø¡ð@@eÚí¨ôtwãä驳®-ì$‚ ‚ ”‹È¸§EJDJ雜l¢ÙÈ1Eæ$(À#Jç2ž ÀÒþlÕ˜ Ü«öD€™Æ H©!:±®“¿kI’§ÙìÝmåŽ&‚ ‚ d ³ÆŠHO¥ðúUD¤õ-Àc«RH³ v6œ˜¹ç…+CÖ à¬uÐôiJ)ÅS,™Ûå§*¥xt–»¸U†¤hÁ"ãk¬QAA(',º\êyžÝ%"Ötƒè ôJñêW¬T;¸‚š0˜2ó»ïß|í¥çžþ*/¬ðCŒQ%U†¸²bˆˆ<þíé «>íKÿµ2gbÉ“dÂjŸà FUfz>*ÇPD|s—Ò¾üÕ Ü/…³8Pîo0Õbrý—ñäqY›×Æ~_œð׿}ýÍ·akÅØ1™t:}÷}t?ú¸Ž]z^rùÕkÖ¬ {¹õö»ÚÞ©Ýá9¢s8Mª Ûï”).úßf…*¼ÑŸ#9ðHßúºN¥=B^@ˆqÌQ‰ø~Ÿëà;°—ÍkÛBŽ“ç¿¬¾d­Éy­#yžïOäñn°iìÈqŒF'!ëyçâßœàžûþÕ¥ÇÑ]zÝ­—|Òmw,\¸aý†ÖûìN¨Û#¦åßOþ÷Ý÷&üëž;^yá™Í[6_9bdØ#È¥ÿüÇ'S'ÝqÛMáA¨2l×S&3•U´³aÃÆ‚üüp² 9âjµ R< ¥ø·šFÈFÕk9­èÀyDhëŽBš[-µgóƒ—ž""¢QžïÌL~^@ÄÓôž¿ €ÝÈÞŒæŠrrä1¢uÛBf³ÈZ© rÁÐ!L›þñ5×^N*›¦LíÐá0ÏóV­^}ÃM·ÍøâË¢ÆNêßÏ:—”<ðà#'OÙ°qÃûïéÅ5mRôü‹/¿öÆ›O?ñû,Y²´ß_N}õ…ÿ5mÚÄiƒX³víwÝûñ'ŸÑa‡¶>lH:u2ØO=㜇úÅ—_ΞóÃN;6¿dø°ößÀK¯¼væi§¶Ú}wÿ¸pð_N=cÁÂ…-vÞ9É_ª>î)³`ÁOƒ†ücæ÷³6lpÉða‡¶o‡Œ§I»¶mf~÷ݬÙsš¸êò/¾úú™gŸ/..éÞµó—þ“cƞš¢Ï>oPßcûðÐשgœsä‡ùÕסjX6mÚtÕµ×oÛºí¦ÿ»®zõj6Î?/½rÊÔi^~õõ¿Ÿuú çfö¢‹/Ÿ2u5iRÔ÷Ø>?ótþï“ä¿qãÆ~lÒ”7¬ßЭk狆©^½Z†6 ¿-ó~\pÞ !¡Of{`\9âºï¾ŸuÝ 7_wÃÍû¶Þçß<àæM:òc›+t|&§žqÎýò«o¾ÿ~ÖUW\Ò£[Wá×'ùªºŸ¢|ÝE)¥¬ÖÓú-˜ìîÚdÞpÓܼ¤—p Ä ¬t`ë-žaaëî:‰ â½ôe«ùKF7+ÃIw×uð½…ß“§LíØá0W^=²  à•ž¹ã¶›ßp.Ó\{ý -zèþ»Ç¼òBË;_rùUétºWÏîóç/˜=g.û¼ñÖÛt V7¦ËWܰaãÓO>öäã/_¾bÄu7d¶xù•מwî[¯½Ø½[—aÿ¼líºu?ÿüËÊ•«ö1cB»´lQ­Zµ9s~Hò·¡¡*ãž2o¾=vÈçóJŸ^=¯½îþO“á4yÒäáÃ.|gÌ«û¶Þgð°.X°ðÙ§þýÔãðáÔ '³OìYÌI±g+ªÁ¬^½fÀC5lxÇm7Y¡Àqî}óIýûpüqŸL4hÀ¹6‹%6ì£oþdê¤>˜pÛMÿ÷æ[ïŒ}÷½Ìþ#®¿áûÙ³ï}Ëk/?·÷^{~:c2¶QømÉüÉ|ãõ×î½×ž×^uù'S'…+’üØc€‰ŸŽ×Ǽ5xàyï¿ûÖo+X³†V3½Âã¬6Éßµ;°#¬œÄ:Ѧú Aƒ[4Ï1ˆ† ÇЮk@xî +éÚ2z:xC8f´ˆ¨EøñËúõß}?ëÐöí-^òù—_]vÉEõwØaÇæÍ.¼à|vX±båÄI\}ť͚5­Y³æ…ƒ.Z¼dÞóëÔ®}ä‘G¼1æ-J©7ßzç¸cŽÅ´¥X¼dɌϿ¸ìâ‹5lXTÔøâáÃ>œöѪի“ìœë„~}ns`Íš5Ï<íÔÆNœôÁÆÔª©§Ê¨]«Ö†“ü­› TYB§ÌÉ9±õ>{W«VíÄþǯY»vÕª2N““Oê¿÷^{Ö¨^½Oï^%%%Ç]X§NvÚ±]ÛƒgÍšä³8Z´K´lŸ÷ã‚¿ŸA×.G]~Ép{-%CœIaxž·ç­þrRÿÉS>Ìà¿lùòÉ|8âª+vÙ¥eíZµúõ=¶c‡Ã3´QøÍ)÷'sÒ‘{ p–èñ™ùØøKÿößoßÐUÁ*‚¹æïÅB(ü"r4ž‹v`‰É××Ê#E|Íœyð83Å ú5+à”ÅŠ‘wÈyVŽX5ÑààV_+¥´›Ò`psDU)A™ÚÆ9¿¦N›~àþûÕ¨QãûY³«W¯V‡ؾcóæ¼±xéRG×ßf°té²ÝwÛõ¸>G_sݨ¡C}ñåWë7lè|Ô‘œjcºY–/_‘——gbwÚ±9KKKcí 4мYShÞ¬ÙŠ+kÖ¬ ÀŠTë7l°6êow¡Ê:eêׯÇÕ l*-]¹re†Ód‡´AaAµj…và³° `Si)2žÅ±g+­ï¾>æÍzuë¹Ó‡iBbÃŽŸ0ñ?OþwáO?•”làÎê‰ú¯ZµÊó¼›7³>ÈØF×"ü&”û“9éÇæÍ›£Ç=>3Mªö’€Nà+/À¤’‘a ðÇP#9©y”qv­žoç¶ø~)íGD (ÓRÊMŠŠŽ<¢ÃuÿwÓÂ…?mÚ´iæwß_rùÕ›·lày^ŸÞ½ž}á¥÷'M¶ܘ.Í›5;èÀn}תի—/_1úŽ»?ì† $Ù9×K¯¼>ãó/Š‹‹ÿûÌrÚì IDAT³ËW¬<ªSGýûõ}ê™gçÌ»zõš»î½¿ÍA¶Øyç þ‚P•I:e\2Ÿ&e’tgSt”¼TÞ¨‘Wï¶Û®ÿcÍڵȮ (--UJÕªU+•ŸÿÍ·3Ÿyö…°G&EE;>ꆛœ¿`Ư¾>惧&µ1œYø-(ó“¹aÃs~˜·mÛ¶=éÈ=8Kôøü½IJ)^ ØÙD€2sBÃ/""¿)Xêé ZÃjŧe v‹­—Îå¼j•~ñ£ <#@g«„‹Nÿùfê*<ÿ¥Š%4i €ãDzF¬Ÿw¹&ˆÎª6_|ùuãÆìe—›F,.)9þÄS.ºøò>½{Z·ëF\Ù¢ÅÎC‡_Ú£OßÛî¸û˜>½ìB6Çõé=ãó/š5mjÊ Åt¹iÔÈêÕ«ŸrúÙ§Ÿ}^£F®»æªÌv'ô=ö_=ÚûØÞûî]·ß²C½zÎ>ã´î]:ºð¢¾'žœŸÊ¿iÔÈÌþ¯¾>¦Ýá†_rE:æ…Z+þ|/A¨,2œ2.N“lˆ=‹³,:ŠçyW]~I»¶m ºbÅÊrÇaš6m2tðÀ«F\wT·ÞwÞ}Ÿe”믽z·Ýv½ð¢‹ûžxòwßÏjÛ¦ ÚÎ)üÄ~2»œñ·S¦Nû¨ÃQÝÏ>oP()éÈ=˜Ðñ‰ßí±' -Z˜P J©tÚ¿=‹^èYÔŽÒ£‡–ªÁJV‚®Ô¿Ôâø±z‹õ­ÎçÃÞ¾À (g×ÜÅ‹ÆrEÃÇD¤”"€‡v8ÎÄ ˜ØÝöÝà=ZPR¼±¤xãkÏ?íúÄrÜ„M¯wñ§°¼ùöØÛï¼Ûµ¼ò³ÑQýÕ«W·l¡Ø„rp×½÷çç x^8¡TbÌSÏ8çô¿ýµwÏá„rõ„ª@%ž2¹RYEWVAøÃÐùõÕ±ò&ÄÉg °bÙ’Ò’âÓæ_VvhÓŒØó=) Ø™:) F J©´µ)å ¿Ez ÔϦxÇHL§*Ä©Z*½$–^7€ˆ«ªeµ5QÀ)AMò @O($Æ„ÕßËX[$½èÓ»ç„qo¹¯¨`*NÒ7a{Ä„?0¿á)SYEWVAøSã0Mt¬”}_®þ“¾  ÌPXš!Y~YJÄôý çÕš‹þ´ãÒÊ ‰Ê"¬†àVúÏOœŠ2Û¶,«Ôp€´„SÕ§Ùl•%ú.t%§0žÝoÛj˶-Ž›#‚”JV’…´â£No'$G—C:$äB¢ÑWZ°z<ž<åÇ­qˆÈÚÒÔÕ‹ïý<OWàËu°¥3úÕ!m»#«ú’mÅF[õþQX9JëK“êø´Á6 œ–SŠFWûwÁÔ2èÔ¨¼|ÎÒqj{€zŠï«=žU rOáY›¨ôwôý£ÇãY´kaJ»–v*ºŸRâ¬NéIê†|Ê^*•c:hFŒTX7@J'X7ÊA‹ ¬Ì-é=K-CÒ…ˆMöV´(§›RIÜx>“äþܾŸôx<+‘/ÓÛJ­ -Õfùý‰rµnîw;ù 2…Ç )Y7ÀBÍAZG•©¹Ô˜¼¦.·ïdìúCÃÖÌÄYó-ôx<1+,UWÔÿƒHßÇ»ëýâÓÀ÷–§³0ÞÌw¹¬ —IÉØ€¸cÊW¡$ªÏÉÖ2dIœµ´ui‘©ééo%mš¶¨¿{H¬h!¥ÙË;,×Óãé^,_­.×Á³æSöX¹3Ô³Â÷–'K9Åø‡fpKIå1€ê·Jh¾XÚ¸£ŠQU²¸¬C\qF³’,½ã¤†t)厼#ñšQ½ú¶¨tÍžqŒÝ4¡ƒ·ÊãéF,GªvœšÐÁÐø5;ª{R¶M‘~gÊyú°«ÇãY¢2TToÙNÉ®Ä-•X§ES~‚bµ –€]NÉ6 0Ïšt‘vÊ¿ÝKÓ¥U+õ¤j¯ [o“Yñ©vAܬTûRC[u{9æñt*ʸJö5]›zÊRé¯V®NzÊ´Õ"~6«Çã)ƒ½ïLRŠçük‘é7²II ?+t¬Ô§¡L¡™1´®LÑê ™hʬGÊRZf‚ÍžÎE €’¬È¶¾t?_{i<Ÿ1Ö©æ={Öö©ZÕ?ô;Tï3<È[?«”¿æ¥T°j2ªY‹^RbéÖ¯Žÿ².±ôL*60u\ÍîC×Ü˧3ÍëŒOgèªrÁãñ|*tRÍÒɶ'¨ÚÌ÷@eû“äA[ºkÿ[o"0þl²ËLYI_•ú¥*fâ S Š¥jú§~ùw»Ö1Î{Æ”¬6{Üñj ›RYÜãÚ’O.aEýW†2ê-cIÔªH¾w)Í e¤B(±»`ûIû¤Þí“w†ÈIuÈjÈÈÖÕwù,­úŒçÛò +Èÿð<Ýœ-û™C7 7ïcZŠòì¼è¦íK yŸµ…T7¡Ÿt6º.Å~gΉº±‹ ÚoÙâò©9’¾­bo/Dún|˜ÚIå^^Um"듦,W‚”<‰ÔwÄšzÔ1 Δ/gUøpÆ;ß{÷[¯¼ÔÒ²lÀ Áã÷úâ>\ÚTO—0¢{VaÚ'])XWG™1¿ÞþÛéí;4“·ªÎ§•cEýW˜¼tËìZaסT•\j¾À5‘(ŠzþuwÃþ‰2ÉÔL›p_ô“,ÖàvËÖÕzùtLWUÝUåx<+Á76 ïø¨0ý“h` ÏÚ²ú˜QUW½¹V~}J«®\±¢Šˆñ”M÷ ¤?€œgº‚å}$™¤ë ;ð–8’ 2H FщYª ˆÎÞ ©çwÁm a% ­ž$´`Ðh&5$íÚ ÈŠì.à®?ÿqÏýüÖ1ÇÏ­¯¿êüsî¸ù†b¡ðåC¾‘÷ótãÏÏ‹D°N5'nQ5¦Ÿ™×"ÌJ¾–ÖøÎÆU; 4=C¾¹(ºvZ{C‹ì¿nðÅáÁ)ÏÙ`Ì:þn§š O·6´HºÌ4}«9aÓp›þ‚æGx§°¸]:°OWóBSqt_3²·™½4úíôÂ[F‚WÔ¿kÈëËÌ®H,Yœ]œŠÍ³…äË\IšG‘äö\ ƒqß(j۱ƈëˆuO@¦/Ÿ=xÑvÕ›ô1ó[åwÓÛ_š¡ÃKæÕÅM{›z›Æ™úVûè~æ õ‚º€7=­]Ë,{EkýqÕé±SÇÕ<7¯8º¯É5#¦&À™cª qÙëm-ÅL9ÖïÉKÇVç®Ês·©Þa€ ±E®/ÞöAA[°¢u°npÐúaß*ÎX]÷NaÆâÕÉ{V'7Œ¯¹ê­öWæGÖðúñ5ß|¬eI*JÚ™à'/Û¦ òP}áÀuóc,×XTpÅÛY))G£ŠÀª±’ŒzQN1Ð" råÈ]Mq¥eç`YŒÕ‰N-ZHÛ \§H÷ƒ€ ”j‹ºa $HÖ„W´ ’Dw5£±ÛÔ¢mS2•šÝm¯*“~rþVcw¨ëÑsÃM6³íX/=ûLÞÉÓEŒhþ;/pÖ–Um‘ót믶í5,í~êèªáuüñKmG?Õ2sIôã­ªHügN´^³Q/ûGßkhðÚÂ(õÉgËLóÃ-«z„œô\Û©Ï· ªá©£«:¶ØwDð§÷ G=ÙòxCtÞ6Õ}—7'lEýW•¼hKví­sÑ‹\H$éýtD‘}Iò*JTëš}iÒó*ó–Ïø«ô/’üQìŸ/þƒÚ¿¯ž‘H¤'†þé-ñ©’ÿÀI_>{ nšQ8ò‰–GçOmOè.™¿§pä-Ó>‰.Ø®zDžü\ÛiÏ·Žhvd/ê²W´RöÊE…f(ëTó’±ÕM­rá«V°"[NÙ«òüWÚüWË×m¹øµö=‡» I:œÎ×5¢Þ´êço´ëñ–Þ-ì6¤Ë>ƒLµH]]ëB×›Qû55»SM`·]ó­T}éLи]±nB{3 ©2™Y²+®ÖÖbsñí<»ŒÛo¾~ά™Að#òiž®`ûæÍEѲ"6®aK‹ÚìŸ{ö2»1¤Žn_g0¤–6Ë#³‹§®ºá]Œékz…|ªÁ~DÅe¦Xâ ÄjùƒjYmPÖ¾ MÌqÍ0·EÖ.ç[QÿU"dµ8Áj¿Ù§Ôª±ÅÛjµåt\ÚšG±X”híˆ^t-I—ëþ4ö—Ú]ÿ,ú ¶©yÚ€FD28`ûæ…ÅøòYè.ɶHT ¨p)é%³¨ÝùÑZDølPcˆ¯è²W®RÚ eïaÁ'í¸fFäÊ){U޶A0¼‡© =Œ§óuÍ]&W¼ÑvÔ&U}ªðA³Üûqáýæ5ôzñ¬:+z|eÝà#߼ܞ>×d´ëH¤˜S}eHkPÝÌv$ÌÜ&-Q ¦þ°õªƒˆÚRÒ[™Ñe [ë*iTÖÝF‘Iq÷G€"‘JU’.“QyIý „­;‚¸±=;ÀJR@G»ÆR] µ~Z~…7vU¸û/·Û˜oCŽõï:lEå«DuNÒЫgÕ‚ÿoMk¼tdÞè)ËBÔL3¸-"h$2(+[íGÅŽå.Ÿ4•.¥¼_:¸¢Ë^¹sÓŒÂØþæ‚íª§¼ÜÞl‡¤æË)½*ûUóÌ1U—¾ÞþÊü¶–"X/,{W7GÙºž›=7¯Ä†—Œ­ùî“-­+vž5‹¶5î\èëî(+tºAxÀzÁäÛ>Z’?Ï×ÒM.Ó|:ÉE—œŠ9 è4_%Ü&®'&5x? ãµ®h—€u›&@þ´ZHjKc’,$Ä çŒ|N¶­ôÏ4Âæw>V/¿Óé<÷Þöçûo¿µªºzâÏÛ|«mòÉž® Æ07Í(˜³LÞZ7*¼vZ¡.Ä‘ÛAë-òì¼â)[T]ÿnû¼VY¿§9lƒàò7ÚÛ#ˆàÑ9ÅÖ 6ím&¿dǼ§ËL3g™¼±0:nTÕ5o·ÇŒªz¡)ÒÈP%;€}G/Íf,Žö¬å3Ë ì­¨ÿÊ“ f¯æ8É^±D&iÜfÃ!ú÷OÜ<݆¦¦¦Ih¸|Ö Òù¬¶ïŒ»g‹äØææ…’¤„.¥ÎP銎¤ü•Û1EÁo¶Ÿ¸YÕEc«Ï}¹mQ›”ö¥WeMK RlÖ×´^Йö—Öµm³õ:æáúâ¼V1DMPþsÔ³ñÞâh¯aÁ £ž!¿ç>†”ΟßÙ(Ü}hð£Ûê—.ÿ¼ZóȪµ¤ôý¬Iö­>+ɪ!•3D'Ø +øJ!ãO4ׂLzB˜Ñ’®yC•¤á´1×dW‹'`¬Q«a F\iC¦–LUñ[B".Ž!bT04ùÏíUâ;n»÷¯«ªN<û'^°®>F÷3óZ“›Œ—½Þ~ÒæU¿Û¥F× ÕÇ~ ¹òÍöÃG†çmSݯš-‰þöA¡ÝIÁGfÝ üh‰Lw‹ÚäÊLsÙëí?Ø4¼úsÕ¼Ôýþû©VÉà¡úâw6Gö2õË¢ó_iÓûžû NÚÜN:¹gÏZß~¼õ“vY ÿ®ÅÝÇý‘¾hñ‚µÛ2`À€~~$ú8oû˜øÎÓ#:¸|ÒtpÉt†²WôVëtªêRDpÍÛíßß4¼tlõO^jÖƒ¹rÊ\•í¸ñÝ™cªz…œÑ=ÝXܼo§B¹º^_mÔÛütÛê5œµT~öz{<³–rӌ¤-ªn_;§E˜YئæÄèÌ Pà° C×îdÀ´G8äßkÁ=.•cñ•C@ ú‹Ðå ìv©àJ¿MÙbrö!˜D%í—…™=‹{Ü+⟎¤FnzøÓ6Zp²×’nuÑöG“ð§ë(©yiˆˆ$ ‚S¬³ÕÛZ¾¸â ¨Ò…;FЊó€…XòÜÁ£Æl³lé’eK—Ü}ÛŸl½•9ð_-¿Ø±Ì’™'þµB{f5µž½{_yã_Ò çÏ?†Ÿ›µò½IXܼ‚‘•ŽéÂ2§Ž«¹ó£Â¿çtöShEýWžrAV7*@¤*€ ŠD"ˆ\¼^ýöc·Kåòt/^xñ¥<$i`ŒíT €ÚekO~ÔÆaüc|ùd?cV+]uåvU9ž5ŠG°Ç=My«ðèò&`{š4DÒ1‡ï sê[—-ðñfUc¬SÓ¦2‚X5 ד¤òTÀu2ÔBqq@‹Øá¡j-ŽrÍЪC„Ð6VM&R€è@Uãª#õ>ˆõ¯ãö "°žÚ踤Ñ:´0nBà&oéÐVëF& ]Á¯o½3oò¬Æ ºüA5«£Ìµ 'bi›Ñ¸žîЏÛýb¿ýÛî<ÅŽƒ_¾ý¿Q{]uåvU9O÷¤Œ”*cJ“$'*®CÔÉ.±¯;Ù…Îq¹ ØA;ž•´ÁQ›“N)ª“eªF[‰jH œB4ÚJ2V¢ÔB2‡ ªæNîUéo ¾ ‰sŠ5ŒÛàY‹8î™Ö¼i•Ye®Y” ™ «îŠŽ ˆl¨ÕÓí‰AŒ~T@ì¬YÑTGœðlkºKNdîê§«®Ü®*ÇãñY¹¨Aî#(Óad—"‰=ËfT¬|ÌYóØ/Ú¢BQÿ•C``0 HP×F+C‚va]HP% 1ÆÐ¸Œ*];0†Æ4a`@C4&Yl€v‰VûŽÒè³ ˆ¶Ðãé:&=׺B7úWÔ¿+HõV¶&vU®:P q[K8îÄI÷Ýÿ`Þ ÌŸ¿`·=¿´hÑ¢|‚g¹¸“ÁÝK0™3dí;[<ϪSª™¼¢ËXG•tiÿ6Óe8 èv·|¶x7‘šÎ tÖHÀ¤^!­aG—¦1T¿ê*¯Öì6ì/£×®`èæc¹ÂãÒ ÂPàä)a³¥6´D-Vbñíñt?RC€Ü®ˆDÇY½ ñ@DEb@R¢ˆÆ¸PkÊ¡¤‹÷x<݉5[yT|)O»Íò¬Œi¹ Ê.›› Ñ{î•¿Tk+BR@ûj×–tpd–Ð#SŸX×ûÑI‘PÈÔÁ²éì©rH-H‹íÿ¸7“Mí.Éãé”^ºYK,U+Œ xíõ7n¼ùOo¼ùf¡PÜpƒõ;ôà/}q¯¼S×qÆ'?÷ßçãÝq;îpÅÏ.J¥{V3A×ZÉßñ/ý¨*µx<žÏ>àH}wMú§É@º­<õ8…ê6›'mÍRO±JN@"‚“°HFštëÒ%:-’Ö'v$tÇþSÝèÖHa¥¬©kcé¬0*`è4«Ëæ¶Ü†}Åm¤ÆZ ``à‚¿©£ðxºîÊ@ÄCZË xæÙç&Ÿ{þ·øÆYgœRW[ûÔ3Ï]õË_Íž=ç{G~+ïÚuzÈ×N>ñ¸¼Õóé ""îqX»î•öy!ëñxºu±ê«@îs¦¢_‚*¹JŽ:î>½«“÷‘µg„ B¨rT%©²×˜ªOÒaµIâ©ý&3l@ÄcâŽ2…1™©z0TïŠÓÿÚâx ­’b<žnDê{jþ"¶#YU¶æ’D~1õš¯ì¿ßQßýŽZöÝgoC^rÙÏ÷ýÒ‡|ô„ãwúܸW_{ýÝ3FŒqÊĶÚr €eË–]÷‡â©æ%K¶ÞjÌ©“&2ÀÑŽßeç^{ýiÓ§è?à”“OØq‡íÓ5VbÁÂ…W_síó/¾Hðsãv8éÄãúôîóijšÙϯ|åÕ× tðAÄö³óNŸ{íõ7¦Mç¬ÓOÙkÏÝã,Ý+XE$÷ðo þà?<Àãé®tpíÇέ"UþÞ]Åüʦ¦¤$-:qSµ©/ÚŸ1eJ! r/8 hÇ’ âPŽ]ËZìáÙOV’Æ’0Æ00&Œ  C'l™€AÀ €16gc4•¦”J‡àñ|V(QŸ@&¶*T+áÃ>ž3gnn$ÀÞ{íaÈçŸAwï¾÷¾ïõÝ;nûóž»ᬳÏY¸p€‹.¹|æÌY¿¼òòÛÿzËúë¯7ùÜ)‘kÒCÿ|ä¸c¾×ýÒ>{_xñe¥B¹,çM¹¨yÉ’ë¯ûÍu×^3·¡ñ‹/Ë{çQuuõ_n¹ñÒ‹Îð¡‡c{¹ÿÁ󃣼÷ï{í¹{ìïܘä$‘r'HŠÎý=ÏZ°ä•wƒy2ZsEq‚ÕÄ¢TÉ”™Òše?Ól8Sâázuf•U¿.M*P3VõÐÝxýCà   ¨’4ÐWÀ #\– IDAT0Ah‚@ 1*\[‚ %q-éŠ<žÏ4©«Ö©Š¼Ltê¤ô_¸p!€A¦Æ˜þýû/X¸Pw:à+Ûm»uÏ=¾õͯ4ð±'žllœ÷ØOžuæ©Ã† íÙ£ÇñÇN¨ŸUÿÁû¨ÿ¡‡|u‹Í7«­©ùÚA,X¸p^S™Ào¿ãÎÝöü’¾â©úÙ³_~åÕÓ&4pÀ€Áƒ2ñ„gž}®©i~:ˬúÙ¯¾öúi§L\§_¿Ç;áhµwܘƒ¿zЖcFû>!‹%’=O’Ó&cÏŸ3ç³ ]<2Öv*î:£¤sÎ’÷«Œ­Å HM,IQñˤ¶Ë¼†ÐQvÔ¨lµ2!ô_úx]»‚€õÔ„Xl%®ˆØÒl½Ô§(ñ–þ²_Vä Jóá{ïæM¦o¿þeŸ?áñ¬&by‘ÞÐm‰¢(þY,£(* Åb±X,¾÷U¢J¿~ý4Λ7hP"[£(š?þ:ýúéîðaCã¤áÆ66Λ=g€ƒ;"¶˜=wîFg¬©©ÐÖÚ–vSrãY_~åÕ †¢»#F ÐÐØ8`@ò˜ÙÆÆÆÚÚÚ¸ðÇëFÇ2dpÚîð·½ûAA†Æ˜ èn|éOÀ~H¨é†Çó?ÄÚþ/`îëkÜÄ:PI;%bͪ¼TÏ¥D„€aò£h7uöœ¹qRýì9ãwÙyÈÁ†¼çÎÛúôé'­ ƒ*‹s†  `Ö¬zƒ Jû 4¨¥¥eÁÂ…*[ëgÏV{ÇYÉî {Pöô?’Õãéöä;«÷Ûc0­)!ö‘ÈÕ|!кĖE2¾Ï»fš’ìdªÎ5Etj¿m3:†•TéIR1ì\«xj—b•¨¦’ÔH«E‹#èÜ$‚H’NRËU Iƃ%í“·<žnC©T-éÝ´›BrÒÉ'Þwß7Üôdž†ÆO/~èáÿ»ò—¿:òÛßÔiLî¾ç¾—_yuéÒe·Þv{ccãn»Ž2xðøñ;_ü³+>ž9³¥µõíiÓ'Ÿ;¥½}埓9|ذm¶ÞêÊ©×45Íohh¼êê_ï4nÇtÀˆáöÚrÌUSµpá¢úÙ³{ÝõjïòÆ|æ‰O†JçIÚÍãñt7èœstrUdžZý©wçÕQµ_etP¬…tT¨­vê>EBc•£* :$#NíðÖŒ gͨo’ð4nå’Ô•ÿbV¡«0uǦ[:ÎŒIÂ@ô°¬sR&੪9"iÄh О7ãçñ|Ö({Žw`Œ–õ¿óN¿¸âÒ›þø§[o»£P(l¸á'ŸxÜ~ûî;ð•/_÷‡ßñÞº#†_vÉ…ýúõ0ùì³n¼ù–3xÎü 6¹á·8¼ªª*)tÅ™rîä«}í÷~p‰q;î0ñ„cóÀOÏýñåW\uø·¿«ë¼õö4µwyc>ÛÄgBüÓv±YŸN=ÏgÜ•®Ÿz\ VÅetjþÃE]Ývz—ª@Wd+cᤜ Þc·™ÕEtdi‚QÑ9zÂÛÎpjÒ @˜Ò¬$iW ¡ÑP0†zŸªgˆP ©3² DEµ«Dl¡Z¹­@¢È¨‘… „sîûü¨1Û,[ºdÙÒ%wßö'ÛœÊø¯–{ö¬Í[;MSSÓ†¬Ÿ·z<«‡´ôÌéQ݈G²êÏ4|ôñöc·‹³/—£'ø×Ýgu>bÀóiò‹/m¸þz:ž5†dzT«ëÑ“8{zÛãñ¬ùìqOSgäÍáß;@ÜúÖeKŸyQî:WQo'§$ ®töÖ 1 kÇX ¬¦{›Ô O¦«@÷R‹žÐÉ¥¸¦‰ºi}®›KyÔà®bJº5 IcBDúy $$ÒÒ\!i-PIM„DÆ0 DÔ!©ð°§ûÖµ=ݲ§øªÇã B*oIlY©šC“b=VÞS¬X)˜Q¥º­5щH2¸qÄ—@\# „d¨ŽÎ¨ÃYC•¼é´q^Ú;ûBès°R$€††»ûotà 1D`´‘ªgµ4Í*¤DÐ5]µ+6avÇÓ]Qu""eeЧ;Ÿ^­z<ž é þ ˆ¢)<¬°SMªÁVy9M¦ŸF¶Ý  !lÐTÕj’•´ÑVð Ñ ••Vñ Ä -jBmšûg+™üDºU´ZT°ÚD꣱Œ\!~–‰ˆ1 ‰Šˆ$Œ iŒ„vÀ¯R¤Zi$EQªIO7¢c…ZÉÞ1×_÷›¼É³–SéLP;Iý™Oöx<Ý…ŒžT=諪ú˜8¥±ýŠMq¬³v;¤–8] ŠNz]mšQE)¨JU! @d+‰íê# d` v²•6™ iPŸ @ŠhY‰2hÍ4 hÒЀ0ˆ Å@‚@h$ ˆAV¡º¦ªº:¬ƒêÀ˜€AAƒ pÍhkÜñGD£÷lû=žÏ2e•GŒ¦vìãéætæ$ñÖãéVèõ®â ö¦¼í+K8GLå~#N0„C€„DPåJ’B‚N.kéÄ&ÇÍ£»@ˆÎ ²“zt*éä«-—6•1a„ATU…ÕU MTm UA{MØVWSèUõêQìÛ#†ôØlÓÁc¶²õÖC·Þjè›­³ñÈ^ë¯0°¦w0HZZŠÍÍÅù ÚæÎk­Ÿ³tVý’™³–|ðÑâ™õKfÕ/™=§y^SKss¡­­(QGý¯§K8âÈï?øÐ?óÖ5†ÕѼ£&×=÷å­k•âjžîLÙ³â»ß?öÿLŠ»¦±:®ëO“µ·ñtSòs§l€°_U“9K ìwýˆC&°*Ó£ÁN$ì"§†&žñŸ.Öjg „I³Š½íoŒDDÚ¨† t(«1A` #H!`T²¦Zªª¤º}{õêÛ¯GM¡)Q{[[[-’æ%Å%ÍËZZÚDH¤oˆæ h Š€V$Ú ÛŽ³õ|v9jÂñ°ÿWüJ>á³ÅÊf© ‰)«Q<Ý5óLX¹Þãñ¬&¬ð*G9» YpÒQ (¯Ç¨ R"b5+Õ®U£3÷i s"PLÙºÓÕŠ!v €*YC¦ã¬ SêxVRÂÕ¡Ô„ÅÚ°P¶÷¨‰Öé X3bxï‘#m±ÙÐQ› Z§M{{¡¡¡í‹_|iÞ˯Î{ý­¦wÞoš=wÑ'KŠ©)¢®­XÕ.5©-HmµE©-D5…(,Hu1ª*HuAªÚ‹A[!l+V·G5…¨¦­XSˆjRGâébþÆ·^{ý¼õSA«¾áºß¬âÛÿð:Oç³ýÑA’Ç£èIòÍ#~ãÍ·Ê&­nºÕuíéæyô1÷Ýÿ`Þºö£1Nè÷N#pRS€Vz2I›M!úÄ=€ÀÕHJ`@-"´TäjIºB$ hƒÐ˜0”jÕÖÕU¦ª:¬«««­ ª«‹QTlim­ŸËÅŸ´-YÚZ,JQk@]*ÖŠm)ê&)Ƨյq±SäÖ¼"ºá¼Šz«Î¬úúnºå…_°Ý¶Ûœpì1vë'øÑGÍ‹›ÇŒÞ"Ÿ°ú骪»ªœ5œOGmx>|ëŒS‡ ’«:}ñˆ#¿¿Û®»¼òêk¹fÄ´´´L>ïüb¡xÉ…Sêêjãrnÿû]wß{ÿŸnúƒºÕ×ÏþÚ׸ëo6lh¥CHóåƒùé9?·ãö÷ÿê¡ÿúçý½{õZõÃŒÉfºØŸüø‡/¿úÚ_þú·¥K–î½×?<ãT-¶±qÞÅ—]ñÊ«¯4ð öŸzõ¯ïüÛ_z÷î•+ÙãÉñÔÓÏî¼Ó8=‹>úðã“&þÖ´é8ãÔ“ãëúʩה^«~ÂwíumŒ9âÈïße§—_yeú;3Ö[wÄ™§MÚfë­P¹ Gùý]ÇïôÊ«¯¿ýö´É?:sþ‚…¾õ¶ n¾Ù¦§Ÿròæ›B‡ÝZÙvžzÆÙO<õ4É¡C‡tÀþG÷;ú¡îY¹íö¿Wú,X²dɵ¿ûÞx²yqóÞ{íqêÉ'ÕÕÕ¦O˜/î½çëo¼yë-7jÞ?žyè7¿s×í·:¤ìyøãs§¼õö´)]:å¢K·3ú†5uU–ÒÓUƒ y+€rÎY¥ë5wÇßå¥ V[ŽÆ! £&¸8ŒÚÙ ¨¿ËàŠA@cL`L€0`hP¢w`pÿÚ FôØdƒ^¯¿ÎÀ~aMÐÞ²lÙÜÆ%ï}ÔüÞG‹?ªož;¯eQ³,k«j‹ªÛ¥ºÀª"‚bÄ(bTôE‰t'R %¢ Š‚+@$‘ˆ1BjÔ¸k8þØ »Žß¥W¯žƒÚ¿/M›þNÞ£›ñØO}~üκ}ÿƒt±Ýwçþû~é¼)é9ý£s~ÚܼäO7ÿáæë7wnùS.Šó>úŸÇN›4ñ÷ݵå˜Ñ'N:ýÃ?ºõ7üñúß=þäSÿú÷cêsÞù}4sæo5õ¾;ÿ¶áëŸyöä(²ßXÒU§)Û ¥©iþ1'œüð£¿Ü|ýMøíãO>õèWŸs~zA¯ž½n¿õ—]rÁ?ùW¶§"O>ýì.;N·xè᎛ðÀÝ·ùKûüôü‹õ‚úñO¦47/¹å¦ß—^«xÂwíu­Û¿óîã&üà»oÿâÞ{N:ý‡ .D‡m¸ç¾N7n‡øûXéyxñùçm±ùfçM>û¿Oýg¬“Ö¨Ô8¥þÒíN@ ˜ŠD u0€1©m€¤ÎéR2TDÕjJѺ†Øjl8ÖUBk1A„© QkÂBmU[ÿ¾f½á5›Œì5rƒþëôïS™Ý¸ôýÏxÿ“™³›|ÒÒÒ*í… (a1 Eª*)ªT5@@ EŠˆhÕ·6ßT‘Lc4Ä«ÃiÀÀÆ  ÎÑ¢ºu-MMMÿøç#ãwÞ)ŸÐødñâ·Þž<ÿú¡cFoQ[[{è!_¿`Á¼yM³êë_|éåžqê ‡ |Æi“ž|ú™yMMÖÿ°C¶Ø|³uuûï·ï²eËN›4±OŸ>ë­·îŽ;l?mÚt ÿþÏãçüè¬áÇõìÙsâ‰ÇÍœUÿÞû”V¦´jïý>ö„½öÜýì3OÓ`RåôéÝ{·Ýv½÷¾ˆÈýüãÀ¯|@LJÐVå0;`¹ÅΜ9ëÕ×^?mÒIýúö>lØ1?8*_„ÇSŽÅÍÍÓ¦¿3n‡íu÷ë‡öø“çNþÑÈ‘öîÕëkðùñ»h–ø„éQW÷å}÷¹ãÎ{´µ·ßûÀƒ_;ð€¸äÒó0NZãqr°29Ù*J*bHØ@©±rÒªàøe@Ø1©úŠØ1ÔŸ‰_üÒ÷ž¿`Á-ºuâ©§ßøûßÖÔtÓu â©ôYÊ!ƒ‹Å✹s‡à㙳Ԙ÷«À°¡CŒ1ÿ¼ÿî¾}óãG—[u)?öégÿ{Òɧ]õ‹Ëúôî­Æt9Ÿ·CuuõO>ýèßgï½ôÏÚÉC¨­©iu¢ó,È&.‡sU4pàÒeË.\¤Åê‡4à¾þŠˆ»»ºýØíâ\žî†~cIŸO?ó\<0 ,¼(*ÑÁ ¿:®kõîä0«¾~·Ïï  €ýøQ>¿ë.Ÿßu—(Šzø‘ ÇŸü{ÿ¾¢‡?þ‚ÉçNùÙÅçÛaûººº[o»ÝÔYÃ)ûY0lØÐ(ŠfΪ×o)iÒ'ÌÈ‘n9fô½<øïÿ<~À—÷ Ã0N*=±<·¦ bc(={\dSc©êbŠv[ ³¡²dßqjRu @†ÜÇ™SºcË·¿Íú#zõéU-Åâ’æ¥ó>ùàãÅÌZÖ0_–´Õ¤G„ê¨h¢bT(FŨXŒŠÅ(Š¢H»Å¤WªCDÇhkÓu»¦À> ÎÅ=Ö®7kG±Š!®>'Hèßÿ[ßüÆÜ¹ ³fÕç“»ÅbñégžoŽ”eÄðáÛm»ÍeW\5¯©iî܆+~1u—?×ùåÐ!CvÛuü” /ùè£[ZZÞ|ëí3Ï>§­½½3U—„Á?=gã7:îÄSTVæÊ1Æì¿ß¾·þíŽGÿó˜Þ B§aÔ¦›Þsÿ‹››gÏ™{õ¯¯Í¥vL¥Ãpá%—pòiù cÝuGl9fô/¦^³pÑ¢úÙ³÷ûòÉuîéÖ¤Oƒb±øÜŸßy§Ž4«^—ÿ|jÇE%*ð«éºpÇ÷¼øÒËK—.½åÏ·ÎmhÜý Ÿ¯Ô†¤\À³Ï=ÿ«k¯ûxæ¬B±X,F­­­‘H'û„˜ÖÖVéÕ«WXUõúoþùÖ¿å=è€_ÿö÷ûpðƒ=|Õ϶N¿~¨Ð†¤PÀØí¶éݫפÓÎÜsŸýÿ|ëß.¹ð§=êêй>!fذ¡'ŸxÜäs§ì¾÷~WN½Fo4{ÖpÊ~œÞ9o¼ÑÄSÏ8èÐÃßz{ÚcǦr$ìþ…ÏÓp‡±Ûå"²eÏÃ#¿õͧž~füî_½{÷:÷Çg§g_­í¨„RÁ©ÿB:ý»¥µ–Ýt^Ü Iâr±qAt 0•LUÆéR ÍfS€a¬œã5G|£_¥s‰“ÒH¼vU\¤Vdÿ 5›ªt«M g`@B0ƒ*cŒ¡1§¸#{d¹/Ow¡oß>œwŽŽ ˆÉ;y<Ÿiþ|³} ‘Çó)ðä¿Λ|ÎÃÜHÑÌÚŒˆY­«;UºÅ£òžPÝ—ìiàñÝüH]’Ë.`ìJ. P¨KTÉwˆtÍq;ÒùcÒ­LŽ07d!¬±Y o i è€W’aUÀÀ˜óϼÁüwÇãñx<O§°ºŠNU¦‚È(ÍrdEY¬Ø“¬~+T(Ã’Õ@7,Œ#űþ޽`5H©ñTY«2SÛD$Ð7†€ãuEˆÈÀÀvr@$\-B QÀ†®uùz=Çãñx<§‚8MTžS´é½•§T¼%%&âQ`W§¢Vi+öN=a¾°lÜSt;ãï’ÄÅ•­­ô! õ4Ø®ñƒh#1 Æ_vÕ7²LiÇãñx<žÎ‘‘£±¨bʰj1‡ª¹\õXV»©-Î,âªÈ¨G›èv 4ºòªcˆ]" Hª $£rÓ'%PÀ}шh.ÀaA†AuMUuuu† }¬- YË(Ô±®ˆ)ûÆy<žµãNœtßýæ­Çãù´ P¥œÅªÁ¬úߤ_Vº\qr\LJÀPl¨R=¡ÑÈT¥@èc ŒÑ40†éf”’!Ý,+­‹q_µzw_ž@jÐjZ³’$ U2Ó¥Ð)fdè@€@WZ5:Œ‚Iì×ФŸ& Eˆnz<žNsÆ'?÷ßçÔÕœ€ IDATÕm4rÃc'½í6[çVŽ;é௸߾vÃk55›îñx<žO•XšÅš1‘s`‡ƒ&^9Ù•H… ÜÓRµèbÿ‰1]Zú®<ÏÈ €†!ºð”ˆ]¹Ê4&¾E¯‰"EÉ%®™±lu«SÇ¥“"ˆ4†@$JPe‚0 à  ¬*µï@ è^©w( ¾êo›îñx:Í¡‡|í±=ô÷¿ýy³Q›þhòy .Ì{x<§{`Tô¹Èh)iç^U–$)„a”ͦؗ!uUB“z|hm]n×ú‡‚‚F‹¨Žµ ¢QR‡úh²³'©šSµ´Î¬2¡ŽW h`£¨"°Q[»€Í+$²TºâuN–5¯ Óßy7oê4ú¯“7yzÂñ;ïô¹×^cÚôwÎ:ý”±c·½úškŸñE‚Ÿ·ÃI'×§woGO8~§Ï{õµ×ß1cĈ§Lz‹Í¯ýÕÔãNœô•/ïû•ý÷ë „Ûÿ~×m·ÿ}á‚…£FmzòIÇÚt“Ìax<gÐ@aêfùª@+U¥%²XÇœŽë°¹Ä¼o(…vÐÐ$ãç hLÖ-E¥*Ó€ÐÕýÝÜ´ŽýA2]†×„ºt¡AVìÒ½²UËî[iѼ’ÂuU>ùšššò&gíçþÿqá”sGo±¹1æäSϬ­­½þºßDÅè¢K/¿ðâË.»äu»ûÞû.œrÞ¨Q›Üu÷}g}Î_n¹±_¿¾]ry[[Û/¯¼¼Oß>7Þ|Ëäs§\wí5: =]lnl@š²%Ìš5ë××^7õ—m6jÓwÞñÈÿ=º*W®ÇãñxrˆN0Zi9•Á)¸t¸èˆNë N ëÀ’”Ôjepâ*¡…@G#€M±Ð¦¯¨ØEE‰"¡ˆtyØq¦ tjŒ–IÖQªA`‚°*¬ª®ÖùUaU•¡14D$Šìà§YI¨ŽÝ!‹¸CŽ#½)£ÇãY –,]ú»ë®¯««=zsµüÕƒ¶3ÚS?{ö˯¼zÚ¤“0xð S&žð̳Ï55ÍW·ƒøÊvÛnݳGo}óë |ì‰'ç=öÄ“gyê°aC{öèqü±êgÕðþ¹bu·,•Jƒ0 Þ=zTWW½Å «ü´zÇãñä褘R©V–WDHï¿ÇJ1S‡SÔù[¶ˆ2E¥ˆkʤÕ3„Dú„!I5AHñ¤(4Ú«ûVuCÀPŸ\"ûe8e­ÿEŸk«k X›M8=ž2H2+Kš®åñx:ÁíwÜyûwÖÖÖn4rË/øiÿuìX—!CëFCCcC‡ÑÝ#†hhl0 ?€áƪ]·çÍž3ÀÁ‡ÛÌž;w£F"UlT*aüÎ;÷“ýú·¿_´hÑÆ<ô¯m²ñFiÇãñ¬"QQ¥j2¿cåõi6f!(Œ\`’póûdïÕ—§ÒIX @ ˆT/Æóþ#‰ÄaHTqœ’šIÆ„A` i` :l˜”$D º¸7ÌPlÙÆbUR>nVÜTdz"zÈ×N>ñ¸¼5u- <¨X,Îmh2x0€Y³ê 4HSgÏ™ëQ?{Îø]v2d°!ï¹ó¶>}úÄI1éK´´×S:(aüÎ;ßy§Hä‘Gþ5qÒéwÞqkmMMÎÇãñx<]mD2Ó{‹ÊÊllQfÜ ÑD‹A’Å*F…"F@" $ Ž0U¹§.I!IñèùتµЙdNnR¬Ž Q¡­Ph-´· m(E †aUuUuUPU„¡ Bi¬’%a(†bŒˆ€ CCºÃq/ÝÕÚ ÄØB+]€€Tøôx<+ÉðaöÙz«+§^ÓÔ4¿¡¡ñª«½Ó¸5È àî{î{ù•W—.]vëm·766î¶ëø!ƒ¿óÅ?»âã™3[Z[ßž6}ò¹SÚÛÛ³¥À€f¼÷~±XÌÙ+•ðü /þî÷7ÌšU_,¢(jmk“(Êåõx<ÏJc•UØòñ+Ö:]Ÿ€Q8g0PGfR1 ®Æ Àhª! zô¬]oäðƒ×1¡}Ô’—•‡Y©§CZI“}–Š[@«¥@("ÅbT¥2¨ ªªB¡ÑÃ#ßÁ·KYúÏÄ[ìO­#h­E3 C Eе  ï!ìPÇÓuL9wòÕ¿¾ö{?8ŽÄ¸w˜x±qÒ_ùòu¸ñÝï­;bøe—\د__“Ï>ëÆ›o9ó‡çÌ_°`£‘~ûˆÃ«ªª’âG~ØÏ®¸òŽ;ïÞlÔ¦¹ÅYË–°Í6[OçÝ3ΞÿŠ/u´â·å'ú¾|ÈŽÇ'&N:å´¿õkV®\5ÜÊqÇùÓ¢«y悹Ä~¦ªdh­¤¥¨jÓÉ •t5Y[ ‹¦€üÜFÀnÍçYYE`(‚ÈÈ€"  ( –E(C(‹¢,Š¢(B(C1»7kþØü­·382€)`B(ËBÕ@õdA5`IBVQ2ï٠̰€öS˜žŽÙ¦SÀ>ž©ã9޳!¢tÉeWì·ïÞ]|éhÝïÌêÕ«=þM““ƒ÷½ç[oý ÑjÇqçOše¬ã§I_‡ª‡! ûꦢl’í˜$ ¢.a¡EHY«i(,8kά¹[ÎY°õ–[l½ÕœùsЦ,tiº‘d1ƲÀœžÆz‘¨¥ZPPÌ~jƒLªaݬ{ûYß™%Ç™‰kÿûû[ÌŸÿ†ãŽY¶|ùm·ÝÞ”¯\¹ê¤SNÛ{ÿ¼òÿñ­«¾½Ñò©,[¶üècŽß~û%ç½íì¹sæXáúõëß÷Oÿüâ—¾rŸ9é”Ó–ßu7€/]|éÿùû#›ŽwÜq糞»U9Žã8`Úk Sƒ‹#—UÌ"•ùž>RÑpoZfê0$ {¶·ØÅ `ƒ€^Q¡ ,È‚¡dè±è‡Ysûs¶œ3ÿAó·\¸e¬¯º^»zmšÃâ¥Ý€f³ IU5‰XÍ™Óßé±KùˆmfÍ ³Z3 ÔlU6Ÿå¦3Ð ¾Ú`C‰<`Çq6•‹.¾ôÐÒ+˃:ð¢K.kÊßü–súýþ§.¼àmç¼åò+¿²Ñòn»íö£^wÜ3žþ´ÓN9©W–Mù9ç¾ãŽ;î|ß»ßñ¹O_øÐ‡>äÔÓÏŒÒ^ÏÝóî»î¾á'?µ6_ºäÒ§<ù‰Û-Ú¶éå8Žãü!0«ËaÆô3Ë™âž9úÙ3óÑ)–1Imt¿€¼-•U™õÒ6„@„#k„{cå¼ùs¶|Ж ¶Z0þ|ëXÿ½kV¯¼ͽ›Ñ™²•)ŒÝÛþérUu³T$› @`ÚD°¤TûtÒ‘*€|»¿‹t¼Ö"³úŒÂtûq9Ž3=÷¬\yË­?ßóÙ àî÷­«®ž˜˜pçÒe?¾á'o8,Ø~Éâ#8ÜÚÏT>•›nºybb|ß½Ÿßýƒ½bÅ=W]ýßtüâÅÛÍ3çè#XzçÒÛo»}öìÙ{íõÜ/]|)€Á`pù_9`¿}Û±Çqœ?éW6Í3²ŠÚO²g&Õìþ’oŽ;*F*YBsM@H_ʹª1íX¡(CY†²ezeY†¢(û½þœ±ÙóçÌßrþ‚-˜»Å¼þ¬~ŒqÝëÖ¬Z³zÅ}kï{`âñj¢*hÊnþA ¢Ê¼9‚ë×W7Þt&«…æñ®nÇ`ozÅP1ìÞ¾I¬¤ôÁ©P#¡ÕÖPYÇÙ.½ìŠ»ï^±ç^û5%_ÿÆ·öÙ{¯+VŒmµ`n¿d‰ÌT>•}öÞ ä1ǽñ]ç½õÑ;î`…Ë–/pÈ‹_Öm¹ì®»ñˆ‡|Я:òµ¯íQÿõ½ÿ.Šâé»ïÖmã8Žãü¡aU­J$ã"Íp›è# ‚ìf¿én´ÀjÓ™°P'MŽCRHÚkÄEÑëõÊÞì±~¿´wõ ^·vý`rPu…ÅÕ,G ØN«$Ì?Û ¨€8€Y@Jh¿aJNƒ$¦ ¬],nXV  æ#ÌÅ€@&ŸötVÇÙT¢tÉ¥W|âcç?ì¯j%ß¿îùØÇ÷Ù{¯… Žß{ß}¦§K—-³3•Oùú×5göØq'œtÞ¹g=n—,Z´m /úâg¶Øb‹‘æû«‡îôØÇ\~ÅW®ºú;ûîý¼²“Nà8ŽãüÙÍ)ÛV÷ûLl6ï Bö¸ô£@‚ù&=I² é_‹~¯?«×ŸÕ‹„ÉÁ`bÝÄ`|²Ô±Š1æ5Æhé«Ì3¬¹£ ’>(jBѽ:Y4ÅAÓÝ}Bµ¢“*Ð,¤Åb[ÈÆñÇÙ×^ûßa°ë®ûåm·ÿò—·m¿dñãvÙù=ïýÀ}÷­^ºlÙ¿œÿQk0SùL¼êð¿{ÅË^r‰§\wý,ÚvÛgô!yÓIÿxàÁ‡¾ç}Øçù{õz=kù7Ï|:Ÿðø]·ß~Æ”Çqç÷GczIú`±O󵯝„€"ÀUCÞ´•ÉIS9ò“U„ Š‚E°¯BÊ~ÙŸ=kÎü9s·œ7w‹ùcsf‡¢ ªõ¬[½êþµ÷®[ÿøäº‰8ˆ1=Ð$PRQ'·D"Ÿqâ=v1y¹vm`÷åIRˆÙ¾Á$® ‘´’h¢ÎÖ¦²í5PÖ0ÍÑ•TûSŒv¨hÖÜôÙgî¸ó®ë×­]¿ní—>óïM»™8ðëãí96ZºÉ¬\¹²©rœß+Í¿â:ÿÀƒ:Äu]WUU×µܱtÙ“žø„îhR ƒƒ_tØñǾî9{>k´ÎùŸàºëðà%‹ËÒ¶à.ì t°ß±òïÖôvø·±ã8ú<û¢•›¢7/ý»W¸{ùÒ‰õëN¼ûIß,TLQS‹1ZôQYºÒƒY²ß¦xVF‹§s¶ü $’ˆ" AZlµ(Ë¢_öz=ûõ$¨ÔƒÁ ªªzPŪ®«ì”ªío:0¶¢i5ùïÇrø·UÓ$£€Â¢ÃÈ×Ñ9„кjk›Œ›ûû–r vD¾]H3{³ Á>Œl:ÿ­ê8†HúÂ^4kÖ¬¿Ý㙣uŽã8Θ±&›2õlÏ`¢•î¡§Šš ÉA9 ›Úd~h È-Bè…²_–eQöze¯”P×õ`b¢TƒÉÁ`P©¢$Ñ P¢£"P]?lŽËÝlŒÐDS€6 @º˜V5aÃ7¥Ê$“Èf [„$€lü²Nö–µ²‰8’´à8ΟÏÛçÀyóæž|â þô•ã8Î RP«zɱšêT(¢1YY+¥ÿÍ™ŒMvlY„‹²ìÍê÷Æz½~$¤ºÒäÄÄäÄd5¨£jÅÚ$’%@,ÖÖ’ÖÖ‘ee^ys!€´'€Iã ¾H¥ “T&÷5‡e>EºÛì ÷hÝY"r¼–öÍ"µI".ŽãüyñÕ+.-rÇqþà˜Ge-ªLCA˜˜‰°ç‘Àô +ƒ)­ EŠ¢èõ{e¿W–b'ëA59LTõ Šuz¦*MEÕ$ éjTŠè`­ŒF>LqCÆŠìˆj/¦mm#f(åSÁ®J°ÒO‘>:;Îä Ó™€é9°)ÕŽã8Žã8Î&Á!ãL«Ø)¤œÙVz6‰‰&I5ó·@{6+”EQ!„þ¬^Y”¡ˆªU5Y UU×±®cMÿÈì.B¢ÅV³f IhÓNä¹5ÅYb÷Ê,†‰ÂN;U†R4—Ö6GO-O’$…l&çÃcd¤hÙDºÌvÇqÇq6‹©ÎjÂǤ­D~ËjH iObц ˆP½²ìÏꕽ^Q!Æ8TõúA5¨bc¥# 3NABÌg-¤™ç’°Únü¶Žf5M³ˆS¯„¤›Ä˜5k’aÛkC0uImÒ2ÍT“4ÛaÛPž¨ÁmgÉé6ÇqÇqgsèÆSBÖ?`z>‹ ÍU@û¢„À¢ªeYöz½~¯_ET¬ªª®êj¢ª«º®*E1ÝGD´\U@²4Ø4³Ý¦µ%!XÂAª&†ßhÕ¬[Ssš:’1F;¶ÇvXÌHs9€4B¶ÏvjSR³UûÞê°«6Ä$ߎã8Žã8Îf0ÕY Ë÷Lnf?)0«jY”½0kV¿7«ß+zvç|0˜œœœœ˜˜¬'k ´wN RTƒEVë¤|ÙØ*b¬mAv½s/}x¥M1¢´¤ÛÔSBz®løÚHÛ=uôŠ€6¤U T€ÌÊS¦ñk 0t"©dïƒÎWÓøÃa]ÇqÇqgÓ°€f:¶$ire¡ɶ ”e¯ßï÷úe(AÅ8鯬¥ IDAT11¨&ƒÁd]תí*J•$IöºUD!ë_DT4½„µ6¹ÍÞG³VI@M²ÙUi±)e Ù7 Aʺk#%¹$‰t½JAצELÕø¥¨Ù°ÀNÉü€]“ò0Mn«•¤q[Û;Ž3•wýzþ}÷¬-uþbX°nþ»ýcŽãÌŒE:ÛS0©Ó}ü"Ø&Q)…µ¡,{e¿ì•½"’’&'Õ ª'kÕé7°À§ÙÝp»A/†dnfuyæ¼€ä‡ÌE²q¦"rò€9ksgé4&œdRâ³,ÆÆúý~¿,Ëc5¬_?>99P%E)*(ŒQ‚m­š¢£j¾eìv:;ÞÙ­l[©MÞ`êš´3™`Ý¡g°ÌíоÒz6,bî*Ø'|`ƒ ÌGµ«¡- ÖœHŠºáùÇqÇqœM¥…YA0Å CT¯×ë÷˲ß+Ê2„B¨«z|b¼T“““ue[«2€%)¦ dÍaMû)JA0£cSœÔÎ<£”²€vÉb©Ò¢›©™Ò¦–Bž 7Cç¸-êö0eF4™|w›¶uVè8Žã8Žãl!‰”ÅZC(CQ–E¿×ëõÊP ªêñÉñÉɪT’e)H}Eí è8[:m}ͺ7µ#§ hß X\é–v`UCáÙé‡6‰Ì™Fn†nòÏÐ@ª’y2² fÔSi†ì\ÇqÇqgƒ0d,Ë_P! j0Të모FŒŠuln#F0@2Ð 6£üt=`¶6„½]!l|ÏN¥lK¬uc}­²$©m%$‘í°3<s‡œ¨Ú]–Í$sa¡©Ê š’ºÂ:•!…ùÇqÇqœM 7«ì•½²WôÊ‚!ĨjP &ªªÁ RLZ§hû ØÆTéy«!HRrò'R:§d&hlÜØf¿©Xꫵ¶|V6˜zÚVVb‰m½ “æÂZ´äÂ4ÆzvL¥3Qbj_ÇqÇqgÓ™3on ã`|²TuU«ꨴMD’ 9ô˜iκËuúÒß ªœN ÙÒËlé)o€­J²US Õ6C¤Ã¬º ¦ÑÒàhÝÜOJ; 8Žó»pÆãûO|P0±l>ÿëê›ËëÑF2œñøþkuþ­³ œ´KÿA³pæ÷Nþ~ë9ŽãüåA„Á ®ƒªªê&°ªNB(Gb¥ÓÓ:ს½®$‘¡ ©‚h_œ$‰h—*ZB@¾¾$¥YxaF›ÛÓÃ%%AìF~…V[í³›êÔŽãl”‹SŸë`Vç-.Žlï¶5ñWk7òËèÎ=ž¾ko}S®Ÿ\WÖ:Žã8¿kï_mGÕsÔ0ëȤ«uX‹6n:ìä¤þž(shSJvhÎI™=šAÚ­€”ªëd§´@vÅ•Ì>j,ÊÚV;nJ DÓN§zêï÷cpœÿ¥LÔ¸ôÎúU;ôþj^øÕÚÀXW>²÷´mÂÜ’?[?tóàîqxïSgýøÞz‡ùáóÊq½÷ÆÁN ÂA)füöÝõoØŸø-ûSw[á>ÛzÏY\\¹ôO7[×qçŽyTІ´H¥œDKEŠ]Ç ³³A4-lŠòA[Òô< *HT"ïV0‚DÅö ÑFQ÷=Xie’d::åï•´XK<¥Ðnꛫ‚) k™º eŠˆ¼í@n¦&7ÊÂ$¤ÎhŽãl–ϺeG?¦<ìáåõ«&£°h6\ðŒYÝ–‹Æø«`õ ý1›¬1Qc<{à bV €mf±šˆæ²õ°pŒ÷Nê«Ëêvê}ìçØyË0¯äwï®L×åkËkç>±ÿæšðº_vgõî§Ì:ÿÖêI[‡Z¸öwVÇqœ @Ó8Aèf`ÚÞVCv9Eÿ† ™·6f*oLE›’ÆóÌñó³ï©Y2@,fˆ¡w·hz'ìï’iGëÚq·$­Œ¤ ÒÈ5­Y{%°p4ÙŽZhS`ÇÙ VôþÞ}ÖóW.­ï—„W\=±&ëéfqÏ„ báWŒ ÀâÙ`Ç?X'#ž²u±ûÂpÕ]õd€Í˜N8ÿÖÁúº<û ý34yãêˆ vÿÍZÝr|Îâb÷…ákËê¡ð¬ã8Ž3ŒÝýHÒØ )QÏ!©ÌÝV¦n£Ý£ÅÙeG‡ÍejÊ: bÀ\ÐÑÇ`¦SG ˜v.¼i—ú´ä‰|ÜE’di–?ÓAº,))ÖqœÍfm…/þº>ôae°b\ß»§>î±½íçpV¶§<®×K)Bgùzýô¾xÔŽ½­úÜfŒ¯Þ±wÝÊh;RIøÆòú€‡»/L‰ÀfOwá/«Ïýª:óñý]· ØX÷Ëî¨_øÐâ1[†/{b€ã8Î!K¢$Š€"  }±°;äDh¾'m³¶æ7ÕðšÓ™5· 6FjßÌÙNž˜ùoÑ–3BؾÍØÁ‚¥&­p6jkßeÕÜ7Å…%Ô€RÒâÔ+wg¹äŽjVç..¼ûgƒ;ÖÅ7ïÚÿ·g޹cùµeõ`䟴伟 Æk½·þ»ŸÒ_9¡wÿlÐT}uY½Ë‚p׸n¹¿qs§ûܯªÿbpÚ®ý§n°Áî׬¨#pýÑRÇqœ™ ÈôôU‰ä¬"’¿"ì -;BÖWSÛì²M‰‰ÓUÁ¦hÈ8ìxMÀ²ETd”r4ÝöRØFBvÍ© _†©§»³}›@›aHÚÈ«ÒÞX$ˆêäM8޳)œñôí”1^ãßN;C­¯ñ±ŸWûùèö§Ç^›¸ùþxè·Æ›Ó÷ßԊ齓zÇOÛÓ.K×éÀ¯·½Œ™¦ë2²ÚKï¨/½#…N7Ð=%áO_9Žãl”…€ˆŒ$¤„ +¦ç®l‹˜h§Dlý‘@ÚðtØ)»¦8D£n©ºHaZ×M·Ý§B‘€P¢uÄÎøFÚÐʺêw䕹ëQJKn›( ì^KªŠ ©ü×tá8Î_(ö{p9a{9Žã8 @¡üaî&¤o´ˆ!l(0˜Û¡ p*Mi£rSK2Ó°!’ަg°¤P«™,Zmn¦He^Gº”ôüÔôD»QëðPl²rGú³Y˜ò6Žã8>û¬±µ•ÞwãÀŸ¾rÇÙ(ý0«¶a!FÔ¤`¯Ã"`")m/E t¢²ÿ‡]-ÑÄòwþ…Ì_¦EØ{°ò¹Å&¶ K/bŒ ÑVfáVÜ¿¶m²æ6権evdÚl´nå%ežéÇù åEßMBpÇqfbno^Œu«:Öµª¨ZŒ j ¢6o IÏRÄ0,L÷"ÅÐ<ÁdEغlă·©þÖ˜ÞˆF¢vœ5 ²/AA¦V“l²3–Ù…}X³’Br—FDc´’4du$©1Z©Í=z Žã8Žã8ÎÆ)B¯½RбޱЍ±®USuŒ¨QÜ•-í5Öh4O%DR±Mr%( "´”4v£î–EÐ~4ú y_òÂÎþ¬­@ ˆH3Íš––ƒ ²ƒæ;€üè”Æ´Àj»S-ÁÄWÊZvw3 $ S–à8Žã8ŽãlŒ‰j}Á^EQ”E( ^ÁºŽUT]iPÅ*2 ½{ C‘|ÐtQé=‡ˆDʰ‚@@”·ŽÔ˜èL¤¥ÝaG£¨ÓôJK Êżÿ”A`§RnÖÖÒrDŒj+ 6Mƒ¦MžmªÈW M.;Žã8Žã8-ëë Š¢,C(P„"EQH±§²Šuë¨Q3Ö‰¶]~`B„_¡Á"œÌßR–À ÆÖ-íxj[œt1× "¥9e'üiøÃ¢ž„¶(ß±7á̉£ÑÖ(d¤ QäÈ­çØíH¨³ß‚ã8Žã8޳‰ 0Q«bÅ@¡(Q¡ (Y°W=I¨TIõ V1ÖŠ5Y !A-8ÉG4§M÷ÆòÓZ•·\%mÇRY\Dœ DWóÚP&`»g„hîïwê`æhó¥AGšå]múmWXÙ¤.¶­4Ök3 Í ©’t‡&tì8Î4ÆûFËœ¿ 4Öù‡¾ã8ÎjTB$(P±®T…:(˲(B( †" A=)ÖƒJU«º®”t¬¶¤dUsDØi€9K(GdM2­Y€((æÔ-ZSûtÒUS@c ¬6Re^O†1F†|Ó_ɲi6iÊ 1 kŠÀZ­@QѺ؀vå©cGJó ÉovgNxèš'=ñQ£¥Î_ ×]¿˜7Zê8Ž“Mì”^1Ê…E@]ÅPª–íZ–!€E©ºŽUÅ*ªŽŠ•ê¨ T”íŠM{ï@DP P~)$'”².Z86Ûž¹_w#­VmÛ’æ(v÷ºJHHaÍ”Ñ=5{u:IS7¯ÉÖ1ŠD‘«˜«ç%æDX ]Gg}¦¶mdwȨÇqÇqœMCLшZ‘°ÿBT¡@Q¨× ½²è ËÀ¢zµbTUŪªCT]‹b4CËFG†,%€€Bš•|OR ¢À¤€¶*éåô¶—T°œ.Èšè)™,§Ž—B¿°!—ؘ ­Ö>ªn(¸Ù e²†ÔY²KmÛ¦AÇqÇqœÍAˆ1G:- IPé.Ìwë뺮ê8ê²½‚EÉ^¡dBÊ’eu¬kÖ1** $ A ¤…ˆt/€È Ñ%ì›F(Û)SÏ’³64§Y3SIÛÓ²NÓJÔ6•HZ’«aÞÙ ”¦ãiýتr6uIíÍå§Y¼ã8‰ë®ÿÁh‘ã8ŽãYÐPj$,… H”b¬€ãDÁ²@Y„²d(Š‚ ½²ßSi/Óªê*í6€(D(ZUi((oãJHŒ–™@)Ú[ b²É`ÁZ"‘jã™@Ç> XnÀtÙøe¶I›4U2ù¹5KFˆö@£µÝç·:«É$3N!%%'íߎãlˆ'=ñ £EÎ_ þ/Çq6ŒmYegñE‚Q$ÀšæZé=Öª‰AQ‡EQEè•¡W†¢(Š*C¯ªk{·V¥ºV%D)ÚBÑÌÎbŽ‚“l2H‘–új– ›R°„ÀÔw*)ŸÕœ’$¤l¡ßD…4vªìšfJ6/$uîÝVÈ’Ú-ÐdÎ6µèN㹎ã8Žã8ÎÆˆiÿdÇ3­ÊOeÙjü€= /„¨A­‚ªÊX,Š¢(Y†zEO¡WªŽ1êÁ ¤JŒRŒ!Ë€8R¬W°j3c¼¤~yaiÛצš÷`™G6ŠÚöK—–NSÀ7cÚÚô‚=ì¢hF¦«¼Mu>è´7ïïÎê8Žã8Žãl2é–5H°˜bŠ·F¨Ð÷ÏžHDÑÚ RŠŠD(UÆP—* –¤Å_Q½²š¬ã ª®UÕªê4 ‰hjÏgY†)`«¨B°wheÈvH›+JÈÚÌÝ$ÁÞÝ ³ÕÄH”´=¥}Cµ¹ •Hì &»#:;µ$tŽã8Žã8ÎoIzÂ?‰«ÙX Z<Òäm¢Ä Q "T×õ ŒeÁ2°,Š¢dA²_ö„"Ö±ŠU«šµ£ªˆ:¦|Ò”:j÷áó~±¢mz%ˆ……Ð<¨eû$löºjrò:d‰”Ü»eH%Õ¤HÌ@ž%ië1m±–¼n ¥ã8Žã8޳q²L¥Ðb[žuŽf`fx‘ vjj¨ùQ5ã$ŠÚ¶t- †‚¡(Ê2”QÑ®UT±ªU 10ŠT”¤:‚Šw‹ÈšÅ  ùý©– Ë•Ò+\äÌÆ˜£§I1-hjè§-#šQÛæ³ùcK6/~é+ÿõ£Þ±ùÉO:õ}øÐHᡇ½ò ÿyQ·ä ¾ô’K/·ãn—ñ‰‰“N9íï_ýš•+WøÍwœzú™rè¾¾ðM'Ÿúã~ÒŒÐ0uÆ£^{ìÇ>þoÝÇqœÿýtÌü®t¤=ÆdåM !Êöq•E^óWмªŽª­£}¡ÒqbÍX‡zÀÁz¬[Sß¿fpÿÕšuÕÚÉ8I zcåì9åÜ9½ùsÂܾúeÝ+b¯T¿D¯_ô –¦¿¥ò#S4mEðPª‡…bgþË/·1GLó°M c¤-cµíÈV“zάˎãLË‹^xðë_{T]×?»ñ¦OþÇE‹¶=`¿}Fý¹±zõêÿá´9sæ¼ï=ïœ;g€OþÇwÞé#ÿòÁ¹sçþìÆ/üä§Ï;w—ÑnŽã8Ù0Ðn¥3j•o´Y27 ×6Ç"“eNH2¢¦H‰$DØ6§ †¢ bU×QÕ žìÕ½’e‰~Y–½Ð+B {‹^èEUu¬* ªºŠ1A ¦÷`Ù”h®€P"D1’æ¢&“Bv¯Š¤,é´É0Mmm\ €’íÄ2&=M}òIwmçtgS)Šâq»ìüØÇ>ú¶Ûn·’“N9íšÿº–ä¢EÛî¿ïÞ¯|ùaö‡líºuùèǯþî5<°vÏgíñº×966ÖŒ3>1qæYçÖuý–7Ÿ:66öÂC_þ'½ñÉOz€+îyáK^~ÙEŸŸ7oÞáGý´Ýžúã~òó_übûí·?î˜×þØc¶[´-fþ V®\uÞ»Þý£ß°páÂC:`£ã~ÄÑ»?m·~òÓ›o¹õÄŽ{ΞÏjº8Žãüa M {L§MXJ*–$ L9œBÑnœ ÄÜ(H$’bÚÛ³(2¢bŒ‘6¢Tר‚Š’“aP”,ÊÐ+P ½¢Gô!Õõ` jT5*ËgílÅjˉU›2ŠKc`'ëµé£aZ™bgÌŒ‡H£DÒ¶KÈ…¶ç­ì³h>NÇq6º®oºù–oºåÀý÷³’·¿õ,1Æ_üâ—§¿åœ%‹?÷9Ïpö[Ï[³fÍyçž½ÍÖúú7¯ºþ?zúî»Y—U«î=ùÔÓ½ãÇûºl ¼ùÒÅ—œ}æ›wÜñQÿù¥KN<ù?uá l9Úhó¹í¶ÛzÝq{=oÏ×yDó;d« üàí/øÄ…/{é¡;<ê‘ý~¸Ó&qιœ|߻߱Ŗ[\ð‰ O=ýÌó?ôOœéƒzó[ÎÙj«Ÿºð‚uëÖŸyÖ[7:€K/¿âì3Oßé±Ùè§ç8Žó{!ýÚ´Ø'!@ÑÕDÏê¦SÖ=6qW!™jÓ!Ë@D¤½T‰¡'–ˆ "…6÷Ù¥2j@…I…’EÁ²`Ù/ú{ E9V”ÂX•Þ§5™Þƒ…6ØkÛwe_L/Èí mŠìIRm=Sšk„’t7°éÒºiÖVÀ¢Ïi6³ã8›Åç>ÿÅÏ}þ‹vü¼çîù7Ï|z·6„°ÃzáÁ]ýÝkžûœgßu÷Ýßùî5Ÿú·m¿ýî¿oÓòö_ýú#|âÀý÷{ùa‡¶ýgæ öÂãÿÀË;ôŠ/媫¿Óí·æ¦›n´ïÞÏo~K ùÞÿwÞ…ŸüôÙçžw×]w?zÇ{É‹÷ø›gtú%ºŸ†±ÛSŸ `ÅŠ{®ºú;_øì'·ÙzkGyÄ~rûm·?â·f#ÔK—ýø†Ÿ|é ŸÞjÁ‚­,8òˆÃãÉç´ËÎ;5S;Žãü¡1—`ÙïѦüϼ”€@H9>ií’äš°Ê~6ÿd {ÛªB4sMmdÏØÛ; ˆ$ˆ @ °f…Éj¼`¯DÙ+z%{EEzûešÕ¬ÍlF”Å9[]¶Ví¹ìbÝ´¸iv¸`…Ý¿ušRSdc´|ßDc°Žãl"–Ï¥åË—Ÿûöw½í¼wú'øÆ·®ºð“ŸþÍoî`÷î—/¿+„°dÉâ‘A\zù• ¶Üâ´7Á7Ì’ÅÛuW¬¸§S9#EYVUÕ-©ªAÙë5§ûì½ÈcŽ{ã»Î{ë£wÜ¡)_¸Í6Ç¿þµÖ®[÷å/õô3Îz÷»Î3iîbŸFszÔkµƒeË—8äÅ/kª,»ë®G<âáÓ~P+V¬ÛjÁk¹ý’%©ËÌãX´hÛn¹ã8Îv‚&C"¦T`æJÂdÓ’:íP²ç÷“ƒÖ\ (yo„Å)I¦WS%…h^K¦¼QðÛ#à IDATù%öŠ-•0(X Ðë…Y%Ê’E`Q†ÒÞ)Ð:¤ EX.­@DXn‚òe¶Š™¿µyPk:SXaç\I‹ÛóYÍ#`¤ã8›H í¦ö?tþ©Àª{ï=ó¬sÏ:ã´'=ñ ³g}î ÿùµ¯ÀvÛ-Š1.]ºÌâ¬]Ž:âðk¿ÝÞôç{öüùó¬°?«?19aÇ÷Þw_ÛX¶ü®æxé²åÏxúîÊY²xñwÜÙœ®^½zÍšºú òõ¯=jÎì±ãN8é¼sÏšš&;wΜƒ_pà§?û…~òÓ©Î:‹mÈ‹¾ø™-¶Ø¢[>ÓµpáÂñññ{ï»Ï´ué²eÖ~¦q ÿíå8ΗPЬP r&¤ j2M)ÝÕ7q,A4 ÇlCˆ¦¾6Dã†M”P›½™UÚæ%0¢¦ ‚HÖ¨+p Á N* ”½`1×f>ÉÒy.oÏR#5ßS‰Ufµ¥6²I‚}Ö:ulµxN]Úöí§ä8Φ"iùò»¾öõo>ê‘091)iÞ¼¹½^ù³oúÌg¿`Ím»íÓwßíÜóÞõ«_ýzíÚµ_zùw¯ùžUEqÚ©'?üá;ö ojôt‡G=òòË¿üÀ,¿ëî}ø_­ÐøÒE—üðG?^·ný|æs+V¬Øã™ÓÜ©ŸÊþûî}åW¾öï^3>>~÷Ý+Þõž÷?üaµÓc3ÒìU‡ÿÝ+^ö’N<åºë`Å=÷œ|êé×]ÿƒ5kX»víE_º|ùò©½6À¢m·}Æ3vëÛßù›;¸éæ[N=ýÌÁ`0Óµý’ÅÛeç÷¼÷÷Ý·zé²eÿrþG7°¶Zó@u¿å³BRRa°›ûfÙ(Étl) º6½añØÔL€@%¢&él¼½SH4Æ «fÃv±Žãl–ÁIrÁ–[>~׿~ÍÑGØn»EGùª3Î:÷5kvÜq‡=þæ?ýÙÖþ´SNúð¿~ì„“N_?þ¬gíñº£_Ý ÈO8îŸ>ø/Ç{»ßùö… ·9êÕÿÖ·½ó¿lñ’ÅtÀ÷¯ûAÓø€ý÷=ÿ#üü¿|ðöKÎ;÷ìiÀÉ.ýøGþåÙÏÚcbbâ#ûÄ™g¿mîÜ9ßõ¯Ï{ÛÙe™~Auyùa/™={öɧ¾ùŒÓOyÆîO;è€ýÿýSŸ¹ù–[büàíOλl:§ž|⟸ðM'ýãª{ï}ÄÃöŠ—½´×ëmàƒ:ãôSÞñÎ÷¼ôÿÇö ¸ñ¦›70N;ã8Î{4ËJ²*"(ɘæ7‘€Å¥=MŽ­:©uƒ®YþsÌY Ù iéÖÁîäˆé€ í9€ Eˆª(ðqGüH±[ZˆÖ¼‘–~*òîHy¹ÖÊÆ†Ú¦€Í…nB*¬°Yò÷t1óá㬹v~Ï·ž·ãλ®_·výºµ_úÌ¿çæ3rà×Ç/ڳݬgsY¹råÃþê¡£¥Žóû¡ùCnÍ÷{­±Q×uUUu]ÛÁK—=鉛'j¿'?âè—ú¢½ž÷œÑ ç÷Éu×ÿàÁK—eYEQv:°F {hÀqþÌxöE+7Eo^úw¯p÷ò¥ë×[²¿XbòÇôý]ÓIT•ò© HŠv*ÙûZØüí¨Éç””´m&ÚK:%D)c ‰$À¤Ö$È …2õ—ýO›Y4 ùEf‹:ö“éjlÒ;vû[?Š,0ÛÖ«“áªákæÐœŽã8Žã8Îæ`ŽhŠi§4…¤ ˜y*,\©,„¢ ä·)ÚÍô¾Œ°§î@RŒd€Ô˜ ¢Ec‚´ ýAQæLu²†#¥ {§€4Ó¤õ SAyÊ´8ˆywU’“ðbH@GÈZ tæmNíx¤¼)qÇqÇq~Kh²×ž Hù P…™¢é˜í|HQ©DÛ" J®˜{#½uŠ€(B’¢…@È/‹%³I‚hûŒn_]ÃŒ”$ Æ2ÆvWTtìP€`o,H:+Hv}©¾PI¡»“μ #Í¢ÖMfÆ4K+ÁC ÜZçOŸžÿÏ£EŽã8Κ¸™ÖYüÑt !‘eÞÊ*f£@ h7ë-I DÛiïÈÊaɘ$B4ñ3»µX+ H@‹ëRbÊj!À´×´’I7™rˆ)V(HÁ@ÙQu³LÉŒ;-W’½#À„“¤D€ÈÙ f¢SÝtä¸ÛÀqÇqÇÙ|’¥MX0&σ…1 °¸$c°ˆ))ÀìÑÔ—EDØK³l ¦„ìªh|Oíj¶}UBHÓ ùž(Ú®[”e (g’Bš¥JRÇéÛhZHŸH:ê¬O€È¢9µ1»žÚ¬¤©9vÇqÇq6Yts¤$9[Êdµ,’»‰hÃŒLÑT”ÎÊN'¬-Ì €´8kj6£I@¦Ûø€¨ „Îmz`„,ZŠ"Óü¼Á.&ÝÍoúç$åì:¥bÓ´ËmÜö±Ø‡5³ŒJîŒÜV:Žã8Žã8›ŠíÿD6±B“9$«štT!¦ÈÔÔNdté\æ}´­ÿÚy6‚f¿1€QŠ@J,M“礂Ô#õ´ÎB™ìdn;¬’ )Æ©@Z£áA›O¡ã›Qnè K*hÏ ÍÞŒi‹sÇqÇq~;bl|tDöÒCüLüòARDAD°T×€"[`Œ´§²@H!˜¹‰($óF´êgé±VÑWQIÓ`éTˆ)æ+”ˆ¦˜5L ¡k›ƒ $£dl– AM‰õE¾è @9Y _4AÚ:ú)À®Íg7d®¹¥ÒÿŽã8Žã8Îf’ ÌÐF¤ªãŒ¶QIID«9,IÛõ”`A A”=¡¥h"kZJS:‹ŽÂ¢Ÿ ¢¢ÂPŒÓò˜nù§ASœµilÇpJRJ  æim˜<à­£©FRw#¯¨VÇqÇqç™ÛuK&£Ýò!º‚˜ÎÍØ¢ruJh%’ãA¦w$ì +$‚2íˉ°6~WÙh¹0¦F*í ]5ÁBÀšà+dAÒ¬y°¾²C2·jç'Ú šO-9{Ó~frm÷‚ÇqÇqœMdH´ºâ·Ê^•´ Í8dbsK_°—±¦F0Id’ô™Ë1¿±u$3ì*¶@D™Þ| K`L{²Rj^l5õ’%äà¨d†j–cÁfqh²¹ÌÑO­{jLký¿JÇqÇqg RŽuvé+S ‚mB È>¨Î2’ÔN‰³6ñצÐÚ¸³:θîúŒ9Žã8Ž!¤‡ós 1iXÇñÒ½ýDGX»žfGö, =†€A¨†,n1mÐtµÃ4†µx&a53,[•ò¤Ô-š†lɶ‚´üXNs¦i†õRj†¬sä³0Rà¶CS—Öä8Î <é‰O-rþbð±8޳IH]S#¤’ÙlWÕ2©Ujt˜"Ъ òóQD -á$i©¸‘›ÁìbΠ´Ð¨ Z+ÔñCӔʠ6 ‚-{8 joŠ™”4›ô +ì:³°N»â´·ã8Žã8޳™H„æÑ÷n™ï«3[X2±Î#O²'“¦•´Œ9¤Y‘G!)Ù[CͦÅÔÑf‰l,cŒ$ìö> )’°DV¤åÃÚÀ.7-DY´ÓpÃC·Úä¶vÛt…šy®¦K>$i]FÊÇqÇqœMÅœNŸuÈVšŽÛ§æ‘ÜQR’@¥’émhl ´½]IÀtnz—›Öñºöh¥TKIsuú‘³â˜ºÉ–1}Æ,¼Št‘^ÝÔ55;³mËVmó¢ÇqÇqœÍ@Ûçâ3Yâ鈑’¶¹© &»NLÅFÒ¦ È(©jªÍìI#e…Pvì0äFŠd^¨$ë`_ ݉‰¬ž6´Õg¿žži…µi/©iÐÔ:Žã8Žã8›Ãp:i–>+³ÈÙ ¹ŠdºŸåqFìI¬äkJ¡Ù(¿@«uÈ®òM=žÁø$¡lmm¶8ÓV@RQ¤ Ymóv­6êÈg°I~9äµÙÛÓ”Ö:Žã8Žã8›Eö¶Ž.2=¯DÚ~§mA݄ԩ¶– ©y"5K—S=g"ÏØ®Š) šJ%•íJéµÈ¹ IÖuMZŠ+ÀÆY‚`ó„ ‚`ƒ4’ÙùT€aî[#[b§°FËÇqÇqœ£ôœ=Ìóºn)´ŠLÁR‹QFôL’íæOBJË7m$¤÷·"¦z›Y Ý„dI®²Ä5s7“§§3”)ˆj…BT4SãŽ/6-›`,™rì»`©BŽÍ¶©¼^¤«ë¬7‚uÇqÇq~„Ø<¦”hTKíI4v·©‘Ä3Ìä„b¥:e‰LŽ;„åäVl~¦‘²[B¹#‰”Ϫ,¨É;m ù4 ”tSíŒÒZÛ㤻öxZS“û!¤yª –~æUæ66fg>ÇqÇqgóˆÉ»ŒlVH:›"’6 ßÖŸ&«ÓjíÌ”ÏîÙwª`£µÓÂŒ4È^ Ë”iK@¦£‡€FISÿ LŒŠ1JQH%ˆµêhÒ d/3È „æâ%;²±R¥^ÍYç8wéžÚiFk% Ñ ÇùŸdÕª{÷Øóù«W¯ÞÄrÇqçψôb{ $HæïD+i­ƒuµ­5F¦sš €’€vhûi:K#ÐÈnvÁ<{@ŒPÞ}ÀªbrDIÓüª¥£Ùh EIa³_FE! +¢T§.I:;W­æ‚3ÝÓ¦ P©½ã8ÎF9êµÇ^ré壥Žã8NÆt+{$Ådƒm vŠ1Æhoaí4±WÂ6©¡ÙÙ$™Tv›)u´õ< @”(fÙ(Õ­5@Þ7@3°’Š6îøãj&$ƒér*ï6¾­ovÝ (Ù Ï”ÊS@Õ¦ÌaÇq6O\øÉýèÇO9ùM{ïõÜѺÍdrrò¹{0Z „¾ùÕM²Ã7žtêµÿýýæô©Oyò;ß~N§þ’}à½ÍñG½î¸ÏÞ{uêÇqþ²HÏÓwC˜õ5^)°}^LXG6îØ”gMKñÉ<&И«D@m÷܆ ö¢U!µ•5ÓuiögL°ví_?nçã=f»EÛ­Éqç´[ÖL:ÉT‚,…êºYÛMU‡Ül¸qÈá€d‡Ô6’,‘ )a®ÒBµkI+´ )ì,+0§PƒJ Š@ÚEVª+¨†jH$A"¢¹*#bXS5¬½r^£ ˆ¨œ<û”baaX ²å´¤¤XÇq6™‹.¾ôÐÒ+˃:ð¢K.kÊßü–súýþ§.¼àmç¼åò+¿²ÑòMáÍgžóÀÚµ=ÿŸÏÿÐ?Ýu÷гßzÞh‹xû[ϺêëW~ã+—sæé—_ù•¯}ý›ž÷œ=oÿÕ¯oýù/¬ÍåW~ùñßu»íaƒ]zù¯~Õÿ½üâ/}áCúSO?3úïÇqþ·#*9Õ,/å§ÆôäQËPOë`åD3À¦içd€¤e`¿ÌÍI¡‰X¢®ym!Bì ù€!ybkÊ}ÚÙBSiª€’¸ÚéPê®ËÒµ–È_yÄÜ2O”GlŸƒîFÇÙ(÷¬\yË­?ßóÙ àî÷­«®ž˜˜pçÒe?¾á'o8,Ø~Éâ#8ÜÚÏT¾),]¶ì‡?úñŽ}Ý6[o½í¶ ;æ5ÿõ½kW®\5ÚøÜ翸ǞϷ¯o_ýݦ<„°ÃzáÁ]ýÝkÌŸ?ï™ÏØýò+¾ @ÒW~e¿}žMtÈ ÚeçBÞ€p˜+î¹êêïœø¦ã/Þnîœ9GyÄÒ;—Þ~Ûí£íÇqþw1ª¥Æ€µ¢fF7ÒPPz¸^é±z>¡õÿ³÷îñ–]Uïo¬³ëeUB ¤òB*ÈC„$ "-D€ØÍUŒ(¨4oáBƒ ´|DE›F”ë£EE EÔFÔðˆ¢€ˆ(D!`ÞŠ$—T*U9{þî¿1æšë±OJBHêŒo³Ï\cÎ9æ\kï½Ö¯Æšs.–²ÞT’1”¬…«$I €lÔê€TT£n}\@:ư­\O‚akm Š@9›Ñ)º @ãQ  ÈÀ¨4ºÑ­ï;kàºÝŸ$IŽÌ»ÿäO÷í»òúŽjyß_þõ·?æQW^yåÎ;o 2ž~ÚiJ¬²o†}û®\[[SÀé§Ÿ`ß•Wžxâ忯³þå_Ÿ÷[¿ó{]tñõ×_à¾ßpÙû˜G¿òÕ?÷Ìs~äÿñ_ºöÀC¿õ!8RC'oâÿe—_à‰ßûÔñŠ+¾ækîÖZ’$IŽ1ŠD&€ºœ»—_å¹®‹Õ OÑR—4jÙTŸ<åu…RÂ’ˆ5šV¨CndhÀA@Ïn~{áKëþx’¦1\ÐAÓÀ\ìú@(öK4_¨* ƒKß芴¼Ø­¾ØÜÁM’dJ!ÿøÝúÖ·¼é®w¹³,ÿ‘½ù-¿ùíyÔI'týõ×_uõÕ’§—^v™ ¬²o†½{OZ.—WìÛwòÞ½.¹äR{O:i\n¯ºê¯|Í+_þÒ³Îð¬Û·Ÿþßž÷~Û#¶cÇ©¡U'ˆöÔqòÉ{;³wýÑÛŽ?þø¦H’$É1N $˜”W#ÿjIÉ9Â:€®%Ê× h5 ßU›JÈmTh2É*{Z‘Ú§†TåÚIüRÝЪ¯´&‰B# ÂH­иÔYÏJ)ÆÒ‘áJ?:Q]= /æªM*Óæ”Uö$IF|øÃ  V÷»ß}?{áç>ûÙ O?íÔû~Ã}^ÿ‹¿rõÕ×\zÙe¿ö¦_WUöÍpÚ©§Þïïû ¿ø†ýû¿¸oß•¯ÿå_ýæozà4È:åð¡Ã$÷ìÙ½mÛâŸÿåSoûý·×¬ÎìÑzä¼ýç÷ ÀmèÄOüÌg/\.—NÞ»÷!yð«îç/ºøâëúÔ§/xÉË^qà 7Œë$I’k4"*ä––Þ'%Á–¤K2 ˜ 4ÒJ }T@ (þ+ý&ùèT½«G€i­SƒºQC J²±ò¿{À@ø©µÒ…U?UTRS¦ ŒÁžjë5ÚLúøYö:PHífTlú¡ñt'ÕN ´¹~’$Ù,ïüßò =°µl[,Î<ãþïüã?ðò—½øàÁƒO~Ú~Á‹_Ö®µÊ¾^ñ²—ìÚµëéÏ8ççœ{ÒIw|É‹ž7.1Ç)§œüÌ}ÆË_ùšÇ|Çw¿áWM*}Ì£þáãÿxê©§Üëž__7¢¡§>ù{ÿæÃ÷ÈÇ|×9ç>ÀK^øü;õW?ï?ý¸'|ßëéW¾ýÑÚ¶mÛ¸N’$ɱ…d•ÿ.šv'-¨dYr¹t9Ûj16Âod©M)»±ððrl*+¤í*í' @‚ÆÑ„WúÒüF!¨ A XB÷éûj\bIë¼ RE½]’JÀdzÖÊÞEhy,HTzMÒÒ¶WŸÌ¯’{§õä‡04åøÐYšV009\ „šiv1I’$I’$Ù…Åb±U“~£ôÛRc>¿OOm'8ÉNŸ”UaU–Õ3]¼q(ä$0£²ËÊšVO½{/´PÿŒ b8«ò ýéI@ZÒ¹€`FšÁh*ÊQœµjVuÞÛ(ÞiØOÛÓìN’$7úž•R,—H’$IŽ!ïà2OÑEß&Bh±ê>…:ˆvú”„ßHšÉ½Ö(§Ûû² I”èˆr­ç×iƒž M·ª2ètE3€VŒðHiûÔ+÷Õ8¥vPé!bƒ±_L@ÙµWƒ½Õ¸V]<sÖ´;y=M’›’ÇwÜÕ×\sà 7è>r~Í’$IŽaJ  Œfíýp¡Éb±'ÁFªÁVݪ@Ÿì^o¤<Ö–Ò‡ý­õ&tYÓT¼“g5E‰é4C E7ëûØ*ÕºüªF¹šìUÂEº– Ø‘¬±k°ÞŠÕH®|*ï$Irs@RËæp»Û]±oßr¹Ü¾}»†?Ž‹&I’$ÇÅ—O`"šØ`@_ µÕ’jÀpÆQK\BBƒ>v,u%ì\æ¼µQNA2,Ã!´$‰¢¹WQ•¦3ûkàÏd•ýcZ‰Rà ¨„1(äàa JË“;S/À#mX,I’›Š¾¿¿û»¿{òÞ½ËåòСCËå²~©“$I’cŒeY–²Ô,ÞªÁ\Òõ›¨qEéYj¡Å ¦P£ŠQ«€4øOM36i(ð¶ü§÷®ªð'iŒW ý,jáJrAE^ô›ŒAŒ¡®$«©–µÜ—ÔÃŒ5‰5Új]d©•Ô¬Irsò´§ý €§<å)_r ­ÛŸÑÖ$I’c%Ø>HÕ¬Sð³n‡Ø3t°jÞ½ üô²ŠŸ6Zú  .dž¢­ˆ\¥{Ü)I£îùKg*Ë}-Œô£œ.D#TG –€©:ßP¶^wûA…Í:Àoî“Ú=ÖG|!ô4|÷Tž$cë°MÔs’$7A¶ï<î/ü%¤lM’$9Ö!–Åå”® æG¸F„C3öÚPy@J V…&ý6M÷¦‘eŠ» ]ÚÛÉ…º×# ´]HÄü±ñÈ„!¡‡ Р¬ÁT3éÜ~$[SµÀˆÿÆŽ™©À¦ö3I’ͳ}ÛWpâ]^øÓoDÊÖ$I’cºœ̃Ÿfè:˜îò3æ_)ZéRŽ€ÇR«tˆ±¢éÿÍ@S3l>˜uI²_‘`Hh`¿[/õØk± È$Kø$¬«âPÅ:kÊ3ýmºE_z`é ¢€€`F«ÃUÍ"tªcèê–mÐc½”rM’äæbÛöÝ{Ž;ùÒ‹ÿù…/úïHÙš$Ir,£µïaðyö ¨©ö€V(í¤Ç<ÛÔªQXÜ£šL¬Mæ3èÆAå‰dMP h<+%få…¬ÑÔxí¼yUzz¨%ͬ¨«€Á4÷Ì ¦54¡@<˪ëÅTÖ½É-Á.k’ÜÜlßvÜîx—»îxàà~â¹?‹”­I’$Ç*UF…ÆÒF‘¦3Pè=%ÙÁ¬SEj½Ð*°µÈ€È :£ÒaÄp!¡™cHX@½u¹+<ôéö( cúÐd á°aWoh@ ŒP†÷Æ7L‘Z?m[‚5ú[ìý'Irspá_¸â3_Üÿ™;œx§ÛßîŽç÷›§žrJÍ=íÔS¯Ø·o}}½ë|z’$Ir›¥Q®óØo£ÑhaI# ÖÌ)ê€Æ‡ë6HÞ9Óª±}„fˆ54ƒº°€â¬¥Æp;€’í@‘¥]€yW‚Ó:å@¶j +\šÉHù4 d( ®ˆ jUÉê‰EEµ2؇$In"‡×¯»zÿgÞýÎ7¼ë=ÿð¿ÿî÷¾÷ýO|Âc?üáïØéìÞ½{mmÍÿǘ²5I’ä6 QâÞ7u¯ßŒ.# AjÉ*?ÛÒ€"åJÐJ•¯FM¨ï¤]KYÖ¤òÑoI$6™ƒ‰6 Z!$ a4JCv%LÕ_ ¸ ’¬uCù^PYd}r+ DnMx¾œè·õFïVµh7ÿµ@N’äæa}ýðýѯžyæýŸôø‡lÛ¶ëWí÷̺mÛ·ïÞ½û¸ãŽÛ³gÏÎ;50 k’$Ém×xÅ$Q XX\]¹c”t]¦‚e‰R¨‡¿–ÂB”Âå:o(X.Ë’`¨·BÈ9{‘WSa‡f>Esº#u¨Þû(ØE5Àïã`¤ meš™O%‹ýiâÁÔ@ #<ÂÊâƒ_}ß t{`@èz}FX È5+…f±>«…Y§! yÙL’›‘}à¯îû ÷~ÿûßÿЇ>ôôÓ÷~ò“ÿÑ~ìÞ÷¾×åW\±k×®;w.‹$Ir )¨‰FfŒ›êdÕ`0)Hˆê޼4›W‡!„]#—Ë%ü~¹u€aM¢’\Kšjƒ@?7Š®45žT†ª{;HÄ£ Ü“«ÛØ F̵þ(—€‡W½€(îÀ ƒNÑPÜÆ}´à6BWÔJ)Kéà$In:’¡÷¿ÿýÿáãß½gÏÁƒŸyöw`ÉW¿ú—N8ᄲ\Њ©Y“$Iޤ¬ —ô'b‘52j¤±„ê# 銎ñêN\ÃÉ_)ú)¥”e)Kr¹Är‰õÂeA)"¬NP=×dUƒ´…:$+u}Ö :€•­ŸD’±ð Kbi *ÐîÌà³¾ú­y\56 aJ¸÷^ #©õ PÐîb’$7 3[__ÿì…îÙ³g±X\sÍ5ßú°ÎÃ:ÿü /üÜíïp‡Ã‡7+’$I’$·mˆe/ÀÀ¤V­W`FRQ W}huÉÚW5 ÅO†XÖ¥‚p[õŸ"¨¡-e ß`›áŨD×@ b’:D[é… @°@ÅUp;èÏVè]yçKµ‡oÀÿxGØ&Lþ“$¹É˜Ù¯ºj÷îÝÇüñÇ_ÈÝ{v?ï§~è´ÓN9xðàíO8a}}½ÝI’$InóP÷Ï ¹ä²pY4߈\² ;–åhj•ƒ WÒkX’ËÂR¸l °‹tÕt ²ëâ0(ñãåc­«>“€ oݰoVåbºZCC_R¢Ý¼ 40¸®fõã ‘4Åac,…ß¿lÊ'IrÓ1³®ë¶mÛ¶¶¶ ëºåryÝÿù?}ÿsž}ö.¾ä’®ó?’$I’c€aÜpÕ¨x ±OÝ_3H6¿Ûö¹ „É€Â*ߘu4"2Ò‘rU™uº•Dªg8ô9Xî†æ.Iè¼½¾^Mû¾èþ̃á a F˜ ȇúdæëÃ03ÓHà(<8ØI’Ü$4JÕ¿ûffvý¡C×^{í%—\\ÈíÛ·ïÚµkm±ð/o’$Ir‡¨Ê°PV‘I1ÎS˱ÆùßèBVšPROY=fšXÍäåù¸†P{®aèÝ‘€¹üT>¥ÿ(GãY)ýëçi»XÓ$ŠÁ¼UÖØh ZàÂ[º¶ÀTØPŸ`ë£g €ôµbÀf‚éW°ÓT´$In:’ªJ¯­­mß¾ý¸={vìØAr±XlÛ¶m‘š5I’äXÒWàR ½à“,ôLTÀPz Íx„r_ SØq”kt‰IšÕ¤EI½¬:àb2D—ôGýïšáß°ÔØ†y$ëð7Àçšžå‰ÁpآѱÞ#*A0:3l%"hD{Ì’$Ùï{ʾýïj-Ò“ÿøÝïi-3[,;vîܽ{÷ž={víÚµ}ûö[`Å€9çÇÞó§>¶&I’$77(0êÇõ—*:©¸B_@¹ÍÈT‰~¡€Â¢ÒD)«~¬,‹É£vUካǥkEG–F$QM )ìAÑþrUe\Ã|“X•¦¢ yFN×b‘š;•½q؉Ɯ$É͉™­­­Åª ã¯a’$Ir›†¡Ì FÖ”æƒþ6"‹ ß‘÷1¬l䣼n¢…RX„rc€@½”(B©Ö½:\8"¸fÓ2¯! úcº H5Â+‹Î <õÂà*ÖU¦Ñ`¹ `ýE jÛôO…‡)6µ3±>¼ÁJ[k’$7žú‘g~˃¿ùÿôÉO_pÁ‰w8ñ'žý¬>à,?|ö³Î<ãþŸúôüë¿|òÞ=ÿ¹ŸøÄ'ßöo¿îºëñðÿë¹?õ-bwÕÕWÿòÞø÷ý¨ÁôMø±sÏ9þ¸ã<éû~àE/ø/8ë W^ù…'}ÿüÉ»þpÏž=³Í½ü•¯þôÿúš×¾î5¯}ݽïuÏ7þÊ/û˜$I’Ül¬“BiI4Ö2ù¸€‘ÛHÚÎúd_l7£ú@Û4ÒÐ…^­ÒϤ€kÜ„ Hê™±ì@É_ÈÑ`j«¾€=@Q\_¯À‡@ƒ @OcI²”u–B¨@ …ý KË!ë¢ÃF™«E&ÉÍÇŸýù{Ï9û‡ßñ‡¿÷èG=òU¯~-ãÄrÞ>øãçžóÎ?ü_÷¹×=êy/ü÷‹.zË›ßø¦7¾áƒçÿÍ_Ÿ÷~•ù^ñ3×8ðëoúïozã®Øwå«^ýÚÞï ¦Í½ü¥/þú{ÜýEÏîyïû³¬I’$_^\\ù]~€EcE!¨DqÝ9’_-…,¥,—e¹\ê®Ôˆzº@[h¼è¯ív¯ýH’ ¨‘e}Iÿ)\Ö.u ‰B,á#c piE#P‹¡€KÉPpiŒÑ«q‘ƒÖÛŠŠ(Kh kk/K?X\K`iX²Ž‡(Ò¯E2—Õ³ûWô6I’›ïyÒwßëž_¿sÇŽ'<þ»®ºúê/ìßïö'~÷×ßãî»vízô£þãÁƒ×ÿø¹çÜqwºÓégyÆü€K/»ì>þ?õœ»ã‰'îÝ{ÒOüø³þæo?¼ÿÞ'¬j.I’$¹(X[ÖåQ—XP€%\«¶” å× ý†¢2dAµ,Ë¡2e•­îŸT²Wý4t-IS¿%E‡¸énšÿo€ÏsUÚ.4¢¶OLjUéQ—ÂIÙ…z[=¾V6 LƒmKÝ5 Œ&ŒÞ%I²)Ö‹õõõÖ²¾~ÃbÛ¶ºyûNPbÇŽí:¬Ínw;%¶oß¶cÇŽ;wjsçbû¡Ã‡ìÛwåÚÚÚ)§œ,ûé§Ÿ`ß•Wjs«šK’$In1ª„$—«¬š[ñE¢«eúÂŒpá)4„4`Ä_?žŽ0ÃÒUµßʧÔ3ÈXŸ•f]¸öI Œ¾áÞ̨JµÐó .I¾#ü†¾ÀŽ’¿ÔH%ˆ ¬ff$ÌŒ\ºszeùI’d3œvê©_|Iݼæšk¾ô¥kO;õ”¦ÈÑQâİwïIËåòŠ}ûNÞ»À%—\ `ïI'ؾcû¡Ã‡T쪫¯ö «É™^I’$·$û1–½¨2ÿ!mW à²S´ÓÐE„”æs –臨©I”Jª o’þRÛ4jàUw!‹©0 @§ðç@«„½žt?¬h”ƒ—T—H.ˆzºõ¯Í·Z¶Ê¡Ò’×¥Q–Ë2%I²ßùØÇüÙÿù‹~èü믿~ß¾+_÷ú_¾Û]ïrï{Ýs\îè9íÔSï÷÷ý…_|Ãþý_Ü·ïÊ×ÿò¯~ó7=ðÄïàî_÷µïyÏŸ_{íµ—_±ïÿãŽkN8ñÄ?óÙ —Ëå8#I’$¹Y)p•hÌh¹pÔfñ1§ñLW€BÃÒXŒ—,Kúíû®£¸˜# ‹ÔlÑ–$b¯"#B²Z$òú>x74¾vI–‚eÁ²à†‚ºð$ ©ÌØpÅ*Sëf-«<%¡=nª{?T=JJªÊ³~ ô£éYÒ°Ž²Nÿ¹ÚŒq´`^Ø’d³<üaýÉgŸûæ·¼õqOüþ=÷Ùkkk¯ýÙW-z†ÈMå/{É®]»žþŒsžqι'tÇ—¼èy²Ÿsö_}Í5OüÞ§¾àÅ/}è·þ‡a¥žúäïý›ÿÝ#ó]çœûœq^’$IrsÒSÍÌÌJ)Ëår¹lFcÂÅÁ‚BhR¤õ2d.OKõv †€4á²€tçRU)‡ž%Äa…,”€i>¼Ui;åao wþ¼õŸ:sGZ|À€P°· 3[}OþR-Ï«;§­:DÕ4b6|÷ ~` 0°ì¸ü…÷¸Ïý^wààuÞù¶ßŽb+yÜû®×#|4Þ`ÿþýw½ËÇÖ$ùòPÿã§D}­øFKщf}}]§›õõõ‹/½ì¬3Ïh½%[Š|ôcw:íÔÅb±¶¶¶¶¶¦D×àgR?ú©Z¯m"I’Û×þÍÈ›'?ýlû.¿ôÐÁëžxù¹£\F€qxèO aa¤«ÜFÄD| ÐpÏ)#£‡Q)I ¦ÉXX@.ÊR1vÀ¢—%L¾ê Uzz‚ÃOß3mƾ€ùØYOšG]t€‘u ĦS’$I’$I–™ÿ¦Jµ èã'úÚ¯*9þܨ `UÄ}s,“Æ‚6ÔÚȽ:a*4å€ËVÄs`¤ëÔf•©Ò¨ëz›^^”%e¸ô j¼ƒŠˆ¥·Bš­µ'„Yô¦V<ÂJ’$I’$If‘³xìè€PXÃWŠR¶F>&NzTƒ `ªœÔ¡„¬²£U/âJ²G±Qº±PšÕûJ/i=«ˆ=kGÓsbͰÔ†x­=sHét*ž ‰ò¶@ì†vìHš>I’$I’$™!D×L ±UZcÕØª²C¢(¤é"±©ÔË5 ’’$êí~©¾^£*€GÐ7LDŸÐZW­$ìÅ%ɰ%פV½™б8{“@!:ë7zÖÚtÁ¢4 —æ¼ ˆéQN’$I’$I6Cè¨^›ÝÕKCɾ»1N ÊY%ê|4è@¤õò7¦$©xj(X—…ÚnF+‰Ð¬ƒàKyyÃæs±jyU­Qb4 KB“« ‹r¢¢5åu°hèÒPWT ‘ÔI’$I’$ÉQPPŒ.·ÁGi+R²ÍU]7P\ôßf{ªÛ8«KC½öf¥ ©ÕÞ¨´â¯Åjv³e€aÁšÐÄJU’Ub†ÒTnìÉT@)Üè£ÃxÈÃh«;ÓZ$¬N±­¨¿4L£c}k°I’$I’$Éf¡nЇFlŸnÜ÷2ËÓ®C{…i^¾¢­±ÐôbÕäÂtß?Êx —”­’­Ô&½»\ŒB˜!™Fд*ZµICG€€Áoð‡Xw¿Q‘€ Ð5SºT°@™4 ÞÙ™F2‚®$l3Ôš$I’$IrôH!èË2Õ…N«äÓV¨Åš ¼Xc²Pºa“@ö µe®¨?=M7¤B#—°Ð<)DÝ+¦ÝQËÂ.%e÷&‰Á„/k2 J˜ú#=M@ë„Òw# EK@ÿCH’$I’$IŽ)HH’AÞ‹Ëá..7¥TU×ýh‡=êÜ«x÷ìýˆ~чÄsj'¢$kô:I’$I’$9 ˆÒKAG«—vZ3?2{½7•Rrf’D-%g#u ˆOLöù2Gւн.‘pã:ÂØfæoµÇ„@©1ס}jÙ™Õ5ªC*Ä;,Ÿ$I’$I’Üh$ÆÆ¦VHNÔ#àeš ©Ñ¹’-S%:”vÓܪþBr±©EÐGÔ‚¦p¬ïI]C˼TUÚÞhÞá—,媗MÌ‚FJÀØÅVÌàJ’dùèÇÆ¦$I’$ Ñ7¶¹V3 Vòï.#ÍPu5mаMxNɵUŒF%T ¬ŸQ5¢Ž,É¿è}òŠª ,þpCÙ¨ðª™b¢>^VNÌÀRƒ¯Ë°Gþá] Ÿêƒ™Xj+º¥gæfM’•œuæcS²eÈÿ±$IrôZ®T÷Ý `!A+€†~óŸJ»RkŸ„\ŒèRU¯½ÅÅa ˜•­”45 5ŸÃ,ˆÒ®B Â5a]]ö€ëÔÈ•¥nAí Ù™Pš®h‘ZC­£ úA«»HX×DsÙ M’$I’$IŽŠZƒ+Q Õ|hƒ̈́,C‰2®p!±N T¹>ÕQxVº¸ƒÅT-P’ý‰SnÅ÷[޹Щ ¨!E8Ê=§j(S'1Þðçé¨O`XÓU³ÿwÝvÏ58ÀBij³º¨aÙ$I’$I’ä(˜ˆ7@r«™.[åɼøu«iËj|uì”´ôb=mzÚ«¾,aÒ¡uÏdç}­E h‚¬*©%WµIšÂ n YLCb߸¯åF’Ãÿ$I’$I’$›¥€º·Oƒ´ €u<¤8‹`#ÉbN’¶BsVé:ðÓjÄâ˜@G3ÎF=:‚U;Öªf\oöë´eÚad4} ˆÐi¯VcGBlª¢7j¦Ú /Ú«rW«ôBÕhü<ÚÚî@’$I’$I²YZ×*<Ÿ4$$YnÒy‘„>ÅÄÐZؾ \×1š¢ÕѲCÕ ¸|T¹ESÑ6U:¸~¥úh Û†vQÁ刚Hzµq+µÚËr_ÙŠhÆ/ÄXÐ×v•Jî`’$I’$Ir´BÓ¤#Ê9¡‘ƒ³ÖM‘¸ ù·¬·Ô5MßÌ–Áü¨ygíÇÀÖÈ(€a–I°’æ‹OÑ2@HåATBn@cV$¶Ï¡Á†ÆH $I’$I’$GÅŒŽry×ä­R±Cf\ ¨òmRÒ-éó½j„ÕóÇÝñ´´¨4+Ÿ§O_ÀpýYkú"u5/ ‡rP«ì£à2´Ï`¸U§ `Ò¯V+ƒUõVäadL’$I’$I6E{ÏݤĚ ¥òFJkr›¾"ݸº{>äúÝuc¼À•_°ajpáG#\ßbA@†¾œº¤?M³xõ›ø€b¼£HmøíwŒu?ëK­åEb–yóë /’$ICý&&[™ü$I² 6RÊ<Ò†F Êd±6¨Ö„E[{MLmÈ(¿Ý$¼cj\ãQ]v Éâ3ºüG›T& …,R•RJMÃ3J)Ëj ¹ô|áJ­Ó–D­ØPÅf—’dKc 㼯(çœûœ?~÷{ÆÖäáVû©H’ä+îlБZ´ …(,Q€R¤ÌP Jqq&Ŧ’….áBR’Q4ºX5H¸Žˆ®ºÃ„›F[ö­ôi\¸ƒðÕžìd4 ¹;ïý!1xÚ¬c1À;3ô‰\cko¤ÿO4#n“$I’$I’ÍCÐÙ¨5I.†º‹5ªä“„¹8ƒìªFUóŠ˜Á*ä\õmZØÕr®YW@Àè3÷£†ÉŽºÜUÈͱ]PÒP¨… šÖ“$Ùÿò©O¿õ·~÷ÿôÉC‡~úiÿñÛñ=O|üŽ;Æå’$I’-A•R¾Ö¨¹êœ¥7´ŽíU͵ãV]¿X¡öB÷…®c¨Öº>«ëÂê¤WŠöÀjµ›ÞF' Э á:tÒé*áÔa¬úu a6ˆÂ&I² þöÃÿâ—¾ü‰OxܳÎyÆI'tÙ¥—ýŸ¿øËÿ·ØCÇE“$I’­@hC/éBùEÂüw@¯ †I9’›>% ýZS'ÃѵZév=Ë€ö^¿U}îÝi¤1óFŒ@7<¦@l‡5‚1f·Ó° álðP.|AWs·0h}~Äo’$G‚äë^ÿKßñí>÷œ³e¹ÛÝîzö3þo¥_ðâ—žÿ76³“OÞû}ÌþÀSôíû¡yæ·<ø›?ñOŸüôœx‡âÙÏzàÎpàºëÞüë¿ùíµñ°‡þس~tçÎ|Ó›ãýøÐµ|ã}ïó“ÏùñSNÞëÍ'I’$·2zñÖÈ)3¿¯H‹õY¾Ñ蛤û1aÔMsÉNó-—”ôq_O ¦i1Ó«–W‹¦±D¿?TëMdSAPiÊÑhTF7¸|F-ê%|x„Á”wF)zð,åŠX] à@}'ÉVe“7>ÿï]~ù~Ô#Ç€Ÿ{õ+”R>ó™Ï¾ì¿þÌi§žúÈo{¸²þìÏßû__þÓw»Û]ßöûoÕ«_ûŽ?ü_föªW¿öK_úÒk_óª;žx‡÷ýÕyýØÇ¿åÁú™×ü·Ã‡ÿÒ/ü·ãowüo¼õ·^ò²W¼éoè6×½äc“˜$IŽyæ%”…ž¼x¨¥/„Hb¨C`…KT¥ý§F]]#Ü¿†BU«ªÏ·{Xüo{@€¢nê¯aúSÌçQÂÔT´M«€ÁŒf¥N&«e¼¤Ûb³Ít/IŽ}6Pd‰«¯¾ÀIw¼ã8£¡ëº»ßýëžô„ÇàCçWã÷<é»ïuϯ߹cÇÿ]W]}õöï¿bß¾~èü=ÿ¹w½Ë÷ìÙó¸ï|ì·<øAW^ù…ó>ðÁç?ï'O=õ”Ý_õUÏüѹô’K?wáçzïÉWš >$d%Ir¬âª®A‚uŽP}}zð3­F øBOá Wu †ÃGy}Ñ6ÒÑ=4@AV¹©E—úPj,:ó‡µBR˜,m°6jïH4SØÕ¨È0=š[›nÓI²å°~µã1fúú 8á„\ù…/ìÝ{Ò( À_þõy¿õ;¿wÑE_ýõîû ÷©Y·?á%vìØàð¡Ã_Ø¿¿ëºÓN;µ–pÙå—xâ÷>u`¼âНù𻵖ä–dö“PÙ +I’­@AižJ -§=S¬ºî ô ”Œ,àT2„ÿTKϲId°˜œÉhøBïª9ß1e¥k³BsP@8«”‡MÛV©´;•$ °¡F¹Ë¿ú”SNþó÷¾ï>÷¾×(ë‹W]õŠW¾æ•/éYgž±k×Î?xû;þâ}5*ÓrÊ)'—R.½ô²ÓO?­O>yogö®?zÛñÇß”M¾òlð©H’dK3sbkÒMÏ—òzVclè`¦“Àâ.G²[°ÿ1éäè€`n+ˆ*¾D­Æ%Ī3•Ñ«…F'(ä2Ú™6”$Ç2kån,MÌì¹?ñìwÿÉŸþÚ›Þ|ñÅ—\èÐ…Ÿûü›ÞüùWç>t˜äž=»·m[üó¿|êm¿ÿöqå!'ïÝû-~Ðk^ûºÏþß8ð¿ßýžÿ·'ïÝû‡<øÕ?÷ó]|ñõ‡}êÓ¼äe¯¸á†Æ•“¯õ³±Á'GÊM’䘣À"P| ¨K5©,å’@<ã •VÅšvC4MÉo!XãÜÿ ¡øúÇT¶]8.¸ZÆIÚ9¥øœ¯IE³*Ú‹Ô2#ZLªše…‹iOYŒèõÂM³ÐZW+v2IŽy,–{Sbš;+>ôMøå×ÿü[ÿßß9çÜç:|øôÓO{Ô#ñ-~ÐŽ;žù£Ïxù+_sí—¾t{Üý¡ßúOþó¿Œ+yé‹_ð?þç[žû‚_ðú‡=ì¡?ö̳|¥Jå IDAT¼ä…Ïÿ·þÖó^ðÓ_¼êª¯¹Û]ŸöÔ'oÛ¶m\3¹YõI¨öÙÜ$I¶R~”Är­ÕÏn^\”öâ^¨…¥ ÐÐÎQ†j׊•¡“ÑEM›ºäµv÷@Ø g¼Ò²Ö©Sê‡ ƒð5 €5k(hNŽÌØÑ@xÄ6¼A.邦—†Î{:w¸þ­÷¸Ïý^wààuÞù¶ß®%Wñ¸÷]ÿ®Gì[7Íþýûïz—;­Iòå¡ýêÖïm›(¥è? ¥”årYJY___.—Ëåòsÿ~ÑYgžQ«'[|ôcw½óW¯­­­­­-‹®ëÖÖÖº®3³®ë”¨Êu*aÇ—‡$InÝ<ü]û7#ožüô³ì»üÒC¯ûÿþ„ dX•›¡Í;µ*ãZZ‰çiµª0›D5B.*l˹§ÞaÅ·ëðX¨T\@!yÙgGQ ih5%€…Nê: ROµ%,o5úñ2/4ØÇ‘wí&êŸ$ÙÚØŠPëÈ’lAf?³Æ$I¶ $ Á À•Z0A{™œQTcTôßFyÎÔÆþêFÿí·‚Iƒ‘®{Mµ dgjT÷óaŒ!pà AÅKQM:¾aKCY<«Ð 4 tM:ÀbhAÝ“@q’l1$XÛ Y×u¥ÄТdËcf]WŸw=xM’d‹C[¶ƒM PTtÝ5LwÃ@é,„”š+ÅifÜ[q(!Ûl‡Òk¢nОÂHz£zñ^—žUùZmÀm:Öëh‹J¸ÕƒÂž–Ó¦bŸ@%½|$j/’ä˜dU uÖØ¾N¿}ɤ~Ú×›7&IrŒ!}[õÊâ¢N6…auJhïootŽøñÔ»ûºÛÔ¡¤C1Z[!¢“>ˆó}©…·gaÓxÖè„·hÖ´¢æ­Ý‹ö²ê…ezMeÓ'ôçI°Ð½¥¨NÂaßD’l¬¬UˆøÿÁªÐZ²Å Z•Q–ºÙf%I²éõUÕT¥7£Xh°²Ü”þ !‚¡X³Å(4ÓÊåšÒ™k½â–n‹aÛ«ObÁàhTÔ66ÝU-DZû>JzŒ Ï?~ƒ6’dKaCñª¯¡¤I*õƒ¡tJÕ$IzÕU%žÅ¤"`¨û†zÒmúS¢¾Õÿ™T6CŽÚ3*?9a¹CiVÖ…Z‰4~µÚ¶¢ˆ"Á*õ9ÎæR (èvHvB§Rï/3̽@mÓØÇª†ï’laº®[.—R'9¤5`±DB¶&I’TF21¤¡•ày³Zkj´¸õO¸t…$\ßJSiZdsKfÓ¡± ¨I A ¹$ eñbQ d¥W«.8å*ÊW©¸w øä.ꨱY«¶mµ¦û~$ɱÍl„l”¨›]×íÞýU_ÜÿEm&[/ìß¿{÷îªSGib”N’d+‚ÌÝÒ‹º^œ 4XÅ+zu)Çð Ïò%'ÕE­ƒZ~èÊ+ÊŸúwîY€æ`4ÿ…ÁC½:¬ÔÜ~;0×Á,põâ:Qzȇ®Ý¬0í‘™wØÓ½ê' (ªê; E[=ð¬ùkIr,cs3®ZêBffÍHÖ;vÚE—\záç??(l öìÞ}§ÓNUµ‹Q­£OÈ*,Åk’l Š‹*ɹ^| `10V8`öDb®¦ë–õ.Boº4욢sPZ´w×ä-$a'©œU˜êOÇ>ÎÚzžýÚ³u܃ÁwD¢wRÕ¬¶¼”A¯“dk`ͤ«‘œm¥ €ÓO=…Íãôôår)£ªTJ´¯É­½•ík›][[³P bwL]%I²õˆS¾)Œ¨ó"JÔ4ÀI’ìHXPØý²ZúC19ÊÛ>j'Š€R§¼È6÷HµkfÍ]{Õ•±,‚h”ho‹?ŒÁ©ÓÞÖc¡„ †Q1ÝZ$I¶Ö(W}¹pUdMÔòª¢WéשNMµzëDoñèÕÌ$Oëked¬›¢õ™$É–…tªŸX0é½O׋ƒ)½™‹õâT­wè+im|&ê¯J”öëïü«æ‚,0STwó ÖîGxQ4_JçRÀH˜©ŒŸ^ãúê¢÷’Çfý#Hh/§ÔæRªDžo“-Gý,Í÷Ë]Üÿ­åͬkV`ÈÖZfªYS¿~eiÏqJ^%CTa*c«VG®Z-SK’$[‰4×c¦Ášæs‘ƒÒ’^~ÞŸU¥£Å=sy3¸t”°¸»>D>ʵ? Í\}$| ÄÓÚíQŒì‘Ј㧠ÊPP§è+¢y³ÀíTÆÛW=ªbßH{¹U"üôI/›$[ ŠW‰•š–6•^©_=)TåJ°*¡2Õ[ëv欑܂´:²}•Ök•ª¢ªÕÑkKõÙºM’d B°…ýpM4C7¥&•V¢j6ú`WUïO'¬/Àj¥f ÇÇ6Ñ×´ùž¦Ò “Ôn¤d«]S/[„ŸÙ_ì|„««çFƒ¸wh€™&Tõª xsn—­¶Ût.I¶Ö¨U¥G¯U°V=Z_• ÙF[«}”˜ÝLn1V‰ËQB︙isV­*ÑViýŒÒI’lH2ÊPBÑ5«‹/†ÜŠ¡d×(±F¤0„¾ÓeÆs—týYÇ[¬˜§ÎÁ2O‡W. ë˜èDs®k^W þoD”sÁ;ÚYº67Æ$9–±É€j¬Y’&£³‘TåJ³Ê®,Mƪþ§ M-É—›éù­Z”è†ÏP¢GjUeªr­Nêfˬ1I’c—ö ß§«‚JÉIjðiNg•@}yãr³×ê}äsAö#ÌlT@¾ Š»Ém£óºM†Y7é 'UÍÌ/·C–1`·B'ɖƆAVYjzmm!aTµªD5ÊÕÜ—nÞ˜|™˜U#¹©D•ž5цT[‘ÚÚeI’$!–ã“û¼¶ÚÔ™cì Àœ±Z6aÑ5héî¡s!ªõYÐ¥çÀä#]ÛAÃÉfP—¦Æ©·)º­€ª“4›;Ir,b“!51z­R@³Î ÖÑk›˜eãÜ䦳âŒçÔÜV}ÖךhC°2ŽkûÚ&Fé$I¶<º”$æÆÈ×ñé¢ ešjÍÁ« l]¾Ï+Â@X†ë€~ÂÔ<žß”ò(i7*§`€ØO:ó}‹Âøò®¹ÔU²å±‰–•jéËji_7Õ:Bö4· «ŽóTeVyÚ¾¶‰J[k”N’$ii.Íä+4“†é}v¸V³©n­ãÖ†éÖk'ã*ˆBÀ` R:hNm~=ÓXÓJc¦×<ëW%=\µ—1²èLùÊTvj5Sd—~¸t,“d«`y:ÍR¢~k´9ʪ¯3PL¿¼«ŒÉ-À¬¬œêÎÙWQÓmÅš˜n޲’$9æ9ò>´Z£¸Vž(ª7Ö—lòF³ë=M˜KÚ~E‚Ô‹PÉ>—.%•48ÛìF{î«GÄ…„ä³¼ÅN–‰H6 xÀúØÿådåÑK’c›èÔÑæ´dûÚnÖŠ­]¤Ž¹50š²T{»¹êuÕf’$[–öl_™=3°Š¹é˜€ÀÌX%!\>VºÆ^!@ù®þ#±¬Ææž¾¡o_µ¸CßɾPˆÈ0ºÃ¦Z'kTÆ ëh_€yQ¸[èÚJH.G6«“¾ k[L’- ë#»N4U¿NÏ;Õ^Ej[lÖsr«¢}OGÒó¨6§¬²'Ir 3ŠdJ¢‘]hê)ÄåZ¯Æ+R¨«‹¤Ãuª`²4“ÌÔѤ$ØÁPÏ) }ÈFù ß#3輌Šy€J7G‡4–wä0I¶ #Ù:µ´2t•x­¬²'·6V½G7BžN-I’l)ꔨ*³V Ö&ÃBî5hÛUac÷©ô½O‡ºÿb­¾VTkpgVô‘Ž£Òóñ¬qõ¢†²o‹ÕýŠ©ÊÔ€s8Wbì2I¶³²ý÷®·TãH¦Ô’)_ns̾e7ј$ÉÖ‚¤”V³ªSœ†‹vc´`¯m^¢€¦$Ô(l;Œ+äݬ+ Ÿ¿?)0 yxÔ´jR‹.‘õ,Iÿº}+Ò¦C7†7Ä _1mÜÁ$ÙZLe«Œˆ/ÒÈ(RªKlð&®ÊZeO’dKÒŠ’cD½{½ñ)ÂxÕ8T0¹$!ëNõÁ”hP§×5LŸ©ûì|<넚4³f¯TžðÞj}„Èœaê¿v^Ç»o:D¨Y¾¿µX’lMfe«ìJLsWI–iÉäÖêwmÊÆ%7ÎM’dëP׺2„ØŠ-Äœ4ê•‚þë4CWW£1|ÕS`þÒ3µLQ™²J³Šè+Ù<×Àíf­Ž÷¾Ô#ÿuÈ®ÛGÆOµoÐÏ$Ù*l O1Ô(³*©fn»ñ½;b$I¶ý UuÀhsÅm·´×’ªÒŽÌfËa³ϰ /àªíºžÀìYÏ…£A/ê¹$iÐL)Ì`4ý t>ô–€iá.—õRp€Õ,‹*šù_H’ñ Ý@˜Î}…7*ŸÜ ™}7àhË'I²ÕœÒ°Ë²®î—V…ªgLI’$I’$É ^ªâBWÉ$…XC’UrŒÐd±Nó5^ 43P[†ÍE ÿõ•²˜ªo¨šº€jFC` Ý)ÅÙ¤ÁpSCT‡Á—®¢? @Ag¬{h±¢A¸ª#eb´. 6›ØrjÖ$I’$I’Aº¬’&+èåcSЯÂxš€%Š‹VÍ;ÂQÈ6_ŠU4š°]À9¼L›  „ ±n€êk'Ô9U™•`&©J2d+à~ä]œ«€¡ ÍZÌÇíŽÚœíB’$I’$Ir$†b°´êM£˜Õ¬éœª«B0mI¾zåçlVÝš9XMuešER¯>ê´–3j×B·ÂÙ‡)è볈>“3‡X%OgJ&I’$I’$G"ÆeޤelôF36fäÍá¹3"md"PjÓ„3^ @[†D3žµ7˜«Û‹nTqª|¬AÛ¶Õ@Ãóa¬èõ·oµ“~&I’$I’$Gf]!ªüæyÝ4(2Ù ¹ÙŠ G²meIƒ¬k6›̶9Õ¬¦ÂÃN÷ªïÈÖ8ÜØ á帧Z—nQß:¢4vu?›6“$I’$I’›ÖÕŸf㌃+AŸ¾hØè(ÄØ¨¼Ê¬ ÙAS¸€X„Ëü@´YëM׺;z-CR5mË|{XäpY‹Éªb1SK•4= æ:$I’$I’Ü(\Bj ƒè$ªR›Ù2Ù©4zYX }è uÓ»ëÓ4Àµ* @³ªB_«-.¨…U†|¬j²âP7;OSsóµTÛC¯rYŸ»`¡¡ãX©BsÌ|V[GŒQ¦Ž–M’$I’$I6ë¨^0Vaå&¡øWi½¤“™õÅm}ÅFG#RÅ]àkGU .¼WM"mþë]B—¡¢—„÷ÒH[½¨ï’ `¾ê•¹:î[V`V"–,(Q¬¥k’¯=n:*7I’$I’ä6Ì=Ž?jyÓKµ¸ÝÔÐh+Ûà+¡ úë¢XQ±B DC«PÍÆe­ö1ÊVGŠ…VRUȸÉ6Di­$[×õRQŸµf•O¡Øh× lmw‰uOuÈ"äZêð/M ŠibúÝ ?{æöçþýáýÿfÆplŽÝøøþ±-I’$I’ä+ÄÝë^sÖö±uS„%à7ǧª²Ê-`½ÄPõØûi!Ñ·1¦ŠZ†±B ‹õY}x‚’ð>É•™kߎý\C“ôÉÛQÝö·XõÅs+à¿Ó>zÇÄ\ö†ìXÃëpãÞ×$I’$I’c‘Ð_û›ó披Þ'÷D½åm¹­­(Y :÷ç*ðèfG¯ 4Ú®n«.†;S©Ò¬ÏŠší"2\Vב`“Iu´Ùè%l´=,ÐG^­‰ž*é›ýñŠìQ:I’$I’$9*z)5q.¿<ÝËBg¸”ÓVìÿú†$]{‹žÐ ±ÖxSŽ”vCk`3ë@E":[k”¦ê Ý(Ló}5ÿUH@Ìø’]NÔJ#„}7“$I’$I’›ŠæÍâz®U‡#|’ý˜¦¢õ›Ú6ûz죗(ñØTT¥H½øŸiºÆt[Í:Û§ºB‘ ²­ØoÌ:Í^MÔI’$I’$In­èZɨ¤çÄ<ËPú°€11w¿µ™ª-+¤÷ v[©ŠÙ·Ó Uƒ"¨‘gÖëëaД¾xlƒiE G–ó{š$I’$I’%ˉ„ìBAÞpªkÍ0§Üj1ƒ´_›Y3Æ6/6;6UÔZ¯OÛ?}$aU÷V蹬€ÊJ§öË] Q‰±ṳZ’$I’$I² š€ªó6de¸ôHšm¢'ÛãG“öÇÞc{•fí£ž¾é/:ÄD°F¡SÆv7bXQ>Ì|¥X3¸Œ® tsÝ—Qöáš$I’$Irc Š‚ƒDßßæÅh+(0(+=­Ô] Í7R–¬R· 9©¾¶Š ¼*þ"Û‹´Õª"]©YWSêžZËÀ}µAæ~.Vcj7†™!Izš’$I’$I’£ÄÌ¥Áæ••Ç {-/ô«÷ôhb.Þ6iÕ‹Š3€hª9éã\˜ha•’Øö4<í¸£?²ÀбÌ6þ{¥v¹8shk:I’$I’$9JH—D•x½suI©6×—]Õ]mÔÐL±J€¦¥íÖÞŸ—|Œþ [ÉØ¯"5ÃaD`è¢Z³¶®n‡im–™úUÒlæš¹ØÕV;v „À…Û‚ÊS–`Ý»Îúø¯«²b\¬ïd«YG‰Ó>Ÿªn64ruP>6jàÖ@…˜ ƒtÝT°I’$I’$GM¯M}©' ä鈸ö4#[¥÷0Q•CL2q¦È`üÀ“6´ÿlâ»hÖµÏÁ0»'CÔuÉSÏÉ‘NöƒVV¤¹Ùæ’$I’$I’ƒ )þ‚ FÏÝ„k¥gÏf*®$d!ý¡¯ÑEƒNWÎÁšvhEo»Ù–´Yßf[{âiÚ܈¶Æ®¯Úýä§ŸÝ’$I’$I’#@5‡i.Š¡[!üæ¹Ñ‰<¯N¶ÍP'qq1ÔšÒÕYÕ¹QÃ^ȇº¶¦Ù>Xco¢¸I’$I’$ÉQ2ª‘ª‚5oªä8”b#fË»yÃ@¤U:ƒM[¬ÝÛ¬fUÆV@ã¦QRW±„Où.ıÒkßgà ٻš‹.ü·±)I’$I’$¾ún_WÓõ¡§!¿f¢R¨#çÄŸY; t€†ËÆ`ƒéšT4vi9wÃ\0úxÖVÕzÑÉά`Ú$b謲F¾ è Ôìéq­gO_ðÉ7Æ$I’$I’d†iho Æ48 1õÁÏ¡,›j4IÇ‘þ‹iYt‘iA%ûW=Ô )ÓBŽ\6?ž•šuÜ2$”æ Ç7h@Ñý|²ƒÑE*»Ú;Ó‹Æ (ÓsVráþ¯ji¶ò €ëvSÈ×j™‚øÏ@”é©%:thðIlF;4Â`41faæ‘]jÑŽp¦{3R¿}æœÀ›x³9WV÷wˆŒƒwÀlÖÜ3‹É(@ëFv¢)IÁ­÷¾ó]Ùë¿Z¾<šïcŸƒÞÀ`Üh–k÷0ÒñNs '–úFk*£S7†]ªxkÔOˆÛGÙ3¦?ÃÀŒÞõ¡î1}&nwHl¸ òL‹u¿àŸ$}œü›Þ¸€æ3Ù.2ÇPÅèáü'³â¾5̽å¢q ¢ ò¤2µð+óö# Á°s¾¿~ØáéÊðpY`lÏ!^FÙ‘:¡+W ¾Ñì'¢J»³C¼lßÇ r8=Øj7Zô·C… 0 ÀßÁ¦°éªh€ÂúC±ò#7·_Q;Z@Ÿ¿ó³N¼V@ô­Ìcß €Í¥{¢«è?(æ}©ç謦i~ÑeKií5Ã㦘9ª€¿ý™\A‚¨î®ðÖÒv€öfPèVœ%gð«'¡ïa4ÀºAEèˆBÒ`°z$§4ç«a÷¬ÈŒfªlú0û[à¿‘Ìö¥šë5®éRM+ot-¨YsŽ›Š]œ¨t@L™ýõÀ[a”?¢"› ³†âuW†‘ŸAš AL>~S×(¸ñØo²'ơΜ¢h§A ßàŸ;8DPé)QÙ@²ÙåIaÊúM¹ž¶ÎæhD‚ oµ,ü›n€Î…Z57ÎİúÑÓÿc¼"4Âkü™0á×.¡ §t%kkÅÑšVÆ%¡ž¯ÄU?´³Õ  }æQE¢½zômŧ…ÕLö’¶ñ½Aïzš€V®µ;ÇþMÑÖeGÖ`elöª£:öÌ™wDejC𞪎ýc};ªŸZ¸ö³¦µ9ô6ã{jú´Ö2`ø­ìÍ}yÿJD"6"ÝR÷hÆc0ÚÙÖϨb[r¶9`R'·âÛ3¥G†X9[Æú6Þ/¥ëfóvûi‰˜¹@:gösàz/¥YãÌrxöôÜ·¥?.}xvB£qV½\xå IDAT”iþSb¨ Êlúÿ“è@*/ÊyÁòc\ß?Ö|"]ÛŒb­ ÷¶ïQ}C¦4®Æ;[³Úv'¤Ý¯ØÏ£gÔ¿¶W°™xŒXuÍÑöA ÐGÎÚ‰ÙON úþ0ÿ­9 ƒÿs‡×ý¾E½éþßU÷Qú/|x»É´]!ÿÅf²dÔ ÝwððÎä¿ÊsGs\€çJj@s¶s{=“Eü,Þ©Ü–B° øMÎ@Œ®V‡¡1°qªbÖüeà¤?h+z;{rD=sGÞ´?2ÖŽÉSµOiì:)5§»!«<Ìõ˜+?µ 1Æ>ëÈ÷̤ýãÀj1Oøw¹æVæš®ÝõŸ­%*Ž{åè(ùí×hÆÁQÝŠ¿ýi¦žõIŒïyµHq_±½6=k¦WïɪO®Ófά€b'FÔ/°þ”¹>„¿ák‹°$P÷M‚P”‰£Öâ uÓ €ŸŒ¼Eo0Îc}÷6ºúTü=©µúêÃ4€Ù}`6TŒó‡pBÿŽDyã88=+³Õ!ÞÿQZ=à 5‡6ó¡kß’vÇ7:¨¶z­«~‰™œg0Š®zC%_ôÐÿ¹§AG«©ÿ¬k7u˜ú]6ô¨Žßø7>”·ÊRëÏîĽuD•„ï±ãÖèaãa.8D)¨NHÂèƒ ú qó}°/düŸri¤ N³rè÷š¬-°ÏÕYܲª‡VGyÏ'gÈ›9 MSu¿нy»+>r9uµ=8jK [¤ÿF'ãƒç¨V«‹Q·F¹b¦ë½ó0ôy½¥åaZF´r|¶LëjÏ%4Zal_…Ãêîwtøj†C“„LÍÿRçi÷Bj³mKÎG€Áî“Øà¿4 <‡"3µT]Õ™,ìJèz~ìà?½zQO°:•÷UbÇN6fîtÍú‰ˆ·¹ÝÏzŸ¥VlxVÛQêeÚ—¨hMöä¢Éèdý„¸Àø€¬üŸÀ,êj{â ™)£t_˜|¦4jæw/U§ípû1®éÿ¿·oYv%‡‘K¨{51ËñÒá…ýÿÿ7µàE`$K:§»'ã^ˆ7ŸE•$ê²$¡õùâ?ͺ!X4®UîÊÖÉ= Ó’[ªj‘×lÁÔyÉ/¤`°x¬*«ÙZØ:0bdî–è[atÍÊ2M®ÊQ¾£ns³µ‡0Ð<Ó8–{çcQæÈ*fRŽA$à• W‹Ì_9ܽ5€;±š™2«ÿ¯¿)0CGå¾;(¸o{^º=èj_s”¯Aãê Ý€ƒ °ÎÝ`îDÈ>ŸÆHÍ:‰—jm0^³±ŽI0ðÔ@¯}M¸Ù0¯6ãpÀ±ÃéKw«9ª®[ ¨$­_áÈÎ|Á =—uí>ióx1PsËVº=é…enïÎ/]ð C´vXT§–WUMæ¤mG“"Ø% ضVS„UôƒC&çpò¶Tž<ü³¹“I¹pPpðZjZ•I›á9 †VzŽN¢;Mwú§Áx…6î~RÆ9âÇËžA cþäô¢¬<%a¸U!?¹u쉮csèŒ[g«UYpæüŒcs|ˆ{Úº1–ÿ•Ð<‹È…Z_$_LËY%áÀÞÜÇ•(p¯ùD]Ug<‰¤óJHbK°~UÌÐ.͡ݰ·ÄHi=gKŽîî²?,V³SÀôðì †±sÄMìa#ð!æÀQz@Êžnsn8uO«4˜Z¤¸ŸÅnÚ€×ôärƒ•‚ˆXvÉçŸ'wóÇçY‹lôèF5ùö4Ltˆ9ÿr³‹“|ú‚8>l˜‚‰íå зJ?]Ê z& ùòW‘Üþ²C¼Âg3àícÚv n‘ëºà6¿|Ð;º²=v¶¯äLÒ†0ÝSãÊ-f^í¾O˜xHåËbÚÁ©2Üe‚yéñŸX~,Ýå*•û*À‹ša4có§úÜîg"ÎéÌœ8™Y™×13³Ø®:FáγÿEÁºí ß ÙX ž5ú¢j‰î>v6÷²Ù¾(€ìVg?gf›î%Òq¤ï;×Õu—‰0fÍÁ§E‹Ý@ÎæW 8y[ðÜ%òPÖ1À•öHDZ¯I>Ì]šV–¥vë`‡è{•SÁUàØ¯&Þ( ÃÍ®yÄXÊ‹'¯’·ºU临øß°B©©~jI4£ÁôW\oQ;öÕúå@5Çr JtCá?YQ8-^G„V?îg„ïMyÄU,šÅcÆ$•³ [[4¨éú„Ue¼t ¿!²Êlòø&º^wÈáëÓ™ú0dži!`F7ãÔ@º´{½(ʇöPHÕ±Sô¼YZZÄõFk,ÁQ^ãÆÜùA¶ÞÈ:@±‹ÛQ´¾Ór¬ö*æØTÈMŽê%ß=±¿›-€©—¾¯í“¤,X/™#L͘²Ø PÃ;÷|E)‰|ë"»alUÒ€1q­Fö0£XÅ8™ƒ’¾*ø)·BÝ]!$H¢à¡ºcg‹kþgÈZµ¡óõÙ""ØÐ@W sV|?~ İ VU±6“Y<ŸÃ×lŠrZ« ~ !ìÑç#øHKõÂÿ£ë}ü?€lÛPÿ –Å»{áïèÛ5jôÔý¨W@~$ôßÃ)„G“Û†q9o¯¿Á—"¾š5Rÿ — å‘xýçüH >$ð'ølØØhMr’Ô™‘¥ßúéÐz¦ÉHû¿5{ƒßU>»õ7µÍZo$Þ{Qƒ8VüS[–H½­;ÿu#!ßûÜ&÷%å›}£ÔÊ‚FS<5[É¡9Œ²yÛ ±ŠýŸšæ¬üÂŒožgíêVT£[ùŠ>ÿÿ朗ˆñ{PwXî#5ÍØoàN8yu’·ÝUOžòtm;ƒÔïSÅÊZ ÜL&¯!o_&¬^¥4—?¼g&b[ö‹¢"®¹EŠX*A§1ù6£*/ámÑœÇç'ì&R[ Ù¡\­ JОàEÄJ³"Œr`w~¬Ç7 Iü +3Ù+‡ó- ²pR"SîÛnÐQ7'€eù…”ˆð±°!ôî¢ûŒ¬a%׳ð Gž²²¾zlâéÁe¢¹ê@%d ½8ÉÀËyš±?óž—yšuGÜÝ'Œ4ÁÖŠ$6ô9h1 Ééí¸c©âŸáäýÀÁ“÷×>­90¼Ýb<â`4×ÉÛ2züg©Oi¹ÉpuÎ9yHõŽçZÅ~ϽÉÖ±Õ|„aŸuˆm·K•ÈçLv\¸™SGhÞçlG‡.aÀa¬-”öo@íÜNc¡ëMÓ\T6OçkJiÉ'¥¼4xwr&éÒ†}™ž}$«u°3ËåðKâR²ö`R¼-Ûà€^°ývCë%=D{ÃzàóžÍMqª]´j¶¸dŽ<ªpðú;H®*/´h•Ý¥©;1±Dmïòn°ËÇçÉwÚf·r¬ÎÕ 77nQC”ÏãLäOt´„LÕþ>MÂÏšO½*µ8ÐÌ(uÁùÿÙŸ‡¤>T'lÎq¼â«u7j‚x[?1&Ë8¶Iq÷qHiæÁ~Þ4?FŸøÂ퓌„žcQ¢F!_9£ãâ‹¢êJì~m(„pcÕHȹpeøÔ ›'™©F<  ŽÎûŒcúOâGÆß`ëNŸã°ÉûÚïÎW½¿µyZä ÃÄÌÁ׸ê_¯±©\icvˆ¢Î°$Áƒ%"ZUÏû4 ©ámW l €ñ‚Û`hª®(;g†¡‘øùñ‰·ûk¤ÞÀ`+5'5•êVšøGóZ2Çd|&Õ;8¸uÎPkÙsÈ»ðIAWt[ÑTâñÞFÜXXÄ£‡W´B£ëø-@îÉÏ:C”=W5¹Ÿ._nxÁëzYÝ,7”~þ¥õ+”qoW »¨ZP· ­ ªíÜ«\uŽÓǸ Ž®íÖ×q)Yñ–ÌÕ y&´|’~¡³¸ïB\j¥£­2­¿æ>ÏßhñWñÌ/Ì/Ò*å¡v§ïМ0°Àvw=Ý,¼xèÛo ­iÌÍ¡ï®<…àΩö[Gpò/Ð{ˆˆæ“ÝõúÙ*ƒ"ªy·rˆå¶=ÀÝ·–Û-ž@Ï9'ßwcp}3àÉS|ã »ÆL$°Ÿà"‰ÒŠ-¾ß$ÿ0ÔL?ù¯Ýš&ö„øí÷ÈÈpD\NÆ\ >íDãOàpjóñ;%wð-ÖØ#9•#[W+«MwzJ%Çã½Ä‘ú`=ܲZzËU¶W”†x§ÈÐÞû90·Èà0óXB–•’·|G:Å¢·ìnŸ°l§Ç')ø?ã ;ÙîßèŸpàöÝš”ŠMbÊºŠ’½‡´&à—GìÏ2Sú­—¯øb&=†“ ýr@ìÓÝ*{ØÎm_ V‰—Y0 Ý^¸»áûjÏPóKJb?c€¯U¥¦›½b q5»¤ÏÎâ5zsÂ-‡ÕZ²¤rJ"(ƒ Þ¦qä-Þ|k"­àäpÕ^Û¨éíËpq…ŸÌ,à0‹/ ;!Uýj¦«ùÔòͯär"+¬å¾-TµBGÁý/À2“µÞAþ|Í„(¢{/Çz9_vøuí&5žÖ¹8Fì{‚{ÖÚëJèg~Œ4ØÝX(3Ú„7÷ŽxÐ\ÿ˜Š öCˆœ—X_…Žêæ[ÍÈ­N†µ,)È?OY6®íZ<ŒÊ}¢cSnOú†Í %®ã~á–âÎ7ÌÎ<µw(ü÷oá“3å¦þ–ðÀmó%~ãÄ—ÉÙq¬õÎYf»Æ9€w®NGø½ üLž»qÍÙr(Ÿþù¶+9a ƈ±UêÅq¯µ ÐP⬛ 6: :]©éÿ…öåj%êÏœô-w+æLA–O¾„óÇÀaâ" »ûÒlb«ˆºf¼¸ΛýU@⤎.xp±úa,sã€g.Ó„ó*ãï¹¢›m²>3]”ÔÝÕX#£]Ü«¬Ìõ Ÿ0‡gð™Uà^Éø|‡Ú#– ­|¥FÊ„d*(÷4í éÎúc€ÇÏŠÆ•kw äyGÉ!A¶<ÂtßïIR˱æj¶…ºÍL–WüSP.f‹Ë¨³üêÐÙ?(óÚƒGu=×ã÷…¼QŒ‘k³[ ËÕÔOf2¼7â FQ<ñÚ¿Õ†æŽ"9@¼^ªJK]ðj;@©&¾i$ZÅKì(]¨ZeçñÚ†X•]·Ú 2År]ñ.:œãŸÕ¨?§Û9ÍEï©à¶ºÖ”.*iÃo€¿Ú-¹ T—Û-zV;œ |ñ `ùÍRé²Ã¼}€3D]cwDH;’–£Ç€bÝoƒ?53uõ™aˆ•.t9Ü\½…«TƒÃõ»®Ôú­¬Xé¾À>Šà½Lž“¶(Ùºt`MpPù)at~>»NX÷àþÞst÷7L„Çp `[6µé8ÿºÔŸN¨ x7…Ñ…9® *°´hl=485dEióø@½ÿAY– x/÷úº†¢'¤p1@$Û “z§ØeH¡6C߬Ѵ­€VMKè Ò JÓBŒd¢ *hX¦:çà Mj1‘.æÌzz‚®áì.ÉÜÕ—ÜîØ#ÈÕ¤» Ñ×âËBÜ£#·#UõÝгPΫÎ#ª* ÄÙ;ÜÔSµÓJŒrwp<Ê´Ðâñ?_—ftãåîÔrÉÿ Ç¿¬)B¢fJs* ;Ô#»Öt½—»ë–«¤=ùTUÇaKÔleÏlDQ§Îì0Gõ¯td(¼»vBòË á¢qyuàT˵¬H(1°{&S¤õ&Èò‘¸=7è9“CB•(våéž)±qôOG¨P³´ïT÷fçzq,ÖE$é{Ou1ha!Ã¥£ÌðRt“P¹.:. '«ÞY©=§ ØÑÍKc9è£z‹ä’mÀáf¶<@³]£šÖê3XŬ±ãDÒk•wÀ놛3ª¡(ž(·-|³`ù5–pRs3>ãHÔâç£X0*ª«šS’]QŒDf0F[´À³ðå?þóÿß/¡ÆbWÙs4Êó)°…dŠò§Y²´° O+›;kIXa–¼±ÿ~0 d=Y¢PÄR˜»ÅacF²Ô¸ކȩfÁ²fjÒ¥Îtª/Ç›mÑ›»<ËáèšM«JšÓЏÐ/cÆ›2bºjhq4"á©A" Žeölz èþËÅ&B‹â6r—Y— ª`S¶T*Š-Ʋhð2;#¬…°ÂŒåp±Qw9ÒCˆ«FGî):†{go¿ì鉓QJ»ˆÕb·R‚,ì $Åðóäc¹)aÖ©$“JX×wó„m‘ç.7•¿SÉðyóŸÞ£º.´åFöâÑ70€!hYN>NµÝUú¾ü0¼BÐÒz™ýdÄ>1ÝX.|üŒß*à–­aë!?Ght[Ê¢½z\lÆ÷QŒUÑFç]pš ©§Í9å*Ëg,+êX–7Ñvà ÝY!Z·ºÏHÑ'Ç®1*Ž»·†ç;¯Ío—â•ÇÈà†í`ú`Ìâ?3A )=Ø™–©ôsÔh¾8€X  ¿Ýú…^<"<Õ;³PìX¡7ÀÓ‚ ?ÛèµG? û?¸­×½n<€ ' õäb3-þ?€É)ÊŽ¼Éáî̳Mô§dc¼ñ'—àÇv´å-Ài¥¦¥W>b.ˆÊŒ1+€Õ ›9®“½]X¹ÜŠ¥NÀñÊ}Cˆì 7¼Û¢î/De¼¿†¢:_kãBSäEñ^}rñ[dc™¸Ç¬Næ5VÒº3¤çþÃÀçÔóL"+Y(bÂIw …ƒÎ¼-Jv¸¢Ø¶ûIòtõ#J|„8»¸ƒNÙ(n– ŒÞð3mW BiÓ´¨3ÆGÉ9’`ö7iQ•²Ïš•ÝbG*äl!te> tCÂÜ QG9/†¶zñÝ5̺cA]E¯8?NÎû  Û¬šúNên¸%äç(‡ÿ–‡äèô‘Ëm{‚E³Gë8I@P²UZnâè3Lèé._¹nS1bÚy|uÚ¼þ€Å¡Ê|H\>£k›—AEê;TÿÒ …£'ÿ¸;‘ÍÝŽ¿¯Ùëó‰àTá`ï‰rt-Ú—lu¶™ãm"?mÛ䇡jûHüñÇþo¹œ0iÚiž[¬56wÿ° æœËl}¦@ÿT>4ˆÒùSÓK¤pStз‘4vVoÂK³!zMÐG [ã¦Q‹Ãž¥jªY'Z[ñϤ–ñhâ­7Òúæo3jõò µï€Ÿ~@Ëa€¹îU yÇ9aM1gs{‹ab¹×gÔ]pQdœïl(âæ=—¨$¯½Èb8øÍUV.õ-Í£ÂÅMl®~Fíy'ÉžÕLe ˆ„Ä^ÍSÏ!n,qiŒmê¾Glv…®YíëÖ 7†#óO¡1ÖåžÒŸÙâÎcÑ«èšÃòéŒPòÈs@øò=Fkm çÉCõÉvê!?€¤óâP⣕±µ³þ"H¾IHUãÒ‹ƒ¸vŽk8ÊT8(Kô}üMsÐ5àOóíƒõo`éd]Þº©åÖ—(Îcê,ÿÉÕˆ|ìÛ ¿0¬µ¾è— 0—~éz# ,èg°nt´‡½0w¬Êî´MÛzäÔ)OÙ}“!ž±Hâ—é ÂF‰åÜ+œ‹ÿö`øCÁFßI‘Äã³aÆ2ô~7ñÂ)3m‡µ*U7Ù!_Ø©ðÓ1R`¸ËpÔv ½—*dL}S{ø-ªë:`üï@¿oŠž# ZØèi(XÏPú:‚ÎJ*~÷—Ž[i£á[ßv=¾GºÐ]Ù@+XÉéA)âíWl«|¬Eχ7ä9¨bvÝæ3G÷g÷\¹ö›ìNyëíBg6¬HóóR»͘FŒUþJ…JÇ%/Æü+‰ùÊÓÅ[,Ñ‘æ€úk~ cþw„g–æšÕOëw¢Q©ã¤é Z7 &ƒš'éÔlˆ~¨˜‡Egœ]Þ°î_Êö}ò™'™¿œØ¢ql ÀQ÷‘8 <ø3ûCXvÍÁÈ}`¯4jë€1]˜›ñ­ƒ~Ú6{òADq®ù¦ cê"G¥­Iöõþu 8; œŒ2ö¼Úë±;a™7WSËï œ4L÷ŽÉÊ÷%Â꺫p‡¿üø;Xì³/+B¹ÇÇ_ä$X>ĉ‰Ó·ò‚TWÎl¸GA‰@üÿÂTi{§lùïà,Õ•¶5^FåÐ’†Fx›Ùs™Áp\+ÓS7 îj¢\³a×6(!ã"ä§Þ6– ¨Ž`ɰ{Ù@)Û ;Hl:§îMª©B‘¯ÎV Èß Î˜A¬­¹™õ@ˆéyÇãX>Ž _ô³1©úÀ3¬²™72:ÀÆñ,%õôZòuÍÖpwàpS÷ÊnM£ÈY..©|÷iyß|—Ñ.hp_»µdfCN}u0@ÜÂ+b9Â2¿C&ÝV4Ï„Zœ‹À½,+}6[7ˆÛ.à=ú(”ò,8ˈ%+G{¬~+ß*ööbÜ|½á¾ö½žE•15NReœ“h\­5q"ÛZ×bTÒ v¹u‹\Le%¯zí3"bfe ²õø&Sþ45þJ¬1·UNžŒsŒ(*JV[²ÜšƒèL~Òëpiý@©mFU‘ƒ3ÌáBð!U6 7…)ö$'É›¶Rrƒvªˆ¯B7ä‹ÔÖ(Ú© @о«t÷¼› zÔcõÛ-ö¬{j¯ÍÕE½ï‘w7o¥¬¡ñ~Ç) Ëƒ ˆZ¡Ž¨Œ:ûÐÏÀëþg©ÕOö©Â¬­LÒ_s‡¿â€öí@þ'x„çÈF7“mÑáØžµ h 9­6¸\Ï. Y%˜0ùɥأjâȳ&+ªv€kgSÛ½D¬ÐþÊëD´tÑBÊæäþ{öÌÉ_ÈÛ½ÆÐóJ½ÑèÑ×è#ÌäØM”S ýÌÐ#zÜü%FJŠkÃ<Êæ€§17ƒ9¬N>¹Ý™° תÏu¶r(Á-6õ%´éÑWKP íP£ÒÀrÿõ|²´PójÀi`ƒÖÇH·ŠJE=P™)bd,இ"ÊÜ)Îÿtd÷á‚{ ©íDØöU xÝñ÷6oãŠÃÂÜ— œ÷vTÿ Á³ØáJ’ºWf:< ©Î 1SºAv«Èýõ‹C×ô¦§.teB« qÜ™t ~¡¦-‚,]UCT1%>ÂK¹¼Ùã¢Ý—£\-¶´² ÈÍqI²Z_!«‰s˜kR0ÞyÔ>IÊòêšÚ‚U>Y·$q!¬:EtăžÂL—Ëa‰È„Œª†RWÌ*_W6nØ«ÔUûþíÖ%ûÓpéƒ`¹Ô4¸tÊaô„[í ×¥fûÐæ5ÝŽE÷?ƒ:áž'lÁ‘öƒé+™¬Ù¶®Y^k³uvYQ:¨‹ ZIDAT×tQÇÖ±ÌWª oE¸@¯z`; ÆõOÅž!Jˆfö£¦ûx÷ ïß$oðnöçXzˆ›QÀ>#t°öO~³iº‘f­´ýfLÂÞ¬ˆRHbv:±Éú8ð{†:ÉKú{ñ$@‘Nš‹?¿³ˆ†š•xF¨TZï1M`8O ,Ž!ÏPwkz ·CΫh<Ù›ˆJyí‰p8øÕ~qdÆòöÖ¡–EÆÈÚi´é%a¨`X;xv»ÅDC:Q­™Y1þr:“¾Ýqu…ŒKîÒ³ ±K“ê’jñ £Çãph5ÅV«v`ôäQî[Æõå Ìô,„B²íLmqÚ!;¢öªBy>ˆ£ Ø]>²]á@WBÇhËÐÆ¦ÊíÔůםU‘Ò­³2ðt…£|z7óUÖg:£5uK ç!SÊgRò å%+¶6:”›jKô¦™ãðKlíûS°)%¯À/éý™ ÿ0Õ±<¾» ÕzÈð¶5ÛAf6î(óRÁKkV¡µ¥ó»l%W, ­nBg¶û®ñÃÓ[p39°û RmÊ}?º@ú'ß‚Æ_f†üMïít,·ù‰éÓ©ÚÛß'„l›r›F’GUs¨°®¬Ìb/}¸Ê2‡ûirÑåcÅÅfUCe/B§Þ£ï HZ䥻Sp„P}Fép8^µ8`8¼LPÏ3\žRï&”«¨û ¯¶ÃªÉëÑÍZ¤Ý)¹p0:¾—b+a€hvà-á;ã³+Óú šÅ[ù+”‡€QŸñc? %ï P¯27Ԛȫ,”«G÷ö(n8Œ… '6¨Qº¡.Etµ¨Ì†˜iwqšOY\!£F *¨ÖêÆ•²Fú>g²žcôŒmC1—aÊpÉáµûŽÒ0Êõz± pŽõNK'† Ò»DCU=Ù î©Èƒæ#>ÇàŠb±4¸K{±úƒád='çLíøÒÑžMµ£å1 vGžâŽy*ÉYz)¼ªø¦ã2 g]ZÛúáY?Ü?CÅÞ@™°VQއ^Òx.ÙÐÍLZÚ3Lbyý¡ì@msÖ¯³ŠKd¶v³”è„H§†Oˆ”8tïë€ÁŒ ž•xzŸn#¯ŽŸÁú¨°b9luÎÓy ÙAìzNZ¬ši-%Rñ X^=aS„.«f«Ü}ILÒèl‘O5«eÏæOÿ©EþqÀàz0'³V•«†QåÜ8ºñÅ/‡ÃÝÒy*sú Ÿ†èXÕÓæ¹; Ìà`‡%ú I•ÙŸÿãÿ)qñ¦ìk £B³|7È€üš„â8ÆÈb–Äã$ÊZ*åuosýïTóN.ÚfuVý ª»îø„O êg“ÙP¶«=Z yáaøÀ,ç—“‚8—áóM2YPÁ(sÇ»XâSz'_Û^‚½ò¡^@ö†…ƒç×GÑ6ª!Ýû 6>":ãEÊgŸ8ëoÝœŸrËšOÄšQšM#*+Ü7¾{RhÞù‹£™™œCë’0`4Û‰mœ9 ºöK†"€û_oî¶7œš{e;ls*gßM Û6÷;ø}“$1Fæ$·˜‚ÙqˆhÀ3“†¤¨Ê%ñ²àr½Z&ÍÙŽNü 3êÞâçžuêSÏ·°8„›d7À¼&Cnlv¾c&Vòõb!_54{‡’to-á­±>dÏ\gœ²ýσ&Lý¼™}ê¸=i,x©Rõ:Á6³'𣶻Á2`–wYåðªeè&Ø•lhÔ¤Jª?õNí™HVzüOFçߨ`üÍsÖë9?€ß« ÅpT˜‹ØG5@×ðܵ:öiÀæ™tG|tàŸ–êÞ‹}‰9 ¹mm˜×g¨ Ÿ=/ûj4®‡ø  ¼yÉ™!ÙÎ9Õkç5x°ø`¥åoX¢÷C–}ÐñÁ<]Å…¯¬TDÇQõ3÷ͱ}@•<4!Ÿ´Ë±aù¯}dâÖšÏLÿåέ<×2æ°x§§Gg‰2wÈ`‡\U˜µµ}Êl<2ý[&ÎhMð¥Ì?Z6Ô+>ࢫ²-Y÷tÙöÛwš3ÀVÿ×™ázƒ=¨?ôï#¾ãÂÊÿ‹³‰›“9ºO•J;–…Øšá¤ì÷8šÎoôS¬w%pevÀcŒKãŸÀn1¼µóo ¬`!epÜë;9”Înøp“%Û@Ìî3› 7L¾y ›?´qœ¿Ê¸S—«ÎÛ!+.‡“î½; wkƒÃ§Å]`ûзH´•ðqS70ûÝÛ¿F*VÜæpR¦i3ë+±!t+ê:Rjè;aØó_Ñ÷п !x†§e:óâT³´-­U²¼˜îšñ‡gÓzŒϳ2¡G‰óXÀ¢W+ee¬áv 0ŽÂn…!@-ž»þöó8ÆÛ1",ý‘¼ÃQ\o}^ÌQ°!œ\ꢨ±¥Ýù®¼‘m¶Íoén²'µÀ˜ÙðA õ=TK;Õ<¸˜N { lÎôbáî¯Âã7~y!‡$*ŒýcIŒ #C1¯œ¸BYwj‰ðÁ‹oøi ¯ÚFG uÂ\íu°¸cgz¶[à±M5%»ÆïðAŽý~ª¨dÈÎÌ ò€„ºì`2o îb´võŒmPÅÃÄþ*~é€Û\(¿ü ¢c0°Ý{üo ›p¼¾×>-× l³§È¤Çt¶œR œOOÁ¿=gU˽ðC#­V%åI>V/|—ΉßIuh”Ç ‡Ç°;ÍÉðñÍ»ðJ×sâšÏCMxVÅïZŸ’xÖÿÎM…¡b—¸¾±¨iEv;åˆÉfðIT¿œÿcÙ3x|AºLÂŽC”¬ý8!ß%‚ªêøpz¹áH|Äg?Øj[Æ>Á×aÄŒ´~À–ÞÄ£'Õ¢ÚéH•ž³íuÑ ß¦Š¯á€ÇÝ÷`h;Š&qósaOÚÑdÌxq§19q£ß±ÒÞ;ÀM“ñT‡4ñ 8±Ü\Ú¡N.=»Æïð9bÎÙÏJž ¼Q®¶9`Ñbä¿ÿ’;ÿ’Úo\#tÇãNiX÷ð‹‘¤!èrþüvÏ p?*“Ï¢9Œ'ùÇò9_À?T²¬›y byèjîQ#´w`}Ñ=.Àëöõ(ˆLT;·[¾¬,z€u9NÑ.ûŒÃ=‡RF™ ÚúE‚fEÀå¼’Pñîh(ÎÿqþZo¡â¶¹Q° ±ÍUâpUÈì€ç#Z´H/Óîo¸÷\X|©„X|ž¿®³S£ö˜:Ðt6nË€\+Qrɲ“ªCø»”j´ø>”> Œ6÷Ô«éä¯0âÒòr•ù}˜'Γø¤ýlc÷ ´ï;LS ß}ý£ˆ7 ì9Ï\®‰è7à»Êg0½ÇTù1;;Ëo^ëŲ#$B,Ëa€õoÕaÌ}ܱþPfö4“,¿ª3‡j ¼ÞzMW͸ÂñûG†,/¤TnȲó_pÔϰr ™™ 9(õ¡²SöHg¦RÙ®Óù'ürüaÿñ¿ÓU“šÃDL{¹cBF_—&×8¼Â.o"ª,LNJ+ƒhe ›¢åEiÊø±Êâ2Ivr¯¬0 Í æC+w¨;«üAÉ B†nU³ÁêZË?ËÝšÅÿN<ŒØÎ¼šƒQˆº”<¬îX£Ûx‘—ê&• ¹]\ÆöÇýßÁý€–ç›Ï(óáÃU‰&DËèiJ¼hŠPãŸðƒ³„ ¨žDyËÙ'+o¶\â°Ps8›£Åx¸™Ëò¡Ê! Ú|”l^¹È™*ÜŽš¥.¡ qió!ذïï)hšàA>zÆ¡æNXüÅJ1 ~B“nµ‹ZðÈ„‡}È̹‡XÊ{ãrb×S¨@俀ÆÜRKÍ>Ц"w7T—îuâìawzN±Ãçïæv*·ì Ú3ù’ íöS°c|z¨‰=°¹“àµj/>¾Ü#r~¿ð²mÌ]ÿQÛœ7Èf÷Àl­×:•)Î[¹aÚÛÐýܦ> ’B6‡Ž­Ùjc|ïãˆ*†{–ôw<ýÛCˆ‡FȨëáVÞñãOñ;=¶’s?söoƒñ [Þx“Î9ë…-sGD¶Öh å‘Ë{˜8fµZÍÙ‚¾’Æx2¿å77"Íi±r'ŒØ<”Í’Àr·;'ö}Î \z¾™Ö´ Ï¨{{yáã!KÅ% ¯ѹãèÆ(+ÊžÖjù£†Ž¥ñ³ 20¹y/¬¯AÓ†:$­NŒkà``CÚѫª¦­0liYeéëÎyl&Xå0¸ƒ·Y¢Ó Ÿ”mÂn•w b¦}®è7‹äÖaqí¤%%ËðHH† ¦³¡†q¨bg 5ì2ÃgîÛʲ²]Ñ œQ† ¢Å÷†ê2¡n¤çç&¸™8b7T:±Á×,Yýmò¸ôhˆ¹»´(;U‰ýJGg¯HUͺÂb ™‹œÊÄ®pYV›õêáϲ’%µ8ʸˆqV’gJQH†Ÿ º{‹ñl¯ 6X霿D›ìá}ÝÕ*Öû­h¬»¶ßFþ•‘[B `ï12[ºe@Ê'÷F’O¦ˆ[–º¶×7ø½,%gBþŽÆŽÈŸ| #±[üˆrUWYÓ#U lA\bŠ6Ž‹¤j®Î檑Än¡ïY ºo°8,£Ì>¹ÐÇŒ~½³¿l¨;ôVÄÅ‚ æ'Ì©ÑÞl‡;ðrwð,!¾”·ñR‚€ÿ¦\—­ì޼/z󘎈#ð/N| î³)ÚT”hAÞ•Ö7c×t’÷IZ^ ðV¯ à:^!'Ø‹Ïó·LJ$îUEÄݦ*í^©) €l ƒÙŒÑ%«›-¦e1O{ŒeV¦Á>|í(²†]ñ:yß±i®dÐßÉL°Ö¤PD¥\áxPqyWR©¨š #',‹-q{±ÅÀ•œ¨‚=vÄ0úÆÑV¹Å{jºÊ¼ªN#Uñ¶w„Kµpí*„ê‰ùæ¦Yý±H&;ê½À-Øê«îá%Õ¼AÄ}ŒWìxÌ™þ½ãöè·ž#ìÖuÐ$¬ríYä)÷-– –JËòb–7†@^kv&φ/ÜÔ=³E >Zü¸PÊrL+Ýânx%d¯›¨<ÐÒ 8²fïÝø#6]º¡ù)Æ„•‘¾!ÍûÜá;xˆÝÀϤ®Ž­“s[ùd_óް̱Ï;bP›×çð63û ¨û·èPpð¢Ô°øã¥Ï³Z’ãê.ñPɪe®¨ðƒ¢wæk ³¨A–åâˆVRÊPèeÂ"O‰Æi+qW—ÀÌÚÕ3ôÌ„6›g`Ýiq¶æÐ_Åí7z:"?J^½Rb›÷€l­Ø™v €&wô™ñ 3It©´[þd¥&Öð8Kˆ†ëàÌ·ðƒº°*»Ñs,+Ã7Ej® êG µèn®a5£×Ñݰó4%ó,þ2u;å‹}üO˜ÃñÊ[7k+¥ŠìåÝÖ€‚Ë¥}‚Ê¢~ð¡Ã°ìèVe2ää•+wž¬âþ¶ . —hÔ7–Y Îg—´»“Ñ€zÀÀ²"t°%—jËkØý”BctŽˆEaàMO„–´Yæ%Uªhùp<¨E¤gFBàÀÝ:w!A%?X,gvDuÜ<’䎸Ãk‚£q@¬x–¬Ä—k 3[§V5Hwï–lm­°Ì€j b}’u°ò'!QÄJ£/rfÀØç©:_o÷³˜è$L.yW ïl‹]í ÀòYæ­»*øl"1­¨W'd÷[„5)^q×Ùu™Ñó66»±š[‚\! Jbøyw÷-û˜ú.¸îç øj% &‹ÿž©Ö¥|wã– ‹ò¾ÑYVš™G›GùŒE¯¥ð¨0™c†)”Ç@Lû“ì€ÍްáÜL\>Jô«ö"NÚvH'o“‚–«ÔGìndzyã[P+þƒ¨ø7ænТZ€»Ywå÷vv8zÚ7±,Ûúò“éά¥àGùëpä›õÑ?TØ&¥øuùbˆ|!ûŒ2‹üɪ.ž~gÔïPŒ-vmÖª`ÖjU® ÏqHª†'ïAØ8wýÊNœëp„rrÞýñøKs v3È]ΗN1ù”{iQßÛK|©’¨¢^;xס{‰ 2{ëš±¯;ßMHrl/i°õßi;à<ïé4)/ËÕÀdßza]ö䬪 ¹VW‚îaÈ3Šæäð‘áÄžª‰¾þ~w £ýa]–ç1Ÿ¬ÓâæYmÚ´f/Dyk¦Ó@}eØ+¢{S %¬ïU0”t<@_:ó Ù±?úpc ¯«©ÓÈAªú|²P®.ŸÕ3Õuo·]\É¿Á.Ü)Ý›ŸL•g̾Óqý[è} ?îFiÐ#ÃØàäÚs(Ÿ¡Ýw+;€ÞÃ¥|7|š:XÜý/¨ºÁöwcÜ0õ=¸¥¨yý_)ë9ý¬tÃyº¼¥owôxw0ZóÀUӌѴÁëЀãÏu³=EžáÛ¤`ßózÿ´£ˆuú‘gS¹PU†{Ò g· ÓÄœž{‹wq}„ëu´(¤¦—Mf€X¤rÙÓ“öè 6žÀë ½”ªÉE£à«ÉèÍú™œ[vBËÕ4¯p„×Ûù ,Ãé=4À–?rFg†ÅéR2„ ~÷³(i} D*Ê ÿ¹ÑL?TAņîi8zZMz Ç1°îô@ —[ åÇæ©6[×Ë:v… ÓÏÓÿîêiDPíâÜ yèD`i'= ֙´°–²×7%þžpàïM)¢E ‹Úɤl Ý[é[0üàìiG‰j›<µOT´ìè… Ê²÷E‹©dg>fïoáªí[g»¢Ã,ˆä«ªÜúzÜ•6c–<§y'ËE9WmÔá¼=–:Ñ:E÷VVx[>Ó¯ÿøŸAø1ÎÎ)†®Æ LB<l¢G5Ž™8ÃZFƒV©]•œ¥¿Q9©¬.½ UöüGÿ`QáÛè0Æ¢*â/)Õá‹ÀòÍ*7¼t€Û—JŽ}áÜÒÛyãt?‚ZQÂ’i»Ü,‹Â8¯mú³ZÏb-àŸ“Þ X)l‚3dÎ8Ymˆ=òzô´Ú"xþ[Uy?4œiÑ Ô‡‡žê3D³r—Ïæ ëÎr¨?›þ³«§¹Žœå- é?Ô]ð@Û5{Tój”Ñ[q°zú±ŒZ¿QÞ»Ó #ßWÓ >`³x†Œeåº\eα«Y²Ðcœ Ÿs° Xò¶Â:@ú]jTºÿ>¨HØvç´uTß¡Tœ°e寏àˆlÒ÷*àyø`ޑ֔iOBšð4ªÉ:%¶Qž'==Þè!T…á­Æ5`~ºée²#誯õP1€ø\6'Hó/ÉRO˜ÝÎÕz@´¼Â(¥o{xù ˆQR?ù¾Àß>ð®.‚Ø`¹ÔÂ6‡õŽ_ EㆳsÁ.¾@ÖÆãÌ%¿:È 1­É‡ÂêÇÛ–¯,PvÆ8)Ýä ¿ ÆêœÉ`FÃ@s»wDNU,uðÚ)`‹òŒ1ß°¥4¸øs,€E¢Ü£½9OùK&,ænŒìÂÉ(°OÅ£ ’#¤¡*ÇðQ-áPÝœ¶áÞž¨X†2í¢L‚@ÜéÒac€x+L§¾7¼Ê¡ÍåÄr•F‰0Í·|Ô!«Lú¶4“s0³L:ct‡¿üåx¿ÍÓ‚*)‘’ÈÊÖsÒÜjcäŽïþ·šÐ àºËýÑŠ»“s‡Ÿ3vA¥‹Òs¤ng…¦T#üŒáÞp¬úa­‘Zžn5xRt½#É =sˆð|cÇiêgó‚ÓíkÃní߭Щc¹Ühå6Ü…ä@½ Õ–{[¦ê! kËÑ­¯pé“6ûÒ>¢°X´nã;éßi þÿs3y% :wBIEND®B`‚zuluCrypt-6.2.0/images/Screenshot_20190912_122017.png000066400000000000000000003372111425361753700214570ustar00rootroot00000000000000‰PNG  IHDR‘ýìâ pHYsÄÄ•+ IDATx^̽[‚ÛH¬,A{w/w‘³ßiÅ|€D>HIeû̉n«’H$Þù K%ñÿüßÿ ’ å’Úy]$€‹|#Ç| € Ákí7‡_ ”b!ÄÒ _Ú5Ì&IàQÚ °t£+ä/@Ý!ÉB ÀKÆÂHä–ž¯[mà—cå —8ê/ÀŠJÓnØ$ãõzEËv—å*"%ÇHÉ&:ÌÉ !vŒÈ–̈e‘ë¥0IÂu"éV%©ú¦v —¥]Ž Œá–3Ã9ú¾Ê(‘¬ xˆ^/†y¯d1^ˆòsÎCŽôl£¼¢ÎS³¹aAɪƈäœ5s.´/½®„Š3ÅðÊ IQèŽQ¦@®ÆÜÃÑ CsC“kˆÙò¥^B .€~5¢gz›ƒc% §Ms²â’ñú12¥då·Ý/k‰nNjöÆ‚`º¹ã25êöÑ[—jËܺI¶¤«õJêÙÙÍ8CÀØŒYLÐ.H¤³¬CB¶<ÄÿûÄ\´g‚‡Ò*r‡ºø+i—lÞ%Šˆè S¾˜+°gçèª%¢R&©–_V% U^ƒAé“(—ÐàóÜAr¢lsò[—0Ï©0×Wíc`BpÅ'Õ6%í“…uXªH댪ðLdÛêƒS°G4¼èÀ_f*!ÎeÎèRdÖ_åHÊO¹É_ˆ#GMò]b KÖ VßÕÌ'Ig È^(f„¬àz¥!ò¢Òºd*;‡†‘Dúrƒýrpè¥j^OºÚ“4o—|µã´ìc#û¶D¸p±"ðÛÆ÷Ý™º\‘ù^·ö†n_ƒ,eZ7\1*HS†‘‚wî¢Ûñ¢‡VpÜnv„–¼ÚRëK<×L¹¾…ö(´25–XH®•¦²PUÙ¬‹)]Ÿ, ,¹ ޾ÖÔ%xqéùä/аzͺ$ "©—€ˆdÙQÍ[1‡Q!æHÞQ:$e¾æÜ4â…<ˆ8Æ_xy²öÑchÚ‰(2NœÒc/a_ÝvÌõpòÄXƒ´ò•S‚M;‹Ajô㿤ىuÄï}òeµûŒƒÐHID>CÊ…lÑ™HþºK#ë”;ÖÚM„‚8lôÑ%£lðÿrW——“B,á‰>Š–D‰öI’"]¶’ Å5À8¾®®±—±­˜¿æ›ò²pìÿU½ŽÐ{(à Ï2ÀÜÒõŽ H±ÿV€Yô‹œìªøÛ” ÑÇÈtäu.ÅI#òšÁÊ Rƒ[“oy®…_/RR#ŽFŒÏ(øÊ©¼*úžµ-·Äg¤FÝШ_¯:ë…×eóÀùèæÞÛ´Ù»zyFFŠè¯.°6ô°Ö£Áf‚O¼Ê N·JÀByàÙŽ4ìàÞœX± øÂ¨ùp¶â õ ¶¸'ÆÌ‡ë0{údÜÁš@ ¤)E‡wk¤(Á¾FäòérhëQ !ÃØ±°Íò\!麼òlš•ÌY].j¿¦CÌÌ„ðéÔÁ¶2VtáÓ<ß ˆ¤¢–^’E;ózX‘RÜ?w„Ÿeibu“„jÎ,£o°iqèšÚv²öBÂØîQÊAÍa¹T­AìF Q»Ž»Êð„õΉR½á¸ðý@ ɇݖŸ¯¹{šD3â˜]-:mOWJº{¾J¿p©ÔàˆŒD õ–‰`RÞ”Maîa Ò©°õ÷ÄyƒÝ™†µâD톺JC”hs¶»'â°bJÌÕ]õÞ{jÀU[o_»µŒIóºÁËŠ°ùøª8ÅÀ™Ò?WÉfŠÌo^Æ!’À™¢nq§cµF•ñþ0—k¯“úÚy¢3M±5ËRóÊø À/4[ãÉ΄°.åuAWl³’Û0­¸ LMªxª`÷(1é]á\¨7Ø+Ž*–Üí @ô==òÕH)c]šƒ´­qÄøg¬¬sêŽ.åˆâœÖv¿FÒgX–àýlª j"ïøW†-ùµm˜rwÀ‡QŽ _qHÇQþ"\LhUíáYlðM_$<²6+%bÅöß/·Äٚ˚IVXÝq‡ŒOXá”`(´GpïM—aQ;i;e9O«QE­žHHñ²ËÃùÁ1Ø+Âî âtØ`D°³Ìr %UŒÌЂƤÍ;zI¤aMUTD·¶ƒ’ñα¨,Îm Ý/‹7`é$YgÖ.ú{ìÂÇAÑé 5ÿ™ùL$ÆOiêÀlóÚû)†­ÄKâ á‹Q7ÍÌ縅±SA–ã²®æ<†©ñŒNɪ5Àl³t.ä]Óǘ•.V磆|"’ ß1Åá½²¹vdöUº’>?ú« Ù˜2)ümEó jÁ‹ÜpÇaßï.W‚Žõu$.ø„g…Ò¾ÝįáöZl(Œt#Ûy)Ìú/p½5íyfmX˜¿×3ìË£c\%þ²vÊ<ÍÇ%ÎÌÐæi²ÇY@¦8è"b•xA¸rGÉŸKŽ+B"ȱ;næ¯6ÅBÓÉîQXÖPê1Ý”\ŸØ…`äQí=©ø^ÈwKg›·³£;½Èçxe‡’$‘#Œ?Ãqøº*b ô>j§ò^-ѹÛ7±Ï&…î#ÀÜOæ½»’õ]NHÂ7-Žyzi‚Yà˜½«?ø=âÀìrÄÂÝ'S€ÙÒwPSo^™QJR $‰ÌxˆHÌraèî|Devö£ç¬ïІEmžÞi1]' )&¦ÓÍ/ºÿ‹IYw,ÂQñ:ªa8µ,y’Àæ˜^[v1ç(m!¸Ñ øG´¿@˜p€š³V ÑSty071{Ô'rÄn|OãŽö™óÐë€mDEôÎÑØ~ W=Om®v6`¡—¨jtú~Î0JÈ.0¼»®ËºáåhÅ‘¸‰ºÇÊ9™9§5*¼÷k¬ù¼-üÍÿÿvQ·¿Ä;Ç·Wóªµ'ëáP;ö²õKJ[ÝlgÔ}¾ò›b«Þ$<*ÍCí.4økÁ5Ÿ_ŸÁ^l!ê'–n‰¼•ç‚–å8ÝB ìä‚WîDu3–Ëu³í¼‚-NýE,ÆÜee%­ƒ_׌Êf—ÐØX÷ÿA˜gV_ö®»ðlV{©/úú[²…oÁâAY~Çàñ¤¹ çxä*JvÖ]Ÿg6úeÁ.&. "~t üÐøWYOjÊ­*ñkOÀ]c¨û;%Ș½*uH?²ó¾í©o)Å¥ì:ÁCmÃò¬Ô¸3»ûÞy,ä#ô¹*ü'¡æÏÜåËH0}kô-jر8ÎÝ€åT±plxÔ“àGDàÛe RÜBPÜt @`]€d˜º[P„áä·Y¸AÌè,‰H‘cpCçlíØj6cNÈ8Ûë i˜fÛsQ£œåžúBÄg^HM fhÃ-vÀ²Vs7tÅ“w/ý"_À!›)tþÕË '¥‡TŠª.Ií× ¯õ±JG yƒR~?âÈQ[ÐŽ5Ùë¾e`hÕÊŒÍÄ{ÔØe®ò}àšË¶xBÙQh# €Ÿ#ô&'ÅßîXú6-‚÷UAôï®ê¥ñ(1¼~ÖPLV{€H¶Ì0ø‚Õ'Kä¸M¦+„ä7P®t¶)S™þ#ƒ\9ŽÆÃqÉóÌÒô\Ô{ é þÒ|ÿe[±«'Ù€wâ1ãn­¹C÷qÏxV!oؾòÑÝ6"0D¥ëyy‘ð_ÊÚþ&ã,,§OªF2*‰7¸íLzó>Y1)„Ú‹ÃÐxX_Ô<®Y²ß0Ã9½‘—ê³2MYIJ'ò°3b}![ê¢BPgÌxÛý ) ÎÉ‚’>³HÀï|L²Fc™]7“Àk‰‰gM…W’ç«$ “yíQB®ðR| ‘×¶p´1ø‡â v4ãmƒ3X˜6¼=6ÓøÎzc½8Ê M~äA ‘'Õ9—˜a¹»•F°©Íš%‡õ2Ãé³a{„B»­\ãy‚܉Ôú"@€ô‚Z†ºp¶½{T£‘Äð7õŒÎjÕ¨ÝB©tð;uÙA²~å׋!Û^’$¯Æp–¤Z6¥®Û¿"â³’Ï6R,9rJ³‰Œ~)ä>ï0ÉšœžgƒÓ{I¡Öb 쯅ƒÝʣ͎¡ñ^õ†&ª[?èDì]Õ¥³t˰Ñ× >ߨWëË¨Ó °´ØÇÆÈ©UH„4±–$ém-F½ò#ÝÜ €y]‚«-BlÚJºo „þ4’d-%É@’ð§ ćÌY ] „ÿ^ÿ‘ôGª>­†9 á´°ÆVm$-+L¿´U%$·´è•”;zk˜]ß’(ŒuL™YÐáºGöÃê*ꌱÌNuÔºñ÷,óauOÝ ç)Úa—¤$[µÖkü°u5Xã1Ë­M9€C|\«¼ÁÚ©›0îÅêÖjò•…ÜØ9 ‘¾¢ó'ó<ÖÆúÀ#çÎm÷c× ,î£@`üÝY†õV§DÔOÖj½•ÚŸ›š™Ý(¢ÏCk>??+\{åu•K€/€ùÒ·8‡ûAûêyõîCp<Gù&½rï©Ç_±e4qÃ"")øSlŒÕ'IÀEFКG~×—Š'éAB*òk‹J¢érröUÍ!Î|-ÓÍ1ÿÛÎô'©Ÿ1ììÔ„‚¡qɬí#¡ŠB †öèCâl1!‚86îÐéAõX=ÖÌ" éâŸ3!I9û†BÁ;ÍEØZZŒX(ÀùÙç Æ àÒÛÏÓt†cXíŽÕ#´à"Q·Ðw"ºÚ!ÓyH¾øŒØ'B_#åICœ~`‚c–9¤Ù)×,}À@s­†€Ýû8g‚Ó4¾C„Q>·É«‹ƒkL é8 aùÄÀC:Ò°r¶Jû”rûÎ’(ž xÊ…{bšˆI(€P8 `™[ò£Ù=¤kxc! z ¨xn­vfMçú®µ­Óù­®É‘$ùì¼2ô(;·á:Ö6ìn6Äš²’ Ý(;å¿Út¯œÑžU"¹{‚¤ÿÄõkAž¤¥ˆî‘-™!À3ýǰ2 & áô !¨mÙXrùj[ Š«ä“1’­JÑøMÜð„&ßb#¤6ìÇÞ ºüÏFU´KBÊìˆÞÿdtòæ˜ÀK º2§å"=Ž{ç 0¶ësveãñºHê«úG°#çt»––./Äó’ðƒî›iG!+߉%kØWìCÒ™1l “6c}i ¡º,?‡a€‡œvÇÈ¥qÑê¿h§ÂÅ|ô@Xh”–€´aHW:E`|°@î”,Ð*/*(Ñwù‡¡ J[6ÈâX‹Ó”û&†©iFzÑ%=˜û„ºA?žºýŠ«]!€0’Seÿ‹û¬‹$—µÚŒÅ~£Ë¸wá`e”YŠöÌž›Èz˜»âþá4 ±G5½Y¥Š­keüD;¶äYq8Õ 8»>ÇûdÒ›Dæñ{pÁ64Ñ]Ko éf§äÿò›2~KñBÄ`M•©ŽÊJVÿDïÞ½#eåäôsÜ1§×JW´ØCš{­\d—ZkŠÏX˜ú¤¨(PEL€Ðî} Bþ˜Ãàœ Îƒl/´I9ƒ¡ ð’:ÝÈtÌEÐǼ`ÙÊ“^[šDJ·1”¿L¥ܶQ¢_Ì< 2]ËåždÎZ‚Ì÷yôr„§"Dßì¾ò»§XX7÷nÁˆ†ê.–ñN=Pɨ«ª*»#Ķ=T¥›A3ñ߉ŽPä ¡L™Ê'jYQõûÛJl®'Aœ#TŸß¼Øâ²ïSî}Ãu@Ä-m:¤#îu'~ŸÊÚkFržòÃü/ljF©{L}ö£ ,sy̯"ø’i<&ºu“ãtÌÐ$G°üJ¥¶–ÅG„=3‘¶Ç ½ÞJW]Ê*sp"§ƒ y-›ØN'Å ;ÉžtÊí⟈ÀæR)L¡ùJ噆gìZ¨\!œ ǹœ$-¡Ïè£kÅÐ{~õÃ)å“…SÜå…ïׂÔo6Ú¨ ßëŸ~½I¥ÅÊ;ƒp BÖÂ0«þ'†˜ c›nÀ%û%«€‘ž"ڜM ÞœCO#á·'”àµ`ñöTšÃ½Cˆ³1í†)šŒ˜ãuFp?‘KCÍ: ¢ñI·ÙÈ9(úÆ¢yëÑ[y”ÙUI$(I‘a%ˆÎž‡ juS¦àE˜@âx˜CŠ Vº§yðLÓI@ÿ$qŸé·rùªŽ¥=+¬‹4­³¸@CFˆèÁi½ǨÌÁ|df<û ¬&‘âÛvR‘‘.¿n!¡9¶†ñ“iG¤—.ÁµwÂ-°îðsìH¢Eª²ê†½]#>sH-k °Q" Hwp : KŽÑ·»mUlÅrÀÕ<Пü(;·!…ª3MrìÅéâG C`KÓâæÞÞÁbÈU„1w¹R̼ÒoÒFZ²™$IòÖò¼ÌPÝ©\À/’c¶xLž¦;ôeïªöh“BÔ %Tr_°aôDã0GÀN 2¢ý Ë-ç([QÔeðÐ š¹ë2‚4u²É,ì“i wf{¥³È)oéª%xê~å;L/Pûè·p^ÕS³Öm…ã:i)¯M΀i-`ñc,HGœ ¶ ³¼ ¿ÆõçXL˜%­nO` ÁÄc›î™'¬¯] ãMð¢Ãè=ƒÉ{Ï#¦OˆíÆf¯sñËDh¼‹®Ÿ¥Äֈ쒌ÓU7¯´·o® ¦» µçF3ÞØßÊ.%ȇõf"ã0BRcãtˆâ_pMÖ¼È ÇiM<‰Ø¸*hkع»Ã(Ék-> Täˆ%¶sXÆ“dìwID„Y8ùÃÒeâEDNä½×€-Y섨ÿá$)¤‡Šn^ÌT(uleÙ2:?AâØ´3lXÁ¦¾ùüø…–/êw~L½[¨¯}Ôšˆ p9ÿkÇËÇ(ž‡ŸP"Ì\n~8ü€1e®ofâŽ(Px³È=kŽ‚ÈáÙQŒ‘K.,0S% áäŒ÷¸ ÐO98L2;ü…ÒįèN‰qŠ$[²²Dyš/ÄæŸ[ãNõ_žšà¶ðîæ±'†–ÿ¼»ýˆÕìÂVüKéó('eìÂÓÓD9â`²+…q6ºX]Á;‰"q:E XÊæðÁÛGù¸õ0­–ü¨l¤W8ö³ÝÝáèç¸,oAý1&€x€ @Óƒ}¼¶C—eù½ëOš„¼¡A )Õ¸—”,¶?j)«-Ž v,ÈÚrhÕ¦AÉð«\Ü'ÉB©ÈôÝ¡xŠø¨¿˜¨I:ïÿ´ê÷uè L’õ÷åŽd]‚Qê5ί“½RuµŒç ßK”žŒ€ëƒ¢^¼`V‚Ò¶£^WRn88y³¹V yIÿ!o`¿X|G©‚ÄZ¥ê ¤1SŠ ªYRò{su´]¯J€ÖÆ¥t“Ò’»ø ORO ì×:Ù&-äºdD&®±“˜{Øaù…E0ÕOcà\·G¿ÞŽšAà`¼õC×|Ji~G{:ÞôÕ¥M=o?ƒ ðu¨¶M†¯.”4CrðHºœƒÒÌ@nX%:,‘9®®*m´öÕIcì3qê=2® †{E„Š"М¨÷P؈À“…ƒÔ•– 7'Žì½QYqš¥/ÇxÒe)€¼,r¬‰¥6jRžR› €‰épgóŽcîÑØmJ I³Í¤b½‰Ïÿ\QdA÷w~ØåªÈÖïx+aPð’®ë"ç„mŸº‡ùǨ¨:ÐbtêüÌr¹gbd#ëÉ’Ç’cmJ¢øï ^þd €ŒOük¾ÄRw¡”œ ·7Ž ¹8R˜GkbZÑ-$0B´ÏnÍÔÿlK[è4gñ«+y^É„üqÍ©Z@YÄ9z½^9m MQR¢·Û,—Í~‹¬Ñ•¾“³“;WÄ0ÙT”]Þ„è¼2€ˆX?#") M$ ×a¨v¡–FÒ1¿UÑ:¬e¿!.×ìò4³¹þ381Ä^¿àéG–©*7ï @S•|ƒG¢ÜذV‡as‰N†ÔtðªÂ¨Ê ö}~’‘ߤ5Â[°R[™EÄ49P¿F¼¼‹¶4]~ÐN Š¸CÛ‚¼_¸[Y KÃŽ9Ó'ˆO3%·Å_ø ã Œ®X "´@*Kr’Ý11W‘¢’èé ô €ÿþ{áòÓ£4.ÆÛæM—û‘ü‹L3z Â›”ƒgöåºÌf칃¡%î¦ôOð›ÊzÒý¡Œ/ù H½$¸è÷ Ÿ¦€Ýo[[vd&‡ƒ¦²Åeh+¶¹dbžìw¡uãnÆÔ«k°ç—¿Jô%à Ñ`øRËöxÛî.zz„…»ï’ÿ¡>§¿SÖ5i ÇI™£üí¾q2Sü{‚ì§MHÍ3&«{ÇâÅI}"´ÓÍ'ÎÜÙqÁ°<µ•#K=Šø}]$µO–+ñOñ‘hоiÎI´©g973®PnŽzXÓx–s€$ÆiuíÈl”à·³§ ŒÈ1§ê¼5äåÊõ<ÑhS'y³Æ3ØN¥zäìØLÚà~»jsÏI”Õ’0·–'<Óå1§…£ü•޼â6}Œ..‚0g9‘ˆ!Ôçı—Oî¿Þ Ê%g ÍÊ«èýD¼Yì˜t—ßà†³léFÛ‰êFi:°Ãfu"9àh|  YضQ™YÙºa†+Lþ=fFBF…³˜ûÀ°rÞÚà®×"¶3DË_¸JBòÙf`ôù7?@jf@l;1á ÉâUøl[çA&±É—Ê1Ÿp4ûobÑû?Š£k7ßÝêÅc•ü˜ÿ÷ËÏáë¸#±%¾dœÌÏ÷+ ÚÚáð]%€kKÉëK;;ÐËá4=ZEÖóÐè%¥GeĨ»;”cBÆ|9AŠÛ)½è€¹Ðòö³|qƒׄ˜ÿd„(Ã6I³ IÈ2kýЯ>´DÈ"ô•$:–!¤ÂÞÛC|¥5 Á¶Õ©÷DÚæbÚ7¤›¿| øÿ¯À7‡ª2éÉ8„ßËê3Àö:§ uRGúâ9Xíb 4¾Îç„ ž[I¶ÐQ9}„#°Èy¦Äanhúg&Úôõ¹ÕQå©Ù2&Ž…¦¥ûXw×£Ÿí–ñ”øB<’šÄ¬±ã9 f³ŠyP|[3I'¢z;ÅÛÌØ.`]¥P¬„ÎPÒWÄ ¶’88“s UÇ.Ÿê0¶±Õ@<°#€ö¨£—´Þëþ!%¹[žæ9«nÕÛ[öcq˜MQ½ Þº I óI×Á¤^BƒäŸM¸qµ^ìŽät,ÞäuéT½”¹n̉uU0lÌÏ¿»¯´ê ~KB Ÿ,‹I»e÷{¾ÑR²¢tW_·gIÌ ] Ie¼Ðçµ[‹×E<«XÐÃBN7ëîJ“Ex®†ØÇh×@Eɳ_³ŒX”[<)I©KÐŽñ¯öh K/Ã&ì>Þ%îc°ËèE»°üØ{=xöõD IDAT»¬&= R0$/N§ê$TûŽ…Ë u{2ow*Qă’¥“ |ÿò4žöpO\?ƈ!†ÌÑ&Õ¶sŽ€Ñ#½Fï#ý<Ô<ýK˜ŒÿÂB/\”·L#$_âã¤Ï˜-%qŽ4Ew ï…ZÌ{)º¨’ǔ؀Š7èÉQ^‚Ñ‹g<¼àî/I‚~oIv† ±Œz•8&GÒ0lÒ}Ä1 '¨ iëXÑ½Û <$4ÝühÆÀÃéAçóôšQŒk|OسDß°/JÇ3”è¦Ø­…gr;îPF»zVTϲG´öÓplNQ Ì1‰ ó=@cŽ"|ûWá°ØœÌ0Ó1CHþ7ý ësÖEè:æç"ÆÙð¯jlöRU¦T|õÚ±ð?yªFîæÍ ìÈœš;H¼I×á\²mm#@³ŸäuxÇ_‘Çs,²žóLõÇuÛ«sC1DÊzî~ǪÚãý‡ŠátLîÁPšRWn9Š#AÏè)F>«‹lº´ŽŠg  cŽÃ>Ãý3’N Ó:}ö‹°uÇ?m|œwðOòõ˜²Ò˜?’LÀ•&©WÃ<}ƒ·«ñD¿Ð¨H¢Ý[J‚ÏÊÞ§°QñÀ%¯I^=HŽe$ë©jÞß§ÊɆå%mËÉ|»á·˜†ôO>þ’&Õù¦‡›±HqÉ‘#¹KgsÔ7–À¯áä «ËųšªmÝaó±—ÇO’Yàº]"CêdetËfazp±GX\ª·ö÷±ÿÍþKu%Ò°iàoÿŽO«Y! üûõƒã†Qœ†Ñé µMîgè2U·Âñz÷Šw.aÒÀmM$jMÉõ4»Õ÷Êkg¬ÞÅãË8½Ú§r¶_ÁXl´£ï~Ëãi=Fôû÷¶2Ï\ÖËú¾‡_öY^u^źˆÇÅm²Eq‘æt~Îw4ƒ'’M¯ ·ÊÓÇáD-=A$èLÞ‰`+Ÿ¤ûü®(|ÙÒR:¢!M_`q€Š~Ïòhè‚Hp{ÛuÄ7¼@(˜Ñ»f|UOeÿ=\ù™ñú?©­çUGYBT ‘W–Ìœä}­YÁ·ï4w²ùÐj—ħག¾yàñ¼ Ëk’ÌG¤5јt!$,Îa3$´òÄÉÕ$Å?4EÁ¥@’µå8rŸÜ¶Õn 6ø3ØÎˆ·4¼RÞùg-¦ùâŸ"µ9x•©†Ê{„'NÎŒ®rTôíL^ÚA; ÷³}ÞôÄ9ûu©­ë#A6âÂ=²X*(sîT„™~ƒ¨Š1ÊXǺZΉÀí:Îúƒ¼$ôÞ]QCxœ…78Ø ¸õ9]2óú²k¤qnˆÐÍPÛRX­¢h¨(f›6ˆµÌÊ I‚Õ\ÚZ6—MR¶ m„Dš¹×_yxD!œCsÔ" ÈËSéJí÷âé©ÃVœ±Hh—K¼3¡ ÓØÖõ”Õ#BÀl›Ûc°;oã8àÞ¶Ü€§cãœ&ÅÇ+þ)vš Ͻý‚»ã[}=7‰I“*Âd|œs¿å³ä5 u¢ý PŸ©œ<À›ÏˆÓ–ÛSO€d³ C’zæÒ ò$½Kh=Í@%äÖ¸˜[Œf]«e¬%œŽf^2Âf"ü ¥·Dpg\Dá¦iá‘¡a*¡»-_,׺ùÌ€úÒ·’¬æ‚’š†0‹ ñÌ¥’X™ZÏ`óq´;õ#ÝÊø9ò“©ŸLrŒ#3 ÏS︄[¿h•G»kÈÚ·©( N)?l¸Š%"”#H3*/ÈÔôÎl¬†=â<ªç}™3ÞëÚìüåo×N@$$Ië{ © “=˜ºA$9·áÁÀû'[3‚ý¦¤ln¯*¦²Ú8Âοz4ê»ò|y‡œ€uld` å$ˆtæ9}­‹/=CÜo ´k /õ u}K™6HDÎö³µD€¤,ú·Úír€HÉJœ˜Ž°±gÄ@ÿ+Q‚ÊQ’ˆÍ ¤â8Ç”LÕû’.»skjÊ!´Õ>G‡S¤ƒº€œÿ°‰ñ€ô’z…œ! /Ûw6ؤ÷°õn<`øþCxìÎo\íþ]î7Ý7ºgæá+HŠCÑ](ÞßÜaÌÕRI—¯;&‡Ú…Ü6DÖSLú³øãr•íà טB¼(Ѭr*!LQØŸðXgÇèéeôU;™£íÿ—{¦åY"šËað°g9³v59û0óiÈ~ºÝ¨åpŸËéävöÔ¥íi‡ù©K­=ƒyl-Êri·}mcÛF¸#ÞóLé†9+S@ÀJ¨Ÿ[‡ìI_"“]M‹ÆeN‹¤Ë§† ©Èjá°œ¼XÔ¥ä¾X%oî–1As‚åõ.í<ÒtŠ^ð×°ª–$¼GÎ\J±À¬FÌ(áÄ5Úa¤—“š LëЀ@މ/K žÂ8ÓøÓ#Œ±!4*T’ v̱îùÙùÜîp²ÆÕ¹ÑÝÜî8l&;O÷=±kÝÜ„$ÛYnªl]¡¬©Ìî嬪—ö6Y‰íé¾ï»1ò?Ÿ¶t¥Þ ’¾vœˆËu›ŽÇ lã~М@­<ñÒöÖÄ`ÞŒ ܨPç_x8Ìx™ê&‡ß†—ÛŽ`9µà¤•)o$ÎØåÑxîâ€]óžñt¶fL#,ꌜŒgÄ÷`uü¡¾$øðú$xêó’× x4ì¡ëÓMÛÒ×n2ã¬9…QõŸØøØŒZ%Íu/kVV¬,[ûÊ(«à¨Ê±ÙdbdìLÁ=ÏŠÁì<ÍÃÝþ 2]¤ “œ.a2¯gßvš(½*žNz çÎ8ãh³$‹}3<ìyeÌï9F!&¦¨†ÒA¼ôsTÄór5¸.ˆ£j›TF±ÿ"7Ò>Áqà‘ø)“Ù¥;?A½%éIHXòÄbäÆºÞX*/I€>De&[Ÿ×µØŒzíS k’è_ã $B™ÉÆÌçtÈCÌýëT†ÀÉ6œ\½ƒÈ }q¯­Ï!Lll%é %í üShû7` Èõ=buƒÉH©Q|´¢b‚WsæÙëV{ày½â>DYõ`ºZc@’…ލÖ\šõ )D¢+H€˜ƒ7ÌF¦™°Ãˆ•?.Úaºf[´†SiJ”!@zRgš#Mû§·ƒÖAq-ÉZáÔÌL#äƒ&mA*žnÅH÷Ž4ñlôt2¥õþ)ÍF~ ç´Lê9 l„Ÿ¡$KÈpí1ÄÏÔ¹:‘j žœÛ•¶µ±#æZ܇–äž²LŽIë§_b`G1\—K.#nÁôãÄ&‚yY$I½Š]°¥?þ"ž™Ñ&K^Ó5ø-ù~­Ð€/`8+é>îåîÒjºóÈ´¶C7‡œ¨…~ qcRmÑTKIbxÍÌZöŒó`°ÁýÍænæËõŒQ]>•¨;ׯãí@Ør‘ØC´'è‹=õùðÝ’ˆàNÁ˜†Ü0tÚôÞ€#´ 9>'o… Øe£€ÜÜÌÙ<'Fo*Û¥Ü.RòSÈ-"jÀo«õÎïv¬vo~oŽk4²ñ›Ü9Rv+Klãn½ÕL×LøUê @²oÚ3J¶†ô±Þ=ž~[ñÈ“÷%°ULÒ! h+~q…ëqMšŽeû6#ÜÆââ{²['¡Î>yM -lÌç+/äór1䬳tØãÜ9‡FöSŠa.@R|EÉ©Êó› Ê—‘÷¤"‚å+£8Ý­_  ¶®•‡Ñ'9¬HŒ°ð=ȘE}VÑ0Ãcú¥hðPfoP|eTé2eup Nwf'~‹ÝJì0òA° â—­þk<´J…‰ÄXTm³«Ù+þʃm!š§ÿÞÜãÿ€f™Îv@®E*^곿÷@:“ÙŽØÆÖñò¿¬^RÈÉB"þ³^?7{@[’±¥)fn¸Vˆ¶å)Ü™ð@û…~~×ùèmú@ W`û§œ|@  €¯öÌ5ò‘ª¡£2Ñ[2ŠžÅ†#x®sPü^!?yöªÕ¥sË®WÕ…¼°YòÉ`0lÈåVð-/ÕÐ$Òæ]€0žýZÓWïa DñŸ¼;aa°íµ¸ÙÊ]ˆí”÷eáe]ÃF—L7:LŒ¶¨S€Q-Ý¥Ó@æËÞÛúî~ ²O@&,µƒÌçÿk’ÕD˜câo fgVÉÛ Ðlõœœ~÷ E3ÚkQ ¿ ¾ãÀ1~BY8cÁÊ¢ÿ N1g:Ò® è$¹ /ÔK(G¢H2ÙKN&Œ8Ïtr2»Gi$'û%É/Gø©m^I€SBár.©ðLBÅdXFJpè$¯cup‘¸¹Ø7¼!9vƒÝé‘ÈdT×€-èáªV¸R]'”Dë 9ŽÒö‰Š †êñ#›–ÓVÎ]Gä78šùš6¹+®¦b>zXËŠ@¢bÏ:“¤nF/hf ˆ˜U“ÓÑ[à²+ ) Å”=ÄžlHCvvyvùrFÓ˜Ù´‹êÁP­Ú\XQáJ†ÍÆv— ¤Yh/”AÎy<³& 8ÎQ±Ç&ø; @Ô§ÉQ™IÀÅëšßtH² "èÝa$Ùbr5!‰ø †)\R¯ôâ|BŠ·&J¼_=š,Iu- ²¹ œÓ3u*³ŸI»?Ò $c%èé5%Ç­÷Î7éøD†]ñÔÖ¢æ`R²Áz¯ÎËMšÄ:€ œì¬¸˜>£y:d©ìü"ø;Ék\“‚(¡œ#lÆ÷a˜'[å9P m °ê.R/Ï‹šÅU—½}1n³ß£3…8µˆWK_ØÄ½Üuþk¶ÕâX1ÒD*NUæA/לax’ÚA@“À gZI@69Ž8ó*4éP‘ˆžâ „pH×@ØBŒ=Lʤ¾U ¸Ø±Zí|™¶Ys±å vQa§™žOOäÙl¨¹åÆ.#(cñéðżºÍ“ˆ s(rT‰œUÆÙ?†Dƒ¾šv{G½  Lz¨U¹:e¨ˆž½=>„‡-–ݪ˜!¸úß`•¡ rZ±øÏŒÉXœœ´E®ŒsíW¸±ÐÄXâÜŽŽÆŸ¶z¾€fŒÉŒÓ{Ü5'0Ú§pӼܟbnìozNHQ¦š·µ('Ž"9=­žGô ®kLCIªFS6ãVÆŠ1ú!ÜJ¯¤EYVÉbó;®w³=NÛ™H£î³ X="zÑQî“C«)iICùÚ©Õ®(_Ü,¬«ÎÎ)À3¹ãÖÔ‰H4ȱ뤿+²mýÏμùGsáXΖ@à¿bÈîÙ­ö¾µÐN6OFmÀÉ´Qmô•/CQW5aÜ=¶ó#‚â)5Û¶Ì#^ógÀq£{AÖ6è¥êîVY"^bÿ’Žêf]¶XmjËŽL—œ 8©5þi`R Éÿ7Á´-bàÌÈ‹bs;9’TLu*eºç€v úŸ07³¾FÊï÷Ë0?©ƒ¾ LúˆDtUiŒ§d=ZщYü &RZ^ËRz ž—KTôŠp³? ÆÕ¦#b’#J<‚@ß;On I$<‘î û!šãß`e÷ÝNŒ%x¹¢õ}ÝH–@v~‡¨ÿMZGW½^†qñÒLÍï3Wh‰ü‘Ì'/øPò¤?ÐWab6™³›ŠßàŒ®îÚÎ_ ÑîÔeŠÙ=ÿÜH†Ýþ¸¼~wù–t|‹aT¦`ÌäG±’Ò§3[óKÙg»…‘joÓ o»¶I:¯: ÷†ÚóŠ"Ÿšyw8Ø0;ñ$Ǧ¹·%`L8؃º U3%¿·ûïú#fÛÌ…]rûW{›ð¹À:–R©7ãýÛ”zGÊa3a§ÜJÐ\î–ûíR>_ì<¡ePðJ”—Öò“« •ÁÝÀúà-žêü…(Å#×V'Ó*÷ýd™-qµ˜eã:W?NMš½ û±K«ÊŒnψªÿ´Àù}É6A"걯¦™öJ™_{ŠÕÙbâÐ4Úc.8"×»zèÆúÀ„ë3«ÚH‚±ÑB°q[K$}Ù7ûÂ' } |‡.ê"¢z=ðu£ÉOs×3ô>“Ô<ì³Èz8 ïF!bþ~Û"_°­¿f·L´žíÙ}ç¸÷ºâ Ò„ÏÃ[ƒoL°³)#„×"L7cŠ¡oBÒb¹|€€Ùñ;§èÊcmž`çµ)‚ï°DÕO¶ÎVŒTœý}I9ëÍÆV k3¶ätg¿E{¾´—Û\ká¨Q©bp¬P·µÚpº3u?âúŸXûOÑâz‡ÚØÚÀø÷/Ñ3%åÜ5Ï”âæ ViÕå¤7JôëpâFøN‘×| ÿœõÝ¡AŒßî¸<Ó8–=¬‰×å¾aÆn¨:…ý.°uí’3á±´žJ€EõµÜýšÓå×íéICìá½½cü±'6N Pü•pw“ óš«#_b‹aÁZ"PÅæÆˆ)½¸•ÊK‚^ºy¢I– ŠÇïЃ³‚#©†Mô ?ƒñÞßЇûá"ÁÜÊüYÅÔÕ}BÞø•ˆ˜ÇÄ>‡´aqp0ËUUªIÊ&îãÜ\[ëáëð >Ï0fÈ;ž%K ÑN–ðÐ&à„ûòlR›ùÁsD&6Œ’¨ðä‘vø™HÒ‘S’–Ó]@v`ém÷HÖ®èOb »À«G,"ÙÄÐ/›ý2†ydükáõî—!&×*¦ÇÿÊáý?FZB:‡S9eä2±® ““¤PÛ£Í)°R¬Å‹† ר%¼ÛÎ0ÀÍçñuD^ššÇø9Iög‘¤¶Â}/ À'Êëxm#ãxZ»ÉW|oêÅéÖŠu©âà›7qÆ•Ï%ÿ´:¦ãð èeGèIJ^ù¶fóäð6ĘC\ Ãã¢u@|'ðêïiNÞ}ÌÍ_]Ý –½÷Yqq%º#Ó`û^a6©ÞIáª6’Œ{?œlcH÷5ia­ðTžTªV Æ&ˆsÉs¨ÿ>ì΄æ ýô¼gÓÍ3Î]¬| ãKþßb`žçü÷,þA8ÿ½ŽŸ7»!ÉØ‚~€ ê¸ýÜ€[¬K·M'ïœßÖ£Ö–Ç*7_’)ð óÊ>Äæýî¬ñVXŒíö’,;­¤èÑð†Æ¿j*;g™F¬ù^¼¶˜­¢ ÷î5\€¤"ÎÂÃo{ïARR,Ù>ÿ hr¤ ˜×òhèÒ®Mø2°÷~nÆ#æYJ²UZE`9ñW»ÌYY×à/àpÅÇ¢ö ÛÚ1eHjúß IÎÉô>Ú\}?, ÏÐþ¤C)?("c"np¿ðÂ8k°9ªy *$úW’‰e" }”îš^|ä]à [×ßÇ¢gœsõ5†Ò,…¼j÷3±Í݉«Ï=ï¦Ç4Š~™%ÑÖžÅϸ°žáPhùËÍ"òº/ôô-ÓloZˆ@”e'&ç× ›ê–” ”1iCr|ž sš‚ïϬš[ÄÇx[MTØäå€$ù®è2| CYV˜…¯*Öë'tÞ§QˆnèÇGñlÿ½ÊÏœ™§QGÔ)vm1©)ú3ôéÑ,œ ®Ô'¥¼ë?šäôlÇ?C¿5VÒº%½hë„RÙ%àE0>z’0;û)üȪ“b ÌD6þ >ö¢å™— IDAT".ÿñ ˆ}4gRWÚ)í¿²ÒÄ’²äkó}Ò%l¹[B7#{ršwfbZ‡Ý\=ÛÒ'€KdÊæœ2”/±qo°07:Ñ =µFW’ÕÆ=y $Ñr&ƒÞçéåˆÙ-Iðí2Ï.[¾âß(Ç#˜t-äþ©ý¯pŠ[é]Í'øˆ‡®[¬.ÞJX…{Õ«®Jœ9‚y+Ó3A™x ìÎ/«È`>Àâ[Ì4ØÂ•Dá÷.üt- 9Ïg€O0æzÙcѬê<=x_ Œ_¦Ë;W~|fe³/ZnM¤LÖ@q[LÀù½Rü^égHÉgióJ¡­J.ÌÙ2úu_¼f×>Üs½«[ö5J'/&xl¦|í5H¶ïÌä¾áþ'Onm„²ý­#€×Ž̳.K‚ߢw;€=dîλµE¹ Y,c›FïVó#XJ=&É /á½{o«þ b·h¹eÜØ,ÕØ&ãÏs=O&¾ÔxVðví'Øztwfuâ]IËŒZËë)\'(þHŠÈ[ gÚ_îú€umº…‡ˆÔ…_ý†ôx—8Qëðéoöµõ3[¶si<ÖÚâžÌÒ«'¿”ÇnÅâ¹8aù±úîÝwp0º Ð ºòÈX]–üIpš «û+Tç¾ Ewþ,† ‡®~†§d‹”F¢˜{Ü"ô.à…pˆˆâ‹~2–ÜÜz•ñã¾o‘µ¢°<±q ¥–PzÇþ!";χïÝÔ<Þçhܵ8ó->É9ˆ¹0Ã7-ÙEé5ŠwGÎVAíO€Ë£ÿ‡k,} ÅÜ0GbʯEõš­" ‘3O{q{¶`HÙp·ÄÄÙ.‹¨£¦‚¥:¼‹ÇÃj€x‰ }‹Xî2YüC-Þø$Dìs1&Aæ Ðøæ¨/ÚÃ3å¢ü%,«cQ]ÞÄöô‹ÿ›©Cpì'†°±'Âv—ÓµV¾iÕ™8IŽ‚DÎtÀUåMä§\–Ù–œ[—ß åTiµõªÈ¡K^ —Èl0×åíé¢lœØ@ÓZšÅ§ö h›õ@æákÄÀ»‘‹O Gœ¾ç!ð[gS†ÝŒøB| “€ÌP›â³aÞ!>1# F0"*.äå¿äK#^B®/KÑT8—UõCXZ zÉ'Ë!Qä¤ùÍ›õ ØIc' Zt—Íë{MSR]Mž=AiçS)S–ˆŒç$éNºŒžA(N°QÀ5übÚ@ÂÛ PëQ‹óGÛŽØ%”íì[Õ’ˆg°ƒ†¸ìî¿Ì¦Ï¬¡8§zi– Ôl:ÈÙ)«_ à]%§§}îcœ<²œ^X»ò '›#¤™Ze»À’ÖÝ9›»¢¿ŠÚ’£žW +nÄ&¦ï„‹ƒù¿šËˆâõä^*%¤&†muü0k h¤µ—¹Âïe”œ¤;C­‡ ÝMåßÚQ—¾Ã>ÙÓ¸ªÈ£äâòw•ÅØ°Ä5ÐèŒxÕ•¬ÒijùŸ` æŠé¬²â®ëŽ ;ù†ë#@' HŠS¦‰ç¨Lá¢W3g˜Ž µÈÓß•·‚^½h×6õÌIB. Í?‰Ðö’&‚>=€ó©¨öËK¯/ƒ“á}­©Ð×>d±Yoµ³3ù¥pk•$Ä_†L¿Y[‡tüÆÖï`®„DøÇŽKü\ŽQÈ}ä˜?'h½˜Æ©,SØâÓ /?Ȉ¸}y‡ˆÛ=!Zr5HÖT ÒãuáHµÙH”æ¿ö`ÐjeH~ÿã(pˆq¾†Ä\YáOû#¡J _,ô´XJó6– Y²“4Âá¯Cui›79Á±¦÷6’3,£ÆÙžE¬*$IÈm¸¡[§;¾L¯i§–±DNl”ÁXj‹áEòÎ)´0E„í €éÄ$ f/ªOàDûÖ ¯—ÂiNíé‹|¤1gÊ쮹í_s\¶äQJË<8½½Áfc–æÊ mlY©(!e-»Åê‡åå›M>0ñŒýôƧÙHGŒÈydÇþ çâQ³Fö¨{ Ϩ ¼ e‘tÎD\§S“sx˜büYˆЗ‘u« pÜ[¸®„gåÊ*þ%»–¬Z†î.“f‹}­œªª#±Ú `ì^Ì‚BíÅ A0u€¹™TÚ§a‰õúÆÚ*²oÕeRµ‹. B²víuµAˆb𳃤ªLx2zþµy W ]ó|ZõM²/Ç 5i%¿ƒ5ð–ÓÂ0o/ãw‡Šª‹0·Ïxä8©J莇œíàAm¢î"¨㟅¹Ò(7/B\kÎN:r¢ßb“€Q¨€;iŠfWJ¨œðEŽ#5Ú} …> [ìf+üm¬»|Wˆ¬<[ÊܵŠ×Àj߀M™§Dï½Gô× áœDÁHÒtŠ9Ù±Æô¢ƒfsº±˜[RÄ¡x›÷ äØ%wXƒ†bÖxr$A.d Óí_P“#ö‡>&ѽs§…¬8¬>3¶yzµí™µmR6°¸Ö±iIùЛC*˾:Ä¢@Úæ…’ÐHÊÉðöSÇ$ºWc ê<ÎÂð€´!Ül=w°.R)]wÌ^ï½ ìãd„[w‰ën³­æ¯5ûmù €äq[w [gBŠ(ye»s´©x¹‹taß›W ÝËOã©Ç®¥ÕÐC1vÔfq_5>D æ)®¬—$Dz€1sÎöQŘƑ#žÑWÜk"‚èÿ§®a‰/·$ë |@[™gÂ51ÓÓPÃe“­³÷˜p¾¬@/¦ùòÌŽ¦X̸©›°R½ÙFZU¿>gÿç÷³.Ëk®"f›Iˆ¶<‘^É×Ä@}•­æZ!ã×vç5ÈýyXÒ †ZûiJˆâß0d‰b°ë GKëÜff3}±+! ðâüõéˆ}¿‘Ÿ6L¨Þ®ªÚf—ò.y)$㓚™x* @ž{Ø hÌŒÿPB~*µ)ð Ýåd¸YÝíÍ©çCdö;§(‚¿ù]É ’ŽÓ6ôpïxîý uÓÜŒs¿eÛ lMr¿NLÒŠØòžsÿÒ3æÓ”0Þ]—ýÇvBÞ8nÄı\', œ–RËä¹* o…¾G.ÖÏ,ŽPý< aëéÆœiAé#ïZmÁ@ øS +\m7Cà];ý½êu¾leðŒT»/å@õ.áù c]¥ï£¿ÇX©êå=Òtâ8Ä)&oObóòøG!è`Fš>‹!?S͵7|¨ñ-Û[†¿ Ž­Óó÷Þódnqß³üGû.°ômñæ×„9:RA@òC8éõb‰/{@¶òj—Óê¤lð¶îJ²éà!)ÃQ#ØÔ<å.`¥oØ"È—ÀÞ¶œN_%û%8{yÀŸ\é‚ÇŒ €ûäôÕ·Ö~ö >Ϥ–ÃØVã'ZÌÊæB5¤!Ð?Nxèú‹xÖ²Õ§X¦çCݓт4Í´œø°17õ`âkAíñª/˜°Ö›¯Ìâ; 3/(=« žfÝŽÅêÆ÷¿‰UE^íÓóë™Ô2„80±Ô€Ò(Aˆ_Úf†1$[FÜî”1|¹~ŠD£Ý¨8ᓼ=Ò½ë¥ ÞnÖ,Ÿqàaê¹ràú߈½€½¤QVƒÖP£zÄ$-Ä]xÒ os±¨n=ÿÿãüœuAÍâ^ß·µùS8¹DÐß—m…-~uÍé[aGˆ™ìõ@n8I€Ä¯í@8ô0>7¦è«ãçé㬔@ñµÔ†šîn/4œŸceWíMçÔµJ-FÅÅ@Óûˆ’Ç‹ Òa$ ŇA„ÍŠ·´ÄÖ~˜BáàŽ#@ ¹0ÞXä ˆÔÏÏ,Þf³¢vB¸`}ÏPÀ1¡Õ~cëlØrSÓÓLo!â åAýÕ=ìc~¦W›)…ˆýúØ&¯Íî1ý‹ †Ñ÷‘XQBfM·èûh3oy†ó¹~@À‹yd5)R”9/-)µîåîðÖ)Zv¦š¼´ ¤lÝ`yÄÎ4Þ£'}Šçˆ9°•ßösøÝ Ì2–kù–?’Öì$P+˜=и?ü9™b¤ÖG³£(2b=G-§«æ×(}¯9Fü8_Y}~‡m~` €ÔH×ßÀ©lÌmâ‚× 0Cuó8öBOt!Si¹¶ÈßÞ•%—çˆa~¸|BÎb$j‡¹͈ÔÜ»>¨’m»±m(§Üý,ÓéˆpmXÇzŽ,ÄÀÍò~cä3ˆ¼ C¤€Hçœ3Á ?Ðò)>:³îà¿ïúg¸>F•øMCË…„VpYL V‹ä~ŽiÁ^R›~Ò?)ßÉSô€…Èxà‹‹!FÓµ{”sÅ«<º¤¡E@yd)A%.(N/pÙ à¨ÀÌ„ v!ÓQÌ$_>²FâÝ L’û„”Ý=&‚$IÁ_þ²¿³ÓÅ"ÄZvÉ©}ô}Fõ.Ýí:œ¤‘ƒD>Jš|G‹½‰MÈ‹ÒK`ì©ôí_’D·! r•EÓcmª]0{üøœ™Ã˜GtžÍàjÕü}‹=á–VÔz@™Pw•ƒ÷ nˆÂ+yÍß´z"2†„übtKz–—’p³Ô1$Â,ÈÅÃ×XÉVNæ‹îxþemœµê÷í!§†nJsxš‡´{ñ®ãÞ¯ÒAßY×p¢78ìN¥)ná){n´1‚¶wçšíž# ²ÒÐî~àíŒÒ6“ãÿ(yw&ÜÑqו3ŒrØ`3c ÌcÂp¦Á5à|Qÿ°áëäS€/¤m«Žã0Ûõ¢qçµ€¡›!"­:‰kõö÷q8³V¼nN}ÕÙȹ=$zÂ#_ë"ʧEÕE`³+À¶×ÌZÚù7‡N"HÜÄßȘ0§Õª áÍ*÷ˆqOìµ¾x6™]Èg^ÐÁŒ®}ëi²ÎŒp ü© Ó}Æx«“cÛæ6@ß–ÝßàI‹šüÕ‡Ó õ„ðÛAõj2d]EÌG§‡–Yÿmø1îZR’Ê|âBúýÖeå0*Ç—Þº¬6 ?t„-ÒÎÈî °XÑWf^åË3怣ó7¼÷¨U¥É³³¨eUy\dŒd°üºŠTþ‚Üý cD€ø•ÂH2>{UÊZRûÿˆ^~6l·&P¿TBŠ;Tê!$›Ö ^Þ]{ z¨zí%, hfÖ™»aدžÆuNŽ°ÛŒ›fÚß „ÌT8¹Æìà‭T6ñ˨µ6oó½°“ÕfD~4…ö¤Ã bŸ>Õ®Ë+Ó2™øœ,xÑ¢:º–Ýf°Ÿë‹ &L8y}‚SÚ=ñÕn¹ `º¼Çè-ΖyȔı§ÖÆF8Z±4÷ùË8^î¾ ¿yÚœÖù[hš«Ëç¥ !Mxòú-b…éÎ$¦öéAã[Ì«Ü9AE:œY7A²\(ËäNµá • ,ûš`ÎL†¼Ää>ëè% (-!àÜwž…®Ò_›w0mñ2¯DD~<Â`\Q“0´sC“Bæ“‘¥vŠq¯ÍbêN{bœÅßËXàõ¨Êû^õgcÉõÿÇÞyÇ×Qœ{ÿ÷¬Ž$«K–%¹áÞm0¦ç†b¦'”›@€„Þ’›^^Bn’›„ÜÜKBBo—„n: LÀ ƽáªbËê:’μ<3³³³»GG:2±a¾Ÿcy÷™gž)»çœß™åÕ·²êÁ×&ä‰ÝK‚ï¯2ËÇÅ:FD$¸}²ÆÇ€çqe¡Ì6Æù,ø¯Ñ£+Lw#ŽÝTY'èO=åÍÙBîñ¨ ÈÂD0³ür³‰Þ!cÇj¸;âªö ÿQQ¢tòŸIß:˜_Î,ƒ €Â $T91Ë PëDò'¯=`•A •ú÷~­¹8¨6’ ¨ —£žw²vm  Í^”„BœÍÊCçU5‰;ʱj€˜ÚO×QÙ…ÿ âsZ$Ødx 9͘DüÙC‘ßÓÚªþaGªQFø¨®Ô»1!‚=c~¼)¬*QÉÄÙƒDŒl¡Œ&ô÷›Ÿ¢6tÃÓ,ø[ÀŠÀg£´Qd ψˆzFÕÐn¸ÚÑŸ!"Ll#nT¨Hy‚,ÒªÛ  J1ç#K”S2š4FW´"JÒQÌpz;ôÃÐ8®¦5»·‚pZ"ìDòÛÿ>°±²ë~jqÏÅöÃÿ.è¤Ëámns pÿ\ðáoUP{ñX—WKö[ìâ&ºT!Dä™EDÑ=«Q¥YÔù§«¡ªŸ%¡NQEp‚n©ìŠ~YYtBÈ ¯Ò—ìÏÜ+¤Î@¨w—ÎÊ‘þ èSˆÔ6KÜ„Ðuð²þ=`B¼ °Ðƒáwz¿á@Ü辡à×¼]º<¤Bd¬DaBAˆá?€0f<™¿ÕíV‘¯4|¾hôA·ð]øÃ(Z4-l$!RB9û‘õi¬-éé«&ôv J—uLD×ö—D°aDðßÛÚf7Ä(“Þbš`«Òþ¡ —i+c—hžõ1G]ªmfŸbþû :”…üÌrÀ@9-ÓÓc½ À_Ï2·õ–“}hP?(c1?„š‚ÏôÈD’ÿæ >:‘lÊ7¤‡úµ‡j­:úÕui £jœ`œïÑ.ý'²¯ÓÌHgýYy #³ôG w‰ðÌÃEDÄ>ü2ì¯ Ù‰ôÛ–*GIBßb)O’ýODBÏ€÷ E —øÂ# „ð+` ßz²ÚüàNòsGŸ¨d|Ïó·¢gr°žq½*`T€Bp¢v0ì€IÖ·Ø(Û !DÄ)fuN¯¨cÍu8£Vú\’F¢ÐXšÙ‡éet+"z«·œ¿’¦µwˆÌ·„ ®9'ªVÜ z-,à¯}BD|Дk¯QÈ"§0ÃÅ:«³†›,ma7¿ë‚Vâo@¨ïDYÝ™fÏXgŽ…ï©þOï¿{‚µoG' ÆÜ!ÿDÇ–ÇÌos¬'Ò$0ê·i` B|Äd8däó¶Ñáp8Ç!"õTk$Ù±ç3ô™Ãø*€ÌDŲöµdYÄ/¼(õF€‰Ñu}%ÂE‡ jU¬} ½ŽUD8ßwÄã~_~ö3‡Ù&‡Ãáp8G?ÚôѦM`G,Z•‚‹Rr ¯°@ –ÇDˆnÊWVœÝ@VG WÀ^ÜJeÐ[Ô…€@…­`™\qæn$ xšmvkºº»-‹Ãáp8‡#¾—ÆÅú¸ÁAÈ¡X ¦+ %Ù‚i¶Á3 Î*Ý—¡L”fÝ€L‘•¶f¬d ëØºººl“Ãáp8‡#,«lq™w:OÄPbfX³œû çÌH³Šà]Þabf¶ÍShÍÚÖÖÞÜÒҕ쳄ÍÍË-)..,,È>‚àp8‡ãSOö#û¦1½Š ­,Ëá¨mSÍòª]"QÊ­vj¯àÜVQéP£ª:cŸz"«ññ!Sê)-­­%ÅÅ•ƒ÷I;¶µµ7ìØÑÒÒ:hРì#Øi‡Ãáp8>õd/0²HðE[ÐÂÆ hè;ÿÚ>ùJ0ÎRn¶¨ì,j1Þ‰pðaÏ„]×ÞˉÀšT*÷6"†dõ¿oŽF'twuWV.,(4S{¥°°„ÆÆ]4‡Ãáp8,²ÙGa‹e 5ϯ}‡vBÆd™Ýáp8Ç'•lÂn‘(á`¦%œjÀÒ(p#•o70Gdc ¨ò2ºŸ?!§¦’š¢ \žÜ óý¤=]qQ… H<~\w8œj:"™ã(û¶µ/´µµåæææææÚ ‡Ãáp8öf²ÙG°­hSõ™m5H¤žOλFJËÄTI¤¤ ”2â<þEüààõ–ˆ¿è[Foåÿúy’f@•¦m1‡¤'¸€kN"jm>B8¯•%Ò(#d…Ëw8‡Ã±÷“Í|Z‰I¿$Š¡¾¢5«ïR@E…ú©òéˆv!©S儱$JÏõè¸i d RýÕ{4ÝY^d·…¸éÆ›.¹äbËèÿˆ±=ÝÝ uø»Õ)bÅáz·(“Óª§§§³3ÙÝÓ!<ÏËÍÍÍËËí5W¯´´¶æåæåå¹Q^‡Ãáp8˜8‘ é%J$K-·ö žª“²Œ&ô"cš­IŸI0 Q°{ ¨zÃc}™H$n¼ñ&m¼à‚ot”!"ŠÒ‹‰D‚ƒp-Xo¹åÖ€ŸŠ`û ‘ßœHºº»ÛÚÚ:;;/~»¥¥¥¦¦æ ƒîéî½–îp8‡£„FæÄID©\ð Ë–(*šÂÌà:~PÑ"*Ü;,3ɽ>«|¸—Œ`V¥·jÉ”èÛ§úŠP!ÏõRG‘(úˆÞxãM—^z‰ÞågXFu>DDÈÍÍå,–`5³CE0-ÝÝ]-­m¦¥¸¨(‘H455²h©Ô®ææ²Òu‡™ çÓÞÑþÑGuu%?ûÙ϶´´¬\±¢¢¢bÔèÑÍ-͹‰ÜîîîžžžÜÜÜžžž’’.7•J557—–”xžgºåää ”“H´µµõô¤ÚÚ;ÚÚ;99ÅÅŪʇÃáp8²%R`dH‰‚Ò9¦sX¢" w’€±Š©/Ýb®öž›é×·²ÁõYÔÒD†=RÖFCÝaøÇ:§Äm1‹À3‹™¨c™)Dif(kÙŠÁ ¨õuõó_œÏÛ'N¬©ÚÓÕUUU€HV;EÜC2/Í û‘J¥Ä Aùûí»/ûTTTTTTHP2™\½jÕšµkÆ7aÂÄTO«ÞŽd²¾®./7Q\TL ÎdrÍêÕ6¬Ÿ>}FMMMYYé’%‹Gî³Ï†õë7mÚ4dÈŽ?c:‡ÃábFF¤•(’(zJI @ÈÙ™$·ƒºËÀ–eR±˜F3—)#¶ ×hs[^17‹Z~K|l 5Q˨}Ýö8ø7š¶kþ@æ2µ%k•‹G>Òî="HáÙÕ•ÔÛ\ðÜÜ<#QÂL†~Î9çH&“íío½õÏ£Ž!’É®TJL›>@]C€ò²Ò¼Ü¼ÚÚíååå;vìÌÉÉ©­­\YééF©oÂø o¼þúGÙ¸k—"''Çó¼;vŒÚgøÀu¨¨(@C}ýˆ‘#LûÆÇŽÛÝÓ“ãyoýóÍ9³çѶm[GÓа#‘HT”û Ûáp8GÖÄ Œ èE¢d€-QÐ[p5Î(/ηòjêI”`1)K˜´´F[ÈL”÷rEÕÎ/_OV»€•Eíx^ì!¹âŠËmSÏ#Pt„ȼa#G0Y¿~Ý›o¾iZŽ?îøaÇMŸ6ý•W_i¨o()-™2yÊ“óž8ûì³óòò.|mÒÄI'Mç3bäˆüüü·ßz«v{mOOOIiÉøqã§N «¯¼2cÆŒqãÇéâF]ßÐÐÝÝUZZêW>|øë¯/ܹsgIIÉ¡‡:¨`€#F¼üòKÍÍÍ•••'Ÿ|²éïp8‡#2aú*Q„%J/O^®Ï(W„lú_ý ÀºÕË ˜G F2­¤îÁ2{%R ‹`KIš»æ_…z-:¸Æ¬H §ÞÑ• …î<•3û¦eúôéÓ§O7-LIiÉI'¤w§L§œrŠ6Æù¨ª®:öØcõ®æÔÓNµ,míí=©žÒÒR³bDTQQV¥555gœq†et8‡Ã‘=Ù Œì#ØV €”¨ãm)^hŽ©¥ý4:£‰á,´Gdvð¤KJ‚dpµUüù¬L¤K4¦+,%û?îFËbàkV:;;­™Ë™ÐÙÙI|y>ëv¿ŽíÛk=Ïûpٲٳg‡*¶gUÕáp8ŽO6Ù Œì#Ø ±x¢Ÿ÷D‘-Ñ5Û[ |«á,qõºjX8štzT=Ò©¯X¹R‹mÙ¾]ÿòÈÍÍmjj.+£>ÑÎÎÎ]M͹¹¹Ê>‚ö¯ãé§ŸÊËË;òˆ#Ì»¯¼òÊ‚}÷ÝwÂø ¦Ñáp8Çî#{‘};- ‘—Ø{ÇÏD€yyœŸQ•¶2¯©/Óú@¾® MPÈ’À˜©[kSS‹f†î“¢Â¶öö–-[ÉH$ ‰ žÃ×Î?ß6Î8ýtÛäp8‡cw’½ÀÈ>B$züu _4ú~z;¡_$ŒñN-vûÐŽ4õ„:˜c«,H»™þ¼(B,(TP0ÈLê+ÙGp8‡Ãá°È^`dÁ$Z‹‡e¡è“,Ô¥ò‚ð3¸®"?_ xºh’NñÏ‚E‹x6šƒºqa"!¢mÛkm«Ãáp8‡C1´¦ZoóM¬Ý ”€ó…lPˆÉ%X…Û$¯ôÇlsfíì É€T65lHÏf¢E”fd㈯à‡"+¸&‘i²ÌØ iêÔ;`ØÐÛìp8‡Ãá€ÀÕ­çÀúM Ý…{öJìA@ÊÌm©`…H©=½ÍÎæ¶O„ɆLÍ*T\M 45qe=+¸ÈÓ™ +ˆ©‚0-¦CTß:‡Ãáp8|"õ’\*PjΡ, ÉeL%}m]¤ X7Î{êî|))eº}Ÿ½”wjù~U@2Åg%€åj@%Û†É6ÌŠŸ:‘Ãþ½ [‡Ãáp8GQ €¾Øo-ŒJüÇÌ#·}?Sµù›}Ùæ D¥øðp0€D°zZúã£r‚€`ɬ×Ã’ã¯}‡µ¹¬dÕ†È_‡Ãáp8Ž>ÃÒˇŒQFç2F¨žÝÚ K=@Ь cÙ•­²+ÍÛˆ5³ÑWüŸú_Ùƒ8ëp8‡Ã1þ£'UJ/r“E¡eÌT¤†2ÆN!5 ;&R±Œˆ·MåÎ.Rc¹FøÉi æüAVè6ñvÿ[àp8‡Ãá`Meˆ/Ÿ8#©«ë¦SÈ‹írZá @©:¹ð@”Ôp²€ôÒ³kede$@¦]WBB}Ò¬€‘ÊG¤îA#‚àЂG¤£•gÌLÂ;‡Ãáp8LÔР/ ƒªÊÖ~A¥§õ=­e•NìÁW!lÖ:3à`Þs’)œÛ+ïÁ =¶Õªkä¶Ä/1tוß7€Ú”mbýÊ9‚w}3x7<žìp8‡Ãáȵ²•máñµx˜Æ €ÀãR¢Ußô‰ @òÇký[¡ÌÜB÷My€’…$ÓdmH?¡^¦K`¥®`YÜ$ä /uOZ D” és‡#–ûî`éûØV‡cÏë‡ããÀQA‰”YBè‡B‘,v ÐÒi¡hÖÇÈÊÐKEävX"ö{ž¨_fhpÕÆª^œ»ö UIðbó9Ž>ò‰ÑIŸ˜†8ÇnÆ#xD=Ö¶K4¶z½+3ÓÝÜftNÒë¹ê퀡­ÓF]¯Éf‹z‰mN[ºd¸ÖmÛ¶/zóÍ-[·vwu•——O™2yÖþû'1Ï˘-[¶¾±hÑÖ­[S©ÔàÁƒ˜5kêÔ)¶Ó¿”ÝÔð{î½oÿýgNŸ6ÍN }ìñüüüŽ?Î4>ø÷TVV=g¶iÜÛyèáG6lØ wG}Æé§éÉY_þ’ÞÞÝG0 ýx×Xµ5ò/硇øà¹Ç“ÈÍ]·nÝ‹/½´«i×a‡î)ßU»©áûí»ïóæÍ™}T~~>[v66nÞ¼yöì£‚ŽŸfÍše*žO6{þ»Æáp8>a°"¸û Êh-m…ˆQm":Œöfý‡QþiHpÜŠ¨*DCÁI·Q…’%EÕ¦]ˆÌ‚Mªì|éX¿~ÃÃ÷ì³Ï :ô¬/)®Qýf̘1Ë>\>kÿ™lYºôý¡C‡V  ­­ý¥—_Þ¸q#3ú¨#4hP ?ð×[n=£GÐÜÒrË-·^vé%ùùùwßsï>#Gn¯­­­­-))9[6oY¼dI2™œê¨êêª`±Cd·¿óî»ï¿ÿÁ9_9›}víjºíöÛ¿þµóKKKã:Ä:Ê‹—,™1cƾ3¦g~¶½ý{ׄk{ßýpC2Ľ¡¶E½×±&‘­¶|‡£_H¹*ÇYåÈeŒö¼AÂ÷ ¡ÍZDlgµ']—®Œ!5œâqV¾{ŸÃè›´ÒÇ2+e¨W?‹Ì#Ø$ä8´…®^LŸE3fÌèo뛼ýÆ¢EkÖ¬6lØŽ;ššš¦MôÍk]Óœ2yò³Ï=¿aãFþ6}ï½¥ŸûÜÉ5ÕÕï¾÷ÞÃ<òµ¯_XPðÌ3ÏvwwñÌ3 ½±hÑãOyÈÊ·/yú™g.ºðÂÈÊ^þÁËN9åäaC‡ÑãOÌ‹¬Õi§~€¢®®~Þ“O–•–M™2ùä“Nlll4¯Õ¦iTÿ ¾3f¼ÿþû¬Y{R©eË–qÄáœ:ïÉ'sssÏ9ç+"%ž~æ™§Ÿy–ë™!«×¬9唓+**^z饇zxòäIçžó•öŽŽüû¨Q«&Mœˆ˜566.xåÕ/~á ÕÕÕuuuËW¬ØMŠ'²Û§L™²`Á+µuuÕUU–-[6räÈÒÒR¤íó(/^²„ÁooÿÞ5áÚš¤i{ø 5à-ê•ÈŽ ¿5­.,(°‡£ÏÈ›ßYVªëþA%<ýý(íEàû¤ ãö¡,ëSž@Ħ~ᩚÆNtd¡W‘^ñîaB}ŸÛ¯{¡Ï,[öá²ežvê©y¹¹íí튋‹m§ìˆ KDE……ímm¼»ß~ûî3rd^^ÞÁT\\¼fõšæ––Õ«WÏ{lYYi^^Þ‡ÑØØØÐÐÀþ³fÍ:´&‘HÌœ¹_[[[kk‹ºïDÖÐdæÌ™Ã‡ #¢ôµ@DÕÕUûï?sÍÚµFI¯ÙûÇôÓwìØ±uÛ6«W¯I¥R“'M°k×®M›6=gvqQQIIñœ9³×­[×ÚÚjçgÖ¬ýkª«órs§NÚÕÕÅ#sååûì³Ommâ[äy^Žçååå%9Æ =Riè,Y²dÉþçùµzßÃV·ÊÏ?~ü²–Ë>üpÆôéè­CôQÖaÃ|lí<'{}טÎéÛ~C x‹óþáþwÛ¶mlëØ`n ­v8޾ÂßD”þë -¦0ÓÛiõd¿ ªÉ„UåP H¹ëú.)…0Z“Ù_òñ aäÓd¯ô½s7lØøÊ«¯~ñÌ3‹Š hii))‰UoýÀk| !ZÛÚ y·¬¬L'•••5·´4íjð×¿Þ¢íššš† ©PX(GV9 ÝÝ=¦[_éµá¥%òešZ­\µêŸÿ|kçÎ]]]†nú0i²›–¾R\T4vìØ¥Kß6tèÒ¥K§NÊ·Ž57·xžÇã‹ÊËÊÙXTTdfO÷ €DN"‘HäææªÝœîînÄ·hܸ±'xâ‚W^ioo¯ª2kÿYUUCLŸþžÏ×íÓ§M{ê™gŽ8òˆÍ›6wvvN˜0½uˆ>ÊiøØÚÛ¿wÞ “¾íá7TyyÙÀ¶ˆ±Žà}÷?Àq~kô©Õ‡Ã‘1¬) XPõú¨&u?VX}‘þ£·#ÆPÓÈÆˆ˜ÑX1ÎI°…­i´óÁzh©k& Áí"&6 õr4¹ÔÖÕ=õôÓŸÿÜç®`ËàÁƒKKK?\¾|ذ¡A߬a?\>l¨vùŠ"%x%€¦¦]:i×®]ãÇ+--!¢‹/¾¨ 4ÿrÀé½áªËãjÕÖÖöä“OŸrÊÉ£öÙ'77wÉ;KV¬XÉIäùG<.{öðXûÏœ¹iÓ&}÷UIIq*•jnn.))и«‘fF‰D¢G‰þö¶ö`b/¤iѸqcÇ+–¯Xþ>xñEf¿ƒEšn=zt"'gíÚµkV¯™úØ1GmÞÁ@„cŽ>úƒ>xõÕ×v66vww74ìxmá•+WYû æÌž½ôý÷_cQssKGGLJ.ñÅ—=ä`}Å{ï-Ý´is2ÙõÖÛ‹[ZZÆO_RR2nܸgŸyvçÎÆîîîmÛ·?öø==Y§Æ‘yÃãjÕÝÝ ˆüü¼œoÛ¶­‹ËÙŠ ‹êëêS©Tšì~ýeôèÑOÌ›7tèÐ!•rhª¬¬lĈóç¿ØÚÚÚÜÜòâ‹/3&<ÈZUUõÁ²eMMͯ¼úª•šž¸mظñÕ×66îJ¥zDJt÷ô¤2~cgNšn'ÂÔ©SßyçÝU«×LŸ>vˆE&GpÀÛÛ¿w ‚µ5ékÛ¼Eé‰ëXÛ/¦Õ‡Ã‘%¶. YHa¦†se‡Œj›CÄ Ä„ ŸKr€œ¾¿=j~ÂÛà}é!tRW–ê"„ŸÜ• «×¬niiybÞè çžþwß­®®>ëË_ŠÌ,¡?aÆŒ .´B:ù¤“^^°à®»ï0fô裢Š:âðÏ>óìs7ÿõÖ²²Ò™3÷Û¸q£í‘–È9²®¶îáGiii©¨¨8ù¤“òÔ¼‚$M·˜>}Ú?ÿùÏÊÊÊ¡Ck´1“±ÈäîŽööï]cÕÖ×Ƕ'²cm§˜V;G¶D©)"©þbHŸ…t·Ëâ‚”–w€E`ܶ‚¢ª#n€\Ñ€8ƒüOÉX‰­Y5@È;Òd*Äw“ñ@n "Bv\8޽/ø >‡}쳟9Ìó¼­Û¶3¾§÷pî¾çÞ<`ê”^Kw8šOç»æÓÙj‡Ã±[Y¿aãG›6ö8! B+³Ú—­”ðä‰rÛ¯$e\Á‘ý»üRô4½Jjš)1«D@D$çoEøL¬VÁÂ2$7ÀëXvÔš¯œÀÃ%k'PÑõND­‡Ãáp8ƒ-15Dê4éLJÐi©*ƒ¡þ/_ hB¿"BÅamHК8 8CµôK£kÊa‰-[!kHs8‡Ãápô ¢ÀsSµ@P›Iõ íE’}ª·õÝWÚ¢‚Ë-.C¥ªÛ¶ Ú2‘² q¨ªG‘f瘰”6¾vý ŸWäp82äÓù®ùt¶Úáp|ŒPú¡C“>é0T)Ñ´¥ø‰JŠH-j« ¦§·ô ét-QPŒÃP¨ü—%¹Þu8‡Ãápd èà VÑb.j°6Kò<£~j¨¬Hx¤ºRè²l2AáP¬@¾ÖD¨~VªM÷å™°‘y ¡º†ú4£Âáp8‡Ãá#ÌáMeñõœÊ5ßn_ÜçD+”¥ ð'à ’êRONÐѤ¨´ƒÅ ð¸'×@*Ô­_²î–•"=Ô†HBm³ƒzT5 ¤f…]–Ãáp8‡#s¤“‚JßÎèy¤Rw¥‘¤ÿX6!i‰ª®û˦؀Òyé¦&Œ‰¤ÆótT’e&SAf &)4‡Õ‡JAµV€k¢†c=°¬í½‡Ãáp8GK.àç úú‹!-3¾˜o¶ÀR—D¼ö“ ÛŒ9 ‘!"1=Ó=«ÐT©ÂÏflrµØy5™®bªUŠ(¹Õ_‡Ãáp8ŽÌÐW裄Vº¥ÅÒo‚ëIŒYáz׬<–" ‘ÓJI¶­1©”^ã:‡Ãáp8ú €§˜©QÔÆ£ŸLv«c¥g?Ë ²HvÕÒ3fÕH}Éü-+­Öð]i¤nUóÕjXLJ™Ëáp8‡Ã‘1JùiáE€ñUò´ˆ \7”WX× Ò(%½ØKrz–D< [aªÏÈLc¤ÙeúiñÄGp8‡Ãáp¤ƒï~"@éT"dq•‚`Ùʤx€0‡ªxµ@4f1µ [ôÓYYbêðzù+ÿù ²gdâ58¹@÷‚Ú?€r WÉáp8‡Ã‘!¦ÄÒ²ÊdÕÈ4Cy‘”»JôYÒi1é ©ýÌQ[cÔ”‚:r6C"r„5J 'd} í®:¬.ƒ²@ð‘W ®†Z!4°jŠ]‡Ãáp8GÆHª/ùEÔR!w¾, C¦õ ™ÅÌ!u³±v`e˜ÐÊYû‡›Ág£P>ž”›aG]¿ýh}©ßõÜDQe2ÒNÑ’¸>Ù#¬FG÷Þ]7ÿÉÜ=÷¢+Ì]†?dÂ8¯•%Ò˜ÍÇ”ŸýŽÖïŒ{2úí”}ë²ì^‡Ãñ &ü-9é¿G"Ù}ß#Ÿºú.oŒaG–žBB¤àyBÈ'•ª¯ @Õß?"ôðS­õ6É2© ÇW‰ü:yâÀI1È5¬$F­xdT#Ï)õÁ "["s«ÇyyžGä‘G`§EBòŸÌ ¿LléjÙi›TÞ¸æ'ŽÞ¶âDæ½ñúߟxܱ¦åÖ¿\윣LËÇÌOðÜ{»ùÚoÆtÛi7óÛ_^3çÈÃmkßùÁw¾yÕ¥YÆkòƒ ÎwO;t8ý!ò“ñð+ ø"¹u£¿:QÁ“c³òZ:€Hµ«€PÑP}“A ¿ð\Û^泦‘ŒœÄ‰[‘Ö?ˆéUgò¥7®ú§ÝeúW‡EWËŽÜ’ÁéòMT„s/¾ò®›X¶«“#„‰:¨Òrݯ¯}kñ;S&M?nìηÞqÏ»Kß·|ÊJK¿vîÙû͘& Þywémwß×ÒÒ    à¬/ž~Ð³ŠŠ ¾ñæíwßßÙÙɹÈÏËûÖ•—äx9¿¿þÏl7I!§›·µR|e" ºî××.^òî”IÇóÚ‹&Nõ÷¡† ­ùßßýêòo¯®¾áº__»ø÷¦Mž4zô>Û¶m¿õŽ{–¯\õí+/?vÌ㊋¿±jõÚþ¿_ ”ö¿áƒ(,(üpÅÊ[n¿«®¾@Eyù%œ?mê䆆O?7_WU³ä½÷›š›gñoO>ó<[Ž;zöªÕ«7|´™@q]Çpœ›ÿôߺñ–÷Þ_ rpÅMüï¯^xyk[Ûu¿¾öý>œ0nìØ1£êên¸ùÖ©“&rÒqƒ½öÆ›7Ýz¿ ãjîp8öR"¿2$Í÷B_>†sÜ÷ˆc ÑŠÛþaS[9 ?_@Áò þ²M ã,€uiŒN‹2û³ä¾ÚÐF¶í鯙¢Î"ðˆrˆrxàDÇ!mS¹`D° årÄÂwæËHêŨ~ÛøuÞÅþ , Ö¼’Á!7Ò>™3ûˆ»ï¾û/¾ô²¯¼rÕe†ôw®º¬°°àû?üá~ü“ÊÊÁúRøU—]8n̘ßüöwW^õ­uëÖ͘6Eg)//»ö§?ܹ³ñw×ý>,XÓY™¸‚Ž>êˆûxàë\pÇwUUž2i"Ûç3{éÒ¥uõõ¼{ü1³xðÁË.¿âõ7Þøñ÷¾]ZZrýõ\»nÝ_n¼éËgå'?û€+/½pØÐšŸÿâ?/¿òÊ-[¶|ïÛWrÑW_uiWW×7¿uõo¯û}ä\‚”Àüù/鹉DböŸ}~þ‹|¥%®ë2䃸ãÎ;/¾ô²U«Wÿì‡ß>|èw¿ÿƒþø'ÍÚÿ°CbŸ¸š;޽”¸oÌ^AE¶_Qvmvì.”Þ"€¤'†RPÀ‘üíaÚxlZªyà—,%üŠ>ÀA-«}DJ Å%Ξ.2 Œ ™ÙAz‚ªLâÔOL‹O „°Vãü?½ù/ó½8¾½c#@wÞ$GXÜï=y%•aŸ@5üh°“L ðÔSϬ\·±­ Ï<ÿbYiiEEˆ@Ò§¦¦zÚÔÉ»íöº]­Ûw6ß~Çì¿_EEù!C>`Ö_nºiãÖÚ¦Žîçç¿´xÉ;p䈿ºæ'‹Þ\tËßnëBŽ]"'Ÿ0÷ï÷ܦ_%¥%q•ISÐ3Ï>»|õÚ$rÛ’= ^yõ¸cç€(7/wΑ‡?ÿâË Ýž{þ…÷—¯lîL=òø“;vì<ôà{¼\€R^¢ÛËïñò*+zÐ7Ý|˶úÆæÎÔ=÷Ý?´¦zŸ}FZ3uò¤[o»}GKûÖº÷Þ?»-D/¼¼`Äðá'ŒÑ¡˜“ÈY¸è-ÄwŒîåê]àégžY½aSKR,xåµAùùwÞu÷®¶äæÚïðÁ¸±c@Wó@@÷r/÷Úë^á÷ _±˜ ìj8v aéEªQð|!ø!Â2,ƒCÃ:SªÍHü ¾–µüU•dé~½‰ˆbç˜ ‹CúÈ™¹BÈà¦<÷‰ i “¡Û§“lú†óFF¸ó¦ëyãËg…§ÝyÓõç]|UÀ)&oOOON"Ç´ä&rº»ýçPïlnáAÁήyy¹: @eåàžžžm ;ù|ÞRÛÀƼÜÜT*µ¥vçM‘_ÄÑGÑÜÜüôs/¤âOi{>«—ÇñÕ\QWPíŽF¡~€>óüüßüòÚÛîºoÖÌ}S=©·–¼«Ý¶Õ5°[Šr¶×ÖU¶¯ŽUWU¸ñÙÉÊ8¤­½½³³sgs+@ØZ}ͽ¡±iÉ;Kæ}Ôª5k=ú¨W^yµ#Ùø®ÛٸˊGcs«ìîžd2Ù–ìáštvuóaŠ«ùÆ6™‡Ã±ùIž!i¾G2$›¼ŽŒ‘Àòg*Àk2 !ç¦êÿÌ"EoÄÒR‹Z5)@Ë?S‡’‘ÙˆB?ÊW¬ÚO@VCž]Êž xFh€u…N€}bÙ7f±²4bE jìpáæk$æ)`ÚœwñUÉæ5Ï=`4-ˆˆ¢"˜‚Ày_Å–°låÛkk‡×Ôh{IIqQQQ]m­_çà©Dª9¼±£¡!''§ªrH}C€a55v4ìÈÉÉñX¶lkm½Ù/ÌŸÖÏ3jŸmÛ·ÿæ·¿ÛÕÒ ÐcÏ»øÂoœ8÷صë×ÿèš_Þð—›¿pÆé?þî·ËËJ7nÚüÈ£wuwsÛ/ºðÂ?ý÷5ìØùì³ÏM?Ö(Ð'š?ÿ¥/ýû™è!©’ø®3¹ç¾.»ä¢›þøûíµuÏ>÷ü~Ó§Yi¡˜š;޽–øoBßÙGØ=Ü}ÛߒɈ»r‡TU}þŒ3më'Éë„ò« ^ߊWú÷5‘Tw¡‹á2—9d&mb4:‹/=ímvìÿIà¯TÀb1,1Ä—}9ó àií£ÉÿyüÖtcÂ…Î*¹ë³Ÿ9Ìó¼­Û¶Zc¥†Ù´ióÈ‘öÏúÄžùìÖî`Òô™­ÍM¼ÛÖÖRY54è’) uÛ ‹³`[=$ºå;<á% Ž²—ê”j’¨×Ó‘ÊÉÈK%å(» T7‰+;¥º {®RÝ$zR9r®ª†RIÎ¥^® œ¸Ê ·‚˜ÜDâ¦?þ÷­·ßñÚ¢·µñw¿¼æñyO½úê+)—Ò ÁŠ”—êÈKyyPµe‹ „—×…*š„— T—®’‰nJusC st×YÝ륺 R ÄE ‚Õ@‘òRI¶ TîÄÖÜápì•dÿ-}Þ®¯ÛÞÙÞö¥/)è2<þðCuµÛÇŽŸ0çØ¹vÚLä³[û$oÖoØøÑ¦M3ž?Ä_…êC["%ïÀK¯ Þ”"MKW¾ƒIíòº*•ö ðªüR%BUÂ/6%lihëG½'âò¼À—“ÎÌeÃų³Ö¬v¿( Èj‡ô«ºç³è"Qöl+ (!bVÿÕ2Hî& ”ÝŸl ÈÉ‹SK«Bâô/?Õ$’Ÿô@Ðs#|+ƒ²‘’VÎ,pyÂ… ³~ Ý#9^"ÙÞáP"70–ž®®dg{{Ž—CáÓɹ_= ‘“KKóøþ$¼„et8Ž=–쿲ðñSU]3¤ªº¾®võÊ•Ófì»níã'Ê'Ř8yJQqqQqñÐaönÞ¼bÅò#FìÜÑàyÞ¬ÌI$¦Í˜±zåŠå.;èCsóúÐð’­"À k<"BNN e£ÉACy|„̩ŚGÁIdjÀT()å–`”—êê­tõ’uеä¼2–Þoki俜Iqj`èTÅ`áÌJ^êvñ(®ïï€ê^ ‘›ÛÕÝ•Ü1Ç<=D^"7DÙG°>ˆÜBÛ‰À‡ÃáØÃÉþ[ ûvÂÇ´3¼8ŇˆTUµ¶´äææñ¦ P~ÈhmininJ¥î¸õ¯ÚM¤R---¡u¸÷(´è ª)­ÄL#RİT)Ë:눥@Ð{•ÂÓ» ‹I^;‹=Ô_Þg{°Ä¤GƒN•ÊêÊSf.CÖÆV“*£Š4àF¯AÌm'@y0n‹vØä$9‰Ø)™}‡Ãápì½dÿ-}„ cÇOxóõ×wî\´p!€1ãÆåäø­hok“ímŠŠKŠJŠä$ç~íë^ðþ„=OÉOcòi`Ú%$DŠÀãû¥IõF€Ò“‚÷Y˜±‰µ!ûߌTPûé1PH ©ä­2²ð K>âè¡{°$2ô†éKr¹î‰p@n‹²«\jU§KùVGRï"‡Ãáp8övx,óc&''gÒÔ©ï-Y\_W‹àÄ«V,Ÿ0qRssÓ¶­[‰hÒäÉåƒïܱã­E‹fxP2™Ü¶uËúuk9î3ãž ùú‹·¥þ \÷ö…˜Gr…C…™ž:¿¯8%(*¤ôxq-½ËP÷ú‡a= s}V•bÍy Pâ™w´Ö4ô2„‚ÕÔ£aU*·•7äü^•Éö‰nȧ"þ_àaW‡Ãápì|ùü‹lÓÇÂÔiÓ—¾óŽ©Â¢¢aà H3öåù/4Ô×—––tÈ!ƒ+‡8éó§½·dñÆ ë?\öAaAáÐáÃ8è3מ  ¡¤o$ôR è±O&x‹±ÔgZ‘)µêËEvB˜³f 0Jš!  €¯YMeé2ƒAý]eŒÞµ7‚c«9؆]ïˆÚ9‡ÃápôÎçN?Ã6ŠŠ‹«kj¶oÛ:~ÂDKÉ ®¬<ø°Ï˜ùùùö™°}ÏG·N@øR¬_mxʪz²€ñrÒ²•· õªä,#Ø.%‚°Õï¡qÖÞÅâÝ€• Á]ÙlRfð2²qÜfÕ &œÃзÃáp8ÙÓÜÔ´£¡ÁËÉ™<µOOÜ‹‘óYEÊ^ß  •­g¤Ê1WsÃfʉÀ = 41«\À°z€/õ`ââ„ ?SÀ¨ëG_bÊ‚þ!c  ]„¿2,D›3aõÕìb‡Ãáp8úÏsO=¹é£ÅÅ%zhiY™ü‰ÂÔiÏF•ZÒX,hI­m*Ô(¬€ZÛIùùÿØSª\@K7dvâ)¦¾# H­O©MeP[<‚“"ÆYUI,Z9„®@\ §†Fí\² öã¸FÊUg°ó:‡ÃápdÍÜO²M€³Îýªmú„ X^Æè*%<….ÕŒ”•u.KDzrq€È˜ÄÁ|a(XIJL’ªdºGD©(ÍÊõ/7J>JåiJÔ´Hõž‘%:‡Ãáp82Æ…½Riòö)ÀSêS¨i’ÒSùg. ÁA8st =ŽsÌ=µÿ1HÉMz„TBñŠ3lµóÆåt8‡Ãápô 5#Ó@9ô¥¡¾jý)@RY¯žT2—¼mËO“)\\ …Ô_Žl&ðx,O±¥„–œ2]לxê-q|+<P™z;,=ÍÝh#yrê¬i³‡Ãáp8ý"4î©g‘‘ò&'¨6rLº ‚píËx*øQþl‰Ö˜ Ì«öD€šÆ Hˆ!<±®“¿«‰“§™ìÙmýŽæp8‡ÃáHCz’ž~ €Z6_ê[@­“E)õ¸,c°3°aÄ$@É=Ï® iƒ€£L! x„%„à© šôíòS…›%Ã.n•".Z°ÈhÁit8‡Ãápô]¦Nõ‘¸/ßô4îl´M}Åd”\dh;à'®zR ?Õ~æU²1¶½É1äZBÖPµ*1­YƒbÙT¨˜m õµ¼ÕË´+wc7H¼Ñÿˆôq8ö.Ö®];rŸ‘ÕC†Ø ‡cwR[[·fíÚ‰&|¸b刑ë‡TÙý¥®®nÃG›Æ•—WØiÇž‡%ä|;)A¥‚äd"ðS‹FðFJ€ä8|Øos(⻵|Òˆ9ŽíV60ªÃq!`^'˨wµÑÚ ûHxB(`8‹²Éi‘>Ç^Jk[›¬ÇÇOuuU[[€ö¶ö¬ªªª:Ú;;::í‡cÏD)HYZ‘©µÔ_m§èÉBn Þöˆ#Añ+EÒO‚ä+e¼´QÁã:™•ûLM¸Î1ÑLµæ³Æd ÛlcØâp8GÆcÂÜ@±;b:»­¢Ôåü Qm°l…ÒŸZ}‘õ¯®ÌŒ¶ö Ç\ ¼–®·Ôžÿž"¬‚Sý¹R+ íM8)N°jÌ–s‹A ¨by"²GÆt8‡Ãápd„^è”5•þP­Çôï0K¡b, Ê¤º‹ûý¸µ‰ä? ÖˆÉÇ’”ˆH®´ÆY €”ŸÒXL#Xå®A Ë»$W*Ð-Ѫ:TbØâp8GŸˆûZ̆ÝÓáØ}¬ÿN±r«Y"½Ë;B©Rê‡0óý…þè‚Ë!¢„àÑW~&—Üx{–…7tÓ|´©¦J‰JT¹é¯¿e¥ú»æ]_‡Ãápô ?Ôo:žÃ±»‘£©¤<•û,Õ” xPïÒGnA=Ó•“I®„ó–Ðf¾›JçaÁ¸ó>¸Hª~ž|D Á{»%õè±¶™õW@0/oùûÎQÔ»‘v‡Ãáp8úNÌ·)ÐÔ´«££#iP5¤ª¨¸¸´´Ôvµ‰épì±h9å V–XêG_¯'ÄÌØÂPk¬t¤ ÕîAÕf"þ§ ¿Œ"ý<ĵ‘Ú6Eª¾‘ H)á—BDit$§š>j[þe£‚GLµàkWÓhaeq|¸üªoÏ{êÛº§rá%W<÷Â|Ûêp8öBR©TKs󮯯†úúíÛ¶mÞ´iÃúõ;wî|ú©'wíÚe{;ö<þvÛí|°Ì¶¦åλî~÷Ý÷lkô£¬= ”€0„œÇ”e%Ol µ+à<ïBê<Ö{¾ê³ˆHă¬ü±ÕK ¨—Ö±ØWëBùäftÁŒÌE¤6ô'ÕQ¾%(|ÃY‡ÃáÈ¡MÂØ®€€hmm}äá‡vìØa{›Øù{ý¦ŸTÂJªq¥Å yüדZ}ê—ü_kÈœ‰%_D’ +}‚/(U™n­+ŽÁJÛã÷wò‰×üâ—W^viqq[6mÞòî{K¯¸ôâ ã¿˜/œ~êå—^ÜÖÖvËmwüøg?¿ûö[ÊËËm'‡ÃñÉ!Ý÷GQQQYYYgggggg2™\»fMgggGGG[[Û´iÓ ì ’t1Ž=5)9eüsZè=) IË´¦–BO”e¤ª•IÒD‘ƒ±1 _ ‚ “ ÊQV™_Íkg âé rÏßÀn¤oF“²À Þð¶3ÊFZfµÙžáè9³ž3{íºu=ö„æÈŽC>¨¬¬ì¹ç_8ý´Ï³å‰'Ÿš:uʸqc466þé/7/^¼D‡|àå—\TRRÈüûÙç~ÿ?®>ð€Yêêë¿töy=ô`qqÑ…—\1kÿ™+V®\µzMMuÕ÷þãê¥ïð÷‡nkkŸ3ûÈ«¿y%ŸNííí·Þvç« ¶¶¶í;cú7¯¸¬¦¦Ú*BSXXxñ_ô±'>X¶ü³ÿvØ~zÍ‹Þ$¢šêê“N<î+g}™ˆ~ñËÿZ¹jõo¯ûÃo¯ûÃÔ)“o¸þ>úhÓÕßýÁÊ•«W¾êòK:ð;´ÃáØÃˆ bãG}´iÓ¦žžžîîîžžžòòòžžž®®®®®.7 `ϧ¾¡þî{î­­­­¨¨˜;÷Ø‘#F¸ó®»gî·ßÌ™û=úØãÛ¶m›÷ä“óž|røðáæø+€¶¶¶ç_xaýú 7öØcŽ4h€d2¹`Á+«V¯îèèœ:uò1G››«suuu=öøã©žÔi§š›››ìêZðò‚•«VuvvŽ9òøãæò |»íö ãÇoÚ¼yÛ¶m'žpÂÔ©St„ó¹¨Aüáë¾0B¡µ^xÒz›èdÞ0Ó̼$—0 ¾ÝÌ•ôÜ€pñŒeíBWŒ,*­²t"C=½,yîï*ÿ¸º9ö@ˆèäO˜÷ÔÓ¬Y»»»Ÿ}öù‹.ü:§þü?=hР¿Þø§žTê¿~ûû_ýæº_ÿçÏùÓòêk ¯ùÙ÷9â¾ñ»ßÿÑœ9GÝzÓŸw55ë;ß]pÀ¬£Ž<À¯ûûd2ù‡ë~SVZzçÝ÷þì翸ñ†ë3<…~õ‹C¾ÁŽ IDATk¤R©5k×]ûŸ¿6tØ1GÏþé°yËknÀ³Ï¿pÍO4v̘ÿñð¯~sÝ?¸'Ã"ÇÈÌ™3ÇŽÛÞÞÞÞÞÞÑÑa';öl–,yçŒÓO:´fñ’%>ø÷‹/¾¨Ð?õóŸÛ¹sgÜÜ€G},7‘øú×ÎO¥Ä¼yóü‰/~ñL?ñD{{ÇÏ<³¤¤øÃåË7lÜ8aüxÎÒÚÚúàßÿ1lذãæËŸüO<1¯»»û+gŸUPPðêk¯ý㡇ÏÿêyœôîÒ÷Î8í´áÇï%ßÖi†î`+LctÆB™Š:4 F|ôlÚlÔvkׇg#È ž9ÈJ¬a팞 ÃÛ*Iå ¶8öpN:Ḡ?úpù ¯¼¶°»§{ÎQGغuÛ»ï-ýæ•—UVVVWU]yù¥‹ÞügÃŽvþxÎ8ýó“&N(((8îØcÚ;:x˜väˆáì¿ÿÊÕkÔÕ׿úÚÂï^ýÍaC‡^|á76oÙºný;¢­­í¯·Þ^0hÐ4ãç¯çy'Œ?ý´Ï-|ý Ã7ÀN?mÊäÉùùù§~þ”ÆÆÆ††>´Âáp|ü¤*}ýõ×çÍ›÷ÜsÏ-X°à7ÞX¸páÛo¿½aCìG“>¦ãccÖ¬ýGÚ'//ï°C-..^¹r¥íCã®]7n<ÅÅÅ¥¥%sç»fíÚ–ÖÖ¦¦¦U«VŸ|ÒIC†Tæççï?s¦¬õ õwÝ}Ï”)“?n.ë“æææ•+Wžtâ eeeyyysfÏnll¬¯¯gÿ8`Ĉ{¦’ák&,ä€ì‘¡ñL¤¿X– „G‚X¥’ g¦ˆA_a‰_£,VŒ¼CéîÁJ>!Ý ®ê-GŒ‰xz«öÑþvÂÜtp{•••‡zðóžš:eòóžš{ì1ùùùjëêrrr†ÖÔ°ÛˆáÃÔÕÕUlfOCYYoäåååççóÞMvvضm€/žu®ÊÛ·o7vŒið‡ýÇÃ4hì˜Ñ¿øùÏ**ʼ¼à•{ïÿ¿6mæ–Ó§Y¹4åå²&ùyy:“d‡Ã±Ç!ø›(l0{öì–––ööö¶¶6þÛÖÖÖÑÑÑÞÞ.¿Ë£‰³;>VÊËü»ÊËË›››Ät475yž§¿Y***ØØÝÝCäñ÷‚Å{ï--((8à>Xã®]þtß}'`×®¦ªª*¬òû¯$|›‚L©P)ÃŒj¡œ†– =J9›VÏ·óŒ[Dž?KD ÓB]Ž·Ë"!…jíÊ6’ùðeÒu$Ggm¤Q×VmE:;öL>wòI×üâW§ú¹wÞ}ïŠË.acuUUOOOmm]uu€Í[¶àwµI~^~2™äíÆÆÆ`b/ÔT×ÑÃÞ×ëÇ߃eZvîlüů~sÍÏ~|À¬ý  zèáGç¿ô2'‘ºÐápüöÎ<@ŠêÚÿßs«fffXEYQDÅgL **‚hDcL4(.Ñg4‰OŸþÈ3š£11F_4ŠF"**(î(** `–Y{¦»Îïsï­êêža|3ñ~lzªÎ=w©Æa¾sêÜSÿ–¼òÊ+_|ñE*•J¥RAÈAAAA·nÝ⮎öG´’nMMÍàÁƒ"@ëú¡s—.AlÛ¶M~dlÙ²ES)æ`Ë–šLÙzôw¾³ö³Ïzèá)“O—¸Iq—.Dê’‹geÝ«—õ^x;3vŽ! Lâ'NzL;u†v´g}Hqq—ëþßÿ0tÿþûî#Æ^½z8bø­·ß±ióæªêêÛï¸ó°CGgY ðô³‹êêê++«îþó½±Ö¶)++=òˆ17ýææòòu‰DâãW_{Ýì–––¸_6Í fîTT”ãû~øÑ#ͳMݺv]»öóT*qw8ÿ> >|̘1£G9rä0xðà}÷Ý·{÷îq?G»dÙ{ï}ùå—ÍÍÍK–,­­­2dHÌ¡S§¢ªêê ˆo0*).Þ{ï½.z®®¾~Û¶ÚE‹ž0`@§¢¢.]º 4hÁ‚›6mJ$ï¿¿üÓ5k¤‹Rêä‰JKKüûC ºté2xÐÀ§<½yóæ––– =6¯þ¼;Q⊵5ÄÙŒ69¡ñWÒS ˆÔÓƒh «Ÿ–Ú-ëºt/?œK/zÑxé¯ZöÊ‘mM; 민˜¢ƒiéÍRÒ52Žv=0íé§Žvtâ ùëýçüନýÚ«þ‡»îž6ãB:ú gN¶ Ó§wãonž|æÙ½{õœ4qÂ;ËÞ{´ÉÏ®ºâþ¿=xÕÕ×lÙRÓß}ΚzFt³gôìÑcÆ´ófßpcmmÝÁƒŽúÖ‘«V}(MS§œ>çæ[ç=>ÈàAR7Àápt,˜u@†¬[·®¢¢B $“I9ð}¿¨¨ÈþˆÍ¤³ãëæà‘#_zù•ªªª’’’É“OnÀ?üð§Ÿ~æwÞéÙ³g¬nÀ)“N~îùÅù˽ú÷ïì1cÅ>qÂI/½ôòÃsiniºß~cÇ~×v!¢O8þùÅ/üíÏœzFçÎ'L8éµ×^ŸûÈ£õ õ¥ÝK3ÆólE¦öK›ÿÿjg¾EÒ¾ &55K)U}"«5GˆO(I æ=´Ê´ˆÈ~³Ñ>§ègf𱵂´˜ mÚ©%Ô²Zy3&´›>&"f) KÑŽ@$qHoJ;’ºùÈ#Æ(¥6TTöê©Ó"Û ¼|]ß¾}âVàƒ+Ÿ{eæŒé™QýºúúÌ(`{àö»þov´?Þ_¾ü[ÿqDÜêp8ö<¯¾þÆÈ|õµ×Ç~X¼ ‚`cuU}}½ä°f2ó‚ 3:o¾µdà€þ½zõŠ78v‰©?š ªb}¢±áâ™ÓâÍŽkÖ¬Í*o²òù¿¾ø²¼ü…SÒ¤•Òt ±zRØÌݤ / f¬YQõɤ÷ »±œ‰™®‰õ)AëCÖzØ'Ñ)n髉=ìÊ’æFÒhåA _§°(žOAD¢nC‡Ý͈áÃF ·:‡ãyžŸŸ_ЩSçD"ÑÒÒÒlPž’-¤G‡'SN!ƒB_£+MC†¸ !2 ‘.ññ–±Dõ‘•œ²-gM-CA1X¤²‚錴g·JÊhöK""X<ìåëfÈB"MQý€­ƒ^Úee#ó£v8‡cÇiíQQ§¢¢Nqk„Ö::AjMƒIV@˜«º½ï³A Gƒ0sè uÄ•ÀP †$’F}åaUDßÌjÖˆ.L[}æ¥Ddxl¿Æ´lºz} Q´†Íèëd«Ãáp8v=!;÷ĘÇ‚(›è$lŒ%£HG±g¶FÙn«¼d.뜞JöÍžZ‰ À7'Ñ û!¢E‡G-Q£™ž=ŠGFT`€Ø(T6¥~P4«vjÕáp8_Ì×_=1¦Ã±G  1e’Tõ-xQ=ˆL$Qaœ¡5cÄnG,’Oo¨IË? ú-dd±Üì×[¸L3L¤|¥”™)¶ÖøÂQÐÖï•d·{‘L«SµN—¯kq«3#ô²œHu8ÇÂÝâw|£Éò  Õj(ºÒ=$7@þ°¨É4Ùf2qeéoÕ¦ýJ&A"#ãkÁJ|È“µDDêÖVµcvÍh3}… 3O#¹V}Â"Rͳ¸(}¢Œ‡Ãáp8»­ÕZƒ êМ"ßvR¥‘ Dàìè‘@®èP2‹JSƒ¢š¡|={†GíhLéuº´Ñ†Tõ±é}LÝ'œZ›Ó³üVàp8ÇN²'~˜ì‰1Ž=D¦¨c}3¼-(S¹!»ÐŽŸ¶û*:oæ"²AQÚ ‘9¬X¢ïÑd¹„ì#džÆ¦ŠM¤”’ƒÌ%9…‚ªªê¸Õápìa*ªª ääUUWóºº  ßý`rttÐÏ)Íq’šUôcQw䩤¢Ù4rwÑȀʈQ’â¯ÒÀ‘ú¬;I֎Ƙ¥É’Ñ1nˆÇ›ŽŽÆÀ?]³võ§ŸÆÇž¤¨°pàÀðéšÏÖ®ý,äç÷íÛ'?ßUoutT$4Z«rJd•lv‡í¡{É^ÿ´–²ÄUã03ˆÈ7Ï-P˜ôS©DXËÃÌŠMìSNM_Hô7À’‚[ÖÈiµ»tgÈepxkÍ´ï•UUqÓSTT79»„RjÈàAq«Ãáøº(..馧ÌÐw± +!tò#)­[¯Ø.ÃÂŒˆJÂBZöª£Ç!áÕ…× I‡½jô]¬G;aíÚµ}÷î[Ö½{¼ÁápìIªªª×¬];x»Ëáø¦c)f%œ¹»I¢v+Æ´ê m•?ñGaÅÈœ/JDöÉ‚u8ìE‚>Óé°i¶t"ÑVM¦gÛ­i@$Š•ˆ¨Í©ŽŽE}Cƒ¬Ç×OYYiCCCÜêp8¬j•ƒ¬Ú²5{V«Ù¦·*Z!g$]XV5N˰päÙ­X9bM–ƒ¬É³K1šLKÛ‘É…°&½ôÊáp8‡ÃÑ:„0x=ÂhfkÑÐLm?`e¦ðk½ù à,ƒÛ…dÔ 0Y¨1D!:kµ„+‹ ;¶'ivy“°5éê²™n‡Ãáp8ޝ E›ÑccjEn"¹[nr¬Œ‹O!„ªÏÈÖ,ˆ2⬙«‹ŠLif´¦M£ñ7‰e$³{V¬Ãv=‡Ãáp8™dQdß´0ƒ)%Gmïνô³âPÇEŒ‚%óS»º²:؉Ó4+Åòee:¤’íÊÛ¯iªW>‘®ñÁÓ­›4´ñQ9‡Ãáp8vÊ¢·´È2¢+t‹4¶ŠÑ¢?Xk=€[)»‘u'"0˜l>k¨õ–}jG“ÒªYÕ*Œ½ÙJö˜(]|Ša—Y_$µUŽ·sa‡Ãáp8Ží£ï{‡›”ìž‘aib/½©U¢ÂO‹F#Û( 1hZ­“ezEjÊtˆ%sÌÝ=Ú‹ˆ`žò•f×oö%çñÙ3àp8‡Ã±³,xü±O>ú0nMç‰Çæ~öéê¸õc²™È 3€@ Ó"­*4ÝŸA¬ƒŽéjÆG¬!>!ÚLDZWÉ›‘Ïš¡_™uùW«MÓ«\‰Ñºë9““x[ì‚ãçiDz¥78‡Ãáp8v"2RÍ¢ÍZ52Dm¦I[QmჶäTÿÑÞD Yª#–ic…ûï#_D…@ò’M^ÚÉ ÇÙÞ%óUNu'ùbŒöó€œÆäXÏ!gPyÆ€€È49:Wýâš±ãÆ?õô³Ö²ö³ÏÇŽ?þäïE¼v3g]òÌÂEq+³†¥o¿c-3g]2÷‘D\‡ÃáØi*7¬îé'ÿþ×{}àþ·^{¹¥¹9îÑq™EÀa`ˆH)+ÒÒôZrcÝÜÀ@`“¹†°Œ¥´¿˜-' ?rk>8óy1D»"ÝÇËe!ZcVCæôu3$§Á˜âã|6VW­X¾|}yyK²¥S§ÎCößø#3—êØe è?ÿ‰§N:ñx9ÿäSô_¿~Cº×ž¥K—.üÓ=‡Œ:X)÷ÛŽÃáp8vËß}gøw?¦¬¡¾î¥ç-yýÕ#wêDU—Q€i*nÇ!û±É9Qyi<£ÄTm*Üæ·áÍ6$Û ½ŒX6f1@°ìÞ ·¡éõ›§Í‚ôô¤¥3¤¤“"Òµ@2ÿîã¥K>â?Ž:j[ÍÖg<¹ôÍ7‚Tjä¨Câ~Ž]eÌa‡>·ø…>þxÿýökll\ü‹?>÷‡üÓ_¤µ¦¦æ÷wÞ½lÙ» :ìÐCf͜޹sgSÎúÁUW\~ȨƒToÜxÆYçÌì‘NŠÎŸyÑc[±rÕêÕŸtíÖõ’YŒ>dÔìÿ¹qõ'ŸþzÎ-¿žsËÐý÷»ã¶[¢ p¸c_zåÕ§Ÿ]d¥³å×\÷æ[Kˆ¨GYÙøÇ}ÿÌ©òÿùù3/:ø ‘¯^ýɧkz”•^yÅå¬Xùècó¿{ô·/¿ôbqkll¼çÞû_}ýõúú†Ç]zÑ…=z”Ŧp8G{ãÑï?ò;c{õé  ¡®îÑ¿ÿïÔsÎËÍ˳©dòåÅ‹‚€>æ8/'磬Zñ~Scc×qd×?Qœ‹s»Þè‡+>°ÝÛ9"¸ìq:¡ˆ#ŽJÔšUc̓ Œb°N -ä²}Š;iÖ=X¥u¢Q‹"‘,B7y#@JeE€xM7xÚ¶¹ PD>‘–Sé¨ô1ÉÐz)i“ÒÝUŽ?aï~ûäææu/+ëÓwoÿúüó¸“ã+ ”š0þÄÇç?`Ñs‹G ^Vªºëù«úúú?Ýõû»î¸µªªú†›æ„=[aásÏOŸvî?æ>8îØcn¸i3_sõφ tå—-^¸ S°ÈÍÍvîî½ïþÆÆÆXÓ ³¯[¼pÁ¢§Ÿ¸þ¿ÿëÙ…Ï/~á%Ûôêk¯Ïº`Æ?~`èÐýzÕ/¾,/¿ç¸ëŽÛÞxó­—_yU|~õëß–¯[wËœ›~à¾~{÷½öúÙmìˆt8G‡ ±¡á™'/(,;î/'gÛÖš·ßzý¨ï{Æ9çŽ>üˆÏÖ|ïTnXßµ[·¸µ]b¥˜=¶+b³Çñƒ‰¼ÊóZ@Wc%‘vÛïȲ{¤n€Öš²&ˆd.®‰AKIbRº ‘ÉXPL+ðŤ <&I)‚>&"x’'aô;IÂ*±vV\"bã_þW†ƒ`ó¦Mò"¿f9v ÆŸðêëoÔÖÖÎjÁ¤‰¬}ÆŠ÷—péÅvëÖ­¬´ôâY¼µdé¦Í›#]³pÚ©§ì¿ß~yyy“NžPSS³iÓvü…±ßýNYiÙCs7”Rƒ <õ”‰¯¿ñ¦5~ïÔ“‡ TPP0îØc›š$Ü·OïQ´úÓ5ª7n|õµ×zù¥½zö,,,œqþ×­ßðÙçÿ Çu8GG£fË–§çÏÛ§ÿ€1ßú6)@)¥”—““ãy~÷²‡~D¬ËG+?¨Ü°at†½}"Š %êͨ¾4´Œ|¤ðZ€”…Ò/¢p 7݉LhÒŸ@PhÔv@g¾‚Á#}Y‘¸šÕù&jKúF<Ùk?{ }l–¯ ¤si‰RæT"±r&]D$@e§Õ³èûAÏÝÆ’·ÞÜZ³E)uðèÑñ6ÇW£¤¤äðCGÿöw·555:zÔ›K–нªºÚó¼ž=zÈiŸÞ½TWWwëÚÕöͤ¤¤Xòrs$šiÍ­@D̘våÏÿkâIã£ö—^~åÁ‡æ~Y¾®©© Àðaئâb=Qnnn^^^~~¾=mN$TTT˜|æL¨¬¬ÐߨÅáp8ˆO>þ(??ÿ†[K§Î]¾=öØ·ßz#ÑÔ´W·nC‡¸W$¤úÑÊ–/{ç¸ñ:uÑ?5Ú9¢±B)fT_¢Ôê¾é‚ÌÊ?@ëH€õLdæÖ›—"¢GiÙY Së*\Tº»Ž"Àf,ˆ9©J"@‰¼$0ô£@6b}1º”–¤ €d»Z©.ƒj?¿•ö«°lé’•Ëß÷|ì±ãÊzôŒ7;¾2“N>éÒ˯œyþ£ÿ–•–¦R©ªªê²²RëÖoPZZ /7¯ÙlÀ¬©©±]ZC~n›Çvèè{î½ÏZ¶l©™}ÃM×]{õ¨ƒ*ÈÏlÞã‹_|)Òc;ô(ëADóù{—.]âm‡ÃáhÇxžŸJ&帩)-mìÃ__þå¢OsÂI6õï>ûöÝg_0¶æ“gžøç”³èù>€Þ[öÑÊŽŸprñ^mE[Ú)QA•E\Ù#™æHÌ‘a5_kÄ l;%¬m•Ùà-‘ÜF=µ´Ô»TˆÈÈŽ_£âfßÃ)Ú¼ˆ"z—LH•L«h`hu»›x÷·ß[öŽçûÇpâÞûìovìF ¾xá‚)“O‹{õêyàˆá·Þ~Ǧ͛«ª«o¿ãÎÃ-AÖA<ý좺ºúÊʪ»ÿ|o´WVºuíºvíç©T*ÞÎôiç.~ñ¥ •ršhN0s§¢¢ßÿðÃyl^ºûv(++=òˆ17ýææòòu‰DâãW_{Ýì–––¸ŸÃáp8Ú]»uÿtõG͉D}mí;K¬0J©£¾{lI×®Ï>õxSc#€ ååï.}«vÛÖ ‚€S©¤Ü~wé[«?\u„IR°†+z¾ˆHÈ&HÖ¨ˆ´L2GDÁE‰êâ/2#[qœíÀ‡J¼$¦K †m$s O­ WÚÈH—•™…XÒ¦2Çr ‡#01X‘§]U[Ïv÷—-{÷í¥žç{ü ½ûô7;ö0×^ýó?Üu÷´èÐч\8sºØ§O;ïÆßÜ<ù̳{÷ê9iâ„w–½›Þ/ÎÔ)§Ï¹ùÖyÏ2xPÖmXBŸÞ½OžxÒ?û§œöìÑcÆ´ófßpcmmÝÁƒŽúÖ‘«Vmç)1~vÕ÷ÿíÁ«®¾fË–šþûîsÖÔ3rrrâN‡Ãáhgrؘ×^Züèƒ÷wêÜe¿†oXWžÖLtÄQG¿ýÆkÏ<ñÏqã'öèÕkó¦êçž~ª¡¡¾KqñwŽççä$[Z>xo€ysÿ.<Ïûþyú§X{F䘕R$j’´”Œg ®hÈ0}˜˜=„™µ åh„«`Ucó¸WØwC8# žú†2px³"2ÄEÖD6ü)—*ÿ@Š ‚S°‚Ò2>›á 01[} ]ýÊ @LèWóÓ#£”ÚPQÙ«§Nˆlƒòòu»•Æ­À}¾;œËËÏÿþÏZ4Ô×çÅŒíÌ}xȰ‘ õ õÏ} Þìh¼¿|ù·þ£cäé;ÿf¼úú#<0nu´?¦þh:€ªŠõ‰Æ†Ó¦œoþ¦Ò»kç¸ X³fmß¾}âÖVøü__|Y^þ­çÏ¡V4kÔDæ,„µš„Ñ„™r3ŽN52T1I5ÄÉÜ@g’Y Ù–!SûðLz±FM†RË{e¦#’çÖ^,ñU¥Ì¹@ð´§Ö¢f ¤d í*bXûHj«v# v?œÖ~%r8‡ÃáØd‘RYLQÂæPŵ‰8éûr’^XÀ`·«€ ø‰0Œô$£ÅI'ÔŠQO"R§`‰¶‘U¢$ƒ¤].H47‡Û¹D¨Â„V `Û“µ »‡Ãáp8Çn *­D—ÅÄV¨áôsL#çæ kGAËǘ5‹¸eŠò_6>”ù‡vŒ¦ŠòtU+,C&€‰lu+­SIÏIds)¹É˜J“DެÇQD,‘]2%Z³~‡Ãáp8޶0Ò-«…äf>ÙÜÖP®eÅ(¾t‡Œ)â†Ø9‘. eµ-±Õ˜ÚH‘^øDb!èìÒ(Š-%¥ ­R{É lf#™ýXfp;: ˆaƒ²ÐÝ"2¢ +ŸZk²Ûáp8‡ÃÑ‘¨dVD|"žú¸•¸gÓva@”]zo‚j¶*’µ0„ÏL$ e}õm}+RH+# W&>V×*›ï LLä$Y6Ú=2‘ $Cô;ˆÂê6Óäp8‡ÃáØdWRäþ~(«Œ&c^¤´¨©ß”†è6Ý'jM'²çJ£•ƒŒ„E˜ý©¢«‹Žh´ O¤}¬#ANôúæ½¾†°ZÊ*éç °Þ‹Ez,EF³šnæÈè—]#I¬•” þF®Âáp8‡Ã±S´¥¤¬êk…˜þlÕ/D”\kŽ ic*±ˆw\ë>y>D9Š’Ùkõ+‘n VIF5[ûUZÚ³RJiÝ™†Jj‘\ ] ÖèY±-¡•1ŒÃáp8‡c'ÈTe+àL© ­ÙÐjY[#R€ ºÙ «‘~Ñf àKY,X (ó$Ò•ª ÍzR&±‰,¶ïÎ IDAT1‹Uv“Y@ù*þ`[»JÆÕ_d@(‰­Ê¹˜Â“Ö„·ÃÑÞ),,°«u8_UU……q«Ãñ $KÁ)sÇ=jɦµâ^;E(X)*7£cF´ævðå‹,\þ0´æ4cÚ«Ò_¤†€8Ä´¥>%"È0VÚFPÌLra_fâ@PˆŽfŒq‡¯Éáhg 0ðÓ5kWúi¼ÁápìIŠ ·:ß<”‘Ϻ}YED¸+H?b«XÅ.#\Åv*Dà남ZE6ž MY*»^–è©ö–—í¢+hOy#0HIàU\¥‚ô’ $O-ì‘|Ñ1߈–Ý)6VWÇM;LaaaÖçO8;‹RjÈàAq«Ãáp8²á~ø~-PL#Z¥eu u ÅšVyy½7ÏL€"›¶Ê0ÊOt^Ú}üð ²$k¶SéZWó9MD€ |JzÁ¨Y"Ò¢PXV’Éjý!LD ÄDFÐF(@ŠßÕ• Ù¸1f#ÖÎ3°ßŽ>Ü,“ºúú¸Éáp8‡£bÔš=Z´B¤¨j4¦ëŠÈÕø ¹Ll•ˆ`jX×´¥„'iSǖ¦>«i‰$B˜d]Is ,AP$qT$µcšQ´æ ó -í Îâ¨GÒK‰tæpi‡Ãáp8Žƒˆ$hã†òì£, Ä6Z¨ûHsk¤%ÈÀJw4]€§qZÞ*Aë¿€õBì´Ö-67AÇYÓÔ7‘,]jMäR)¬Ò¥IËM‘«fuDI‰ ˆˆ "[°´ªÕcæ2˜"R¬dºª€Ãáp8‡cçѲË`„"‘Ö¯Òõ‰+/q5Ç:yÓ¶˜ó´Yh…qR¤D¤êÎâÂ’Y¢@ òíâGú@® RÄà´‰ˆˆˆ!WH¶‰™zªÄ "ø,ù°DD R`ÒyzBZM+=‘ÇAéB±‚JWô‡Ãáp8Ž"SBQ¨ ‰)P£(]GJÄôö'A4a‘ÎH%+þhµhœµd&9ƒHRMM»ügêXÈ,ÅMæ …©õéüPqt5 "RÊGÀ̬³ÈhfôEëÍZD p yÄ‘VÆsö‚a‡Ãáp8Ž6ˆj8c mÑã ¤Éê±ìžvw=B)Q„¦Q—F•F#"£×F| °3@LøD¾8o "‘·ŠDòFWH ç%}gŸ ò¬È" @Šyæî¿"E27+‚gj1ª/`"8 À‘IÀP~zÃáp8‡cGȼYMؤhr+Z؉&•`«ˆ¼˜&c˜&{ÂÌ€GŠIYµv%ÒÑV†D5å@d¥V¼¬K¾ Á$K3ÿé PÚ–)23ŠhÕˆ`Õ$ÆRrqIÑD ˜Y)ò¤°ç)å“R `‚ÒŸ‘<‡–d¹@ÀAdIGÇ£¹¹yî£UUm¿øZ÷nݦL9-?//Þàp8Ç.’¦'Ešðª¨> ¢hñ¥[Lí©ùªÖ;¨Zt`2 ÈvQ ¥*®ÏèI¬]|˜øä)°Þl%K&<:•ô£ˆYÆ •)Cf&Ež_U¤@P±{“bX?¹y9¹¹~®ïåzJyäù¾çùž"¥àyfÙÌU_רÔÔÌ (ùÐëh®Çƒ”"Eä3X¡EQ‹"‚œ´e:Œ¬–††§Y‡Ã±ÑÂ+ÙìbÓr`3@ö=ñ$©@Ì,ÚT J)éÁŒ´u]ã„‹•‰Áä20X ÿDÜùX"ö)ÅàÀSç‘ïS^ŽWŸST×¹s^ç"åy©ææ ‘Hn­Å¶ú†Úm©¬‚@JxJå*•b@I©"0+ é21Ê# RÄyŠÈ#¬ÈiVÇ7«~qÍÒ·ßùÏË.µÁµŸ}>mÆ…ùùù æ?–îû•˜9ë’S&M½{O=cò±c¿wÚ­¬X¹êþ¿=¸jÕ‡ÉTjŸ~ýNÿÞ)Ç;6îôÕøÚþ"Gûç¯÷ÝȨQ#F 7tpˆˆYvEÑv¢±Ðî ÓרO('5vó…DHåTIQ "××Tó(+飔RŠ˜Àx¤<_)ßç\äçy¹9*'×/((ÈÏ÷rsSAjJ$ÖWRí¶æú†D*Å)¦PHJÅj±Í)9$b¥”‚Ñê"Œ­S`j^ydÒy¤°›¨©Ùúúo|ñÅöÞ{ïï|û¨N:ÅŽvÉ€ýç?ñ”•JóŸ|jÀ€þë×oH÷j_œvê¤YÌH$ ž~öW7Í8`@ÿ}÷‰;í&ÞZ²ôÚëyÖÔ)W\vi~~Þ›o-½íŽ;7TTœsöYqׯFGü‹p8ŽL(nBaf%¦Ñ!b‰ÔYŒfÓµ÷‰!à %^5þi‚UlÌöÔÌΈ|<³éŠˆ t‚€(™ã#?Ï+Ê÷ rrós<•£ˆˆ’©77§jëš›šÍ©`ÅL¤|ǬɧÉf0 3ÀAZ½U­WåJˆ`Ü%-7]”eÞ_¾|ÈàÁÇŒýnssóó‹_Xðô3S&Ÿwr8Ú%c;ô¹Å/|ôñÇûï·_ccãâ^üñ¹?üãŸþ"­555¿¿óîeËÞÑa‡2kæôÎ;˜rÖ®ºâòCF  zãÆ3Î:gþctêTtþÌ‹ŽsØŠ•«V¯þ¤k·®—̺`ô!£fÿÏ«?ùô×snùõœ[†î¿ß·Ý]@”¬ÝãN†¼¼¼S&M¼ã®»?ûì3Ѭ÷Ü{ÿ«¯¿^_ß0bø°K/º°G2¿¸æº7ßZBD=ÊÊÆŸ8îûgN•=7mÞüÛ[n[¾üƒÒÒî“Nž3ßzûN:ñøþàûbwÜ1¤è×sn9þ¸c{ô(ÛxrÁ?ç?qÏÝwÊiùºõ?úñôîû‹,,Ê®ýE´v ­}‡cxgÙ²÷ß_~Þ¹?’Ó­[·ÞõÇ?Íœq~qqqssóË/¿òɧŸ65%†Ýcsrrþrï_ X¾n]EEÅÐý÷_¿aÃÏ;WúnÙ²åî?ÝsÁÌé]ºtù˽8pÀ—_–WUUíµ×^Çwlß>}ŸÿDEEÅS <µ`AïÞ½ÏùÁÙví ùW4Š df!Ó9PiZ½FF»é¾dž.%n‘y’`áÈ0QÙ ˆ¿é0мòöÛ«{‰Ÿçµ456VVׯý¢níµ_¬¯«ÜØ´µŽ›sšƒÜÎMRN ^*    Å`È‹˜9“@46ÀÄqJ!å{"3X³Ø#ŽgÝ~¾óí£ ˜——×¹sçáÆUVVÆ=ŽöŠRjÂøŸÿ€EÏ-1|xYY(n®ÿå¯êëëÿt×ïïºãÖªªênšöl……Ï=?}Ú¹ÿ˜ûà¸c¹á¦9Ì|ÍÕ?2xЕW\¶xá‚6«Ù=îaH$ÿ|ü "2dˆX~õëß–¯[wËœ›~à¾~{÷½öúÙÒý†Ù×-^¸`ÑÓO\ÿßÿõìÂç¿ð’øÿ¿_Þ˜››ó·ûîùŸÿwݳ Ù‘-_|ñeEeåqÇ5óÝ£‰èíeïÊiÛ >ö˜ïVVU¯X¹JNŸ|jÁèCÎ*wí/¢µKhí£p8»À°Ø´iSUU•œ.ÿ`E¿~{Ë'ž|²¢²ròé§_xÁŒž={þë‹/Äçý–çÛG]ö“K9ö˜mÛ¶•¯['öwß{¯ÿ}ºtÑ%ß}÷½ouÔE³.:tÿGy´¡±qÒÉ{öìyÒøñ?»êÊv+X *ªQIâ”òEŽw’€)+! %¡NÒ9ŸJEŽ"Rvd+CYöù[I*cEנñfÒåùžï©9^*ÏOæç4w-V{÷ÎÔ¿Sÿ}ºîÕµK’yCuÃg_Ö®ùl[ù†º-ÛššÜ’ôRì§Ÿ9Èá”HUx¤<"13ÀÄ,ù¢¾eùŠˆD$“Râ‘<©K@@²G‹Äm÷RW_¿rժĎvÌ„ñ'¼úúµµµóŸZ0iâkß°¡âýå\zñ…ݺu++-½xÖo-YºióæH×,œvê)ûï·_^^Þ¤“'ÔÔÔlÚ´ÿ;Òýó;nü‰O½óî?Ͼ}z¨Þ¸ñÕ×^ÿéå—öêÙ³°°pÆù?^·~ÃgŸÿËöRJ 4ðÔS&¾þƛ֯ßðÁŠ?¹xVIIIïÞ½Îÿñ¹ÖÓR³u+€îÝ»EJ©®]÷ª©©‘Ó¶\PP0îØ±O<¹@KKË3 Ÿ;éÄ¢Qvö/¢µKØîGáp8vŠüüüÁƒ/_þœ®X±âÀGضmÛ'Ÿ|zÒøñÝ»wËËË;häÈAŠÏ!£FõéÓ‡ˆrsr† öî»ïH¥R|°â ‘#ÍÀ8øàƒúõÛ;77wÌá‡wêÔiõêÕ¶©Ýcä`ëÄd+ ‘ˆ!AJ•–“ZÛ—µ›  sHÞCyêÔH"QW±È÷Tà)øŠòòr:ª.EÔ¹°À÷Ñܜؼ%QS˵u-AJ>8'ulb¨zT"Ö£œˆ‡«Â,‰õV¯€º¬þ¼´ø–—ߌ°{X¹jÕÂ…‹t/í~ê¤Iñf‡£SRRrø¡£û»Ûššš=êÍ%KÅ^U]íy^Ï=ä´Oï^ª««»uíjûfRR¢«äåæH4'Òš·ÇŽt—|Öš­[wÛïïûÛƒ‡:Z)UQQ`ò™?ˆzVVVè¿ïK/¿òàCs¿,_×ÔÔ`ø°ToܘŸŸ_RR"ž½{÷ŠvJŠ‹lܸ©´{wk ‚`óæ-¶ãvЍÅápì88â‰'žüîw.//ojjÚoÈ[·n#R{í¥¿£ØH*€Qü×ûî;ö˜±k×~¦”4hm*)û–””ÔÖÖÚÓvÏ©¨˜B‹!:V¶fz›[ÿ¤ÿóäö¹Uw"=Å—Ht &) €Î‚?#2AŠÈïVœSïçç{¾ï+R ©­µ-µõ‰ºúDs ì3|f`óô,¹Ñ/pTKÚÅ33‘Ô¨V"ÈꘉˆÅ) Ò@Jr³úî*Ã8à€¡44Ô¿õÖ’‡ç>òÃs~àû~ÜÉáh¯L:ù¤K/¿ræù?Žþ‹QVZšJ¥ªªªËÊJ¬[¿@ii)€¼Ü¼ææfq³Ç6 µûok”_qÙO¾ÿÃó<óì„ñ'ö(ëADóù{ôG€-[jfßpÓu×^=êàƒ òó›÷øâ_PÚ½{SSSMMh¾ *¢½„~ýöîÑ£lÑsÏÝ?k|þ…ƒ =êàˆc[ì³O¿¡ûï÷ÌÂç^}íõÆ×ö¿ ;õ‘hJd½„Ö> ‡Ã±Ëôßw_ß÷׬YóñêO:T¾‘‹‹»0[¶ÔdÊÖ¨˜éÞ½[ïÞ½?X±bõêOFŒ.[Æ…­[·ÚãšššÁƒa{:¯½À¬c­y úºHo%sÁ&¦¨²*ôO‡šC@ç×Êð¶“4Û¯ª_ŸN]:år*U_×P½qÛç_Ö~¾®±j3×7ç%¹0@nRA*H¦‚TJ©TA Æv3ªAT' «Îm–BD è§!À¸˜ÇÀ*R2Y¬¬þîþ‚EEE‡vè¶mÛ¶ìÀOq‡£ý0bøðÅ L™|ZÔØ«WÏG ¿õö;6mÞ\U]}ûwvèh ²8àégÕÕÕWVVÝýç{£½²Ò­k×µk?O¥v[±¡S§¢3&Ÿö·J&“ee¥G1æ¦ßÜ\^¾.‘H|üñêk¯›ÝÒÒ’hN0s§¢¢ßÿðÃylžôíÝ»×ðaÜúû;k¶nݰ¡âO÷ü5mh]2ë‚'PU]][[»è¹Å·ýþγϚš5'µ5&MœðÐÜGW®úpüöž2°S­]BkEtL‡Ã±SÑðáÃÞ~gÙêÕ«%1@—.] ´`Á‚M›6%‰÷ß_þéš5éý4£>èÍ7—¬[·näab€eï½÷å—_677/Y²´¶¶V²ó;u*ªª®‚ìUKÛ Q±•lZ|dáKt(Š¡ ï‡›n±ÍT­î 67ëB­¾‰ž û˜ÅŠIUm¬ÛPU·®²aCuÓ¦m-õ 4^н ð’R)‚$s K€4™n¦+Ší©èMýéXdjÔ'r ZV|,¢Àó('Gåäe‘ï»3?ùÔ‚ªêêd2µm[ío¼YTTÔu¯½â~GäÚ«^PP0mÆ…3/¼¤´{÷Ÿ_y…اO;oëÖm“Ï<û×ü÷QGþGz§,Lrú’¥oŸ0á”Y—\oûjœ:ib"‘xúÙ…~vÕ{÷Ûûª«¯9uò™·ÝqçñãŽËÉÉé٣njiçÍ¾áÆ“&ö‡?þé¨oiû^{õÏÏ>ç¼_\óßãŽKÛhe9bÌásnºaÅÊUçN›yúÔ³}lÞ¬ ¦ÿèœÛñ­#PŠy`ŸÞ½ãm;Fk­]BÖ¶:Ž]àÀ#¾øâ‹âââ^½ÂT¢‰N*--}xî#wþñŠ}úõ‹ô2d)ôë×/‘=xäÈ—^~å÷wüaÅÊ•“'Ÿ^XPàðÃ_»víœßÞ|ÿÿþ-êÜÎˆŠ«ÈèÂÌ&IW -ka[´4ë1Œ"”ã4E€lÞO—“iБ?¯H*ų,GˆB€ Eb†"f¨HÜ—Mfª]½ÄÏ#J”IžÕeÐë4»©¢Ýå¹]rjÜ ov´KnþÝí—ÿä⸵nþÝígžqzôßYÇ×IKKËéSϾôâ Çýx›ÃáØ3LýÑtUë ÏœoþzI¥R·ßñ‡ã;nèÐý­ñ/÷þõðÃ6쀈ãÿ kÖ¬Í*o²òù¿¾ø²¼üئÇhÙŠH”±FˆªU Á i¨FàyQ7Ä&BK²Õj׸°¦p…ÀOy€"Q¦Ì0Aní›A¡“Û¢ë€Q¨QKôØ(O[¥ ‘t½d¹e\=J)O‘§HÖ†Ý÷LúÐ?nu8ö$Ý»u{÷½÷>è xC+V®,-+Û©½:v#ÌüÏùOæåå~;âu8ß(ÞY¶,Ç÷÷ÛOæû7€X™åvókj]]]CCC¼-ÂÂÂÎ;ÿ;ý[Ù±xæÉÆM‡ã›ÄÿyyܰÖê¨Ä2EÓÖÄ @L×zVÝ1Hd¡)÷„è¾ðÌîzÒwóQta/]( `@éJ¦ PHJT)Â@Btf»ŽhKt•áÆRBÁjÍ ùHˆÄ’ðJD~ŽGžR<ãŸö9ÿ]ÀáèhxžW\\,Ïbq8‡ãkDë*2ª2ìDšÒÌFº(Ë‚{œ®ß²Ã­Œ¡I×@f3˜o#ÅV[o#X"j<2–F«ÌÈ1föäƒ!@ÒxÍÌ "OAyJ)ED¾ïÁÌ„ X‘Y]|^‡Ãáp8ÇŽÓŠ8 UžQ´Ñ³]'S¼…#†â‘¡«S‘L©Ée}§ ?>X:îÉrœænO‰`WÖ¶ÌO†ˆ žŠ=ßó<Ïóìƒh V ‰¿í*d–чÃáp8;Fšµ¢Š"Fk`@«Å&Us»ê1«v›íÌl¦HSºÑœ ˜A ßÔÀÕÊ‘e›˜¼Œ ´›ó™ÂÄ@wqSžNUJ‘"å‘Gä+‚R L'"’}W€b"¦Íüà‡Ãáp8Ûƒ ¡&->3ĉÙ0ŸÖ$[öu¯x³¨¾ð½l¼×=˜dè€H±<ß5º‹ƒHd )Àä¹ùdvYÉ\R&ñUD§¹/O‘kÕMá±NÙ’¥[ˆ [̈£Š0‰´Q–ÞDÇfÅŽG:bÉ¥$ƒ†D%@«ç@Ĉ@Ÿ‘$踧èX]xÐÒÓ >Òlìa«ô--;«”/ùª)è(*3tÔV0Ð}9"fõ¼2 ø«iÕʪª¸i‡)**Š›‡Ãáp8:ŒÜ,ÿ*Œ¢ÒBˆX´Î£˜Žks±Æ¸¯ÏÉH’)‘}Þ€ÄdM)*Q™ ©îop£‚šåˆ<ß“ZÜÊ—ÒU¹A‹]2¯t”¨e[˜2"ŽwQ¸ö(+‹›v˜ºúú¸Éáp8‡££ÁúÆö®Ê©4Œ‚‹†Á€dtj¹7èÄ""ŽTÈ‚’|È l@~*ÙL¤XyJ)"@: KDJ¦ˆ(gÒÂÔ ŠR|O)OyžRJÉeè23ÊŒ(ë!ÈPz}€aå€õˆ"[ú8”æææ¹>VUUoÈ {·nS¦œ–Ÿ—op8‡cW1"k;ˆNK³DÞÓ `$RM”¢•vâQ„£±µ±+X#&äƒæ &"Ò‘QåùDžÍ6°šUÎee¤JŠ(O<ÏÓ!RE€QÖò‡‰Y+p¥e«n•168ܕňl×r8: s׿ÿ¾ß;åäÂÂÂx[:ËÞ{ÿá‡=ûûS=Ï‹·9‡Ã±K숊jM°fAQ.Ìâù¬¢f)01H‚Ùß ý^}&¶•Œ„A* 0dÛs2’AäT2H¶¤’Í©T3§RaÔ AÏS99^NŽççx¾ï)%Š—À,"TòQ ¬$á r- –刄gÓhr€ÚøÜŽöOUUÕÁ#Ü®`0ê ‘›6o®««‹7´Îù3/Zôüâ¸Õáp8ŽV°¡Ãè‹E¿¥7eºMÔ/-v %(. fÅìs (~J”Öw #-YºjX–!˜w3€ž‚´jä $›“ÉD²%‘J6sD$ˆYù¾Ÿ“›“+jÕWžOžG¤´’%‚"VÄJ1<‚Gä)ò)n`bÄô +°2 dÒ"ìSºŽŽÊŽVKCCCÜäØIf]rÙSO?·:Ç7­¬¢@ï·/ `âŒPâã òDÇ¥µJJ¨BBÒ@•"R(,Êß»ïîe{)_A‹>’—–‡éRO,ŠHkLRéÏÁbˆê•i‰ÁÄÌ©Tb"òr¼œŸ<_ÉåÁÞÁ—"ÈÊÐï2GnÔéÈDPD,åcIëT} f‡ãKyùº»ÿü—+W%SɆîÿý3Ï1|xÜiÏpÕ/®Yúö;ÿyÙ¥'x¼XÖ~öù´æçç/˜ÿXºïWd(Iê IDATbæ¬KN™4ñ„qÇÅÌôï¿ïùçýhä#âNî¸í–¸)ƒ6¦s8ŽoQÕ¨5¬FÄašf„‰ÀFç Š&îÜ¥¨ÿ€>[6Ö4Ô6%š›C1 y§*&U¡Õjh1BPßÏ×F,tcbV€S@J¥ˆRÌ-Aª%HµØà+˜™f£2E¾2À:MÀ†yex©­eæ“&&‚RZɘDPRˆ+¸Ç7—Ÿý×µ¼óö‡¸òiß{ð¡Gâ{’úÏâ){:ÿɧ èiÿ:8íÔI‹.xäïÿ;d𠫯½¾¦¦&îáp8ޝ€Q„颋íA®Z`JƒMéH Qwõõ ÿú¼¼ºjS*•$ }ˆHO‰(*<#X?kQºN+ Ûûe~1‘"¥rý{¥Ý»2êà_ýòzÛúå—å—ÿôg&vÎyç¿ýÎ21þâšëÆŽÌñ'õƒsÿöàßí¯Žçϼèž{ï»ìŠ«NštÚâ_jllüýþ8õìNþ@ccãâ^œxÒ‰¶µ¦¦æ—¿úõ÷&Ÿù½)gÝø›ßÖÖÖŠ}ÊY?xgÙ»r\½qãØqãëêêœ?ó¢¿üõþØšgÿÏ«?ùô×sn;nü¬K.3cÇ),,œ1í¼ÆÆÆ•«>BëSGs¾Êt‡Ãñï KH2ý)Z¡¥é."RŒ´$‰QŠî3M,ÂŽHTc]bý¿ª7UmkN´A´¯Ìœ­ü"Z †;³hÁH•"¥È÷UŽïåø¾ïëjX`Ì)fR©TK2™L&“-©dK*™ ‚”\Íxá #=ӖŠàI"ƒù˜ŒHM“°;¢ƒŽcJJŠûöé}ÿÿ>°êÚ››c­ Ÿ{~ú´sÿ1÷ÁqÇsÃMsä{ð†Ù×-^¸`ÑÓO\ÿßÿõìÂç¿ð’õúÙ…ÓÎûÑó{ôw~õëß–¯[wËœ›~à¾~{÷½öúÙ±•¥Ô„ñ'>>ÿ)‹ž[ÿ—õŒ2aü ¯¾þFmmíü§Lš8ÁÚ7l¨xù—^|a·nÝÊJK/žuÁ[K–nÚ®!+m¬¹mþtÏ_ òóºÿŽO½ËÓ9GG'SCQÑX@‹h‘ie½Q¯¿héF¥R)0<òˆÉ'H¢ã¯,XÙÊaÞ)û2¿dµ*%ÅVI§’Ô`Õ!O é?úºLI*b‚‚T*$•Ržçy^ø(,$õ®¤AÖ!#i=!:§^­Ãñͦ{÷n—\t!€†††…Ï-¾nö ¿ýõ¯y €’’bñÉËÍhNxéåW|hî—åëššš v€Ê>"®¢¢Àä3`›TVVè¿oÔ"”””~èèßþ¦¦CGzsÉR±WUW{ž×³G9íÓ»€êêên]»Ú¾™d]sÛücÞãÿ˜÷x~~~ÿ}÷™}ýµ{íUòþòvpê]˜Îáp8¾QX¥%Ê-®tI6Mq$ŠhZ£ô"šdÀ”ee•Klµ/eΑÖ%üÙ@Š<åyúÞ?ÁìŠIU˜k­MD›C&F*PpR1)Ï“º\¤óÉ ¢¸A(Wܘ °°ð”“'<òÇV¬\%š5“-[jfßpÓu×^=êàƒ òó›÷øâ_ ›Í·U²D4ï‘¿wéÒ%lmI'ŸtéåWÎ<ÿÇÑÊJKS©TUUuYY)€uë7(--—›g3vdËÙg7gã´S'ͺ`FÔÒÆÔ;BÛÓ9Ç¿7ÛUXZœ1ë¬Ô¬š¤Ú™” ežÖ¦w¢õctäFD«Œ•ÊÉÉÉÉÉõ}ßÄD³HU‹ ÕÆí¶ƒ\I)˜9‚T*ÙœL¶$›[R--Éd‹DU=žG¾§”Râ'㋪%3l««q8¾Ilܸéêk®[öî{µuuõõõO<µ ¢¢rèþûÅý ‰æ3w**Êñý?üè‘ÇæÅ=ee¥G1æ¦ßÜ\^¾.‘H|üñêk¯›ÝÒÒ÷3Œ>|ñÂS&Ÿ5öêÕóÀÃo½ýŽM›7WUWß~LJ:Z"ƒxúÙEuuõ••UwÿùÞh¯¬tëÚuíÚÏS©T¼¡Ú˜zGØÙ釣#Ò†”"@î€gúAHrSÜÄåf<$… „ô®¶Â6{{ˆH)%Æ¢›|Ï󤨬6‰ %Ë:²Kª]™™¤è¬-iÀ2W"9¯ò!‰†„@qŠ•OÌŠô3  äCƒhV@F8¾WÌáøæÑ½{·‰ÆÿýáGV¯þ$}ûô¾êŠËupÜÏгGÓΛ}õµuC:ê[G®ZõaÜ ð³«®¸ÿo^uõ5[¶ÔôßwŸ³¦ž‘““wÚ×^ýó?Üu÷´èÐч\8sºØ§O;ïÆßÜ<ù̳{÷ê9iâ[C 5¦N9}ÎÍ·Î{|þÁƒvp_TkSï»0Ãápü[Á ÑŸBtW”ˆÕP:@g5ZMl«¤„ª“E4²¢ÎN™;ff€ˆtä••¤óY0Ì’i@u… -m—mÚ‰@DÌ,–Ħ8Ŭ×v£Ðy³Šˆ@€$¾*¥$0Ì,Ÿ ±yõ¯œqäc”R**{õÔékmP^¾®oß>qëSW_¿ãÑš¯“Ûïúóa#êêŸû@¼ÙÑ.¹ùw·_þ“‹ãÖV¸ùw·ŸyÆé½zõŠ78Ç¿)S4@UÅúDcÃÅ3§Å›Ö¬Y»ãòæó}ñeyù‰/]omf£ Zƒ‰»ö7Èì  F=ˆšµ+‚–Xw¡4Í*ÏÙb †q€2D †R¦“ÜÈ·³2ëÛû‘ud¶"Auà•VfwW؃äÙ8)!™L&š“‰ææææd2pJ×I2DÉ:•îݺ½ûÞ{qk6V¬\YZV¶Szu8‡£ LU‹”ÕR-æBïxŒÒ ˆ¥&«4Yi KË#¤@LŠ•„!#wÎCÁ‚ £†€ÙåÏÌÌ?Ò$¥¦ ”oåÍ´Et§U±Ö()l,,$ÎQÍjNíà A@D)¦TTŠˆ!W1àpt|¦L9íá¹¾ðâ+ñ† ÊJKÇ}TçÎã ‡ÃápüØ»ù h­É6Ë€RY…"@D|Fé0Ò´béCsºfÕkbÒ«Ú9"7Û¼V¼ÚF¹¤ð"™!¥ÀÉd*@ yJ)åIäØáè°äçå}ÖÔººº†††x[:………;w– t‡Ãáp8v»,¥BY()›Q "³€D `‚]; Ë^/°ùQ"Ê@šfÕ°Ö‘‘õIælT_¶‰ñgHð5ÞDÆ´§0ã‹:˜æ PJ±òHeÆáè0xžW\\\\¬«„:‡ÃÑ‘ °éC«¸ÊQ#è¼Vq?Ž$dhVjs´¯†èÔ,áÕ A,©,E˜R©@’ ‡Ãáp8{“«š"’íúF/Æ3P"b–ˆ,GÆ“.­ Müš‰žŒÈ·:’ˆÒT#E„q†¦l =eó¬­ÑðªNw Bd bµ*K²†£8ŠÚDòò—6V6$ã ‡cORZàÝ0:¯t¯’ ªª«S©ì?_w¥TaA^qq‰Kãqt2%œ¨-$_Z’l»Ö”z,PgSh²¥ ”4¢Rħ9̦'" ²fÁŒÅ>Òu$´RLë»T2Êr7ˆh˜Y)’Ê ‘YZÿ,ŽvÎå/UVª.ªkQ¼ÁápìI6%®~{ëœÃ©¾¡©°°0///4% D[KJöŠ·9"ýFÑ`©ÂP|‰XŒ!Âc¢@î G|ôIºv‹vl‹¨Sd5&Î £\còTìQíh+!R)bˆ!‹Óݳ ÑGÖÀÌŠH>NÛ7ˇæpt*êSª[¡©Ùáp8¾.ò *7mnjJA——›í§ï.’Ÿ—[_W×Ô”ˆ78 Œ#) 2ß)„P€‘-k•¦Üô·Thoýˆ(kMC̦§ÞöK)l%’?²H†Õ©Ù*íi*3”zíú µü€D€FÏý$"3„WÀLDA戃ÃÑa©ˆáp8¾v$'»“=2¨Ãñõê+-É@¢6‰Õgu‘M%V4ÚT?‰JµQkDEžÈEÒ¦†«~ée%hتY?& 0ô $;ø ¤µ©Ù ňl¨23dŒṁi &«7mMÄÍáèˆ8Íêpü_á¾õŽ]‡H„ŸÖ…`&˜˜(ˆ˜‘­@ª½=n’Q­PŒ(Z°¨_yD•y¢6] D å3³Rª•_‰L=„9H«v`»fW•bŸ!C‰Ó²ø8gu8þ¯¿õÜ÷ Ã±Ø"QìÉUÑ2þDôÿÙ{÷½Šúþÿý™9Ïew“ì’d7P!Ü’põk­·‚€¨­TýÕÖZA(-QñRªVª­WÄ ë·_Ñz¡x­—Z‘‚( ×…P $!›;ÙÛsΙ÷ïÏÌ9çyöÙ0 Y2/×Í93sfæöìóÚÏ™™#€ ƒßDs–~¯¸Ýï>Qƒ¬Þ1 ˜„7i¹­ŽIY•œîtïK7¦.éÚß—å)´u «ŽD¦$¦ºc#‘ÈN%|tìŒÏ_c$²;Rè¨Gô¹xÈ£þ+1…!8‘ê1ˆÀ÷L»e²|¡@‡Šˆ@çæKv{ ïÛš,‘ÐÞ“ŠƒcªGU‚©Ô¶HVBÄ‘È3€gDž.ì”ûogԉ쮈—´6_+óÚ7+’[º¢ÒmB½t÷LŠc ¢c Aôí]* =2…wK(þ¨®n•3-Óâï†g"oûË¿~Å)'ŸzÊtf<óˆcž)üÓ‰o?”ýçš¼3#²ÛÇD"O"'èœ*â¿‹0¨™€ز€Ðå÷ @¨•è‘ ¨ÊúFý[O…""FD¬@T@»P˜+Õ@úa¯9!úJªÐ}qe)Ý*%8ÔV ¬’¬Ô_¤USD“Ú‹u•óHdzÀâCd§sÅñͯÊ~üèÎyƒð›-2=(þcÅÿh‘È$ÔQ1.ÄK^—Û¦HL9NDD`t~=/u¤ˆt «ê©hѹVј¨ˆˆ#B1b­I´|a™ðÇûïÚÝw̒ĸÜFŒPE\8p TËCG|nE…^vmõ”§VI# $~Jìμç²öõõ^òŽ·W/ºø]ìÿì¿<ÿ¼jâÓB«Õ:ù´Wu¦ƘŸüðúÎÔýˆ6>°¤¹rÄ}á¾V5ñK/èýöCéõ¤EÊW_ØûÕZj`ÕCï<ª9§!X6¾a‚ûöš7R_Øoƒ{6»o<˜Þµ©Œ^õ¼žù½]ÞÖãˆ3~:Ò™úäyÎ,sæ‚úá¦aeÕ¨ûŚ캇ÓÖïüÊ¡OœÐsýÊô§«ÚìóóÏëùÄ]¯?°~Ì Àë'ø³ÕÙ×V´ôwÄÛo+ wÔÐõš?yØí÷xd7E?TwÆ_;¡ÊHdg¡ÒU‘1ñ¿ÇÚç©,j‚€ åKüaŠ·¶â¸"¹øÄ'"¤hyXÀ+*…"bF`¤"1ÆÔM­n{zz°¢–%ªœ>ÃcéÄE¬XG§`²2V/î†U|NWU tDW}ü•º ¹ì6œ~ê)ïÿÐåœwîŒþUO+]uÛíwœî9íŸêõúÏ~ü}Ý~ÿ‡.ŸÑ7ãí]Ø^d'éÇLNŸ\˜íÅÈY5¹lIs,Ç%¿Íà²%{6¹¿ºyt$áýæ¨ßµÔ‹Ú¾}¦7‘Wþd«ÖqÉ¢æHÊOÞ½ÃÖB?v޽tqÏõ¤Wß7±nÂíÝc~oï䄹ö†ÇvD¤³ýÜ÷í3}‰Ü»9pÝÃéî°‚çôÛ÷/i¹=Zº~IÇÕäÝ'Ëäÿ@‘]ˉƒ €›‡;Àº§—ÿ±žø¿Ú¦M› lgz$2m‘©îˆà]˜äq]¨[™X=P|lÔÓîÁ"^2m°g,ÆJ£Ù¨5jÞ†­×jÖ$@n£è‡J®Ë³Ä¢·Fˆ›Ð_ÚVÄP‡³ |%“ª Rß–85þèÕ$)ß9^Ù¹œpüqýýýÿñ“Ÿ¾úU¯Ô”ë¿ÿƒ… ;ðÀ6mÚôéÏ]uë­K!rÂñǾí­gÏœ9³íxàÌ7¼ño¿èØc–^·îßð§×}ë3fôõÖó—,^tï}÷ýÏýÌ|ÇÛ/ºãλ¾ù­oŽŽýþ‹^xÑ…èêØØØ—®¾æ†o=êÈ#.<ÿ¼yó†:šèÊ¿_ÿýï\÷ï_ºêsº»òÑUoú‹³¿ö•/Ï›7tÖ[Ï?ñ„ãî¸ó®X±ï¾û\ð¶s<âp<ŶºZ»¤ëîäDŸB€óšòÁc{þgsþwgê2¿Ç|dÙØº1`Ù:·l]ù±}Â\û›u‹ù𾦲‰OžÔw˺ìð{ð,󩻯ß|hóï[¶>0·)W¿pÆë~¶u$cÓÊŸRîPÒ›ÈÝó+ï™X;æ8oaã?M¿|ï¸ÖöÐãù5ûoµæ_®ÉžÓoϿчu÷é5Ÿ{~ßY7Œ¬sŸ<©ï7ë²#ö² f˜ÕcîÊåË7åï8ºçàY毎hüÕ{7ço¿ymçâ¯^N,ߘݷÙí?Cô¤®8±÷Ç+Ó?šv«¡Ë5ï¯ËÙ‡5ÍNüv]öÅ{'O  7‘?9¸~â`ÒW“_®É¾tïÄx®ÿu²aå⣛VðÑÛÆÇóî“®í­éÔ¬ÈS¼øèžÝ>VÕÓ“‹j~ìö±ÎÛ§ø`îHž‚+<ðÀý¥žnÚ¼I·³†Hd·ETÇÂo²aë0µ°«¿oEÄ“úõV¨”@ª¯€ÕD]$Ës·ЍaRô0k#Šˆˆ@`ŒII½Qëíëmô6\î²4Ù:惷ú™ÈÊ™öÉ,kÁe½½õÃîsÐs{š è/~RKúSg±Tž–¯‹EÑ)(=ÝWÖ¶L+‹Ñ‘Ý9õ”“¿÷ƒên–e?þñON{Åɺû¿ýðÈÈÈ®üô•Ÿù§µk‡ÿî£W”Gn7üêÆ·{ο}ýk vñ;ßýÈÊ•_úüg¯üÌ'ÿû¦›ÿë—7h™ÿý?¬|ôÑO\ñѯí+Ï~Ö~ïûÀ‡¶ùWòÒ—üþck‡ï¼ënݽþ{ß?îØ%…ƒþûõßÿó?{ãµÿúÕýÞ ßuéû6mÞŒ§Ö» ÷Xg⤲ÕãAìßg®8±÷æµÙ·¥¹Oß4áVº×Ô8´ßÔ$8a0ùõڬ܇ÿ™¾lŸÚWî?ó§ÿbu ýmPd†æ/:²9¿×¼ë×£þ‹­+GÜ»5î×'C=æg«Z¡|Õš?¿||°) ûf¼_méúì±Ñ\‹²_í«ÿ3ñg¿Øú_«³÷Ó3«†Þ6zÿ–üï;íG[þæ¦=ª8—âêðÐ~sH¿¹sƒ¿Å›\C×kþ®£{z­\pãÖ ÿ{dnS.:²©éÙ¾gøûà­£c™Ó“/Ž–¯^Û²ÕÈïÀMkÓÝ>vñÑ='&šrâ`¢{ÓÚ΋ŒâGþsm_ýý \°bŃ7oÒ”›7­Xñà‚ô÷töß"‘iþÔ†ªÿ7ü{Y,|Lªb&Å[[ÛÐc ºT߬|á¹f?ûJt”¨1F ÎI.¦&µf2cfoÿìþ½fΜ ÁØÖ±-ß¼~Ëã·mÑùI_ÐâÊ[];/"tÌ€¼è*¼MÀˆŽT áž×!ä…:+IT¼Öÿži»F&ØÍyÅÉ/èáG–ßs/€_þêÆ,Ï~ÿ÷^`õê5·Ý~Ç…œ7gΜ¡ÁÁ ÞvîÍ¿¾eý† ÇOÍk^ýÊçrpOOÏË_ú’±ñq Óî·ï>Ç,^|ßý^·î†_ÝxñEÎß{ïÞÞÞsÎú‹GW­~ðꬨ===/é‹ÿýúïHÓô‡?þÉ©§xÕpúi¯X¼èèÞÞÞ×ÿñkçιáW7>µ¶H„_Õ¯íLôuèö!ý¶að¶¼ ^rËȺq÷7Gõ\ûÒYWœØ÷¼y‰fͨáYæÖõé¶›¸þá‰å›2×ýcç6å¤yÉ'ï{l,ÍÜ—ï›ßköŸafÕÀºq4:ù«¬y¶a­Ï?¿|ü¸ÁdvƒM9q(ùÄ£oÍG2÷Õ¿öí>»Ï\qb֤߯Ÿ¹{L¯ØTGËoóÚÆ¯§øuÓÚÖÇn½øèžç%ÏRa­ü ”_ú¹2Å=Øåk ¿Á<¸âÁM›7nÚ¼ñÁ.8ð€þþÉ%'šE"»3Þ¢D‚©éÕC õL¨qUí­Ø®¨˜ HhÈ10þ‹ÆPĉqŠÐ±ÖØÄ$‰I¬ISK’ÄX›ÔkõÞfÏÌÞ™ý3fôÍšQoÔs£[GßðøæáM#›¶NlÏ&²ÛGà º&ŽBq±±lù=ëÓÊ hŠé]Õ¾émÉ"F#Æ}ÝkÙ ¶ÒZ­ ý¯ûÈîËœ9sž{âñ×ï ;ôúïýàe/}I£Ñ°vxØZ»÷¼yZlß}æž3{võðmÐß߯õz½Ñh4›Íb·51`Íš5^ûú7†#à±Ç;pÁÕ”©8ãôÓÎyÛ_¾íܳo¾å7Öš“ž{b‘5þüêöððº§ÚVù`'íé9‘H[b"H]yøOmøè }ï½eëý[ÊYVëÇò+ïЛȋ÷©_²¨÷Ý·l½cCvÜœÚÝó±tÒøšöv‡ÇtýC‹>‘óšÀ5/jÔ1Ô”5£À܆¬ë~‚Õš¿ÿðÄ?>oÆUËqÜ`-'~ýX«¸­×ŒæE±5£ùܦÐ_öè8—뚸jù˜æõ˜¿:²÷Â#{>~û(Õ‰òtªÛEJ`nSrâ±Q%Wdæ6¤nÅkFº¬iõ²ýê[Zîú‡&Šzæ5Ý.Îÿn!&_ÛÈâ¦ÇZ»ï9¦ÀßÞ:rÓÚn£™ò³c»ÿ# ÌX°à€î_à ƒ˜5°ýÇF"Óñ·C[L± ÿ/¢†[DE‚ Î§WÝuX-h¨p h`Œ1 !"úšŠ…µµZ-©õ4ëõ¤–$ò4K[iž¦yæè:ÕL PQ¦½(zÑ Y6\ªü€ò›bÊÉb’áÅ_z²Tòa8¬¿„!ðce“IDvGN?õïÿÐß½êŒÓ—Ývûùç½U‡ó<_»vxhhÀ£«V¬ Qo´Z~6·NwØ~æ Í‘oã_gÍšÕ™·ì¿ÿ³vèü“~uãÉ/Y’$E–ª²zõêçtâSlk²6zãw¤¯Í÷é5E⬺̨ɚ‘Âçâªå£c/?aÆ~³õîã#GS^ÿÐø«h>`ïXŸž0”ܼ¶ÕÖ tö§ò-‡ºñë¯ùìµc9‰7üt“Žõ,à±1÷¢ùµ{6v7†jÍ?žÝ·)é¾õ“æÕ~²r"+_‰‚y=åYïÝcn~,…àRÞ~.þê‘X3’ÿbuë/ëùx‘ßÿŽ&_óuc¹ 6ex̘ßk¬sÖÀöî‘Õ£¿|þùžÑck{|ßû³ukJS]¥z";–›k]|“°|ÒP.þ“úoÐß?ðœCŸ`Fߌ'u`$²›F( ¶Uý>"R,Þ 4Áãü? ¿ðDD ŒˆÕ?££YaŒØz­Þ¨Õõf³é Zi:1:‘Ž·²4w™s.ôÑi؆ZêèsE!ðú,€Ía 'Å IDAT [=;’ðŸô{šM‡j·EåáJшh,¶D¤püÈîËñÇÛß?ëý¼üð…‡-8`Mœ?ï£:òŸ>õ™õ6¬þÔg>wÂñÇM²|Ð?øÑlÝ:òØck¯úâÕ¹Ûfhhðù'=÷£ûøÊ•NLLÜ{ï}ï{ÿ‡Ò´»BuåŒÓOû×~ó®»—¿¢ý×]ÿýÛn¿ctlìÚoüÛððº<ÿyO±-v'eü葉ßß·~ÂP­a0·!çÑûÐÖüÞ~ˆ^qÈ5÷Ž~ã±?cÑì„ä솼ïØ‹f'} z-N~V}^¹gSfÀcçÖ~ýXÛ`S@oÙJJ{OØ’½lßzo‚Á¦üù¡=Úýµ£ùMk[}tß>½¦npÈ,{é1}‰Ð‘Ÿ¹säåϪ¿é9=ó{MÝàÙ}æÏi¾`ïÚäšI^ÿÐøØX¸Wò£‡'ŠD§<»qä^¶iñê¹Msãš ’ÆÝ3­IvœKQ3È¡¦¼p~}Å–r<«n°½vëÏê‘üÎ Ù¹‡÷îU—¹ 9gaÏo†ÓõãùÚÑü×kÓ¿:ªo¿>ÓkñûÕL´†Œüûe[z<ÿð 3ûk©/N×#;–»7¤woèÃZáG¢í–Üfô͘Ñ7£3µÂS¨3Ù] ªÁU7 Ð{‡¡QÌ. JFÿ&”h´UDŒ1VŒ¾Àˆ@ ¬5bŒ$¦ÑÓè›Õ7sÖŒ¾}ÍfsÛ²iËæ[F¶Ž´Æ[yšæyF:ý¬rpŽŽ¤uA}Ð_•Q€Ñ~@„p@ù?œ…ˆî”çú]apVTõuø_]7O…ŽJð+'u.²»!"§žrò—ÿùš?}ãªéï»ô’Ï^yÕ[Î9O Çwìyo=»š«œý–7äcíëÿdŸù{Ÿqúi¿½uig‰mò®w¾ýšù¿ï¼ô½7nZpÀþoxÝ×j!Ü.^ðü“>ý¹+/:zß}ö©¦Ÿvê)_ºú+¬xpß}æøò ô÷ã)µE°ýO\Ï4Ï8ÀupÞ/7ýrõDÝâ‡4ß±¸o4ãëÓËnÙ’u~4À7ÏxÙq3>²tëÍk[ßxüjÒŸÁª‘ü·o]¶®uԜںq÷ØX—ÜÅo¦Ê¶O¹úžÑ‹Žîûê‹ÖŒºï=4¾xnM'ýÃm[ßppÏŸ1Ð0=ž_ûÀXêà·Ã­wÞ´åu÷|üy³«FÝϸ¹mtiÙÖ¯™8çðÞÛ×§«F«1þðáñ?=´wÁ,»z$¿ì7on9ß\1váQ3N?`öý›³«ïí8½z6·Üë³/Þ3RiÈ7]­á¢7G•œ÷ËMYúøÙ {?óú Þ:œ^µÜ×sŲÇÿìÐÞ0³iå†Õ_\>QTKò“wl=kaßGOšyéÍ[Ö»©.Îä+Ù۸ø÷Q$²!"á¹:€Fô ¶>úöO³™* ~ÁTèA¥ø Ä¿_J BR_² øƒ"bÄ&6±‰IŒ©™z­a­!™¦Yk¬5>ÞJ[Yžåt™wIFÿܯ¬Õ¢=xþ;ÖÁŸ -Ô=}./"F5Üï~«›ŠßðÙZ! Ä¿…‹ÆhAßF‡°Š”‚[IŠ>rÛŸ=ÿ¤çcV¯ylþÞ~|ä6X¹òÑýöÛ·3u»Ù:229¸;ð©+¿øœ#ŽŒŽ|÷Ú¯ufGž1{Gÿ>ß°aCO³Qõù]xݛΰvͪ‰±Ñ Þú–ÎìH…X±ýzó¿=üÈÊ•§ßp‘×7JñQS5Oè(Mƒ ]~b–.?åOÓD 1êlÁÕŒKZ_…ˆÆVm’ØzR«Õk­µó4OÓ4˲<Í\–çYpJæ$sÐ×UçÊg>ÎZ¤‡ ŰAo ý-6A”®ZÚ¦8BЏ©¹…þ«)Z/:DÂè P›këg$²Ã ùë®o4ê/|Áó;óvúe—sâ¼úÇ—=þ´4ÝNÛ¿ÙÊyãªñêï# ¶ÝÏÝí\"Óÿ3³3~rvF‘ÈNB @è²T êYîAEKüÂU>E‹™ð¼Bˈ¯'LZ‚ˆkLÍ$õ$IlR«%µ„DžçéÄDžfi+MÓŒ9àHRÔ À‘ÎÑ€”â«å“Ý,ŒZ ü¢ð'S¹=}6¤²+ áäÒA§B;A)&~ùß-z5øóC"‘Ï)§¿zÆŒ¾wüÍ_Wg_ípžðŽØ¼ågë;“žV¾}êàHÊO,Ûž›{ü/m^¢Ýí\"Ó Rÿ¿#ÙÑõE";‚¥êyÇ*²}"…ÉRKÑÿ_]P¼±Q·Ú£¨Ñ‰›$µF½Ö¬Õê5™glML´&ZYšÑ9æt9}úO#Ô¥… J£ö}«È2$ô¼8ÿñá÷Ip _úýHï¾ê°váOF;Gxm…¶âµ¢ß4R €ND®K$²ÃùáõßéL|áÊOw&=UÈîãY÷4^õ½µI€ó}4²³(þŠw`dG=*hY[  ѹD @ÔuHk($:ÉÈ+DŒÖkm­^Kêµ$±"Æå®•§Y+M'²<Í\îçTùÆ@Ç\ðºU I„ tXÈè ,©â_&é–΂j›8¥ÕW„ »„ž¡5øþÒév ý7Š6+0aúJ{v$2`q£F"‘]K¼õ"@Õ«=E-«âpjpzÇø¹IŠ ¤jŒú›#ƈ˜ÄÚÄcêZbc ³4ËZYšfYž»P¤°U8—k‡èõ±¸OÛ{Z½}‰ºõG’€Î+k?7]=µóŒ@´JÍ&@ÐBø×è0ÄןFL%’J€ú>Øn¾êëC"Ó—y}ÉÚ‰Q©÷tfD"‘JklÞŒDD¬‘‰‰‰F£ÞYà©211amœ™>h@Óoë?""*Wj`F @kj u)ŒE’Ôêõz­žkBç&&Ò¬•¦i+Ïsæ:‡JÈŒþ¡¢sôÏÁÑ©^BK«ÜïµV’@."Åê¨ôõCŠu È »Z“—K?_ú kQF#¦,ü’X,X ;©þ @ω¡šbl«¦øq™[¤G"Ó’½äYÿô‘Ç6nî̈D";“y}µ4Ôl6úÆM›·nÝÚYâ©b­íi6šÍFgF$²[¢‘ÎrâÕKüS@kt‘(?„Õ“$µ¤žÔ’š5FDH¶&Ò,ÍòVÎÜ)ÐÀ' êPT}@O1Þܼ½ù–C¼ÏIH¢Ö3‚¨³Oöáwý¶ §ˆWâP/L ü©ÞYv‘þ¢°è]Ñ7ýVüêµ8y†2¸×À'_.ããÅ_b‘Hd "ÍfcÖ¬~ÝÞ÷`µæHdZP„4Å[Ÿ@` :ëÝç&¦¦¯­Jk­5Æ¥y–eiš¦­Œ¹Óçý€À9:G8Tæ3X( õÐÂîD¼[VǪV!¼ÐRUësT⬅§V+!`Êåª4»C.©c¤í@oíÅ ²£1ex:ˆ¯ú»š«ø¨q8œt^‘Èô£•fY^ܪ‘HdWP«ÙY³úõ#y``¯ÎìHdÁ9'¢/i1FÄ µÖZ+‰m6ëõz=Iç\–¦ccã­VÊŒt¤£¡Ä9º´ªŽ²ø ©öVxg5›Ðe¥*ãUW¯Þý§gÛ,uGÝÔ/ߟmK#%Jè•@ØÐÊꣅ‚êÙˆv Z\àuÛíE"ÓŒáõëgööõ Æñ¬‘È.eddlÝúõCƒƒ‘Ȇ5V-K +4޵Z­^O’zÍ&‰1Æ“gùøÄxžf­V+ÏtiU1¤ó+€ >šú/…4„É^í´pÇ¥P´JK&ÝôÅ訔$B¡*ÛeRõ“ZDÑÊw¥²®€P¨ÒÃHdZ’¶Ò(¬‘È®§¯¯gæM©‘Èž‡ãEJc­Æ$Æ&‰­×jµZb,Á,o·ZY–f$á¨I}àŠêPq6¿[úš^ävìn_£~@ã²ðïÐašÕží^µJdðH_sQ5ÿŠÃø,ª'~tÁ”zJN1:7‰D"‘H$²MĈˆ#Ib‹¬5Žišfcy–¥Ìá]îŠGãpNŒHˆˆ5ØÃìz@m­ }ªBXøžîJY¦héÂúJ”DDèœöDDì°R=àÂa jµ[ÚÕ…µ†"+(R:¨ ëdÚ¶ã:D"‘H$‰D¶ƒZ#©%µ¤fk‰cœc–fi+e–¥iF絎N×Ð…©ü|+€ Iˆ ƒ?á‡s’j‚ÊÛTâ7úª¥u<« ¨zêRš¢Ê|Îk.´DIHôu´©g¥Àd* y&‰D"‘H$Ù~zgôYc:çÒñV–fy–3'rG¿L p!Bb¯¸œBP»§þN“nYÈ&à_& ]÷ã¤TI)ÕTCµE~3¨.!ñµùÊ ˆvÃq¤_a ‰D"‘H$²C˜4Íó4Ͳ,/«¬ •ŽXiwJ'|:h[늤ˆ)Cª”/N0$)(»JÑáü¼”á…­ß,w} W`G”jä—(µU¯Ýd§ŽD"‘H$‰l'#[Fœ®¨ê\ˆ½Té*V£ÛTƤî$’Ú$½ªs ÕÕ u‰V€ôÙ€§Ô @Ýâ*|TÐ(kX­¸©h Ztw²§îÜˉD"‘H$ò %ke€W3¨_ª•»/"`1wª“IvÖFÐÖRÛ)·YËÔè›»@D¼j„å ´yMPµ\hCmÕA×õ£yµp0wª¶¶]"è»Â¼ëQz«)‘H$‰D"‘'…¡ Œˆ~ Ú§‰„¨¾uª'éã±S´ÍÛÝ$¶qè¨(Þ)ÔX{ÒÑŒ:¥$4«1c§ ç-º­g¸*ÁJõ;‹;¤];Ð1B@+D"‘H$‰Ô×@­WU=°h±ãA¿×v‡°ì@(Æblô:Ú+ÕèÎ+‰D"‘H$Ù¼GDu¦®mÕ&“ô¯  w,䬻H¢k,’¤ªc'B€HP:b¥~ÅG‚Ë©d>¹"¯Å”³mB?,Õ§(ûMt„TÏÅg9ˆÃ®n'‰D"‘H$y,¬Ãÿên„ÿ&1„€!Få°Ý‰`€“)R •›œè^ö4Î*€µªÉ¢Ôæbc’T†~øS Oÿ»""ðcRKß-ò¼ãwž—c[$9‰D"‘H$²½ÔM#×aÁ9ä"„¾K}¿èèD Aúa¯˜J@”úÿvWó{¢bù;›šLù2-¾+쓎~ăš%) œs íÐVjáš\¿–e‚†2꨾dpdÑÖt¸DÑ¥ ÑS@$‰D"‘Hä è«Íp.Ï\–»b豪{:Ñ‚¢Rºla †·½þV˜^‡F á©8«d­Ÿ U!5ÇÛd¥.ÝÒ*ë°%I”Ó­|¦sšâÛ5O’,Œ€/£mwžB$‰D"‘H䉱¦fM-!Ë˲Ôå9saîräPgBtØ«Ëa4Шž* ÀˆÐ•ƒ\è tÚ|È¡×Ø't· ‚úO¡@›÷y/¬¬P $Bà„‚©Zõ] AP?á¿ø L"|XõCZº âK:—Œ,†½B³HR®.‰D"‘H$Ù^&²1+5c¬µ‰5¬YÉs—9æÓÌeNœ"tBë}Pu‘jlÎ@àG耀#5@°0Ñ©ðÊbAoy]Žò]&ÎQ¤-+"¨;郠@{±2Wt Ú +„¤¢LQ HG1ÎÖg„3àöG—#‘H$‰D"%c阕ÔÚ$1ÆÂk¬µ–t5&™Ës—;:‡\\.€:€:žUTÅ4ø 0á$ þæG LalÕÔŠ§–É^CN{-¨SVŸ:Áõ¬`@”Iች gHÐmu¤!DÄ A éXà ´â»íÈVÖ[ˆD"‘H$‰l')&rf’‰±Æ&H¬I ¬±R³¶FC32O]æ\N—‹ä( AP48)!ލNÞ°eÂl-BÍ‚ˆ®XJKBP' ªye(Ѓ«{ P<߯äAÍQÛó•v Ct)(‡ßV… Ö@€ áb]Ø @a½ÚQTâ³ÒK·)BÇ‘H$‰D"‘'CŽŒp!„.Ϙ™ÜXX#Ib­1ÖŠ±ÆZX‚5ÒåiÆ,sYžgô:–ëü`UuD讋ˆ0DdU2µ˜…`0ÌÉK´úò~§ª¦€Ä9X- ùÌП€8çÄ„‡þô–-j“ªœÀaõXÍ%„€£ÓC´B=s`EJC ññæH$‰D"‘È“‡¢bÇ (â‘Ãä™3 ­1¢£]“ĈM˜ç.Ë$sÌ]ÆÜ1ƒÐ1ˆ¾wÀÁ4È 0ÌG2Þ É ‹Ž ¶§îW]H«TÛ2¥Ø ›Õµ®<$|XÓhž¼ÚïøÂ>Èú¤ýçt²¨«‡.†°€?JÿTmËÈn›QG"ÓŠz½622Ö××Ó™‰Dv&£££õz½35Ùó HU4AN'ÐÿÁÑÇ „…µ¬ÕL-±5+ÆJbÄÖL-§sÌ2—e¹qÌs Å©¡£1 @èh|kB‚ŽÞ÷H#Ä+`¡­ôzÙÝö¼ &Ý‚¬žj½ÉÊäú|èz€ )Z§D4W/U5\,Š ÉjüÁ¤žjYÖW‰LCæÎ™³nýú ›6ufD"‘I½^Ÿ;gvgj$²çA8"ÐýS~žÖçyžånÂä‰55+6‘š1&Ck’D’Ü¥¹ËsÉ££#DÄt H#B:ÂÁ?K@€Ô¨ƒÓ§çƒ ô q`°SñGvàµ Ø šéSÊ#uÔ©ï Ë¢¤ˆè WE½³(õÛ]ýX³BÖâË«Ëwé|$2=0Æ v¦F"‘H$²K ¨AC²0R$`!!DHç2 7a%±H¬I1ÖZSKê5&ú2­,Ïüjp„Yé«Ã2®RœŽL1¤Ó·8o“FƒµC8aÏ*ö)€Ž è&‘…_›ÔF}¦x?×½â @#8½PhmuþV¥7oƾ0H¯ä"úw@$‰D"‘Hä© KV©Çi|Q Ž"€äb ®åМ¹ µ¹±°6·ÖÔSKŒµÖZ01µ,ÏõÝZóœáH§Oþtjvs$HçeS éD‡¾ª¥B›$tÀ ê;?žURD@ Õø&BEG¯±“eW5“ÔvA²v­–BÔj2€bäl‘[ˆnÏD"‘H$‰<ίÿàxªUa&Q­ÂÿЩð„qLsZa–¸ÌеÖ&’cj¶FSK˜;çÒÖKhHµh1žW¿Ð1¿ìkQ Å{°Ô# E-ó§æw}À7 ÚZ­»ÝEQÔÖNUy‹ì°Q)¯Þ_m5™n´Z­å÷Ü;>>Þ™‰Dv&Fcÿgï×ß?`L±y$²'âY SôñVGr¢Óýƒ' œNËÀ éè&aâLž0±’ˆhü‰­%Y+w©cž3Ë™å¾8PŸ¥#L•X::cŒ¾C+ uU/¼!#@B$„6Ãa$¡ïn…Úª§#JZîŠ^‰¶ÜàSHú•Ýœ.]$2Y~ï}ûî·ÏÐÜ8¤5Ù¥ ?ôÈÊDöêÌ‹Dö0ü /®jc>$¨ñHÝ–‰à„02‚æyž&.±’I¬µ‰X©'5ºÜe.Ë]–KN8ÇÌ!w~<©:ªÏáÃz±]ôŠ hD1QK×ð*X¬uUŒ ý$’ wï’6•d1Db B+^['‰i‰–,äu%#‘éÂØèXÖHd×388ø?÷¯Ÿè̈Dö4‚LùÐb™tNÔÀÔðœˆÑ]UC?åß8ÀÀ8æâZcs]Ò5±b¬k“Ä$ŽN®™K3—åÌ gÄQ„Ž$s`CÜ• h4"«K€BïOÕ±Ô±±¤…+A@djc ÑS¯˜4Õ TŒS»áÔ¨uñÙpÙ¼ w ¬–Úª»“ D"Ó ?Ï‘Hd×ï¾HDq€@çAƒ©$ (&z¿s⇟jQ§o18ˆƒ€’33ΦÆ&b­˜š©Y“ˆ1‰Ø„óÜ¥iÞÊ]–¹–Ä@@'0Bç‘äÈÖÀÎé[S ¡82áB´ÕgUE¿Ð+)&oéNØô„_RHªît–©© |÷¿Dº‰D"‘H$Ùñè|{Pí°t:•ZDB›*‹rÀˆ#@¬XêÌ*’pis‡,O­I‹ ’ÄÖ¬±V’,Oâ\æH0@ã Œƒ.}•â øVuž–P_KHRCå{­'Aè *réó4Ž«%ħùl¬†N}Z@%Ö7Uºm|…UE"Ó‡øÃ‰<]Ä»/×-CR¥P­Šjq%š¦[í·ŽŠ^0AëëÒª""bIŸ An\–3«!O$±LŒk¬SOê¹Ë²,M]š3ut„ËárfÚ.‘ tñV€Î@K» +ãY‹Ž8R%GQLB•!ÝJuŸdÐßò ¯J‚ÛW²»ST¸=v‰ì¦°r«D"‘]I¸óZ­ÖµßüÖÚµÃm¹Ý˜;gΙgþa³Ñè̈D¦1…EQJ‹ 2ZH^ér]>³fä;ÑGöŒ…)æB‰ˆ…up9ÓV:¡¯$¨™ZÍ$ÆX+¶nëu[Ï]ÞÊZi>‘#äBä0j « €¤ñ¯Æ Ó°„ í¼úe¢ 5E@ %,“8©ÄF @D„ð# Ê3¤^Âü ±›!ýâhDZ4Œ«WÍWªëvù"‘iBüéDž.üÝwí7¿½`Á¯yÕ+{{{Ûò'që²Û¾þõoþÉÿ÷:kmg^$2]ñáUÏ Þ¦½C!o€þ;á@*ê´~gþµÆ¢«bB1br¦âLJ“8khë¶Q³u+I"µ¤fó¤‘1ke™Ë2f9S‡, ŽÐ)OBÒ‘*õ5µ3õË÷6à7µD[é\uO§ƒ•ŸÐÛø¬–¶Ø©!¡UPÑÕÚœÿÿ6jŠD";— 6¾øå¯ØËÑã° IDAT¼yKgF$2MX»ví’EG?¡°8fñ¢õ6lݺµ3#™¶ E"¡˜ „”“$T†dª:º ƒ$è„ÎÁ9ä9rÇ,—<—ÜI–Kž›<“,—,—Vʉq76æF·¦[Ÿx|4wcscLÝÖ›µÞÞz__­¯'ékHO‚†qu‹š•ÄJR³õÄÖŒ1FŒMè [¨“û•p~?ŒB ’*³'%tÞ—*p¨FH9Ê@½´hÊYý¾–Q;†nGeL[ô/°ÎÔiEõÕμHd7¦úóº=ÂZ0::Úßßß™‰Lk¤¼%ôy6Ð6úSPy_–æ„+‚úp@ñ0b!¨ï ÂÀ”«–RDèèRäùDÍÕj¦V3µÄÔ,¬n×\=3$›håã.Ï€ZËÌeŽ9À„aÊ”„Õöð'@=EÑ~‰·Ó)e£h¹ü´öyZ½s®tz€~³¬Ysü‘]ŠD¦Ýî˜w]úÞ[~s+€žžžìÿ–7¿iÑÑGuŠD"¿#Ýî¾HdOCŒèÜy1Kåë,æÍ­#òþñSwÜqçÜÁ¹gœ~*vþñ‰<ŸÿÂÏ9ë-K*zºtémšD#‘.x“ÒØ§€€ŽPõV¦w@@æÅAA÷¤øÕO¨œ•¹~-U·]E`ê˜)ž³“‰c*4-šD¬Ža­Ûº•š›4mB43ÿ>­–Ê`¯.ß|Ñ¿ ¢g¨Mïô’ªý™Y~¼±:X¤8¤tÓ ­€FŸ}7´åHdáò^À9·âÁ?tùGæï½÷‹ÿE+}ôó_øòý»çrð+Vüü?qÈÁuM\¼xÑ£«V­];<44xëÒeûî»Ï­K—:ÿä[—.[|ôQ:úƒ—¤§Ù¼ê³ŸrÎ}ôŠäïÿáò½_[ÿáþã²÷¾{áa‡cþúíï¸æê/ŒŽýí‡ÿ¾ÒÇHäédÉ’Eçœõ–ª¶ÂZµØH$R¢. @g1©m]=€€^’€!>©å¼äª°Rÿ-þˆè„~G€4ˆŸßUè0I‘ð!HPÄ9 ¹ƒÔд²q+µIÍÖ©ØšØÄÔ2©ûU¯*6Lý vZždè­ß­ø(*‡ûmB"·(Љo‹$ámúÓí8 ™6lû§wttô‹_þJO³¹ð°ÃŠDcÌÁôª3N¿ñ¦›$6I’¤¯¯·^¯/<ì°³ßòæ©gΘqÈ!ߺtÙèèèÃ<òú3_ûÛ¥KܺtÙ1KX½zÍíwÜyÁùçΙ3{ppîùçžsó-¿Ù°aƒ¶{Æ+O;âð…Æ˜U«Wßqç]žîÀÀÀ>óçŸõæ7…®E"O?…¶.]zÛ¶…uÛw_$²§ #"Bˆ<ô_ÁðÔ\Eh‚p !¤€ ·R€ ¨¹_@@•Í‘¹CîÄ9aîK:"wÈõ.º‘çºÈ€d¹d[)'R¶&Üøx>:æFFó‘176áÆ3¦$6Ñw ñM„@ t,-!pб þŒ42J=ë`âD¨T˘JšXÙ'ÛÿëµAY: D"Óοܔo}çºo}çºf³yÀþûà²÷ ô“ü¯_Þð¯_ÿÆÊGW8âð…$çͺô]þ _Þ¼eË xͯ<ðÀ]³xÑo—.9sæá ;þøc?ÿÅ/ŽŽÝ½üž¿<ÿ\’k‡‡­µó††´Kóçï à±µÃ{íµ¡ÁAM^×l6ûûû}±½÷†žF·‰Dv=‹}öYñÉÏ|Ào;wñ⣧øá욉ìY+~™(Rƒœ>¨JRéû§úä–Ò„”ƒ|M¡ŠÂ Qj"‰\íM­R«Ô0¯@qÈõQ> AÉ‘g”iêZ–Ö"©™Z"µ06@ôÍçÂŽ»Ýw•*¬EŠŽ…`ÕK½l†º4J¬‡p¹¤H*jl—Ópáªã""‘g¯~Õ+Ï;ç¬jÊÆ›.ÿÈÇÞ÷žK–,^ÔÓl~û»×ýü?©YÏ=ñ„çžxÉŸýü?ÿúâw]û¯i4]Y²øÃÅÌ™3Y²xö^{Í™3û[ßùî¬Y3Ÿý¬gœ›ç¹°jÕjCƒsµ•âþ›;wÎøøø¦M›ú¬^³ÆgD"» K/ºäÐáÝ‘Hd*Œ1€0§Jã“Þ:Iˆm€O×"N¨¶FeThš&B…þë5O«Ñì0ÀÕU+D˜¡Àé¶Zm‘ B˜åH Œ8“¸ÄJ¢ç jè;N²tL_E‚’$‹©eE Ác($…§Ae€ óš^ÅéÛÕè³Ð^±‰ì ´Z-’}½½µ$Y~Ͻÿöíïjúoo]öå¾fÕªÕY–åεZ-çØ5À‘G>:2ú“Ÿþ\³xñµßüÖ1‹kUó÷Þû¨#üÔg?·aÆááuŸ¹òªŽ;vöìÙ¡ ž}æÏ?âð…Ÿúì•›7o^½fÍ—®þJGHdwàƒŠÂ‰ýÆ??kpîÜWžþŠ{:‰ìæÄØHjRT#(ˆƒµ‘ô(ú@ ‚AŠšž—68@Ó)z()^õÚæ õ»ÅžP„wjŽ ЕˆÀ@ÄÂè$ý$¨¢¯M#¾:m?TQÀâ[±oô_HÒGgý«ÊÎi!ŸBÂÛ@%Ë®ŠÒÖf$2éò#üwaª~¯ýÃW¿ö_Ý‘˜$É™ôš3ÿè5O˜¨|äòÛ'Ü¿]%³÷ÚëÝXš¢\ùéªîÎ3G1P^yÚ©•ÌHdºÐåî‹Dö8Ô¡vªVVêûú´[5Å€p^Îú6ÀAÕ—H:§aGÑÀ¤·d”hDtA…êâó|HWŒZ „ÀÀè; hÆ÷GP -`šô%¬®*"P‰×žU´ƒ µ@¥ÝbW·;Ò‹”H$‰DžsçÌYºlÙ’0HfÜy×]ƒCCOêE¯‘Èô@ëA©D¯«I"€Ðª)ªŽF]ŽV„F‡ŸBzW GÿuJ õ¼Ó(ªã±Ô¨¬ö8èG«äP#1Å%Ε«¢¢b‡Þ*+þa=©ççóK%iª=Qé R|+,ÝT)Zô­”ÜV ZkdZSüœG"‘§…3Ïüï_ûÍbRã6|ñ‹þ¾h#y† *nªuT]D@Š$„ƒºŸW0! À!@§ë GÐ8]€ˆ¾#+„%—TNÅOíVc­" ¢q]!çP@@µ 4’+Ä L²B‚bt0«À×Ú‰Z&©Æí»KRß Â)"¤‚0¶A?Â'»iÇvµ@$2M‰¾‰<]w_³Ñø“7¼nëÖ­£££m%&ÑÛÛ;sæÌ0Ï:yfà- (‚Î{4ŒY|PéÊý 8£S¤Ú£ª¯„}i–VTdB@}£* ßcÙéB–#Œñ͵ù…¢«n u´€d*)µT’ôâØ½€¢EüV¥(b‹]­³ê©EOŠÜŽíHdÚRþœG"‘]Ky÷Ykûûûûûû+¹‘È5ºÙ‘âÍdÕ,¼»QP†ÅD}>üpV©Éé4Ì @D㬾< Ð) I"þ1>@¡!ˆÊcz@¨Єâ@ÿ$?ô@kГñOó‹ãC ÊYuJ Äúf+–[¸+ô²èÅšZFI Wj.3#‘éGõϳH$‰Dv%úzU‘âÃHeÞ*b8*á|Ž ¤/ª»€7:¿Oõ>Hè ´¶6ÅÓÖ¢öë Ä‘ðK}ãaP?©;‰·C@uÛv•$’ÎåDhD´P{¥•äÂ7+¢\P­:¨ Ü#ÐÖzQ§v.‰D"‘H$òÔp®ðÑÙó“ø¨ø… ¯ˆF‡ºØ`ΉÎÊ‚€„1FÍKª7¢T?«‰F@QÇ¥#L¥Q?ÌïÎÇ|‰N3‡ª!è\®mˆq¤ °BèÀX,RôX„“6 „“ˆh*úI@®Åµk3×P’þÿ‘È´$þʼn<]Ä»/¼áøRUqF](@DH Jý aIÑUOb…„¡PghѩȪ–ŠÞ‹b4: ~BàèhÚbœ:î@ü#ŸBP(>ÎZÖíB8IÒ Ý Íj5¡Â6[G‘ßIøÃ•УBX#‘g$ÍžÆÚááÁ¹þý¨‘Hd×0¼n]OO3~ÄD"T·«¦¨ŒVÓÛ¨ ¢ß×ÛI߆*И$ ~*P#E ßj"@ „ª}a ¬Ö_½G jm!ÑùBLH§‘NÍ (‚¯ Iƒv†@¥nˆ„Reû‚rÁâªyg/ÊOMÈ­žP$28ä ïàÁ+ì̈D";“žfs¿ýöm6‘ÈG›hUÅo„úò(¯m(ê1€+épÀ‚J¢ÒKŸºœ¸íhTͰªØ ÿæêðq~MV!‹×x[õGQ„à(©†ª–꜃@ŠÎ¢)Åiv^µê®ÒÕúŸø,#‘Ý•þþC>p||bòv$ÙyˆH³Ù˜5+.ÙÓ!C¬³JeN:ü,Юdô)0§J·êµ2Ôa(¶H!鲨J¼XNfŠJHç‡'@{/F¬ªhuiªâ\ü6Ü0ÂÇY ãYÅ! ÑEhê…ªtÃKí¤8«^ê5Ò2ÑY#Óšááu£cc©‘HdgÒ××;44dŒÉ²líðpžW'šüNcz{ýýq×Èô€ð“óC ÑkXÅñü³ýDEX«ž¦[: à§aÀAC䀘 nÎ/Pª›¾!´kñTªf˜”*IÀK ýaNýÓ£]ÖøîûÀ²oÓ7Ó®—d1°¡Í:;®…â·Š<ß§Hdz²bÅŠýžµßPωìZÖ®~`ÅŠC>ø±µÃ½½½Æ$0>11::*²y``¯Î¼Hd·…¬ê !%Õf«ªð¥| 2aJ€RæG Œˆx…ˆˆj$Ý6Dnr³Š:#P[rB‚ô½×bÔe€€¾3A1ðƒ Ð2¤~+³|®(ØÙ§jJ×BŽ #p#‘éÇÈèhÖHd×344¨o½rÎ5uýŒÚ!_ÍFÝ97>>ÑÙd$²[Ìj’`cE,¼8–VVLyÑ'ñÔ÷»N^¢Má}Toœ¶b])äUûÐÞ]Iœs"ÐÇûI'ßAUhBËðƒ^µ oÞ×Õ4õ¢N éE™ªPKh«8$lê5M¨¤G"‘H$ò$hûàÛA´šþÿì½y¼fGUïý[»OÒIéît™ƒ@ 0$ ú* Êt}U®b„™‹ˆÊ` "}E‚ CÔ×+¢ ƒ@D@æ) C†Ý!é(ét‡~êwÿø­UU{?Ïé>'Ig ëû9ç9µ«V­ª½û<ÏùõÚ«j'ÉMi:.ŒìÖc‘l«æá¿ád]ÿ¿ólë±ú4À´·« 9·ø-³ð­T+ëô–ÈéÂ1šýG,SuñnÔ4g<€0ó]»üTå͸§vìFše“¶1©$I’$I’d°¶.Þ±©0£O'ŠÔÌÆjnž˜™õšØX ¬˜iØ„Y!Y]ÍkBQGwIU€¥Nz!ŒXÌb¢¤ÖZA_•~`CHO¹V{èëÅ,¬Õžd5¨­I’$I²zÿL’[ãtÒ}ªÓX·¤Ðå—߇ñ¸,Z‰åzšÆ´š†ì%ß|yÅGK­¨¹ir’­É5k|CVMÃ`±]«¼N®ÁŠôåH×v£7‹õÓÖ$I’$Yý_Æë‹ëßc’ÜÄ/n÷¦0_4dæi¨µ€Ö$Õ~ój-ÜÜq3×p‘ê¹1b›•yÔkI.µh@"r”w;›ÍÌ”â XÕ¬€Á`Ö49 F0ÈI™ãŠÑ¹öeiŠ]5 Óº$I’$YsU®ö†Ï$ÙKШÍõý77¤¢I¬AÌ-¦LäIíæoÒ7¿ª6$¾Õžª$=¡•0Ý„´ª TâëØupŸ±a0O’@¥mPG­Kþcå¿*Y K)^YÝV‹þ²t_Í­ ~2ãÊ$¹ sùåW<ðÁ»òÊÿš6$Ir“cîÏÑuýJ’› DaUfBâÏc‡~P¨[ë£_ïÝ 3n çnPšˆÍX 0˜Á ƒLUûOÖ.ÑjbÙÕRóeŠÆ[‘qèîz|•pÿá°;’Š+CËÓjKôCx3ÐódøéQ`7Ég7^’$I’¬–ö—*In™×]"”Õ`ðU÷éÄH´A7Àñò¤ªýÌLGþ ©¦üš¾ë¥¢At  kžik]ÚúR~ JRïïš Ð"•3I[WÀ¤[ER‚KX3wóù°8¡²5¼çÄåÓ¡õW³ÍªÓ¾É:¿õÜßùä| À~ûíwôÑG=þ´ÇÞýÄ»M’$IVCýS|=²\&ÉÞDZ®“@ÈJ‰;·1—qzãøïyûm¯¿ù.T¥ð¼[µ·ðÀ”7 ÅXuHP"`'X«8nQNÀ€RÀØ}€‰â!d’ iÆäŒ-`íñOmö_Ô‘¥°5ƒ 3ï1évÖ$õZé«™ƒ®I\£äžŸyô#?ðOÿðηýå?îyg¾hÛ¶mS‹$I’U£¿@×ãW’ÜŒ‘ܪž$‹«Áf¢g:5ƒRJ?S€ðGÂÂH‚°Ðl$%*{SƒGE{1:€F-Är6y£ù¾ªcfÆñÓÅïLÖÍ(«úÞh|[ß`»·ª¦w9ïf²! T«g'·ößÿ3N?휿ýû/~é+÷¿ß©Ïý~âÜ7³6<ì¡þ¥_xŒ~µÞýÞsþæ]ï½bÛ¶;ÜSŸ|ÆñÇ·°òÃù·×ÿÅß|öëœýÆ7¿å¯ÞþÖ7½iÓ¡_þÊWŸýÛÏ;ç]½fÍšmÛ¶ýñŸþù§?ý˜ÝçÞ÷|ÊŸp›ÛÜÀãŸøÔSO¹÷¾ø¥¯}ý¼g=óéw?ñn¯|ÕÿþÜç>¿~ý!|ÄÃdzN’ä¦ÊÂ?eIrËÀ×Ó#¢œèªÐozû Á:Ù`ܱևLóød{¿UåJÀÖ=lÌ € `¦º:\OÝŸ•ð¤ õpXºvœŒ$èÏš7@š™ž0kÖ§3Äé™”÷8p÷1 3€ž8 EùsHni¼ôÅ/PJ9ÿ‚oüîïýþ¦C7ýøô¢‹.~퟿á_qÖ?î¼ó/ø—~èøãŽ[XyÒIw¿ø÷.Ù²eë† ë?ý™ÿ<üö‡}ê3ŸùéMýÔ§?s»Ÿ¸fÍ/ú½ß_·nÝë^ûdzRÎzù+_ú²?øýß{‘Fÿ?ïû§ùü;ß釆axƯÿæmo{à[Þô†íÛ¯~ñKÏêæ˜$ÉM–úgùzd/¸L’½C!µ©Áƒ®»z³¡õÐÆ—3r*MËUãjf!C]•ú.^Ë8tÁh-Qt4½¡š¨à£E¸Xk‡¥ ÖÚ @(O’…œu'Jin/ЄºU;Í k¦Zd’ܢؾ}ûëÞðÆýÖ­»ËïT+‡a8þ¸cý¨‡ì㟰fiÍÒÒÒþûï¿ï¾ûÞåÎwzâã·\åmn}ë;ܧ>ó™íÛ·ëÛþÂc~îSŸú €Oæ?ïyÒ=lÞ|ég?÷ùg<íÉ·»Ýí6¬_ÿ´§<éÜÿäw/¿\ã>ê?á.w†á’K6þ _ø_O{ÊAtØa›ÿ¸_«sK’ä& õÇäzýŠ¿rIr3 ‚¬ ß\¡j}5̤51/m»7€Á³R—Á›†Øµº2@‘Ò†OÅ»øÐUzœÕcÁff2"Í(€‘3°Î~€’d½Ç@r€oH[!aÃÔém hºlæ!hOnCíóÚº`npKâ]ï9ç]ï9gݺuGuä‹_tæmo{€}ø#õöw\xÑÅ;vìp×î`Ó¡‡þÎsëÏ^÷†+¯¼ò˜cŽþ™G?òØcŽYX àä“OúÔ§ÿó€ÛpÂ]îtʽïýÚ?ÃÕW_ýÅ/}ùO{ €-[·®Y³æÐ5‡Û¶ ÀÖ­[owðÁ6nØ ú­—]¶nݺƒ:H‡‡¶I…$Inêìæoj’ü ã›£Æ P¢d^«󊋤ä`êê : f633Ón«t³œŠY‚ÍŒ´xŽ+ÀªZk04da›…—–ê?I !Uk‹Ac¹õoÀ¨µþ €*]ÕmX0(ÝQÇò+Õ“oõˆ9¸ZõsKnüÌ£ù”'Ñ×\qŶ¿ôe/<óy'ŸtýÖ­{÷{ÎùÀ¿~HM÷=õ”ûžz ÉþÀŸñë¿ù®¿~ëÚµkVÞó¤{¼ä¬—p›[ßóä“>ø¶‡Üîàw½ç½pÀ‘GÜÀ†õëg³™’\|Éfëׯ÷Ä;gý!‡ìرcÛ¶m’­›7_ê I’Ü´É?!É-™RôôÔ€ã—q)šM}I§ºö¬Uæ‘,‘ FG‰]’@ Ù*µ©Jï«B̈¾÷ÖtnzfUó«Ÿ-+ 0Ë Ô~Âh3`†RÈB+°BÌŠ’¦9ÑÏQ> ´áT˜‘…˜z Xû¢¾Ú9À]%·Tv^³“ä­ou«}––¾ü导óÝïQý§>ý™×ŸýÆ‹/¹d×®]¥”k®¹¦”²°ÀÝîzÂöíÛÿéŸ? d€“O>éíïx×=O¾‡\mÚtè‰w»ë«_ó'ß½üò-[·¾æOþô>÷¾—‚¬=‡¶é®'ÜåÕü§Û®¼róæK_÷†7N ’$¹ ²7þ‚ì ŸI²—(䬔úµ‹E;@M¾fô¯ï—ïïâ®]ÜU0#gD)\s3éºBÎPÔiwíb™¡ÌÔTf¥Ä–Se¦çU¹¼ M׉;µMßVÍ g·†ôÙ möß²nCÅ~r ’¼PumÅ™ï´JÐ|£ZȆÖ<Ú­1€Úlfs‘êä–á7žqúi/~éYÿýßß»ãñÇýðîÿ¥/}ÀÝO¼Û×Ï;ÿ·Ÿ{æeß½ìðÛ~æóŸ³ß~û-¬°Ï>ûÜõ„οàG}€{|Ò»ÞýÞ{žtRåÌç=çÿ{ퟟ~Æ“ vï{ÝóÉO|Bmê9óyÏùƒW½ú—å4íð•¯~uj‘$ÉM”˜É-R;RLÊ«“ÕRrް ßgDV­€P«ð]µÉBn£C×HN’WjçåÅTÙjG?ê£Ú¬Êu#€ ƒæe}d¨Ö ÌÏÜå)`¶€Y·+ì`™šRTÀl0ÓPÌ !ˆ:¥Ê±ÛŸ}ÿûž: ÃæK¿³éPÏ;Ü ]tñá‡ß~Z»b¾wÕUóa¶›¯yíëïxÂݯÞ~ÕÕÛ¯:ço6'7=>û¹Ï=à~÷Ö&I²÷ùèÇ>~÷O¼àß<øúþ<¿üòË÷[·vÓ¦Lj¿~xÌcŸ`Ë¥—ì¼zûÓžxú´9é8ÿü V.o¾ù­o_xÑEü̳ã†{UW.Þ$òvwäiÚ,€q uK|W€SÈb´ûÅØ IDAT¿l´W¿F¬ KqáëyZ-…]Þ$[— é)­4 a¾ªSÆ µÖ)Ry½yWh–, ¸J›îL[|¿@×…€ftÅ$I’$Y þ¬^gö†Ï$Ù+HVÕ3Öà%ÀhRÎëè})gMš‰^6¤åZ}Q=uÐÄ25z³óŽˆÈiïµCÏPgwf¦5]¥² †¡ªÌFŒçõ„ŒcHíy „ VX`F_5Fuìj’Å8œŒ›$I’$«€úu½r}ûK’½}%R„öC/ÄÌÌwnRÄ’T@” i'IIû¡0¶æ' ¥*í«uf€Þ;ŽÅ,«W»‘úªi©«µØ¸i“Ÿ€Ë×&'} È2¼˜Í©†q‘êU µÉ@HÐlÐÀ ‹œÇ5$4LŠI’$I² òOHrK¦ø p0é7J¿hÒÖ÷/¥¶ ê8©žèd€íMžéâc!']VÖ°zjîÝhIóSð3r 6ƒ–Mp= HKº3*1€Gf&Ó¶K‚¨šU“÷1ŠOÚ_ë õt§“$I’$I’¬ZU¨¦—[ } €U÷)¼è¡S]’¨l£i\ ½Ö(§×7[ƒ„$JLD­Ös‰ëôAÏ¥»ŒøX #ŠÕH®|²÷A’$I’äÚ’ 3¹%Sè«ò=˜ˆ.6(,“wJ“^îS=DŽح‰³ôͦRWÂÎeÞÄ[å$£†ZƒÕ¢|»øhÕ¥n ü‹Ì  ùv]€«X©Ð"ý)íN¬Ñ®ÕQÈY"NÔ\¤*Û ë’$I’$I’¬œY™Hr¹ ÒN!ª‰‹šâ° Ä΄jªíåbW&<0) *«ú°Ð?…l(ÅF] 8 ˜Ì€KIdÕÈÞF’ÔV\E@B:XM ?þ*ˆ^Bõî­Û5Vâu~2Iró`ÿý÷Û²eë´6I’½Ì¥[¶ì¿ßþÖ ¶sçNÿÃt}|íܹcÍš!ƒ)ÉÍ…¤±ŠKU5W)¾õ©0 µºá¸Žë¾Â˜0²‰B½1$ PÆ'‹DÚVÓÊmà—”µ2VIþ4À`K&M CÜ¢>Ðfh0˜aˆá©ºNh‚@Ô Ù(n RñhÒcÔ(È êbzàÙžZK9ȆäæÊ±Ç{Þù|í¼ó¦ I’ìMnµÿþÇ{ €ƒ:ðŠmW~ï{ß›Z\[Ö¬Y³ßºµëÖ­6$ÉMbV\Þ™icý.àJé;À£ýýy-p‚$% -§H¤²µ¹~›/·ªIÍ<î2ti«'—4½Fdè ¦’Ý­¶ZñsƒisZ2vc•r¹€Ÿ§AÙ (•›Ðº„Î^Ir3c†;Ü´6I’Š<ÈÌvìØy}ý)1³uëÖpÀÓ†$¹IÂB—s€A²Ì Ã3˜AK¬ r<%Õ(ØØTßèT´ü_{µLwô¿»>I²íH0&40¥¯¥›&\"f !™“dSØPÅ3 ŽuÕ”fúÙM‹¾õÀÌÔ_f€­€UŒú@º†®n9I]¥Çz)åš$Éʹf×®óÏ;oÇŽÓ†de¬]»vÓ¡<ð ]»v}ù+_ݱcÇÔ"Yk×®=òˆÃ<ð aXv0 ÃAÝvZ›$· ´÷= ¾ÎµÔÐ¥ƒô˜‡`»žB5 ‹{ôA×肵kœÃÌFºqÔ9DbŸóþ,‰Yy!«@4 ^'oÞ•^kI3+š*`0­=3hh  ]˜çy¥úº™lÝ›ÜR°&Éê9ÿ¼óޏÃá6l˜6$+ã;[¶|ûÛšÙ·.¼øö‡¶áõS‹delݺõ[^t”Y Ç$¹q¨2*4–Š4€B „™‘`6¨ < íè]ë2iHYêk„â•¥,‚ÕìÄêþP«¢îP0NK`æû¤6^­¥z N)OÓIЦ®€Ü¨éÙÑ€i§­ê|Ëp\]”Egž$ÉîÙqõŽ ë×û'T²z6®_ÿõ¯·cÇΫ·_‚õº°~ýú¯ŸwA†ü“äFGDÏ[$Öˆ¨Àâ fæQ×¶=?h¶ûðZRÅEËúç *ÍéI­Á<ºjˆ4éû³ª,ä[j£ÕçnÕxÎ0!P€5ÐtèW‡òSHúùbªæÞFÀl’›$ÉÊñ7mr`ý\Jé]Ék˜$7ÅSB`Õ|ÒxSRKêC–>:qVP²¾¡`A1H¿ÊG“£•R”h‰G2K(cö) 4’âÙ­Ä}yᩯ•S‚ ³40øÿ^’‚ð=âi%˜÷ 1€g?SM½²0mP-“$Y)’$I’¡Ó\tªÞ´6ú?åL¦R„’^3¤ÕX7wB+‘ZEo F»—Nˆj2²ŽH Z9ÿKV€%h¶.w…‡>½>¬a`,º&”õš ˆÄ5ølüÀ©õ‹Ðå!X£§Ø‚»9õ$I–…ý›.¹Vп“ëF^Ã$¹QÑ[° 2—d½ôs0‚¤ëÖ @çÃu›‡$ïœùjeÿ­ë iMaIO²B©1Ü`„d@4é`Ä•à´A-€­µ…ÎÌä¤|2ÐÔDµªdÍÄ¢£FC’${&ß4×]Cê³(¹äõK’¢Ä½oê^¿]F4‚Ô–U®ÈŒ i@‘r%h¥ÊW£ÔÒ®¥ÌjRíhGN $ú€h…$„Ñ( qÖp`±@ÊC¥²Žë*Ìu ¦ÃR­²4õ'@Ò§BÂ@´°+ šNä»á$f†·$IVýœ\{âúåu¼îä5L’ ×Y®×\W4 Ò]4`œÒêeª0äX! fƒ ,UÂ_<ô©êy~ØŽÍü.ú\P Ìt Ÿ®•—ÂŽðûøéBÛÕ£™/%«^Z<˜JtÂ#¬,žüê§I`5 t=Ls±zbf¥Ð,ögõX˜ žÒPÇL’d¥L>’dÄSžþ̇=ô!?õПœ6$IòIÆB#3ÆMu²‰KƒÉÆíý¦¸+2i¸vœÍf€î—ÛÖÈAt’ëN¶¶6Š®4•OªŠª[=H€mV é\Í €§¸MÑ”QàaQ·)ð T·qoRÇ `þúT“/R‘ZÒ©o?!¿I’¬”xK'×ÿè«?€°ýiÙ{ìõ’$YT(@y›U¡D±Ý 'áQ×P‚R†Tc³33³™ÁʬâÑÍÒ-tü±ÐÊæ/>Ožèög­õL”šô62žbB Ä–Xž€f<˜ÁW}µ­ù‰C)V3P½y€¤©[°0Ù!I’Ýáoó”Ï}þ g¿é/¿ðÅ/íÚµë裎üùŸý™‡<øAS£›º€7ÈeüÊW¿öÖ·½ý _üÒÎ;;ì°Ÿxà=ú‘X»vß©ÝÍ”ä&I²bÖ!5J£5f$õÌ'W}hõiŸ®ÚëN ÃÌ wàE¸õá!IÛÿW¹óÉÿ¡«`%k°„O<æÔB§ÑÒºŠž`¸º‹ê9`Œ¹øH5ŒZgb&Áj¬jTǯ©Îͯ—Ñ"‡"I’•Ò½›o >þ‰sûù/ü•_ú…ç<û××í·îc?÷ÿè5—lÞ|Ú¯þÏ©éÍ„¸|{ý2~ò?>õ;/|ñ£ñð3NÜúõ‡\²ùÒ|ð_?~î¹?ú#?<5½¹²×¯a’$ËQ 0 HHVú’(®NAø}í¦7 Å_1}OŽ\­AÏ&À`€É) ˜´]SÃS"Ó{rÔIVM¸väܬjé2U¾¬Õ³Cí¡ÔW€šFóãîqHW÷⹞ ¦8l\?ÝÎ>I’U2úßêÞ†ä¼ê5øé‡ök¿¢š‡üäƒÌì%g½â¡yð¡7þêãθï©÷ùìg?Þù~ûÞùŒ§žx·»¸úê«ÿìugø£ÿvÕ÷®:ñÄ»>ë™O?tãF¿ú¸3p¿S?÷ù/~å«_»Ýíþõg<õ>÷¾W?â ‚_Âñÿü¯gHþÑÿþ“‡üäƒÎxüiª9êÈ#N{쯨éyg¾èÜÿ¤™mܰá¡yÐ/>æçõéxÆ“Ÿvê)§|ñK_úÚ×¾~ðÁ?õÉO¼×=O°}ûö¿xÓ[>þ‰s¿wÕ÷þŸùá'=áôuëÖ]}õ޳߸æûøÇ¯ºjû]O¸ËÓŸú¤ñP_‚{õì’$¹ÑÇ=×UvæÉ­f#Éf€¢“hRnÑ'†É€ÂöÑ ˜ œ$P:R®êÓ Pþü#w2 RcSSjN ÉB”‚R¼Ì¢¥Ç d#ﲩõ„éÜ‹> @X»ÏOÆ(*²°ÌXf`a™•2#fDŒž$Éj‰7÷ ðõ­o~{ó¥—>äÁ?ÑW>èÇ8 öÉO~J‡ï=çïŸð¸_{ï;ßþã?ö£¿ñ[ÏÝvÅ• ^ü’—]xÑÅòGøîw¼íÈ#ŽxÎó^Pfþ±ôÞ÷þ'=áô¿{÷;úàýîKÎò‡¤Ü_7ß¾ðÂK¿óÿħ €—üî þùÿþ}ÿÿ9/<ó¹ÿôþùà¿~¨6½ÿ_þåôÓûη¿åA?ñÀ³^ñJIϳ^þʯŸwÞK^ü‚·¼ñì;wÜ~ös^öŠW^|É%øò³Þö—qÄÁ‹^"ã$In PbN_VŠË²ÂªÏʬ”‚2³2³R¬¨#]êÕ/W{þ¥ *I9·Y±Y¾ 9›qWá¬pVPT˜ùWѳ¤ K! XèC.;¥/=9U2Ô‹YøYîîTS?é™.a}J…,3r¦’&½â£ÓÅk)e&ýZÊŒœîêž÷•$ÉÊ ¾o ¯+®ÜàCn×Wƒ|ðÁW\±M‡zÄOŸtou«ý~ù~ý!‡|è#Ù²uˇ>òÑç<û×7mÚx«[í÷ä3ñ%—|ã›ßýÏýÌ£ïrçZ·nßÿñ¨G\qŶ˾{Ùü¸{÷‹°·ÕÝ•Wþ€CnwÈ´¡c†ãŽ=öQ|øÇ>qn­üzä~èŽk×®}ÄÃjÛ¶mß½üò-[¶~ìç>ûYÏ<òˆ#n}ë[ýÔÃrê)÷ÙzÙeýØÇŸõ¿ž~è¡÷ßÿ'œ~Ú%›7ó[ßjÞ÷>{û&I²$½ Ka‰ cý C÷¡°5‘ [–²Í%ÝôƒRº¶F»–P½…3bFÎ$@gÕ­kH]zÔó§´iAa<»5N wì¥e>)”kU×±†h…ÙಫAú©Ã¨Q5G£ \OOÙ'I²G¦o³½ÌA`ëeß]¿~}­,¥\~ùåÝö Íä°Ã6Õ)¶iÓ–­—]²ùRüÕ°ùÒïsÌѺíme¿ïÚ}ìØyÍ yFè>¹âi¯pÀØzÙe‡r»iðá|ômý΋.¾dÇŽN¸Ë5x€Êûî³€;v~÷òïðéÐý„7o¾ÀÏÿÒ¯Ô—^ú£Ž¨)yGPõJr(5ê –šo"Ï[ @E|±K™H’dUè}zC}™á™OÊßýý?œýÆ7oÙ²å¿þû¿Þ÷OïÕ«_ó«¿ü‹‡nÜÀ{ÿöïÿó³ŸÝ¾}ûÛþú[¶ný‘Üã†õ÷¿ÿ}_rÖË/¼èÂ;w|ù+_yÎï¼àûß¿Föã!nÐÓñ/¶Ë¹÷0³g<õÉÿø¾÷¿þì7]|ñ%;wîüæ·¾}ö›þòCþè5×\CòVûï¿ÏÒÒ—¿òÕw½çœiç16¬?õ”{ÿÁ«^ýí /¼êª«þáß÷‰s?¹aÃúûzÊ+þðU]|ñÎ;¿úµ¯¿ðw_òýïÚ9I’P °B΀Yˆ6¥ŠÖ¤ÕR´ˆ(rX+žêZJ)3€fŠŽöAFúw¡]Ò¢ Ì0+œ‘¥`6³=çU©®3^Ë^¯ÁÁ‚²äJÑ•.Ám®/Æu€‘…PÐ6Ö‚i++×Ð3h…»€ƒ"ÈC,¿’3éhyÕ(F—áNû{Ñþ $ÉJ¹ß6÷»ß©¯zåËÞøæ·¾í³k×®£Ž:òéO}ÒCòà:G<ü§þìõ¡}^þû/9ð  <ÿ9¿õÆ7¿åY¿ù¼Ë¯¸â˜£úŸ¿ô˜¥}ö©]T¨¯7ð ñ©»·¸×=O~åË^úÖ·¿ãiÏükvî<ì°M?þÀ;å”{¯ÝwßÓO{ìKÏzÅï{Çwìîwß/}ù+u2ubõ•äoýƳÎ~Ó›ûygîØ±óG~øþgœ~Éßüg¾å¯ÞþÜç¿ðŠmÛŽ:òˆÇüüÏ.-é9ˆò±wÏùž$7.,zö•B †Aªt V@3Àÿ§¾ø K€Å?ŽÓ6¬%â9¦j·úh(Ä'”—P#F@¶VC`0ÖWõÓ í°¾…õ­^ CT pP§dC+Ã7wòÓÌ”c ¼Xõ$IõÀƒ‘ÉÚn¶•k<¨S‰û¿úþ÷=u†Í—~gÓ¡›Á2\tÑŇ~ûiíŠùÞUWÝîàƒ§µ7^óÚ×ßñ„»_½ýª«·_uÎ;Þ:mN’àß?ù÷¿ï©ÓÚ_{üáç~öÁúñiÃM˜ûø'îpøíϿ৞rŸi[²>qî¿{ÌÑ›6µŒ…$éyÌcŸ`Ë¥—ì¼zûÓžxú´9é8ÿü V.o¾ù­o_xÑE'|øa°¡Æ;Õ0=ÍÉ`JZ•þs6„Ò$¤«#5„’CÆÿ¦¹%HÛ¹DövHC«Õ%%=\JÏÁ’{E–„<Á¬Ïm5 Ž¦2AW¶dÄPI³ú¬Uu)Ò£ÞŸô‰À€Bf aVHôÏi5`´×k’$+…ÝÇÃM„›à”vÏÍk¶I’$Ë"èB/ÔdU™„'¤’Àïꛯ8¢K¶ 9ŠBŸ´ßª+ýÛŽT¥èG§š[ ½ÝšÊðZOB58x¬—„ l¼VH3=ËŒœ¹szgùI’dŒþ{“ }vÜ\ˆéN>l“$InVp¼OT ©8‡´]1€³F€†EV´¯€Áf(26X1€š”ÿ¡*]DÔT?Øi¸Û¨qªñð& À’de÷qL¸+_æ5£’*%à²ÚÌâZ˜…k’a)W 8À»ibXã£ú4 ðˆ+©la’$+æ¦ô¾9ûÏÿ¸iMi…¤^½îä5L’‘ ¢$®†Ác”¥jYêÛ ˜…†Y|jÏ\óÁ 4 áaÕÂM6² ¼ ë”;^d£Ðµ±úg5xN*\Âú½x—¡€‹Úˆ³Ö ë"¯Ž[Ââ²ô– ÁJœš„)hæºgÄ*âKÓµ‹sO’dÅøçErˆË——ñº“×0InD¤ñ€ÐrÅà‡­ HФټ ÈX‚ÊàbNúP¤ó…Bk¡ŠŽ‹þ#K€>¨Ôb›aÚŸ•ˆØ'PUdû€éÏFƒ¨ÁÞnHóCƒÕ`nk­£BÃIŒÊ½Qh üËÒ,Ä®å^WI²j|$$«$>¹òZ&Ir3fúÖÅ?û–ªÜª,$úïU#ŽñšN/‚ô{ü[ª˜ë=ï Œé‘PTWÏ8Xò³(3˜D')i˜Ä²¤¥ûqo”·ÈÀUÃO›‡™ãlÀݸo2ËË®C›Â4·¯èh*4ݬV¹°Ý÷·pIÙ+ÙJÒ§Ë¥I“ $AÍ»S´“†ƒßà±î~£#3`è–tɰ@4 Þƒžß # AW¶jM’$I’$Y=Rg…ú¶Lu¿ý*ùtj±6GÁ7ëª,”nÔI {ƒF Û‘+êG£›†Th´–´NJ†¨gEÂt:YxÁ¥¤ê}Hb´à˺‚¦þÀH/о¡ô½¢% ÿ!$ ¸ð™­˜$I’ܼ¹ÃÑÇM«’ë)I’$I’$¹ÖHŒM«z!9§·é¤FYöÌ+ѱ´›oí¡ú/I.v½zæA}!h Çú™Ô=´Ì­ªÒöA«ð¿`‘”«Y~ŠN´0 Ê”€qˆ£XÁ•$I’$I’¬.R•ÒjÄNþ€ÂY”ª®– JÛ„·\[ŽIVB¥ÀÚŠª 5³t"ÿ–@Ÿ“w$Pf0°øÃŒe£Â«fЉz¾¬œ˜¥_gQûO5|jfb¦£˜–ž ›š5I’$I’äzÔv¥ºïn Z”@øÍªìJ­|r‘Ñ9"¤ª^[‹ÃHX([)ijJ5_Ã,¥ß…@Ƶ`CÝö€ëÔhUM{nA 9˜Pº©h“ZCíY-iUb— ºh.»Ø$I’$I’dUŒÔ\‰½æCìdJظ…ÄZ8)PçúTTGáYéâKµh@Hô'Nºߎ|r¡S— áD(Côœª±L‹ñ†?/Gãž®šý˸ë~z®Á"ž5 @ Ë&I’$I’$«`N¼’[½ÈtØ+7HæÅ·×fœõh IDATšŽ¬ÆW§ÞIIK7kôåùYEðuTÓU,E tìFÓs9ø\« ¡”€.È*Km¹ªCzÐMcÉbJeˆsà>¼—W’ÿÿ I’$I’$Y)Ô½}¤Õhlà!Å…Hv’,Ö$é(4g•®#?½F,.€ 4óàlô0` XµcíjÀõfÛ7 ·éW„‘Ðò) B§M­Æ‰„ØTGÔL: 7mªÜÕ*ݨVÿ¶ö'$I’$I’¬”^ãõ ÏW# IV…›t^”G¡O1WÑ×°!A¸®c E«Ù²cÕ ¸|”ÝRSÑ]¸~¥æh Û†vQÁ刚Hzµs+µÚd¹ïlEtù ‘ úÞ®RÉí&I’$I’$« š&µQÎ9:9¸°v…p"nCþÍê-u-Ó73‚e´>j1г¶Ø0n2 VÒ|ó)z"Ô…TD%P!äîq1fEb[ 6®ŒÂ(y I’$I’$Y t”Ë»®m9;f«U¾ÍYz Aúz¯aõöét¼,-*ÍJÀ×éÓ7ð\Öž¾ @ÝÍ è¡\ Ô*Ûc\†¶|óÀ­&]“~µÚ¬ª·"“Ê$I’$I’dEô÷ÜMJ¬ Rªm¢´ænÓW¤w‡îžO¹~wÝ/på7l¦~”áúKôÒ¨hvš’~tÃFàÕoâŠñN"µ]à·ëyÖ—ÚËMb–ùðk’€›$I’$I’$+FAÁNJ™G:£¢Ó‚ª2„Xuë¢}}-Lƒí–I{HøÄ4¸òQ].¤rF[ÙXVÀ¸¿ï*Ø3VݺSâ!UûºŠ÷¬ýbDZ¿æ ˆáTgŠÔV‰œ$I’$I’¬‚ºÜ?„œž}EX½%^t§]ÑPjG…J‹RS]ú ¢ =‹ƒ¢¾„žœJ×Ðq„OÅÅboçå*áSArÉ«CHöÒÐ…-ÐÝoÄDg¨ú°°Ÿ@rúdÿ¨Íß1€ã'I’$I’$«ƒ +4²SkU2JÝ…A-Gƒ:Ñ5&a.Πzu£ºÕŒÐ©¬BÎUߊ…]µsͺ Ì£°š4ÍÙ§rsªD—{°4Ô &™?=I’$I’$Y5UJù^£æªsÎ ”Þ¸vZ_Õ\Ÿ·ÚMª½Ð½«Ðu ÕZ÷gu]X4¥Èñ \¡Öc7Û˜„Ú¢U îaÀ . 7PÓX´ a6ŠÂ&I’$I’$«¥ ´¹Š&éBùEÁü{DÓ„£Š9;’›¾$ ¾tÊSgÇŒ³kôÓëõ,ú{ýTõI¸w§“ÆÌ1Ãø:˜±ÖŒœÝâ©Ô‹|<” åºÒÜ- Ú_ eü&I’$I’$«¡‰·NN™uk™¦2R­_ìT™VI5¶œ€¨ÔMsÉNó#—”ʦõõK]-¬€+½ª½F4åí|¨Ñ»È¦‚ Ò”“lTÆ4¸|F5u O0€ 8€òΰ¢„çX¥å»k©ï$I’$I’dÅ,–P zyôâ¡B–fÔ¥ô# 5V¸DUÙ¿jÔÕ5¢ù:0…2 Õ­ª>?n °æ³ö3ˆ^èsI=öÙ+V݉¦hÇeÀ$SA H¶ºÓ^S3kr¹okÅ$I’$I’dÅÌçŽôÖˆ© œÀ9)H€,½±Y‡>:¸«"‘´6.œ—$¢¬ga@ß …R>`°¶•¶H(}°6 4йwš+ccì­Ðkeõ]pÕ’$I’$I’=RPº§’GBËéEÞ¼Ì ú*xÒ'P2²€ó’1n÷·¾½—YWž É`iN„PúBsÕEC‚²RÍú&†ÐuΪÚÙ´}—JRI’$I’$Éj˜×V“'båÑž™Zy?+Œ‘z-X0I`q— ÷ºê†3}‡”´ÈF YQE'ŠÃ…šÔê> ªÒª¯˜¯·j#z™„ù&µó%I’$I’$+Ç3G ,ÖÁSåhµgÐóT%ÉZˆ±W•c玻jášQI©! çU]kÖ­¢êÀ2–÷¥åc¿-hê“ÿˆ¬ƒiG³*Ú¥JÁˆ“êf w´¨V½ë`wÃB{]Õñ“$I’$I’Õ@’%±\kIHzko¯<„êºmÞJ²r }ÇÊØÉDIê°ÊÖFèÖ%r†¡0D¦)``¡Wô#Ê!êr©6~ºIdšqp€?ÌÀÓÀ8Y*»¢?Ÿ8iLÒ0’$I’$I’U£«J’nЬØmmÕ;õº’€7¹p”Ú«MU.°`}˜iȺÚkĤ&v- ,)S¤4N„ºm÷c¢|=:ׇ±ŠŠÔœ-6o5ºÆ77ãÄ;ÐÔì¨%I’$I’$YÔÂþ^­M–'MÅ_Ð+³9•©“~¤w¢ ú£Ês¥·£`‰¤ÁH›zÈÁ4¨îçÃCà†%C„ËúÃâÜmÂ`(0‹§bš€¡›ÑX¤ÔS!0(N’$I’$IVm†nu”aЂЮ»Æå¡Ëg]BJÍ•â|cÜ©q(!Û‡Òë ¢¥ôâo €FÝ¿P\zVåku¯ó<Ùù̃°ðZ¢JÃigF„Ø'O¨ó®–Q‘$I’$I’¬é«8êoÕ›×Ç}ðHÒlªkªðzF~¼±œ©fÔTÒ±‰=!XãÆ|³ZòñªL¤u-•ÿÐ}þè£á­?‹¦k«±êAÀêZ®nN]– Xè^%½zƒ~„Ã6D’$I’$I²:š¾ªšÊ÷PÙBƒ”åŠô×È(„`FŒ„bm£¦nhtVÒŒKÑ·„po†QkSŸ0DAÓ®qWóªFT µÍQÒÛ `lx®øõ‘$I’$I’¬˜¦ºªÄ«‹Š€±îëëI¯Óõ£öc®Óxz:jcb?§ùÜ¡4+ëÂ|Ebå¯Ö:Ä£­´Ÿj‘`•úIgó„T´Kë@€ä` º@ô, æÞ  ±il»T ==ÿ$I’$I’dLdbH+Â@ñ2e¾ÒâÖ?áÒ’pm”®Ó|ÿIë\0›OAõÐþ¬abµ"¥¡IWu¨âÑí.‚éÔ«+µû\º ÔL|0‚Cï1®L’$I’$IVÁD°µe¯Ø&¬2Ò`U)ÖäUÄÉn^ºY ¡rOKª,¿Àx¾ü9X¤ù7L 0` @­í pƒt0 â6?¼f¾¡WhwkÄ3 ¤ÏÅ ê©—€¢­xÖúµ$I’$I’duU’sM| `10ß/*·æ×Ù1WËõÈš Re’F‚Cgº;w]Û’„#0ž$õⳊªú50òº3_ c[Ú.ïÁà'¢ ÑœT5«#·"€2šu’$I’$I²R$»|S)±¸aîB¬“ÖIÒd{ €Â@ÝVK?$î|cºê$—%P—÷0÷HkfZYÖ.͉È!muñƒ‘œ:?Ûz-TaT*¦[M’$I’$I’Cº ÕWlŒ?ZôÞÊUqµâ¡^ü‡º5‡Fß—jwDŽ(@WÍ-ðk°D˜)Ú§£öç^Ô­—2Ó)檼Xf.¥«AÌ^òج=2€„Îb$sÛ¤ý2- K'I’$I’$+A"ÍõX‘póÜ„AeI/¿ïÏ‚ªÒÑåbx3¸t”°î¡¯ò‰P® %_­ ëÈ1­Ó^"ŠqЀí ]€¸ÛßJÃ!ö¨M°"†7«\í ²y?ªc¤NºêÓNøzÑm“$I’$I’C°¦‚ˆ–®‰.uSjReªf£'»ª{§9ë °¼R3Ðãc»èë2ôí! U^Òrª^J†YšfÙû qÉ”€g¸ºzî4hÿ˜hý`1"¡®€çõª«ãv“K’$I’$IVÁIFU”P`tÍêâ‹!·"#”:%Ö‰4æZNZm*$CÒ.«“å¨k°ÌËá•KP픘Dkš(ÈEhþ»#,¦f.x'' €‹ ›$I’$I’¬†^bµrUc)9gP+|™Ó¨jtéI6{S»¹a2ïs‰l™f61ˆ»òŠ»kšCO5˜ s“á\W3Mz »}:I’$I’$YÄl*³k«Å §®,ªIÚ•!58ó÷0¸Õþ¬#æu-™®}Âx±4¥ùÊyoó,L%`$= !I’$I’$¹žQ\Ò0Ò—ŒÌשBëB™Š-.„!—3X)5é@ψZ„°š†[Õb[0µoï¬3ÅVu 0ú]B{ƒùÜÔ±@Æ€ytÖ›“$I’$I’UÑç†èb•§fC”½A·â ƒ²53ÕÑ…_iêÏýÒHr‹ºN Û¢,Y(ˆ¼R€*wÐóYJA{¦ýƒ?²5LCe×sn^]ÃöÃÖVªžQMÃÀv*Õ )Ë$I’$I’äz¢CÈÕ£x@i§¥Ö¢ØL«Ve÷ؾÒóX¥9#:i.DÝñ"úZu6ÿÆ’&`´úàV“^…%K«+=ÚMM¤¥*>jÖ'61ƒÉ\uU~•[OFI’$I’$IöL¨¬VÀ`ãx§t—èíÙUHÚšß‹wªWzºœ”r„¯U²QÇÔ«T•ΰä:²›P›±Lü¡ª%$¢%“ Äʪ˜¹¥ÕMª;aˆáÌÌÜL6ÑW¢Ã2~’$I’$I’=Ó‡7áKqÐÌiʹ !Ù4\5ëÇi"¯g¾¦Òš¢ŠK!IÇûTÁT# iæù¦q[?) 0Ôs ÈâQÒEŠ03ÜFfÞÔ twuH@¹¼‡I’$I’$Éž©K¢ªÌZV°v Xìѱ«Â®Þ—ÒôA¼nèþwkÛ+ªúUœu¾ëhޣą¨ÌóYëÍý‰;†²ïÍêyuÙTc,íª•ó.“$I’$I’£|M¸x­2kô@4->0Ž×vLC•%Ô(lŸF€eäÝBW–|ýþœÁ\ȳÀgäúžÐªEa,¦D"rRéßÑ·"mÚ9ôÊð†Øá+Ö¯M'˜$I’$I’ì™V”#êÝë…¢±b<‚j€?*˜—©ľS.ø¬e¸ú\ädReš>Ïgc¤&ͬ;+Ù>[í ˜÷_'¯ŽÓÓ7]"Ô&?ßj–$I’$I’¬º×•!ÄVè$ÖHÏUAIÿvºÔÕåQŽßõèvÌ×Ì#›²œf1W²{®×w7ñ19IÄ´Æ6j˜\ IGvjU_µ~7óL’$I’$IÓ’T Ô„Ñ&ÁJ2§—_U¥í™•Úa¥ϰDßÀUÇu?¸¹?Â…£A/š¹$iÐJ)U˜Áh Û žzKÀ´qáÛzu™­‚eQG3ÿ)ƒ$I’$I’äZ 9¥´Ë²®î¼LCH.“†sÉçå‘xƒ6bõ²:-,Çžû!ëFƒîFxvI‡1¡ZÞ:Ï.¾K€†AWÄÐ2t•µZÝèöhÉFúò+G9Š&¯ô¤’$I’$I’)$‡úÀ€nÖXcÕ²ëËNê±k¥y(Ñ÷Ê ƒ^Ö²P~BìK°ø9X»g)t#ëK”ëä*}s½ïf:3wûgU/í¡Vf®h#ä ›ì’%?Ôœ‰E9I’$I’$Éž™<0 E àÛ ªÜ”…a«x“–s ™•zdµš©Ã*]Ì|i·“î™°°cT²+{½Ôg—¿3¨Ù @«7 ?nkápI’$I’$Éjijl ý{y"žX­Xuè0ê:-O¡_,;ÍÍ95H^ª4JiÎ.îIÔX*$N:ä§ ”jÄêÞ#«¯•”QôÛÝé$I’$I’$ )˜U”ß+_ sòËОGÕZçÌøŸØtæÛù7Û¡nô|ÖÅtkÿW9²÷—ñÃñä'³ôVFœuÎ I’$I’$Ù3É%Á6ÏœT[$¾QU[Ъ ³m‡ÕàÜ{¢e^³j&˜–ÅÜ&OÒêcª#è©«=ªê‘“ˆ¼rÁUªWÁ@–9‡I’$I’$É )ÀàKþ]mšôÚuÕi°y\°FaÕ‹Å.à8¢Ú/aÏ«²–v³¶I·ô§µÁ¤c^µmðÂh–s]êiðœÙ±#C’$I’$I² HJ°reëöÃj72Л˜VcEênä%ªÒ›w?=1gì‡3³vv„Ëè6·€4 ×a‹¿À  ±_«›´àk;aÂ;ÆÙýi$I’$I’$ ) 1“HcÓV.­jrjÕZþ“01„±d^`4Â`EVÌHJç ˆA‘]# ‰HÉG†í£ÕQ`݈½Ü¬ÏÁêÅî¤ÜÔkœOêî^Öõ Aókcâ™%¼™‡[+ ,ª^P•$I’$I’ìê¥*. t•ª¤kH²J.‚š,é0ßã•A3u4b<\Xø·ï”À$Pý@Ý4Ô0JiXKèN)Îä¨ ŒÒM ÑߺŠþ,ƒ±vlÐbGƒpU3eGb´n 1»ØrjÖ$I’$I’kAº¬’&+hòŠq¨@h‡waÀ: MN]f%˜Iª’ Ù ¸ùAç20´DV3ÏÛŒ¹p I’$I’$Éž‹ÁJhЪ78 3«MókªF®F ÀüHòÕ”Ÿ³RugèÖ`uÝÕhE½zÖiµ3êÔB÷ÂÙÓôýY ĜɗXNž.°L’$I’$IöDäeN¤e´J3vÕ6j[„·.i“*U¡vC8ÓÝ©ô6$º|ÖV `QßÞ,¦QÅe¨ò©í'Øw#¥æi¬húÛúƒ¹y&I’$I’${f]FTùÍózhPd²r ;‚œÈ¶e-Œš"¬Ù°pÌyÍj2Oºu¨¾£Yy¸q@Âí¸§Ú—^£¹ Dhêyvc&I’$I’$׬»?u,Œ3Ž*$X úò%@i£“c§ò* Ý´’´„ ˆM¸Ì¿ʵßü^WS‡@Ó’‘’ªe[æÇã&…Ëj¦Z™ÅJ-uÐÍ(X4$I’$I’äZAÐàªRcE'Q•Ú‚#óÌN•Ñda%ô¡3ÖuNs×Ê4Àµ* @«ªB_ËŠ—¨U†|¬j²âÐ4/ÓpëµÔÛC¯rYŸ»`¡¡ãZ©CwÍ|UÛ@Œa3Œ³e“$I’$I’•ã:ª Æ*¬¼Š@(>ÀUZ“tªf}ñºÖ±ÄÑgTqW3|ï¨ÊhÀ%ŸU7…(›û”ÇÐe(€˜%á³4RÁV7õSÒÆÌw½2WÇmdf%bÉ€ÅÚºv•ì³ï>Óª$I’$I’›3û®^Þ4©·ûí`|%ÔA?]TËt¬(1Ðr¨gç²ÆV[Œ²×‘bI;©*dÜ5ÂZ;ÉÖ}½4@ô'AíYåÁS(6:t‰­ý)±ž©.Y„\KMpkULó¡ß•°aýúïlÙòýk¾?mX1Û®Ø6­J’$I’$¹‘Øwß}Ö¯_?­]¡F øÍñyUYå–§X“¸ªÛMÇv0o$ÚóÂTQ˨¬bVOOP>'¹2sí;°åàºòhN>Žºè¶¿ÕÀª[oÓ$I’$I’d•Ìæ$ä òú€óºÖ ‹”[53HûõµaZçf sPE­5}Úÿhc„UÜj¡ç²²•NmÛ]‘Å´vÊ\·$I’$I’dt:Uçí–eÃ¥{ÒlsjqîxÚâhÑþÔ{/§Y[ÔÓý…À€XÖ)tª²?XVÔ3ß)Ö .£ëâé«Rõ™áš$I’$Irm Š‚ƒDßßæ Åh+(0¨;=-«»šo¢,;X¥nrR}}xUüE³›ôݪ"]V³.O©gBj/÷Õ™ÛZ¬®ª?7Ž„|Iè [èvH’$I’$IV‰™+,Jƒ-VVƒlZ,^ h»÷ôèb.Þveõ‹Ž 1:ÕsnŽKà Àœ–•Ķ—áåÇü‘†–c}ü5ÎJã:‹âÌ ­å$I’$I’d•4Έ*ñšsuI©6×—CÕ]}ÔÐL±J€¦­:íÖߟ—|Œ þ {ÉØv‘ZÀ aD`¢[³ö®FnÇe–™ú– ivkÍ\ìê¨ÏÏU OYöl’$I’$I’³@fýmnWqžBàÂmŠ ÁŠNå©I°MÝŒW}ü×]Y15k“ì5뤰û²¯§ª‡]€2WGöqP·*ÄL <Óu·¤‚M’$I’$Y5M›úVO@ÈÓ pmt™­Ò{˜S•cL2qÉ(`„IZvñÝ4úç`Xx&c4uÉSŽÏʼnNö‹V¯V”¹Òá’$I’$I’kƒ )þ‚ Fo]ë¥gc%—%d!ý¡¯1EI§Ë®ÁšŸÐ2³aœfoe³6fß{ÎÓüpú›ÝØ%I’$I’${†j Ó¢8(Æzlá·˜kÝÈóîdÿØ,u—ÆZs·t†“>ËMn2°yªk_µpÖÕwQÜ$I’$I’d„Œê¤ª„`m›WrK± í½z·H«*t6?bÞJ5«¦0­”ç0%uKø’ÿ˜B\+½¶9–‘½Ëó‘ûØ´*I’$I’$~øþ÷«åúÐÓ_ ¢R¨“:.f}Bè¥ËF²ÁüžT4i»s<†¹`´}oÿ¨8lM&rÒ¿gꀵÉÁÕ´é<Œ@³Ê‰ùu›»xs<ôÔùÓK’$I’$IvÇÖ÷îÂ¥7ªj2t· PÌW*å44k­éǬ⯭½Ÿó3 ï­Óh‹5ë2ŽFÌ+tÔŽÆ&ªšæƒ4«éÄ¢|­¨ýh¶ì×í¦¯Ô¥ê/¬N'þC@ Ð`0£÷8 I}KëŒ<²K#zâLoÁ$v{Õ9;ç͹²z¾cT©ùG•-ô÷Ì¢K2iãІI=ÑYFp@ï½M~¨1{ýW‹jósl-0Œs¦3€nû·þ £ÿR€Þicæjê­ëŒAÓO©>à­wRCü¾Ä¤9`WM£éÇødç`&ÿšC=cú¹Ý!±ñ.È F¬çÿMÒ¯“WÐýNö›ŒÄ5Ô1f¸ø7³â¾¯XôO.:·"ºÐ!O²©ÆS¬,®o}Œ'ççë—^®Œ/— >3›ýÂŽÈõШÿÐFD•þdÇøØÿ;Î!‡ó[ãÆˆþÏ!c (0Ä{°3¶X ÿ k—bÙ_¹Eç½cDôõ0ÿeÖ¯môÕAÀ 0¶Q¬¬Üˆ©¢ý¢„>¨Ÿ'0X-Óüˆþl©¬³fx\ ®*àÿí‚Ìý ¢»ºŒ·ž~Út6# `XæSrþדÐûŠ0`è£ÆÁ D!i0X½’ótŸWãéY‘7ÍÔÙôËìÿ>ñkɹÔêú7®›R-«mò· 6-rÜuü*е#`0wo_/O™¯Zö¦ÃGYÍD¯Ž½ù_Õ1zGÛîrÚ…t"uÎÙ¢˜~ãà¿¢å,¯ßr±ÍÜ@²;å9c}”µC¹žÝÕˆ @ïj[.ø;Ý}j×Üø$.€~Ô›­#tÂkú7Þ°‡K\§„j@Ä/68 IDAT/é/Yß+®Þ¸j™Š©%4óeqÕl­Ðÿ;,F‰þ—¹¿-¬Õd“´ïÝÌ®Ñôr­?9¶Í£æh£*û«½ÜUzæ‚ÙÔà3uú•õŸ£ú©Æužµ¬Ã±·¾ç«Æ>ÿoo_°äJ#—ÐÌicë£Ãû?þÿoz‚ € ,©ß›ÙŒn5 È"Y¥jÉTÒÐÏÊ%^úqJd!²¬¨ˆ#Xµ3ªæÑ°µIL/q|ÐRâ€!?9›Âê¦Ñ_,סtwLKŽÃ=pÞU;óv¦ ”OXò¨)!W®˜\”&·Z6Ñü5/*ÍY$›;`n¾»e‘‹L¹] «;¥åV|@'wƒ-Æ;ÔâÇòz½ðÐý¶ ËÐ [|“2ÛöL<€c/w1ÙS=÷;o1ëüÙsÖ@-#ÕnûÕüÐ' òH` Ë`7^¨É¹s€Ù3ÅùˆjºÓ8Å„TI.Ã&ÑN­!½ÂÿÎY²5ÛLVÍqÄ -21f€{_…£|:[V^^wF²Ç¹èȆÝP)6^?/¸³.õ¢MËPä¸ú“åò™j*&ÛŨ:d‡˜šÁV•úÝ¢qeœ?Ç৬`‡û1ÄmÍ´7¾pÈ™ztGN‚ícXüV ]s›÷uyd§ÇÝ‘°ñ^'|*7k ¥âpÄÏDªª(ä„q{g» >esêáI;A§d¶ yÍdyÿ,{êÉìûíp½á·Í@žTË`Ü¡1¸¥šÉÏoœ¬¤]Ø'GT"N™7ÆCa£¥’ï9'%™î:nNü“þ.3ff~áPŽáà%±(Ĺ\µ…“ë¢=ø»J²ád`–?w?ÐÁÀ´òïšfjÖçÄ<ÏKjpàåp’Í÷+{Z> {ùÉmä´ò¤XA Ô Ìäï8qH{ýÀË#ür bc"¼ËäÃ[~a§ ÍÄdÃaÎc‹ÞÓêSˆ>©V«y/8ÆÞ`ÖwŒçnX=’úÏئgVê>$ø2™fšÍ$Çí0è´K4ð§¤Úý³®b‰ÙæÙƽÃ[‡rûÂw©]µf’7Þˆ±Î0™¦²9àqW'Þø7âQÞÚ–Úš%ˆì:Gm5q ¤ÉP,ÜžAv¼ß(#îóx˜`5È7ß[,îyMy{¤‡i–㽦Váå€=ÏÕÛ¶Xqchõ”÷ ip›A²îqUq5xX ¿—!‡žT59ôEt¿I2FçlV͉AkÔêËx VÝ’”vB·ãG5uDÔ:ø´Â”ßgXexÚ»ÀPäi‚Er•z†FA§@ ß—î¤åÜ‘Oì’B£Ê™,å,0‡QŸ6Äô DM°œÊW“ŒqyÆiºöÙÍgMàG”boÔ¢J‰:_v.ÙФz[4=IÖ 9€™ë•À¤ªiÈ9è°¼”Ÿ±Œ*ÃâÝK¶QÂ:Œ«LûQ–$´1_ÁãЭBEãZån¡8°Hí™– ØRPèCÙC;ÛWj&EckC¸Žá©qå3vî& i|yL?8õB†»¼³aÞÈôø%e»¨Ò¸¯"¼hÙñ £ Ÿs;ÏDÜt$™9q2!³2ÍÌÌb#¸ê<E;ïý/ ÖeWp;€bc)tÖÙ/S;(t÷±³¹—ÍöEüã°:óœ™m¶W“Ž£|ß¹®¡»\„ëpk>-ú»Øir6?P5àĶà¹K.äMYǸ¬´Ï@"ÒzMñaî‚èеª,³Û;D—Ø«œ® Žãjâ²0hvË#Æ2^:y̼խ"ÏK‹ß†JMõÓJ¢9 ¥_q¼EíØWë7êŽE J¤¡p€ÿYQ8-^G„U?îg÷f<ÄQ,š¥cÆ$ÙP­-šÔt}ª2:ÐßYevyü†‹n×róõŒI¦þ™ãÃô0#͸k é-Å^/ŠâÐ ©:Šž7KOK¸Þh%8Êë¼1wþ#[ T`³ í(Zßi9V•rlªä&Gí‰‘ïž ÈØïæ `êeìkÿ¤( ÖËGåS3¦*6´ðÎ=_‰GJ"Àú‘Ý1ö*éÀ˜¸V'û ˜Q¬âœ‰ÌÁ–¾*ø» mg£NW ŠØðPݱ+ˆÇ5ÿ3d­‰¿ÚÑùúìlX UÜߟ1¼pƒUU¬Íd–ÎgbøZMQ¤¥aõ@Á2„?r>‚´Ô)ô?Rïçÿ¨¶ê¿ƒåñNï!ü}»F‹ž¶sõjÈ ý÷p áÑå¶aEÎËëoðe_Ý©‹ßÂeCyÞp9?2ƒ ü >;v 6ZSœ"%3²ô»<úžI #éÿwÝÞàw“Ï´>âfaYëÂû(jb¥?­`5©·Õ#ðãà¿nä/â;bŸÛÚýÀHqs o”ZYBÐhJ§fK 54‡Qv /›c!Öf?Ƨ®9¿(ã›çY»¹ÕV¾¢Ï¿Àÿ»ªd'büÀ–ûHM3ö ¸ާ¼’äåF§ê©SL×¶3Dý:U°­EÑÀÍdêòòeÂê¥IÊrñ1à=3Û²·èXqÌ-RÄR :“o3šòj¼-šóöù »‹´ÖBö%(ªDµt$x ±Ò¬§Ü˜ÃÿÖ㈠þÂÊLŽJÇáþPÙ8%‘)÷m7訋À²üB¶ˆð±°#ôí’ûŒ¬a%׳ð Gò²>zlâéÁe¢Qu ²…^šTàá¼›±?óž‡y7뎸ºOe‚­)lèsÑb’ÓûqÇ2Å?ƒäýÀÉ{‹kŸÖl·8¸Ýuñ¶Œž~s«Oi¹µàJÎ9yHõŽçZÅ~ͽµ­)b«ùÃ>ëûnoUM>g²ã¢Íœ:Âò>gû¸%|ε…²þ hÝ€ÛÝXèzÓÁ4W'•ÏÓýµ e´Ú§¤¼¼“œ‰ARÚ°/ÓsŒdµžìÌr~H\¶¬=˜”¯CÏ68à†l§ÝÐFIÏÑÞ°ø¼gEEs³Aœj—¬º-™#*XÉuCåáå‘­²{+@êNJß1Û‡¼ìòïóÔ;m³[9Vç…[Ô#¡ó8¹Ç-!Ó´¿O“ð³å®¶ÚœÎhfTºàü}æó´À‡ê„Í9ŽG|µN£&ˆ·õ;¦¢Da9çmJÜýc\²5ó`?O|Áp$#¡çXT¨Qc´¯³ãÞó:¬ŽÔÀÎkCÁ­«FBnÊ…«Â§ݘd¦šð€Þp ÞgÓj~TülÃés|¶vľöûEóÀÕîïú¼4Zâ‹ÂÄÌÁ׸Ú_¯±¥Zécˆ’ΰ"Áƒ'Ò´"ª‘÷iRÇÑ´-8°-,vÅ n'Cc¨¶¢ì@Ü3üÄÏoŒO¼Ý_#õ[©9™©Tïø»ÒÄ?š×jsLÆwaÒ¼€ƒ[ç µ–=‡¼ ŸôwE·å0]%Œ÷>â.À¢Ä"¶=XÑ ®ÛojG›œñ¬+DÙóqU“ëéârà †X×Ë H³|ÜPöù—Þ¯PUĵ]-ìbjAiZTß¹W¹ê+¦q@ݺvüÚ½¯Û¥T„-•« òžÐâ % ü@ÿæqß…¸ÔÊ@[ezÍ}ž¿Ñâ¯â;•_˜¤U(ÉCí.ß¡9a,rÂÛÕõ@³`ñ0¶ß@zÓ˜›/Bß]y ÁSíµŽÐä ^ 'ì!"n˜O~×Gèg¯ 6QË»—C,·Õèî¾õÜîñœ2çœX|Þeœƒë“OLñ]Œ7ì3‘À~q“(½ØÑã ð­å?&‚–É“?íÒ4±'$ÀO¿G~A†#âr*æRðio$‡;P›ß3rßb}ÃÉ1’S9²u´²úkÒé)•÷GêCõtçî”Õ²[TÙ_Qvâ"C{ïç Ü"ƒÃÌc Y^ª½å;ÒÙ,FËNû„uÂvyü'3Þð“ýþý Þéï0¬)©Ø4!æ`[צÔA!­ øáQû»Ü”}ëå+¾˜IÏ'é!y9 þI·ÊÇv€sÛ— «ÄÃ,Ð./ÜÝðŽ}µƒ÷Pó·%%±Ÿ1ÀתRÓÍ‚±‡¸šŒÝ’³³‡xŒÞ å°ZKV«œÄE’ˆÊIoÓ8òo¾5‘^p"ÜA³×>jvû2œF\Á“™fñAa'¤©_afRͧ–o¼ˉ ¼8°Î(÷m¡ª: î¿ËLÖnxõó5¢ˆá½ˆõr¾ìðëÚMi<­s!Fì{‚GÖ8µ×‘ÈÏ~ŒtØi,”í½#,×S1áÀ~"ç%ÖW¡£†ùV3r«“a-K êÏ»,›Öv, £òÃ˜èØ í)ß°ya‹ëy¿pKñò s0OD­Å þ-|"Q~PºáÜ60_âwH|™œ§†µÞ9Ëì×ø 1ðÎÕé¿Wÿ“çn\3@¶ª§¾íFNX'cÄØ*õà¸×ÚNÐ0⬛vvtºRÉ?a}Q­Dý“¾ånÅœ)Èò‰K?¦¯Š€ìî˲‰¯êšñà8/ô[‰6zÃŇ=²Ìž¹LÎß4ÆïsEw%Öd} fºØRwWcŒ~q¯²*×3|ÀރϬ÷J6Àßà;Ô±ThÅ•Ù&Z¦¢§ioH:ë_+Gf¬Ý-Pç%‡lÙó×}¿'I-bjö…Òf&‹ÿÔ”KÙâ0*À,?:tŽOª¼öàQ]Ïõø}!ocäÀÚì–¢ºƒö©L…âB\Á(J'^û£:ÃÐܱIž ^/U¥¥ÞðZ;@ÒL|ÒHôŠW³cëBÕªšÇk;õÀªºÕo)–èŠwÉá<ÿ©ãä»B\®KdñÒLñÀ–ƒ…RÝ´ƒYÂ;‹„æ8áϸè Uîµu¸ÊÞÒ̾ŠruÚ¸Þ;À€¸9&Ê#£ñHä|\Þ«\“Ï„|ª …ÿhô0'Ö—Çì2…ã¾ZîÛrhÌÿŠ.'î£TÞõÂâöáä+mžìm,àSmösºÓ\Œž n«»aMéb’>Üñøý¢’›@ ¹Ý£gµÃ™À–ß,•-;ÌÛ8CÔ¥1vGä@ùÛ‘²<{ x!öÐý2ø³S3SªGÈ C¬tIC—››k´ðÆ*µàpý¬+õ~++VFº„/p„…x/Sçd-ÊÄ S‡¬ N`*?å#œÎÿO§ÇnÖ™ÜßbŽî|ÃEÐ8†cû²™Mâüë"R>]PðncïíÕËŠÆæ@è¡Ái!+ÊšÇ/e/üÁ¶,ð^îõq %OHàâ€$Û “²Sìm(¡5C߬ѵ­€VMKè Ò *ÓBœÉD´¡a¹êšC+,©ÇD†˜0ëé ¹†³S’¹«/¹Ø#¨ÕZ÷†F®¥—…¸FGnGªê;¿ lÎB‘W›GTUˆ/² v¸¨§i§—8ËÝÁóQ¦…žß|]–З»ÓÊ%ÿ+ü²¦ˆˆ–Ùª”ÓHøq ®9´&õ^îF¬K®jí©§¦:[¢æ+GfŠ9%³Ã5¾’È0x§vB9òË ábq±:hªˆåZV¤FŒ8¼“)Òzdù(\ˆ‘òœID!¡F»ñ¤g*lZ'û“èj–ö=€ÚÞü\/#ŽÅ:ˆä ¹÷T—‚2\e†—A »<ø€j‘ë¢ã²p²ê•:rÚ » ¶yh,‡|To‘\² 8ÜÌ4ßuVÓ[ýV)klÇ8‘òZåðºàæŒj(¥å¶…o,?ÆÒN*pîÁcÆgÙF'µøú(Œ†ê¨æÏÿ.º_29ã=ÁÐ6‡Š54žÉÖ4çÔðZ]8˜„us#Ê–uZ†ºá¡cKµa@-º«œ SÅÖ•.ò¿ÇB²%qq¹â9ÌL…k­¢øÕ wŽÚ_¦ˆ®÷vë¿,#“ÝUar,’,v´–|jéhë[0‘îÐKˆ*ÞcÁ-G4=šÑL0Ǽ ùzqlˆ®•6õPdòË*“mðÓ‡Œ2ù^÷|´%çZN«Ê¤É8L9KQÍ8Ü@*/Å·:šá:o»B©¼ï°|u¸ÎŸáeÜPoÐå&$vA0g‘I÷ØwÌáTÓ»#XU=û(*™¸X8nþr¸ór˜–£Cüs'ÏG²ë!Š‘‚È ¦ÁÀè‹x¾üõ×þŸÒûM¨³ØUörÆ| l!•¢ü¤i–*-lÂÓËFg- «"ÜR7öß®¬§Jê€XSc·8|ÌH–Y×Ë9Õ,XÖLË!ºÔ™NõE¼ù£¹·g9ˆ®Ù´ª¤;­„ ý0f¼ÙF\W =ŽN$<-H$”XfÏ&Eç/[zÚÈ]f6¨ÍØj ­Â øØb,/³ã©q„µV˜±.5Ú."=ä€P5ê8rOÑ1èÙ~ݰ§'µ€X-v/Õ…]¢8ýzí‘§r½âÚzÜëÆƒ¨p²PO.6×ÂÿLNáPväEwgž} ?µ ëã?¹„¼?ö£-¶§—š–^ùˆ¹ *3ƬtVìæ8Nõv`ÑÈåR,mŽWî¢ÉÞq¡»-êþBTÆû é(ªóµ6.l`ÊG^¯ÁêÅo‘eBYæ1VÒ:ÊsÿaàsêyOMV²P„Sî@69ó¶$9àJbÛî'Å“êGTóââ’ ±±Al¸Y60zÀÿi³8ZÐÊš¦EÉ%ç™°¿I㈪¬0P}мì;Ò g ‘«ò©¡@7$Ìu”ó`X«‡ßÝRÀ¬ é*z½Àùïä¼zºÍª©ïdî†[B~Ž"üGf’£Ó¿\nóØ,º=zÇ)B’¥¨ÒrëGŸaÂNtquäº}Lňi×ñ5hóø–†à¸ü®m,CŠ´w¨þ ¤ G&ÿ¸“ÈÁænÇo‡×ìõùÄpªppôD9†ýËA¶ÛÌñ6‘Ÿ¶mòÅPµ}$þúë?ÿ·N˜tíôÏ-Ö:7w~ØæœËlˆ|¦@ÿ *DÙü©‹ÉÙ¸:ØÛD;«·ÆË²!FMÈG [ç¦S‹›=ËÔ„U·N´¾âŸ),7âÑÅÛh¤÷osjõò õ¾@Ëa€¹îU yÅ9aM)ˆf£½Å0±èõuo¸$ržïj(áÆžKTŠ×^d)œ üA£ÊÊÅXßÒ<XÚÄFõ3j?8Ä»Hö¬fÚÆ€HH\á…Ð<íbáÆ² —ÅØ¦î{ÄæWäšÕ^°î½pS8*ÿcî)ý™¯ÑÜù¢q,y]3cXœÎ#:—ï1zk;X8O‚¨OµÓù$B‰^ÆÖÎú‹ õ¦\ UMKÍup\ÃQ¥ÂÁX¢ïão–C®šo¼K’uxF”­/QšÇÔ-XþÈш|kØ·aXk}É/A=`.ý2ôFXÐÿÁ¸ÉÑörÀܱv*;išµõÈ©³=Ud÷M…xÆ"…_¦ƒ›$–sG¬p.üí Àð—6„)¾S"‰ÆgÃŒeèõnâ…SfÚkUªm ²C?°Sá§ÆÈƒ¼Y怣v°í½TcÚ›ÖCÄOQ]Çã¯ýº)FŽÜxpõЖ@OG¡ê|†Ò×-謤ñÐwY\»•…pÜú¶;ä¡ð=’B§²^°’ÓƒRÄÛ¯ØVùX‹žoÞPç`V„9tgžÝŸé%¸jíÙ'œò<ÖÛ…®lX‘æÿKí<˜FŒUþ=TC*—¼šòC®$æ«NoÞb‰4O¨o±æ·àó¿#˜Yºk^è ¯ìæM€L£°s Ý/RGX“è0¦5Ùô]¥¸çÝLQ#Æê·[ìY÷Ô ý^›«‹²ï‘w7O¥¬Cãõ޳.‚j…Ñ6èì@ÿ\÷?ˬþgŸÌÚÊ$ùš;ü7hßäWqAÀ#ƒ>=Æj5æ VfMÃdÀHÞZ•ú,¶ùèŽ<uw@ÆÉ“¯äõ^MéÄqÏavý"à1mvìbÊeyF¥Á–<´N ß!×´xÙiú2f\Àoãœæ†´¯C)€g™Ã{bW¹>rÄcù}ô/‡#>œ">vÃÞ¼ðr8^xI°á1F~Œƒäã£\-ê@Y`YhÊ8€µyЩTP¹ŠÊ“Φû”=uø[ØCSZ9`üðÂ8_s Žji¸îs䩆ÐSù˜ˆR**Žè¿>÷?ƒ:á'lÁQöCé«6X³m³¼ÖfëLYQ6†Ö¤¨çÖ±ÌWš ·Ü W=¨çõO›=C6”ËíG/L÷ñê @ß¿ HÞàÝíϱì7§€}Fè`íßüdÓ¤‘f­ôýæLÂÞ¬„RHa:ñÉú¸á÷ %ÉCò½0 °IÍŃÿ¿³„†š•x+ŒÐVé½ÇXv9à¼kÐ`qò ¥ëXÓcÐŽv^E㽉¨”מ‡ƒí·ÌXÞÞ:Ô²ÐØY;Í6½$  k‡Îî· £Ø‚hHÕ›™ã7§3éÛW7ȸä*= »t©.©/0z<Þ‡^SlµêÆHå¾õa\PôX0`¦g! RmWúèëŒÓÙ½°WŠùŽ‚`§|T»Ân„ÇhËЦ®Šö¦@éRãëÃkU¤tl‡L<©Pc”¯Í€>Ì|•õ™ÎÄÃL]ÒÂy“)ÛgRòË«ý­\ØúèPnÔZ¢wÍ<¿ÄÖ¿?»Rò üÞ úŸSËã»S¨Þ@…°­ÛmfçŽ2õ&xYͪ3´¶l~—­ÔŠ´ÕMèÌvß5þcxppšc n&7ì~‚4 åºÎéñÉ·`§ó—™!¿SÀ{?ˇûÃüÉéÔ ííï¢m›r›F‘GUóTa]y=¸Ä^"Æp•e÷Óäb3ÊÇ +Š fUCe/B§Ý£ïHzä¡»³á¡ÆŒÒáp¼j-pÀpx˜0 žg¸<¥0ÞM(ª¨ë ¯¾ÃªÉã1ÌZ¤”8ßK±•‡ð@,;ð–Çð€ñÙ•éýÍâ­üŠaD'`Ôg2~§aDã}ÊêÐæ†Zy”…¢z¤·GqÃá\˜° ±A’†R:6AÊÕ£*b¦Ý›ÓÝxÊâ 9k´  Õ»@]¸²­Q¾Ï™Ÿç=cÛPÊåET£2(9¼v¢QF¹^/žÎs½Ë’Äh¨òÞ¢¡ªžüzÚäÁòŸcpE±XÜ¥¿XýÁqªž“s–v|It gSýhyœ;‘§ø1O#9K/ƒW?À´c\fá¬Kïá{@¿84ëý3´Ù(§U”ã¡—tžK6t3“žö SX¬?”¨mÎúvV¡Dek·c–Ijøø„H‰C÷¾ÌhàÙˆ'û¤<:þÖ@ƒËa«sÞà)Ba¶Ôýdú(þ5H¸×r>8|ÙMÙŒµÌÃGhŒŽ¾ŸÛT/Ÿ)-<‡ƒµ§‹wì™›ÿyMÓúz„»&R†Y Ykâ>âsà}üÏpgk­ìÎÕdw÷èÝ^±PË€SJ—/ã‹o7Šn¦å)ö¦ïG·qµÚ ,ç¡Fô@o6ß…k8”$&¬S ¡–ddWp‡®=í39Ž"weÒùÛj@ó™äY0äh„°Û9Y °j¦µŒHŃ`±zÂf"½­º­rç’˜¢1Ø"ŸêVËž/̯þSüã€ÁõÆœ`ÌZU^ªF•sãèÄO¼wKò4æô?|b`ÕLŸçá40O;,ÑWH¢hÌþþÿOˆ ›òs¬ým šå»AäÇ$”Æ1F†û°'QÖÒÈ(¯k›CÓ/ñ1!ñN5¯ä¢ïaV7ÃjDµ`·ÿáˆúÙe6Œíf@F+!/ ?f9¿œ Ä}þc¾I& Ú0ÊÜñ.•ø/½×¶—à¨|裣aáÀüú(Ú&5$½Ÿ`ãð1/­|މ³ý6Ìù_nYóiƒX3êѲiDåe€û¦1vO À;¿q”MæLΡuH0ºí¤6î–8 ºöK†M÷_oî¶7œº{e;I¶9•³ïÖ Û6÷;ø}“$1Fæ·˜BÙqˆhÀ3“FK1•KþãeÁäzµ\šs<IüfÔ½ÇÏ#ë4*¦oaqnŠÝóš ¹±ÙõŽ™XÉ׃…H|Õ|°l*JÞZÂ[g |´=kqÊö?º0åysû4p{ÒXð2¥æu‚mnO0àGl§Á2`–WYE xÕ2tkØlhÒäøàžTqÑ+/Ññ¬zÈ™ûFì&P#]È'írglXüuŒL¼ó´¥å³ÒÔ¹s+Ïu œ9,ÆééÑY¢Ü2ØáÀ£ÖCfmíCe6•~‚-g´.ø²Í?z>4*>àb«²-Žª{:Žj ûå;Ý`küëÎÌp½@‚Þ¨?Œï#¾ÓÂÊÿ‹³‹É<»O•*;–Eغádì÷qt ÉoòS¬w#pUvÀcŒCãŸÀî1ØÚù;V0‰hepÜë;¹(ƒÝðá&Kµ˜Ýn6 7L½y ›_´iœßʸKUçåo+.›‡;Ýû v@¯Ö‡O»!ÀöSBßjp )h/ 8àãVh´˜¶€ÙïlT¬¸Íá”L×fÖWbCØVÔq¤Ô Ðw*±çOÉ÷; ¿ Ñð OË$óâT³¬-«U²<˜tÍøÅ³é=ÎÏ{!#dBo%ÎÛŠ=Z)+g ·Ûã(ì^¢´â¹káwOðd·ñvgŒË~$ïp+®÷>æY°!H.sQÔØÒï|„*odŸmó›;bj:›ì)-0fv|HÂ|ÕßÒO5.¥SÇ$y‚,î|ßñË©8$Qa«Å˜0q*怓V4GÖzb—|@pÀâ~ÈUûèˆaN”«¿wìJÏ~ ¼m@WÍÈnñ;|hÇq?UT1dgfù‡€„Rv0™7†v)Z;zƶ hâAá â¿$àvJ.¯‚Lt e¶kßÄÈî¯ï-§EÍÀ>{ŠLFLWË9 ÀùôüÛû¬êù# ?tÒêUJž,àcõÂwéœø½VåıÂáqÚæäøødнñJ×sâça&˜Uñ{„Õ§„$ží¿sSaäT±K\ßx Ô´" v›»äˆ©fð)T^ÎßXö .“°ã%k?NˆÄw‰ ©º}8Yn8 ñ™{mËØ'øº1FZ?`Koâ‘ÉG³¨~:Jc¥çl{]tƒÛ4ñ5ð¸ºòzã mGÑZÜx.ìI;ºŒ/®!.'nò;VÚû¸YÒ›€G<Õ!]|PN*7J;”ä²³[ü¿Ó΀˜sö{%OPÝ(Wß°ä?qò߀‰Î¿dö߯×ïݱǸKÖ5üR¤h4t9~»g¸ÿ*“Ï¢9Œw<òås¾€!¾¨dy7ò6ˆåMWs¹A{‡ÖÝã\ °._ ‘‰j÷í—•Eï'`Ž»h—}ÆášC%£LÐl}#Aó"àr^I¨xw´(Î߸ÿZo¡â²¹Q°l@±*ñ¸ˆ**;àùˆ=RÇ˵ûîý –^!¡‚Ïû¯kÅìŨ=¦tÛr ×ãJ”²ì”jÆÄ‘þ.£äσyBÆdìž ?v:ä«m}rÍHæ{>z¼pÙ _bèËaäòÀÄñ ·I(n.Æ’œQ¯œ0¥ ÍŒHå4gÉæ®HŒwHrXàäwð8Ìã¾IY;=ì«›!lëŒÉz|?•> œ6zÊj’ü-Œ¸´¼¨2¿3ãÄyŸ²Ÿmì>>ã}‡éjáÛ[_ÿ(âGŽÁ3—k"zã ÀÀ8ÁaÆå‡3€>bªü˜Ž]€å'¯uâÙ-¢Y–?Â럪ØûyÇúC™ÙÓL²üªÁ¦u*ðzë5©šq…âû Y^ÈV¹  Ëʿਯaå mf24äÔ?•²G93•Æv›Î?ÁËñ—ýÇÿJ;ÔLZ1íåŽ }˜\àð »ØDTY˜œ6”UÑÊ6›‹²”ñ7a•…2Ev¢W^ÐF&,w¨Ñå_ ¦G•lf–( ÖW•- Atò]oü¬q¦é*m§±QÙómÀ¶£‰Cžï1Él¹‰(œd»G\ã:k™2Éò¤Áã%¥‰©ÕàaM÷£¼—&,~WѨ `,Ö¬Žº$”ð˜~ºÐޱO4…5O NIhT‡Ü¢ßVuö£×4l‘‡€ØòÉf¡Éi@Í0œÒB¬ólÃ*îP:«üÁÈ BNÝ:ªeƒÕ±––»7‹ß.<œ°]yu£/¤”:¬îXg·ñ 5.'X˜›R0ävq9sØ_ÿõ‡öZžo$žQîƒÃÕˆ&DËèi¶xÑ¡Î?á÷. 2‰ò–³O^Þì¹Äa¡0æpvG‹ñp1—å”C´+ø:$Ѱ±r3UÐŽše.Bâ²æ£aþ¿gCÐÚÇÈ8ÔÜå‹o£ØÁV ƒÿ¡IDí¢<2áÀaòsî!–ñÞ¹œØõ.T rs@Sn)ˆ¥f?‹¦!w7Ôô: q ìawzN±Ãç÷æv)·ì :2ù’ ö³aÇøõ0{`s§ÀkÕ^z|¹Gä8|á TÛ”»ý£µ9oPÍî;Ø[¯uW¦4oå†éoCç¹ßšú€Hþ Ùznl=(È^ç÷~ÑÄ g)ÇÓ¿=„xh„Šºnå1þ¿gÇVr®à÷rÎ~ãm0~`ËoÊ9g½°eîˆÈÖZ ”<#rùbǬV¯9ÇáOÐWÒ8€Lào€í7‘æôX¹Elޔ͒Àr·;'ö}Î \F¾™Ö´ Ï(½½<„ðñ¥â’ބ׋ØÜq¤1ÊŠò§µZþhDOCDzø¹¡*0¹y-¬¯!ÓŽ:$­î:×À¡ÀŽ´#«Âª¦ƒ­0|iYÛ’ë®yì& Xå0¸ƒ—YbЋž”m Âo•w a¦}®è7äÒaií¢ÕJ–á‘ LgC ã1ÅÁf8dgîÛÊò²CÑ œQ† ¢Å÷†ê0¡4’ù¹ n.ŽØ] „ƒ.lð5KÖx›:.B„<:âÅÇ_î”–d—ª°iÙ¥j@7X*b!s‘S™ø5.+Ðê³~A=ø,/YR£ŒKó#ÎFòžRRá'¨áÞb<û+ˆV:ç7ѦzDx_@w³Šõ~+šêníw#ÿŒÊÈ-!pô•-iGò‰ÞÈAêÉqËR·vÓú¿ß–-gBþÄbGäϾ…‘Ø=~DQÕUÖôˆ¶ .1EÇAJ5 W²¹j¤°{è{Vƒî,n –ƒQæ˜\èçŒ~½²¿l¨;ôRÄ¥ ÌO¸S§uz³îÀËÝÁ{ ñá ¼ˆ—jØ)ðoÊuØÊîÈë¢7o³‘8€¸>ðŃûìŠ6U‡$zgˆw£õÉØ5äu’–—Á¼••\Ç+ä»Àañÿü-“‰{Uqµ©F;+uea­a(›1ºTu³¥´<æÝc™•é°Ÿ>ö Yáx¼ïØ,×2è÷d&XkR(¡J®p¼Qqy7R©¨š #',‹/¡½ÔâÄ•œ¨=vÄ9`䯳/¬r‹÷Ô-¤Ê¼ªNgªâmï%–jà:TµóÍͲò±H&;ê½À-Ø«îÁ’fÞ`ƒÄý¯:8 ð˜3ý{Çå7Ð/<ϰÛÐ=B“°Êµgw¹o±\°Lz‹YÞy¬Ù™:¾ © z¸Í)øèñ7À…R–czéwÇ+!{ÝD垆pÀ‘Ýpp{ƱÙúè†æ§VFú†tï p‡üîà!v<“ºRôNÎ ìå“ÍGÂrÇ1ڼ¦8‡·™Ù_@]¿Å€r€'/Ê +¿^ú<«¥8ŽnᕬjQHE?ÚqW¾Ö0{€:ɲ\ÑK*½\XDàÙ¢iÚJÜ•˜š¤–ƒ‚­;7“)˜ó809ŸúØÉ¥h•MÊu\‚i ; t§æ@Þ—².k¦.öæ¢eÛ)zRÞdŸ¡Žp¶R¥ƒIfűKµYa¬†Ð ‡Í€4ÁØevSíÙ03_ËmIÓ1š9ûÔ£&Z·|ê.ˆ†fQà=±]^)Vçæ-ƇÃÂgIÎŒOÈÍnyýáMa¡ ëˆét­d—æÐZ:~t ZÃýß4¾Ðs-£;’^«Ã“µ@(Dk¦¹)BÓx>ÌÚÍ3MôÌ„6³&°‡á´4[w舯âIv‡™ŽÈ-¯ì€l±Í{@vVìJ»À—;úÌx°™"R*ë–?‚¬ÔÄg ±°iÈ| ?˜û‹Få7FŽe…à¸)Òr½XH?z¨Ew£†Õ\Ïî†]§ œ÷`ñ—©3Ø)_ãÃŽW^ºY[)µÉ^Þ¶\~Uö f(âøC‡aùÑ5¬ÊTÈÉ+Wî¼³ˆëÛZ$¸€^¢Qn,³*œÏ ®ÖîNEêËŠ°Áž\¦),Ö°û] %Æè‹ÂÀ‹ž-e³ÌCš"ÔÐâp¼ P‹„ÉÈŒ„À»wîBBJ}*°XdvDu\!h ‰V}‰3;Æ>OÍùz»Ÿ5ÀÄ&arÈ«jðxgƒXêêÇ€è –Ï2oÃUÁg©ˆéEYÃo Ö¤xÅÝf·eFæíÜìÎjn q…,¨ƒçî[ö1õ]pÝÏðÕJJ¿žiÖ¥|§ñ «¡‹ñ¾ÑY^š›GŸÇö‹KáÑ`*Ç S(Æ@Lû“ì€Í°áÜM\>ªéWýEœ¬íAÞ&-W©Ÿ°»“Éò¦· ^üQðoÜÝ #D­8w³Nå÷ýìpô´'n>bY¶õá &ÓXKÁò×áÈ7ëc|:h°MJñíò¥ùBŽdù›Uq^¸0ýΨߡ[ìÚ­UÁ¬Õª\žã)©žp¼=bÓÜí«B’:‘ëp„qjÞùxü†Æ²Ü‚Ýr—ó%DS\E>eÅQAYÔ÷þ.US´k¦q¶Ws‘³ÍÞ»fëÎwRÛK:lãwú8ï÷t™”—çê`ªo£°{rVUÈG»VW ÝÑgäð‘áÄžª‰¾ý~u £ãaó˜ÏÞéqcV›6­Ù QÞºiÇÁ5P6΋ѽ+EÞ÷ªÆ z>@_ºò Ù±~äpS œ¯««ÓÉ¡Uùd¡¨.ÎÊLmÝûm·Wñï`oÜ%ÍO¦Ê3æØé¸Çþ-ôº€w#€tèQaì p¢öÊgèðÝÊ p)ߟ¦wþ57Ôþ4Æ ÓÞ-EÍëøÊXÏég£F“§Ã[úv¢Ç«ƒÑ›¨šnŒ® ^7}8þ^Û³É3|›ôì{¾@Cvlb]~ÔÙL.T•ážô™¶aº˜3ÃóhñÞ\áz=ЍÙe— i\öô”=§¡Æ;ðĺÑ^Æ ÓÔ¢Sð‚ÕdôfýLÎ-;aåêšWá1Ïí|á$@†˜ÃòKÎHfxœ”R! fð;Ï’¤÷yn RQ4<øs£™<Ô@žŠ  éi8z·šòl·u/$n¥6{×Ë:vƒ Óï/&ÿNõtFÐìÒÜ yèB`¼‹0¶§uç•ÓΟ@ã5ow¦€_¨gïìå›k_AÝ ÁVuC©LÎæÛ˜!(Ü=:ô”ò-DÇ»€óI»Ó# êI{kÙöú¦ÄŸá‰€rkJ=b8xtÐO&eSèDümeoÁðƒ{O;ª©öÉSÿDEËŽhCYö¾è1mÙ•Ùû#\­}K6±:Ì‚H½ªÊ­¯ÇUÉa3f©sšWqò\’sÕ&œàí±Ô‰6(:[YálùdL½þã†àÇ8“S<œºƒ*‰ð°5=špÌÄÖ2²Jíªä,ýɹH duÙ]¨²çùÁ"¢Â·Ñ`ŒEMÄ_JjÀ—2€ÅÍ*7þlöÏTOs5‹-éêª@t ýš7{Ôòê”Ñ=RbuµDƒúÎR‘&Í=2¯LjÅ2èvå@ªa®X»VìKÒúªmÞ½)ʬ#¬ ²œSúnp¡ûöjCk)Dù ê¢7ÄJëÒbÇK6•0ŽåÛê~ÂÊd—JAŽ ­…Saz8ÓkaÔ Óö,³e €¨>{ñdõ䱜Z¿PÞ‡Ó #ßW× >`óx†œª>Êu¸Êœcy ¬nÉBq|ÎÀ.`ÉÛ { ër©II;~>˜HØvå´ T Ãß¡Tœ°e妸àˆÙ$÷*àyóÁ#­Ù¦= iÀÓ©&ë”8Ø&yBÜéé™pðBa*[kÀütÑ ¶É «j¼ÖCÅâÿ²ù8AºQH…lõ„9ìÜQ½D?À+Œ2ú¶7€—¿€8Kêë ß¡ÂWøÝgÞ5ä£!l°ÜJ‡p€Ýaý‹ã×ÂcѹAv.Ø¥ÈÚxœ€¹äG´#fC£7ù§°úò¶Å•¶1N‰Å0yȨ±ºÏd0£c Ñî‘SK9qŠ—"Æ0’¾ƒ=N g(eOCLC˜Ù Ê0þð(ÐN-‰i;Ed®Wk $]g|hÒ™^¸t‚éxI‡ÄÇVÌ?öì0µØ³Ôø“‚?ÃáØIØÔn®gª¹€D$}â.Ï:“Ãl›ž°Ä¤@4;ƒMžwÈ@ž‚œR!*ÀÆ­2±FÌÌ`"â<Æ“ÎãUû9Š3ÑÀ¹ Hz²PŠ3ÛþJöc Ó•fØÂþ’<G€éZ1‘™`GÃ?yñ—u¾HJ{ l¢F×!L[“¶y²æÌ%f¾uøNÆ^@ñ\¡¸ŒŒ›„ÛYz‹wu0ˆ‹Œ 43}#Î SFàI3yßm q°ôsÜO&1(êIFŒ¤: z‡al÷â“$ú—ࢠØâvв‹dœZ1€(1µ×]¥@¹Å7Àõ»TAb"²WŠ\LÒÒøW8ó‰’ˆ(`¹Hf`0@QdtÉÔJÄé~QmÌ Ss Ûá‘Àž‹¬œÅåÒ-u)Ù=Å~äQ¾Nw É)¿$5<3“´Â–ef&{ÁŠq’\«‰æÆ•lçR&ÜŒíäë!ÆVMd{ÉÙðJà»ÈKcó¯M¯šÀ@²ÅbËm-Dr7ØúÃcÁÜëM3%Ll ">&Py¹ÉÝG3]ãED¦Ç YIÊFŒôì–&9²Z"„N å\£bZ¶ØeÒ¦I# •h‰¹Î$™ª¬%aÛrn¶JÚDò¿¹m±ty—:7›Œ–Û‚ÄÌ„¸.çg«Øˆ™L‹•wŸw 0“©d„8m‚ÁT`""¿´Óál–¬¤ã²ÛHäZÊ%y‹ 0×! mbff€ÀDrm`SÁæ c‡MŒÇò ë[çó|ryÃÌni —^jà0’½´2"Í€mºI`6A‚s`\fò™(a—ó¿˜b]T2¶;ì¹½_Øc„='#JÖI&ÑHs¢m6ø†üŽˆ˜ÙKŒLyëù®QöÌ¥§{-Õ‹ck$À7ÄÔÈÆ”Ï» œ›V;û½Høæ¶)eoØÊl|oXþoÈEÆZ‰Þb1ÑÁ`˜µC±L8¾U )ucÜÈÕkXFó’K€™äDp×C¶Zë åwK|å¦ QÆÕëá_ŒiÈ]@`Ì ’— )`U‰¤­ÆsöS\Dqm¾W’ØØxbui¢OÆÀÌQ o[3[a;ºdPËoÛ D˜L“`ZC"4"oއ1›,À´)y½ÀDÄf,åE‰´ (9:O±ùïcÚéL"’D—MD`wÍ¥ ª%ƨƒ_3àn;vì ±ÃÒ-²zàŒ¦Ø>¢`$4ÀùF3¤„»ëH–3Ü"õ&;ŠÝ/—y#&@>´X%öÏ¢ßþ¶wÏ8M¬k`m–çïžÎV;àÛ˜î¯ Å?‘¡â Ï03¬×½ž0Bl?9&Üì»É@D›l£þ,Ž)è·ÓSåNý°ù¿9˜f#)G`ù$ÃY—V1Š loVjØN+eÒ¥„Šƒ%‡ŒdÒšÄ(H%h‹Úܬã¸wÉ ©×¿ÁpPÆšçø6Õ@Â,»Q–ð 'NûO†rÊ„;í©‰t ˆUZU)TG²TèU2¿L{È΃R»û8Q/èñ…¾‘`@:Ÿ»S ¿HÄ<›ia„…;1Ng 0Ë1$ÍI$z–$—ÁäãQA~‹,‰zCŒ;ƒTŠ—*B2«ú. ÉÌ÷¼;`ÀlµQ!xÊO÷p“Ù»ºdâH{3is˜[*±Qà¹ÂiÌôEpËdWĦD`Œs2‹_Â[eºÉ“‰3m™y#ß¹ÚÒ5•L²ÒÀj»hc×–¬ÇLÛ‘ðCÝF°˜+ I¶•¹ kañ%¶e ƒÅg’i¯7hꃛ°3qÜq{ZqºÉ®ƒ2ÇWfb@)2!líK›XoäOx¾Ì@ÜݰÇö”‘¬?’ÁDušVüÊJ×Û]Åa ==ɈÏ,˸v%ê̺?“u­ y}?3`»Ø¤3ÁÌr ŠÀˆìÅþ+Ó##‚™@ßÂSæ‡6™‰ÆO6ø-2–˜¨ÚT*e|Sìü @š`,¥¼}Ò¢°^äawª3gÛ ó™;ζ­°+¢ÆËâF033Ån\:2‹‡³"BG§K¥S20úò^GÛ±´ €¹ÏÚ’<ÈÞO’÷n×Yõë"‚|²ŸÛVJ‚ˆ@nÄäg9ŒÁEÚ(EIf M6>ÓÜ$Y¦I;ˆäc^"מ‰ ³M2‰¶Ç*’z,ÆÐtãW’ubD™®¼\vE ¡Ü/å®îTí¹0 "s娄,ƒ–ß £×]E~®¹–ãXƪ1×|} '0É^ä2+KyÄò\a:ä5L˜ø.E¶—R.)P/ ÿ˜ãzà+´ˆƒ¼ÆJ —(óHP2Ã\K²E¾`B‹Ç ´ÝB¯ —Ìȇ¥Ùx/›Øi…õDг[™öšâHW!éN•;ðÓÓÁà”¤šÖEQ$ßy¢¸Ý™‰)U… %f&»ÕŒp?ŸãIÜ®\šöÚŸeEZUF³ëIÒwâ_4‡µúµœÈiÒÃ>NaÿTnIVHÈ²ÌØ" e£¶oÌ ¢ÌJmäVjäÝ„+râ`“ çÙ?ØŒª¼¹¹ú–°ÄvB³Ã1Q6åA·w")U ,1]{¶eÏ`A£–!1…z%L aq¾;'ó?ÛC_ƒ'FAÀCÙÀZNý¬Bî1ÊJô¦ FÜUïÒÿ7rA œå…äadä¢)¨✺ L)—b3ÝGS¹²‰Aò9΂´HbPñÉÀåwó ô¢HGÈÕ‚|Ñ>ÔïŸØ”"^ ÖV“­ŒS3ÜfpóB˜ÃÎaŽA²âY€û¤(žg°ü=AnquÄ ’ÅO .d~-NŠmVRTlV…Bfûm÷eDIIø £–î"OfÉ©…$²ÿ>b†3ƒ'³Ñceˆâ»2q1ÅE1Ž÷N­"6ưùøÎL”-½ ‘15mKˆ[–%p{u™Dë #¬Ê¸°‡/é›ûaʘ,¬Ÿ¥Õ¬ar»M÷…+%½ìw½Ãø'NÈÃÖd!뚌âÏw% ºBsSø'Z—ç2¢<ћ˫4ùG¬$Ò)¾K™Í¨"föþ ”¨|L‘:pÕG×]"SÂÝ'^ìes%/(h x£•¬o²™5ú:Cý&‡­“1•e*õ’€¬È$wbfó¥7Ñžº, ¹ù3˜ä¯€n—3ŒúÄÉüé&'$ÕfÀ˜Å21€ &åÁvϱåR:e„,{Œ°éÄ&Û•6S¾øbgŽÌ ?I‘˜N®3Ñ`M·“º?„8À=G"v~^lñ ã;÷7@îÄñWКBømL÷¸–¶|\È êT C¬Ê6ÝžFD¯˜‹ýžŽleöò±Uà ²M,@Á C¢^ûažÍEÁp÷bc¨ù³‡KµqvØKŒîº H"}Z@Ÿ%®Þë ¯2§É6Â[抈;F7³¯Ê(ò­¿¥ùÀD ȈHb¹ÆDlÄ‘h–ÄkÇh SœpÅ:y1;13‹cUA0˜È'jÜÄÖq¦"27wð´–C'±üʳy&šLÀ’.þ‘_òg>xH/6È‚‰»rÚR¦5Š8¢•ƒŽHL.*ÏErågÛy0¶\ÒV FŒ½K;‰ÓCîWé>1,í!S»X È…è=³ F9œƒæ< ÑADÛMÞo#n r¥aM{m=q¦;r¥Ò`+åÅîÔ‡ˆÜ_xýÁ`Áœgffòž@¶6ÀV+†%ºÎ·?Äø'LÎÆˆÙ¬=Û’‰n–D2Ï7ŒÛÅæ®‘Š…±…HèJ4:y5H÷fBD wÃ…þoG†Ýlã¯4q…«Ná©ò­Ó æë²8[;A±8Ï78ÛxO<´Þ•uˆ6{›p%Gk"F9 BèX""’{¯)•·O•”\D Š"Ã̶0j­­D’—P ˜ú­‘Dä¦+@Dy–ˆyÎ¥T€#3jóµD$OuDb‘Q`.€‘5±šxBšÀÌÁ 㟊UN‰½¥™\f¶a‡½ât ÙôT'2dæ1ö…ÉhÓt)éGÔ¡ªlâÙ Ù(7oÿËU&uºë’H?™cc—ü‹À¶‘ˆ¼Ñê~›Ä:W˜ãµ ‚Fx•Èð¯…÷²ýœ¹;µ§ŒÒƒÙTŽ&9%ìL(1 ™é!¾œ‘$yXc%àaé;9–| 6eC§äÚqš ÙF0S"Aú2SJHéšfpÚÜàÔ'=t™ÙO ë$òüÙPœ))íYˆaœ¥'Ófg´D´éR Ì÷c³uH}YS¨Å}äÉ"¶–Ã¥éh¦Tºw “…Ôœ½éˆ"òóƒ¾w˜¾w>N®ÆÕ—lw©=l¹ËMd8GÊ"S¿$åí Ò-$šûš§.¶ˆ LD y–¶‰™ˆÈ8Ík‘ìDd'cÓK»Rä·ç‹W—t®±Í÷jâêŒûÓ¤Ùî¦x’ònŸ éú$±~ª…€'Å"ê=ê8›G1FV˜a,¼kÊÓc"5,¶d˜çM‚q5’b¬„]æ4Jlƒ°;ÒÃ@ä2=cÞ!2ž)* ;ð’xCœ‘Og–ëüÛ™k‹±6p£ÁÉ›ò@(áð“ÝqYÀËbùŸüð1ÛàÄÙZ.bb™7(˜€·>Ã0‰I‹ ̃)Ž.L]D’BîV¡»²`æˆ"2Ÿ3Û«/®!wšˆ Ö’¨‘¢ ¹TÓCZ ó)5ÈõƒãD œD|èŽ}\)ßCÜçüBÂdy‘\̱æ‚‹ãú‚?GÄ)Åj°˜{ùL `$’:cmÒ(³$¼¦¹b@þpnî〠².ãB7²—,)R‰®ÍD€m8Áó¤)âc suJÒ&«×¿³X\Š9P¬/$Ç\&D0!6 ` g¦¹µÁ¾ÂÂà»4t¯™Mº+Æ 6:¬H,*<¼‘®€§¡tâÀ:¬ÏØdf†ë…T).7¶Æ—‘Aè²Kff–O!¡€?dz¾c¦žx? fâ “—.PYf"Ëw²%—eØ–0H>t‰C’Ù ˜Ù”/&U ©6Üg6ÞͳÂ`€l,RbÄÊI~ìÝÓìAЗyï>ÍNÊé·W—½GÆ8yIL; ž~Qk\*†eô£hÒYþ£œ·«ÓÇäþ°Þ±Ë ä$ …­åL÷ˆß}™˜"M²wâ”@xˆ¢ˆföo=%! ÉînKA–Ü-2̃µò_œ.ÿ¤LËTÊe‰Ø1,g䱉‹ X’RÆX|ñà˜aªv–g‡Ø) Ý.>’¡‘<8YžWAlšh×G¢Ô -¬ ±v¶" ~lˆ½“k’ Êž8§˜¼d¿Qàj³°¨#79%úÞSC¶¦$¶^!›n„ý ª~ -Çys–®€1Ìò7?i¿“ή‹ˆ(˜«EЉ¨K(Ü„ +Í0³ªåÊN8ÖbÇC2Ë|ÈÉ*`I{Õ¶&,d«He…‚%BðbkËU`ü5N0vqg™”¼f¾šb*B'xØé—½iÚ\r=K‘ýŒKAlðTûµøÇ Û"$Åò_üÚ#ŸÄ°ÀŒÀâ_¡¹+Å¥ŽÍÙôÙœo<¿˜"I2Ž(þI×¹’³nQãaÓŠÂöH†Ad…ÌÞÖjà¦c—fntq¢?¦¸Vz¡ß ùŸ¹5ÎK°ó œ‚Àò8X#™ì<)$öo[ –afjdÞO|$ôIŽT¿lÜ™UÅb‘HÔ+–ÚDJ]Ëë»ü«"Y8n1Ë/f°y*1±2á1IÖ-’ˆ~æ"JM1"m“QúÌ,a{Ë<Þ–™ä—ˆã "Û4{O""L-"»÷˜çÅÃlB7ÖxÏîÈ~LEº¥EDSÍ+o°[ ³{Tž•+7Bäâ!òîan¤)ƒ’dø?(2ým7¦§ìÚ¤{Uö\:µv>1‰I¹çÜ6u6¯ŽFInR¿ÙÆzuÆd$eR¸îxí´T])lAwE,ýdß̉Ÿ ™¡.eÌ wšï7Àl_F²/¥#Pž`Žÿà`Æ­R¼´o®P›lQƒ2[©XKNŽ`ìI&’Ø#É|Ë –Y—Xª´…-ör`pr.Kˆe…³ ÒIÒ?¥àäo1޵S%#ášúÁ¶rÛ ÅI×Bl'A0²ñ³Ÿ!ID¢Á¿¢3›æü\²±?áÃD—',LøÝàZ!*M’ÿ‰È+åÜë•åw®d›™7 AetɪK%ˆXu£w¹K»N”¸{ À`†ñ6%?ÚÙcÌ^,’ËHâC')I€{3I`o¥IM^‡ÕÂ-Å·‚$\-~0õ¹(P.ÀX.Y…­ÓÒYÃ|Ê i:R-ñt˜‰È2’O€™¿ÜÔ˜&È)Yg‘—lË.½ñÌ^°EuBdã­tUÌD ff3 %‘L2Ĥ( w©û¦$œgÜ"dFœ°êÌ$ÆñŽS±Œó–ÅvÉ¿D(ìŸÄRëkÓ_.#8NVèN¬©pÞ2zB8ÖaTøÎñrc2½’tƒÁYE5„&`Þïf+b†Ä©1Ékç] £ÄÔÄÖÆø„i™ØVÊ sÄ®Â0$é;"‚ÿæp¶£.¶7£®Ø?ÉcÀÖâúP06²ñ?Á¸€I*„8B\øšMé‚!±¾+‚(œcÅ1¾ñ‰v8;SEnœqB´"뤙5Ä ½n š™>NCNÀÎ"d®@²d¤ˆpIZêè6"Ñ,BÌÌÌrë,×E, v§" ŒˆâòG¢¥¶9$§~–;ÎH“Œª<œRfÉ3bˆsÌAÆ5Ò¸áx‹EôdjFjP¸S#CÒAI© îÔ8?ÓÔ@IJ§#­.K€éA¥œN®5¦]ñyé¦Ç$5…ÍN@ž 2bS!LO°\Éú¼3F¼''¼>’¤‡ ªêíÁ·*çÕ~ø°ýäÎôµ¼ÃÂDOuÛAE=0÷Dizè Dƒ ïìôþg ¦iDdB@ßëJŠý€#–ö0f È7–ÀÌl´›*|óÌ€I [“³%Î,ëˆÓ²ÃbjžÁäÖ£–˜zŒjwÜSuAž«£t©°#R‘ô˜—¥¢^Ì.ž…S!®™%Ï ¾d¢ú\‰i9Š?N//H.MPjâM›çð:Gþ-ôÉÌfE`D çWiñRÒ)ñ]˜@¶¥!ëdãI–‘B&€‹ÈeÙ„*"dE°$€Tcâ4‹Ä„y‰Ù’J b$2‘@ GKO ؽԹИ¥hœøt#mŒRAW]¡XŒøŠâñ&ÐSEV¬3ú@Úà·'“ÒLa؆0EœBwPX“'Ë™=`׈÷M2Þœ-iÄÞµêFrÜ.×Äô•¤8Ïø.*„“qòq,îù;‰T›”¤øIaýrnê2HsP½õ g>V4p†«žã ;ao­ã*• wrÁbWõ€Œ`Æ‹Ìꮃ¬m™õÊH2Ž‹˜hMªi΂8‰(b®…ý”E_¢ÞÇUfrÓ7³Ë2Xc]ì`w•8ýþaØPï<¬ð²qV»$YK–ÒÄúÔÁŒ"kÒY¤]Ùp†“Ť Ù’ñŒ9e©)Œ4˜å¹I•u-=n}2ÛUg©$d/õƒ£d(åµÛ'b0vñ.=¹ýÄb€œ›ªE' ›à´qÉfޤ\=F°7,§ÚXÈÛÇ·a•ožˆÓ ˆ‡â»F/1‘›) ÈØ Ó<—Â`8/^c©…aO¡—h¤#ÃNãÔ0ÍÈaBÂæ¨ÊôjÜ"À„Ü$§qy"– 2-R<'ºj͘dëWµ•H5DÛ`_À˜—Y¦0ž¸˜b•X³EˆhÿüOÕ üö&W$ÍpeÓ[.Ãu2ÄïqGDz>z”ÜþŒS$°NAq˜%×@ž9Š"¢¸amç ·ÒÊo‰`äù§™ƒ2¸ªÜ)¥²V!Š·¬!¹+¥<™9QÈQËfQEQEYEÙeò±Äž¤n+u.7Ô#°&€¢Ìì=:žÙ[”tëÙ;q®(Š¢(Š¢(+%ßOžPµhaö:`ðºéÀZÖ ë³¾cck÷§œE øùŠ¢(Š¢(ŠÒÈ€º@̉XS‘¢feš.¸ÇËQ[[&)Š¢(Š¢(Ê*MX]êæ0?ØhâN]`½dIUÕ¢Eµµ5±Pi”•å*›4©¨lÒp a†¢(Š¢(вBix€×p aƲ ÇÙ¼‘çµÀ}+Qddw5‡!5Û_&Ѽø¨Z¼¨¢²²y‹••F¶–TU-˜?¯ªjqyyEÃ5„yŠ¢(Š¢(Ê ¥á^Ã5„y C6v¤÷X &D&Û»Û?Ü©±½o·t]SÛ¢]«òŠŠÂ{L2¨¨¨¤4ý—Ÿ@Ôp až¢(Š¢(вBix€×p a^]d­D›xØ=#9Åá2ó„O‚Y”öþõ`vÉ^Y9 *¯\šå•DDËBƒ¢(Š¢(вRÑð|íDE IDAT¯áÒH gù©ä¶‚¤¿Œè›WøFÈ™yw¤áajiˆþ†kPEQEQV*à5\C©м0Ï)k+ˆä†q69g[æ½Õˆ–†põe¾6rôk#G…Š¢(Š¢(ÊRÓð¯á’)aô,1o=«0uE4Ë›´YÞõ £Ó¸ï>ú1·³!4Ñ2ü®[üÓ#N<Ý?Ä]i R6(’™Ø‡ dEQEQ”eE:À+â!b&Ëùø–-šWxÝU—rÀ¾—þåüî½ýæk¯Ú´×Æœ}Æ)믻Îé'÷ă÷]}é…RJôGôGôGô§Qþdx%þ ‰ƒŸD<çkˆ ¢Ð?µ²VŠ<`^ÕâC$ú€àq{îXؽ;†åW¼ë:¨»EÖW3ÓÍÉïLÉ#O:ã_w&¢ê ç8‹hðùtÜ8÷Qf¿}÷ý¿ßÿ~ÂĉI‘¥¡–ñúëoì¶óŽ·LšÜwÛ>_ýÍô™ñ_Î|ê⪪?^pAE§œrÊàSNüÛ?®÷Jg°Ãv}®¿á¦~üaÝw|ê ÇŸzæM7ݼzçË^~ù•Q£G3T–QEQEi$ ðJ¡xˆ˜™ˆ¬ 3 \J¦l±â˜À:Ž¡ã ™‰äq×&°.‚˜GÛ‰ƒB6e¦{‰Dæ'Kò_wÞäŽyèÁ#OìeZLñFY •Øa»múöí{áÅ—,ªª62NØ?%Àï¸LD¯Ž}Óu×´hÙb—ú=øð£”+—ôÎ:öبûéCΞþë÷û×µ¿ªmÛ6³çüZDá‹/¾ü픩 zùµ‘x@Û¶mgÍž P>ÊÕDõx½¢(Š¢(ÊÊex%a‚´B2‘HwX=HWG˜ùZ â(½Ùú­ rNIÁRwævVZ©øg€‹ªÝò³g;2ËèÝ«çápõ߯™9wA˜·´Ì™7ÿÓqŸž|ÜÑ•••ŸŽÿÂ¥·oß®¶¶ö§™³ÅûÓ~™)‰qÉ,fÏ›Ï UÕµ**t}ZQEQ”U‡BAZ) K¤!ecØîé` Ô‰Ý b\'’S— W^¢hòÄÂí&ÎÚt´}äIƒ—Ì›iw‘'ýH5Y‚¨úÈ“KÊ¿î¼)X·Î ö×é²öSN¼îúëøiº¬HX²dIeE…œ´iÕ þA]2ôò«o\zÑ_xèa¶ýEÀ¬™3ËÊÊ:¶ï0cæL«wî `ÖÌYT‡Â„å’ž—? x銢(Š¢(‘tŒ–¹H*dxi ¥“" ™×ga6t˜°=ML9`˜¸Ù’Ïça"o3À É*¶3Ir‰´´Í¢¬VW¶j¤,™73H¦t†بZJuòàawÜ„”ÑàNtìÐþ‚s‡Ü3tèW¦Àmt¾û~j¿í·ýê› Íš5=쀼MDÅd¤¢¯¾xð¡‡å£(çÊþ<}ÆW_}üчß9tXTVvÌ‘‡}úé¸Ù¿þ ¢‚ ƒ{:gΜ.k¯U–+«­ ?É(Š¢(Š¢4" x™dx™‚¥[_8"ü%e¶1^œ3C‚psää0`6¢"΀ª%’¶^â)"Vž`Ãë2ÿuòª¹3’i)1IHipe+[uH'&„S*·ü¿ÍÛµm{ö™C\ÊåW_÷Ù_>øð£§ž|â7_÷ó/Ó_yõµMzöð ê”aŠjËš‰ÝpÓ-GyÄu»ŒÁã>û|ØðábY ž}îù“N8n÷ûOþî»?_re˜­(Š¢(ŠÒX(à à5\C"3Á­US¶œÍ0¡/Éî]ÈZ+­¶Í-0y~ Ì L[¥ .²*nh·àþn={/˜7WN.œß¾ãjI‘R™9ý§fÍZ4\ƒŸB\Cù?…£ ¦à(_ ΃ˆ)Gùê|YQ~ SS™‘Í’¡ü â(ñrxâ<å—ˆÀ”¯!Î`IãÒL…Q¾Š)g+ET»8_V 8å«Eù¨BrEQEQ ð®AŽgLÿ¹jÑÂ]'HDÈû‘nê.0Á² ¬ó(J¬œçl,nÅ Mœî¾»˜Ò]’×§P€Yão°?…©œ£Ì/R¾,~Ú†‹’ýÄB2œ10•qÔÔž—Ud}$ÉVhÃqC>gõPY>2Ѷ¢(Š¢(Jã¥á^Ã5„©¥ï$&,ÿ8ë¬þב.Z5µÕ9yö\}¨©©Ž¬AQEQEY©hx€×p ¬<'ÒÂWš£dAWEY”[²hqÔ”råõغP]½¤jÑ¢²¨Œ–…EQEQe¥¢á^Ã5BbãV´) « ¬X—AØ.g[íÖ–\yyuMõ’_«œh‰E¹ò 5\C˜¡(Š¢(Š¢¬Pà5\CÌæ[ˆK F>XUY`7HÁ@¼,—+Ë¥ª¨ × (Š¢(Š¢¬T4<Àk¸†$È“:Eæ!xn[‡ÛÏí‡Áñ&of¶O³Î1ò(l$Ä[DÜ&yâµ¹_ÉÄE‹‰Š¢(Š¢(в’дi³ø„ï]/DdÞa“L2Ÿnm‘Ä€ ­EH…± ã]‚À3|F·¢(Š¢(Š¢¬@>úDwL€ÙÏá§ ,QtbQ9ôˆ…(‡†l(¬m+Š¢(Š¢(J£¢à s=ƒÜœh! ò¶ªt•U+Š¢(Š¢(œ|˜÷ÖIÞ¢7Œ®½­Õ†¥¨AQEQEQVfî© é5ãÒãßâUgG{ÛI‚˜:]‘¢(Š¢(Š¢4väºbÀò]E›ÃY[5Ü 53ç\ ˜b ö–°Éê` õÈ¿„.hä­(Š¢(Š¢4:2^N6™MœT‡ä¼•hO#Áäˆ Ð‹=aD´Ê5ÌZ\sòû5‹kÃtEQEQEYT”Ñ}¨lY÷û%Š–¥d2á±ûM6Ê.]™Çí…pÞ½ÎÑ„ëö ” ;L,ÄÉïלܭbÇÕ£0£d&ÎËØZ®(+Šï'Oì²Þaª¢(½~ÚeP'¾ŸUÚ Z.”®,/Î=îð÷ðÞè‘aF£bÕh…¢¬„#y%4I)‚ß_Úw+9ÚAËœùs瞸߀÷0ùۯü‰·Z̲DÛw 1!ãÍ‹ K‰x Ü—0…ªT pÝE|óÅøMþoËÓ/¸È%Þsõ¼õæÚë­ÿ×ÜèÉ®D\vÎ?~7EŽË+*Úwì´uß~»ì½_.—< nþÛ¥ã?Ûo÷‡r˜§ü–pCh·}Ø÷ð£$ñ;oýÊ‹6ìÕûìK®ôå—uŽÀ¥Û%²ü ¨S³²2à÷¯°n×î\}Ÿ²Ô,˜7ï采ÿh쯳g—åÊZ´lÙcÓßyÊ¡\ èpÂ2õçJ 3?rï¼5**+Û~—Ýö>øpIÿ÷ý÷|ñéǽö&7óÈÐÝjûŽr.€ùsçž}Ì¡ŽrÎÖÛ÷³úV5Ü—á­Ugâ¢dwÌæÕŒ`B.—÷•dKTncs/®Ö»$¶í¿ë7_ŒÿüãçΙݪM[‹.üäýwl××Pz%C.°Ÿ¦ýxí…<ýÐðùsçxÌ ¡¢eÔË/ì±ïMš5›;gΘ‘¯‡Ù+ˆ¥Û×Þû@˜Ô–¥ᢟ†¡ûn¹þ³?tèý š?oîWŸ}úÍçãC!¥dŠø³áµ’ðÞ¨‘#_qæE—Ïž9sØ­7tݨgÞ›Mþöë‘/Ž8ïŠkêü<ÿ€ˆù‚1­ÿ EÀ¿ì€ä›³‚édÈŸ°¯¿ ŠÏæèóð½-Ο?fԻÞ]½dIyEÅ–Ûõ°`þ¼ç{øóÆÎž5³mû›mù‡=÷?¨I³fž“˜ÏçÏøóŽ~¿Åì™3þxâÑ.»éŽÕ~·æYG²`Þ¼=ö;hÂW_|?iB‡N8úøñøÞ›¯ƒhó­ú~òéQX8þˆ?üه̙=«}ÇNÛößu§=JVV[cÍͶÚzÔË/~ðöh¹÷»%™²²\‡Î·ßy·îà’3OöÃT#_1òÅÍ[¶¼þþ‡EÉ´©So¸ìÂÉß~Ó¬y³=÷?d»WöÊ2¡M»vsfÍzóåvÛgÿ×F<]]½DRœ@‘ñ_dÌŸ{ÜásçÌÙmŸ¦Nžèª"#0“ôØ.bT*‹7ËϽ¸Vaü!ä§—83çkk¿øäcëuÛ°¢²²]eÇmvÜy›w0ô¦¾7ê­ûîxìà³|?i•çŸUV–»öÞácF½1êåf͘޺MÛž›m¾û¾µëÐ!s81£ô»L#¢ˆ?áuVÛö®»è¿`ÓfÍoþ(Jî¸Ë´©ßèÖ³×ì™3ä´[‡ÝzãNö^·k·Pº(¯x&=–PÔÓúïð;nùnâ·:uÞv¥\Ltam2|6¸¨—`,UË*³ýŽ#ropÌkt¼ü)/¯Øj»¼ûÆk’"ÿ×gۦ͚×ÔÔüã¯|ãùg·Ø®ïµ÷ï¹éæ/?óÄ —_ä^’Rø<ŸüáÉç]°ÍŽ;Oûaê—_Ô¾CÇËnº3Š¢·_eìÛ£ÔÖÖüã¢?½6â™ß÷Ùö÷ük ºýûþ{zW¨(‹Àœ‹®»ù®'FÜùøs—Ý|GEÿvïÇï½ à’nëõû-ôÛ}À]OŒðCŠOßsä©C?éÔY3fÀGï¾½`þ<¼=ÀÆ›m>sú/ÝwwEeå?î~Þ_³Ëzo¾4Yé3ê¼Ë4.ŠøÓ§{Ï^w=1â®'F\|ý­M›5P^QŽútÜŠåw]ºøö‹ñ¾üÀkwyöч8Ï>,-ÊÔÉ“2ÇR?ÔÖÖÜtå%_×À s/ÿû” ß„JW˜€¹Ð<^‘}¬µù×»;Õÿã””/xƒSбÝλøï?L™ðÍOÿùQ¶íËG·/>ýxÚS‰h·}öoÚ¬ù®ƒö0ùÛ¯'}ýUR‡!*dl½ÃŽ-[µ^gƒnˆ¨ßîZµi³ÚkøyÚ|ñÉÇÿùþ»²²Ü€iÚ¬ùŽ{ 0ê•/\˜Ôòó´ÿ|úÁ{¶Üv{?ˆ:v^­GïÍŒûžŸ•f»wm×¡ÃÆ›ý€|>?ãçŸB eU¤¼¼bÇ=Î3ûÆË/^´pÁ.{ïEe.·”ñ_dÌ7|Pc»{|–¹½¸;ï~S¾§uâ~þ=ìÞ0Û£^3óGWV–«ªZ<öíÑÝ}û_O;aè×1óº]»­³A×êê%cÞ|ƒ™?z÷-[õí·há3§ÿòþè‘ÓúiËí¶ß÷ð£B)fÔy—itòg(Ì™5óæ+/^´pATVvÌég¡4­ lµ}¿~»¸ûŸ×<ñ¯ûö<ààæ-Z¼öÜSG>ä•§Ÿ<÷¸ÃÏ<êàïº-Ÿ¯óq(4–Šøá›ÏÇËÀØeï}›5o.|[I)|£‰º0C¶W€ÚDD”s1²ÈÈ)™¸Ýb‡–üKÞò6yKàÅlQkvY§Ëú]¿Ÿ4á7^kÚ¬€ÕÖX³ëF=Ìšþ €Ê&M++›hÕ¦™5ã G¬¢Z´j@öK5iÚ,W^î²äš™9ýµµ5§²oœU[;sÆôß­ÝÅ¥ø¼?úÍ÷G¿Y^^Ѿc§~»ï)q3¿üôãcÞ9kÆ/U‹‹äì™3%S´lÓ@™ÝÎUÊe¬¬ì°Ûž/=õï©S&µlݦώý6Ôe5pü7dPeŽíúÚ³Ì Ð‹k•!su&õš™·Ýi—zõþäý1_~öé7ŸV½dÉ{£Gnµý=7û}¿Ý÷ºïæ¾õêKëlÐuÖŒMš6ë½ÅVee¹-·í;öÑßs€¨¬l—ûdÆÖ¥˜Qç]¦ÑQÄŸ¾Øâ… oºò’Y3f8üÄS%·­ Ñ!ÇŸ,_Q­©©¹òü3wØ}@õ’%Ï<òÀ'ŸÑiõÕ¯»øÏ]Ö[Ûþ»ÊZlyÔ\×gŽ¥"~Í'••Mš6Ъu['°RÁ̳Β÷¼½€ÈFÆq`FËIL’—ð!³ÕD)…íúïòý¤ cß]^Q`›þfW»ŽT-^TUµ¸²²‰ûnÛmQCEù|¾¦¦ÀÒý©Wê*¯¨¸éÇÊÊJú¾Bæ½á³Æ>ùÀ°Ê&M.¸úŸ«¯¹ÖCwß>êåòùZÉÍšÊo™fÍ›o·ón¯>ûÔN{îU^^ágÿK7æK™c»¸=%Òôâú Rß™¹}§Îý÷Ô¯A³fÌøó)ÇæóùE‹Øb›ívïüá±ûîðû?ô‘Ëíø³Î;ôÄSÿ3õ»ñ}é©Ç_zêñÝ÷= i³æÁpª¯« …ü騭­¹ãÚ«ä›{ìwÛ(Ü=öüãTWU :䈷_@÷{uè¼€§~ }ÇN?L™¼`þ|ž?®´lÝ@E™c©ˆ~= À’ªªÅ‹5iÚtýÜ•@EZ’«%-ÀÌv™Ùß B.Èf„o‹ñ•$Ž¥Dº¥[n·Cee“E Ì3»¬,×g‡$½ç¦›¯¾æZÌüÒS/Z¸àå§°n×nl.u^ãw¾÷É¢… ^yöÉ ·6Þlóß­Ý¥zÉ’'‡ß¿xáÂÙ3g¼?úÍÛ¯¹2”«‹šêjQT–Ëå¦ý0õã1ïø¹-[µ0ã—Ÿóµ&P”Ž:î®'Fì±ßAAzññ¿tc¾!#°¸=%Òôâú R¯™ùê?Ÿ;æÍ7¦ÿüSMuõœÊÌMš6Û`ÞrååÛößÀw'Øjû~¾Ÿ4á_·Ý4ãçŸÖY¿«¬³6iÚT6é^f¬2ñ§cÌÈ׿÷ €­·ï7èÐ#\z£óØS&¿üÔãG6¤¢²RÖÔ'|õ…l¼^³Ë:¶îÛÀ·_ŒŸ2á۪ŋßxþ9í;v’?°KEüÐ}ã^V[À+Ï<¹pÁ‚WŸ}ÊÚ²AŒ$Á³g%RbCò¡×…ž øÑ²¿ðm2ÕhÒ´éÿm³í;o¼ ÷[¶lmþÄœËåλüïÏ=öУß|åé'Û´o¿óÀ}öÜÿ`Û‘1‡Ÿ|úƒwÞúöë¯Løê‹íúïºß)+Ëwùß_xò±qcßóåZ·iÛ}ã^{O%²ùÖ}úØ{Ì›o\uÁ9]7êÙcÓÍÞý¦ËÝyà>?|7ù«Ï>=ùÀ½{nºù /‹K*J’âãéÆ|CF`q{J¤!èÅõ¤^3së6mŸü‘¹sæ,YRÕ¼E˽7ÛëÀCÛ´k'¹}wÝóå§ŸÈçómÚµï¾ñ&ÖZwý {mòÈÐ;ünJE]7ê9ðÃeY1=œJ7c•¡¸?…êêj9xoôHy_Œ<¤^·ÂÉ×ÖÞë Ûí¼[×è¾ñ&>쩇ÕÔÔôÝu>ýúØ|ëmŽ>ýÌ7_zþº‹/¨©®nÙºÍVÛï0è#ä/íEÆR!?”•åÿõÒáwÜòêsO}4æíwÙÍŸÐV‚ù½ô ßÉ1@¶¹Ãϳ„{¤²¿äÈD F^¶‚Ð~Á½Ýzö^´pÁ¢… žyìÁ@|à‹ŸÝ±IX/&Î S”È÷“'vYoƒ0UQ”ÆÀª}ý^ó×ó'~õå®{ï·ß‘Ç„y–U»ËJDàûÉwê]¿Gf† }"€_~šVµháž“-%’&!²q2 \ëŠå)±b] ³w„$Oä¸_Š¢(Š¢¬p¦ÿüÓßMÉårú,sEY 䫊aœí`† ˆAI1rDä¾êè®P³ Ë“¢F©¢(Š¢(+7ÿíÒÏ?þ°}ÇNûqt§Õ׳EÉ" £³ ™™Š—•mÑÈÉ~ŽŒÐ:€À¯CÖ-«(Š¢(Ê áŒ?_&)ŠRÌLdbeBêywò&¼o*fF⹜ÏÎ 1Š!½­+Š¢(Š¢(JcÆ‹¨É=¨ÃÆÛvy˜Z—²n`û£(Š¢(Š¢(¿5 GÂ9¶v[gm¼v¸¯C*Š¢(Š¢(Jã&Ø·JØ‚äs¬K€aUé^kEQEQeUÃì±.[;‚-×õ ¬ýÝkx­(Š¢(Š¢ü‘5g÷•ƃ`_L¾°ùÅð¶x/'fΜ9g¾ÆñÊJDë6íæÌš¦*ŠÒÐë·Ñ¡]u u›v3gÎ Së y˜Ànõ¸h4+ïuÉ„ PCW‰ÐÒçõ _Ï.a’¢(Š¢(Š¢a\‰¸ìÈ(ñ®<…ϳo^,iSGR‘Y¥–»áû[+Š¢(Š¢(Ê2Å„tÁÇIŒàíŠDD † Öà ë ±0CQEQEQdþŠîm6²‹“ñkr_^d‘1é6!'âÇÓãzEQEQEYɉÜôÊrQiÿ© ~V¡H9(.bõ³@QEQEQV"êP[ŠÖu“È.VËf4¼VEQEQV dkG=ŸÊa¤ëXK-Ïç“SS§·'DQEQEQA+±nÆ*v¡-€èHÖ%®<§Þf^g EQEQEYy‘}¸'~D ”²n”(°b]$ÄÎHÌHREQEQ”ÆBüôè`¡ºØ*5øOɬ êÖ£(Š¢(Š¢(«²í¢ˆŽJ£à¼îÅg¶?Êÿœ|>¿m¿]¶èÓwô[ï„yËR©¢(Š¢(ÊŠDÖ­mÄKòÈQj_6 ³Ñ$ZÖqõM·Üöô³#DQôÚK#ÂìßÓgÌ´ßÁçsæ üô)ß}_UU {·®~z½(¤¼%VÊÌ{ÚúôrÚ«g¡wßžQ”ÆG}¯EY©rÎùïŽyÿÀý÷=ïì!~ú[o¿{Á…—TUU5kÖlä+ÏGQ¸Ê¶Š‘ÙÞOÇ¿ç¾ûÇÿ¢¬¬là »>íä »w Kzd*IóΘ÷žyîùÏ?ÿrί¿–——·mÓfÝuº\sÕååååµµµ}ûï.·T-Z4_wuN<þ˜­·Ü"©c¹ð턉÷ þɸÏ,Xø»5V?ìƒöÚswÉ*Ý…$ßzçݳϻ n×®íË#žž6í¿×\wçŸoÓºõùçœÙç[¨©©|Öy5µµ·Þx]yyyPp…އÁ^¼\‘°‘qĸ@ºÐz´Kg¯\û?KÇàÓO}ã•®¼ü’0ã·Ê°á¶oßnÀ»é_ó-€Ö­[uîÜ)È*BÊ Qb¥DôÂ3OŒ}wÔZk­  [Ñ(\Q õ½^e¥â›o'èÖu?ñ©gž;÷Oá|À&÷, ®2d¶÷ý><ùô!'M¾÷®Û®¿öê±~tú™çÌž3',lÉT°¤ºú/]væ9œ>}ÆUW\òæk/>õØCÇuxm¾VbÇÉS¦HTý؃ÃÞ{î˜ IDAT{d¿¾Ûÿü‹?þù¢|>õTˆeÍÂE‹ž~vÄ©'ðÌãuø¡“&O¹ìÊ«§NýõqEÉí¶é3öÝQòsÓ?ÿ!ò;îз¶¶öìó/¨ªªzöÉGÛ´i}Õ5×IÖW]3}ÆŒkÿ~åJU©ˆ–A™¡mJ,Phu˜âk÷=ÈŒ0_YZfΜõÔ3#Îrz.—ðÐ#=òï'æÌ™³a·nÍš5ƒ·r<öÆ?øÈç_|Y[[Û½[×3N?¥WϳfÏÞuÏAååå£^{QÆë‰§œñɸώ;úÈ“O<ÎWþŸiÓn¹ý®O>·`ÁÂ.k¯5hà^ƒîY¼ÒW^{ý/]&µ·jÙ²ÇFžsÖàuº¬-)–,YòŸÿLCjW”ÆHp1*ÊŠ%sÎpêgýèãAüåOç}6þóSÎ8 ÌÇ{ômwÞ-¯¸êš+®ºfȧ~ÈAwÞ3ôž¡Ã>pÿ?úxâ¤É½{÷JÔ±ÊQ¨½7ßvGmmíûí³Áú먨¨øõ×¹Œýh×wJ”PXIÀ?o¸ù•×^_§ËÚ·ß|}“&M´k×vï½öÜ{¯=Eà‹/¿@Dk¬±zEë­·.€Å‹×ÔÔTTTxš–=Íš6=ÿœ3åx›>[ßyÏP -B}\QŠäâÅ‹¯¾öŸÖXcõ3N;yò”ï&Mžrñ_þÔªeËöíÛI~çÝCǼÿÁ}wÝÞªeKWpÅÃ$á,Àd3ˆü“‰r’IP‡Pf\¯ÔŸ=øp›6­ØÀ÷ ½þ¦[W_mµ'{hà^{¾3æ=Ý»uðô³#NrÎÌY³>ôª+.ýdÜggž}þ¯¿Îm×¶m§N«««§|÷=€Qo½ýɸÏV_­óÑG(?ïO¾öúÈëþþ·×_qÖàÓ_}ý™3g¯t—þ;ÉçÑQ¯¿´CßíÞû`ì•W_ã,0å»ïå“·ÖÊ*€½(ÊŠ¥Ðœ`ȧÑsÏ¿øî˜÷Ï:ï‚ÚÚÚ¿]qÉ1G~ÁùçèØ±ƒÌÛ‡¸ÿW]sÏÐaG~è‰Ç3yÊw6í½I²žU‡ÚÚÚ"í8i2€ß­¾:€éÓg,Y²ÀìÙ³]q¡¸Ÿÿ3í©gžpìÑGHTæË¯¾С}ûÊÊÊ9s~}éåW °ÇòŽªÌüŸiÓn¿ë;õÛAvq”è ”&y×½÷O›öß(Š.¹ðÏÍš6­­­ðóôéS¦|÷á‡÷ßq‡çžñ‡½þW¯±Æê~Á•ÙDZÔDD‘Û{m!ÀlÐ6Û±m¶ ä=¹©¥žÌš=ûɧŸ=êðCËËËÿûÓÏÆ?àOçžÕ¡}û¶ßNd6ìÞõçŸùç73óàÓNY­sç>ت²²rî¼y_~ý5€nàÛo'ÔÖÖÞrÛÎ|z“&M|åù|~ÒäÉê™wß}¯k×õï¼õÆÎ;©T„fM›þaë­Lú£Ÿ>yÊQÉÇYEi¼ø×K˜§(ÿ[ŠÏùÝ»uÝm—kkkÏ<÷óçÏ¿äÂ?÷Ýn[Sø@—µÖ%×Ýpó3Ï=ü±G~êIŸÿ<ŸÏ—••mÜc#¯žUŠâí]w.>øð£yóçß|ےعS¸ã±¸Ÿ1ï½/ëJ›mÚÀø/¾Ü¢O_ù¹ø²+EFëé3flѧïÎ{ üæÛ ë­»î™gœê©YŽÜ7ì-·ÙaÐþ‡Œyïƒ-þï÷—\h¶D—è ” 9a⤇y À¡¸YïMlؽÛá‡ôÀCœ2ø¬A{ïµé&›\}Íu—^ôç7G¿µç ýûí²Ç 7ßꊯLâÇèr——±IHH/@›ðÛÃEß¡¨²´<ðУ-[´¯I½÷þÕÕÕíÛ·[wÝuÌ;WdºwëúÆ›£-Z àô3Ï‘ëV¶mÉ_U6Ú°;€o&L|ê™ß}?uë-·è·Ãöò(ŠöÙ{/#žñ¼ þºû^û>;â…â•VWWðá#Ž9a§]l¹Íüõb«­ÖY„I“¦X{­5 }^W”Æ‚½(ÊŠ¥øœ`ûí¶ÀÌ;í¸Ãn»ô—DYøX{mX¿9ú-÷ ¶EŸ¾gžóGò]:ù[åªGñö^qéE›öîõò«¯ï{ࡲ$TQQñûÍ7Mê¨C‰Ï¬Yfá¶Ie½zöûî¨æÍ›Ãî¥\²dɤÉSœsÖà±ïŽzöÉÇZ·n5yÊ”û†=kYžsÔácF¿~×í77kÖlì‡ 6\ÒKtê’Ìçóûûµµµµë¯·î)'ïJ 9ãÔ‘¯¼ðÒsOíµçî^zÅ3N<å»~ì†k¯>þ˜£|ø±ñŸá„W$^ $žá!)ÅqÒþÆÁt1JE׆”h*A©?sæüúø“OzÒ òW¡™³fÁ›7Ç~ô1€¦M›¬µæšUU£l´a÷ ½+.oÙh£îÆ}6þ•×^Ïårçž=)åþtÞÙî¿Ïc?zúÙ“&Où÷O °G‘Joºõö~¬{·®þëÞÕ:w>á”Ó?7¾gòƒ»ü™¬[Wýæ¢Ò¸I_/в‘0ºÐœÿÕ×ß\qÕ5òЉQ£ßþéçŸWëÜÀÔ~°¶]±~á™'\‘ÃŽ:îÛ ?ö¨“Ž?Ö%®boïúë­{÷í·Èñ·ÜþÍ·ØoP«V­\¡¸·±a¤I[ü~ssæüº`Á²ãâ› kjj¬Û¥ €ÕWëÜ®mÛ_›ù5ÁåD.—Û¬÷&¿[c 'Λ7_Ktê’|â©g>ÿâË\.wéE©Hý¡oúŒCÎ9ÐÀ=Ü߃;º÷&½ºn°Á÷SùMÐÆ3ƒ"Šò…bç$²€Í3À`޽|¥A<øð£M›6•…d=7ÚÀÿ™6qÒäI“§Ü=ô~]7Ø Š¢­¶Ü"Š¢ 'ý𣪪ªI“§Ü3t˜ìÖ‚Ý òÕ×ßÌš5û°ƒì²öÚiå—^yõ¿ŸxªiÓfû¸mŸ?è½ÉÆÅ+•ÍU­Z¶lÞ¼ùˆ^÷ÙçzmÜC “¦LЭ›n°V7Áõ¢(+–"sþÄI“O?óÜE‹]vñ_wì×wÉ’%·Ýq”úeú/ª«—¤wŒþüË/(ðçþU’ ½ïŒyïö»î™>}Ư¿Î}ìñ'~ôߨjËSO>À‚ ¶Ú¶ß}ú~2î3_RJvé¿£ì”øç 7;aâ’êê?þÉŠõ—_~%’ë®Ó¥¦¦æåW_ŸòÝ÷eeeì3ï–gŸÁ«¯½1gίsçÍ{è‘Ç&NšÔ´i“ýöÙõqEIÓg̸õŽ»œpìÑé‡ó.\¸pÈÙܸGÁ§€Ásæü:oþügG<¿ÖZk®$_Ê"o‘ØlȰÇ`€íãðŒl¢ErV¥Ã2ÉÕëÔq¶’RyþÅ—¯»þF9Þq—=<õïGZ·Îø´´ 3wîÜÇžxê„㎮¬¬””?l½å ÇýēϜpÊé½zölѼùÏö/JmØýÚ«¯:lø¹úkEEùë­7hï½ú︃lݺÕk¬>mÚ;vìpÜ1Ge*?ô ý‡ è¾=0wî¼N:{ôÇsTñJ=ꈟ~úeÜøÏ=á”mûüAfê{öðÞcÏ8ó\Ñ à–Ûî¼å¶;¯¸ô¢ôwŠeå'}½(ÊŠ¥ÐœÿÃ?ž6äì¹sçþùçößq‡õ×]ç‘£^zåÕC>`ÃîÝ?ôàG{âÖ;î¾õŽ»¸ÿîTUUÉ·;u온f%ÝÞ^={Œ|sô!GS]]³Áúëýé¼³ØCÖMÇ}öy>Ÿ///ï¹Ñ†Å•TVV½ëözäQ£;é4fnÙ¢EïMzm¶ioÙ"¬ì9hÿ\.ס}ûþ;õ;ìà7î™XŸZ|Àþ÷ðï×]_½¤ºcÇŽî¿ÏAì¿Öš¿C}\QDÀµÿ¼iÁ‚÷ì!OJð©­­ýÓ_/nÒ¤òòKþ*òç5øªk®0è€^÷¸þW­$ßcñ_KžÆæJ°D½¸Í"Lí·¿—¼¶Ñ'L³=6¿Av‡y·uëÙ{Ñ‹.xæ±mºaà‹ŸÝqé·ÞΜ9Ó²Û*ÆwÝûäÓÏ>ûä£ËcwòrU®(«z½(Š¢¬bô{vf:=øèüòÓ´ªE M>Æy DÞu¼_%+'`&æÈ|û° V¹;qJ¥S¢ÔÁ¼ùó}ü‰Ã=hyÜÈ—«rEYÅÐëEQå7Ž‹håÍ‹ñ)Ù‡å…?N†êñÖX#èåCË-F¾òB˜ºŒX®ÊeC¯EQ”ß A|KDöäõ {É>$x’Hú‹s½jPEQEQ”F@Ö“õÒ)ÙHÙû†sÙ=MyW9ƒåíŒy€ˆe¡;ocz6Û¬¥¥×¬(Š¢(Š¢(+²+ƒ%˜eÈFÃYÑvŒ¿3Þs¬%VL¼Ì.ÆIrÇä„m5l¾ÃëVEQEQ”FÙ=Àî‰!Ôõ>D’/ˆ‰l¢9`×§ÓÇÞ·#ý|EQEQEidD^XMv)ÙÆÚD²ðœÆ0È'ëQ<ˆWEQEQ”F@Ô’,`ËJv2 !²{³ËŠÖõzÅdº"EQEQEil€xçÞ0}G¿õN˜·ÜX!•*ÊrâèãOÞ¢Oß;ïf(Š¢( L¸lCcïÐîÀv¤O‘ýJs2JDÉï&.§ÐyÜgãzä±/¾üªiÓ¦ÛôÙúÄãŽiÖ¬Y(ô[búŒƒö;ø¼sÎ4p€Ÿ>å»ï«ªªtïÖÕO¯…”¢^•¾öúÈ'Ÿyî›o¾Ís~ë-·8kðé:u …å‹óì1qÒduï )ʪÈsÎwÌûî¿ïygñÓßzûÝ .¼¤ªªªY³f#_y>ŠJ~U\ã!³3gκãî{ß~g̼ùó×^k­“N8¦ïvÛÖY*àÓqãï¹ïþñã¿(++ÛpÃîƒOûöÎ: Ší‹ãç& `wa=EìûYØŠˆbüTTv>» 1Aì; AQD)“vç÷Ç™ QyÏo8sî¹÷²ûfØïž=÷Ü1Õ«U•:ñ\½výð‘c=ùðñ£žž^±¢E+”/·Ð®žžžL&shÛ‰¾Ã€©©I…òåGÚ¤‘­òùû÷vŒúôé“™YñíÛ¹ŽNŸ`ÞŸ‘öP­HHx³pÉò{-Rd²×D»¦ 77w‚‡w®L¶zÅ===Åÿ!œxæ²3(Šê‰W!‚PnOä)D² # 6‹„!\DœoÿgD5À®€À>½zì Ø±hþ¼­\½Vêñ›±}çn3³â;Jì‘QP¤HaKË’¦¼£ipMäqR–egÍñ›ú¿Ùuk×Ú°ý`àîJ•*^¿.õCáš‹{IßÃjÔ@aüDFE@Õ*•ÅÆ ÃG&ùLgår¨SËF­vüÙQû“’’}òôYÿy¾û÷ì|ýúõ”i3£ŸÅhï%áÆÍ[cÆ»?‹‰Ý¼aͲÅóÃoÝ?Ñëý‡R?€/99ÓgΙè5%99ÅÞì‹gOí :x L.£R2öùsúißîí7®\håÐâá£ÇS¦Í”Ëó¿ÜÚƒ‡\Ý<®ßð9=hÿžôŒÌm;v >ßòŒ´¼€š4€L&óœ<5;;;äÐÞ¢E‹ø/\B‡šç¿09%eñ¿‚¢ªÓ»\–†(ÔÌËbÁDY-ƒ¢!@Ô,^TdÅQ6+»ü(‹æûуòåÊ99v<tX¹ý÷"5õ]Ðᣞîãuuu p_àþƒ>|¨^µ* ä ‘ãð[·wî|ôø‰L&«VµŠÛx×Ú65ß½ßÁÉYOO/ôì z½Žru»{ÿÁð!.cF þ:!áïµîÞ»ŸžžQ®lç®]œ»:iŸôôÙsÓgΡ³.T¨fê^Ê—+ ûŸ<ݶM«Ñ#‡Q‡CÓù_óTdîØzùJê»÷•*VXð×\k+K¸|5lWÀÞˆÈ(†!U«Tq5¢^ÝÚpáâ¥ÉÓþ§¯§×±C»k×o¦gdØÔ¬ÑÊÁþȱ/ââŠ)âí5Ѿ™Ní])úuäûÑtuuó¿}ǹkçé>ÞT?ËŽ6dÍú´ã<ÿ…óüº»دïúM[6mÙþgŸ^·nßy[·nm¥9~ 4=ÇK–%&&õîÙÞÚ¥J•Œ~såêµ*•+ié%aÕšu2™¬wÏî•+U}}ý?Ý ¿Ý¡]‰çÒå«NŸ=W¾\Ùµ«–@ñâźuqêÖʼn:<~„’%­†©X±deeåææêëë‹FÊ._ “ËåU«TndÛ¬,K|úôéÓ§Oð-ÏHË ¨ID?‹‰‰}>kºOáB…ÌÌŠS½¾~ã–k7nnݰ¶p¡B¢áÿc´ï–(Fò¹GÐÜt†Æ±%Í‚‡ÐĈu´BЋÂÚ?Ìý+Uª(µþNìØ½§hÑ"];;ÀúM[–­\mmeuh_@×.NW¯]€jU«@pÈÑqî^©ïÞìÜâ?Ï÷îý='üø©x±b%JXäää<¡—¯Ü½ÿÀÚÊrˆËÉàÞ>ÿ;{îÂ’;uÔcÂø3çΧ¦¾Ó>iû¶mÂÃBÃÃBCÏlé`ýf¸ßü… “ɶïÜ /^Ä99÷jֲݠ¡#ï?xÈ=%ùï_óTXËreM›4^¿f!äiDäÙsç`ïþƒžÞSs¾|Ù·{û_sfß¹{o‚ç¤× „aœ:u˜âí‘‘‘~ëvص+—.ª_¯Þ›·‰;wÒ¹4Ý•Â/ƒ ß–«ËÝm,!äȱa×nxxO•ÉdÍ›=tðÀ©“½ÀœþÝî×§×<ÿ…›¶l<°ÿ¨CcŸ¿€zuë(Ïós#“É4=Ç7oÞ^¾­ì©ó§ÏŸéO-½T¡éd¥¬­ 99åË—/ðþý{‰[üë„ ÃG`ØATU«òäi˜›™|øðñä©3е³c¾«j¨Y£:¼MLJJJ¾~ûYL¬µ•%•øy|FÚ_@M@&“@bròóç/nݺӶuË#ÇNìÚ³wÙ¢ù%KZ ƒ,~!|·i e^ŽA 3JZYŒêð!„!ÀÂBÓE!ù¡§)AÁ!÷<3r¸´á·áÝû÷‡‚C쯧§÷æmâöà3ÉÃÜ̬e îR®^­JbbÒÒ«X–0ÎÕÊÒÒ®icƒOŸ??‰ˆ€šÕ«@TT´L&û{Ízð˜0ÞÐÐP<¸\.‰€A‡Ã®W©Riýê––%´LJ(ÆFFM›4€—/ã "2Š~ µ°0ؾe`ÿ¾‘Q^S¦Ñ; Aþ+Ä×<ðºKgG»¦­­,õõôÀÂÜ99÷çîY¡|¹m›Ö›™‡~üôîô#/‚ü›ˆ¯yˆzö š4¶€¤¤äÏiiP¹r¥ ¡—¿|ùR¸P!šŠš›››™•43ŠÊqÛ†õíXX˜—-[bbŸ@ÕÊ•@û]‰ ?ÂW¯®öÍ€eÙ6­[vlß–iàƒ^«pñÒeØ´e»­ÃD¯) “ÉÚv¢ßUþhyŽô}ÊÜÌŒæ7>‰ˆ¤Â·‘mC-½DcsÌóY¯níSgÎõèÓ?öùsÐ××oP¿žÄMxû340€Ú65ÃÃBMLL€O­üòå ýâå1!<,4äо"E Ç>¾uû.Å(ùÄ«Wñ}¸\¿¾lñüг'Z¶°‰}¾|ÕÚšÇg¤åÔ®ÜÝÆ^8}üä‘ .Nþç;ÏÝmlìó»÷ì[¾xþˆ¡CvïÙ÷ðÑca–ÿøµÄ hY!‘Eº—vaÕm£€Ð‘m®2ˆTÕû^ºx~ùrå¤m¿ >|{NWWw’çP|¼=ûôê~3üvpÈјØçûuíì¨eÒ•«×îÞ³¯ZÕ*»wl¶²´é:þÞý‡ô“kñbŨéR% !á +Z”~FÿÉ5ÿ61‘~o^­JˆŽ‰==½òåÊÒ|'SÚ1üÖ–e š5m’œœBß\i¯g11ÂqNN΋¸—P¹r%à–Ej¸+äGÐ~u=ˆœç¿V™½tåmb¢•¥%¼|eùˆõñÃ….Š~6bØàÑ#¸ŒØ_-ϱ©)Pi W¯^€¦M•/WVK/U*U¬°qíßôxÅßk#£¢{÷t.\¸°²!Âè˜ÛõàÇééé@ nDF?ËÍÍ€ åÊ€µ•eñbÅ>~ü¤vÕà²uÇ®ääûæÍíš@õêU/^ºLÿšAžŸ‘–PÈÑ¢’SRܽ&;wuêÓ«GßCêÖ©]¥r帗ñ v‘è÷kÐÂJ-âÍ]Ä!keYLU³Æ'C@Ї´%ÐVi‡¼±yëö£Ç–/Yô;«jؽg¯‘‘ $€Mÿ:áYLlLìó[¶@•Ê•†iÜÈ–a˜èg1á·ngggÇÄ>ß´e;MÏ>äiDä»wïüÙ§\Ù²ªƒûúÍß0ÈÈȸ‡sWz§Õ­SKû¤4VW¸P!“£ÇOÞðjת 5kT/U²$ܸyëÍÛÄ»÷€Û¸1ænA~G$×< <›ššX[[]É^¾\Y]]]»&uuu“žFD¾Š½låß ÃL™äQ¼x1š"ê UªT€qqô}‘®|Ò~W"È åêz;~â¤ÌÌÌ9³f´nåðåË—5ë6Ñ^IÉI“ó…~ƒ/&1) Ô}Ýÿ+!yŽM›4ÖÕÕ}›˜ø:!áÉÓˆƒÁ‡ÍÌŠOõöRê£Ò+==½qóV¶vwï?€«×®¯Ý°)99åãÇOûÚ³wÓÆÆŽ%Ò¾mkšb±tùª¨èg_rrnݹ „±~òä)õ¬P¾\nnî©3çž¿ˆÓÑÑéìÔI4Lþ`bl ¯â_øð1úY MþîØ¾h}F’ç®åüªÈÈÈp÷œR«fÍ ã\€öÇŸÓÒBŽ+S¦´¤jÍ…„V¯fEr—âÌ,× ™  K@‡?—s’œ°@X Âö1Ü?r5Z~@R@ffæî={ÀeèjÑÓÓ;uì·+ òéÓ§}ƒ@fœÑ IDATFb``@-M›49|ÈÁC‡GºŽ¯mccjb’È…T£zµÅóý¶lß9Ég†¾¾^劻uiÛº%íX¤Há’%­ÞXX˜:XíàýûöÚ¾3`ëŽ]Ÿ>}.QÂbØAt¯–I‡ ôömÒý‡†tmn×”þ¥®ec+–.X±jí‚%Ë23³ªU©¼xŸ¤8(‚ü›¨^óTXÓeï •+U€*•+-]è¿aóÖ1ãÜ ÃÔ²©áí5‘™¨°VôŠ€*•*/²‹-bnf_»+äGÐtu½z?ÎÝóÓ§OÓ¦LjÛºe¥ åÏ_=yúLÿ?{W¯Vu`ÿ?÷î;¸zÝÆÕë6îÚ¶I¨(•M¿½)añËî3 úË—+»ð¯¹ë6nî;`ˆ‰±±ƒ}s×Q#$edU{ÝðH.—ëééÙÔ¨µmj^¸x©ŸËМœÜÊ•*úx{víì¨6„d``°eÃÚ]çC/ =ŽeÙB¦¦uëÔþ£^]ô¥ ÖàäÜKWW×Ü̬m›VþìSë¨#ä:fdNnî¥+W»õ,TÈ´R… ÇmÛ¦h}F’ç®åÔ®d2™ÏŒY††sgÏ #{{Lð_¸¤³sïÚµj.[ä_@*îi²,÷ƒ––%bq À Êš˶{Û†±;K”g!,Uê"£ô÷(š¼¨ªMÝÌŒôÌŒôÃûv+7B×óY!­Õ¯Í ©©©´²Û/ɺ ›‡„Ú«iùððŽ ¼æAV!©ªôÏ!£ émBvfFÿX•e£¼à¥Ag„°„!м^SyÌ!α&D´ÍŒD3?‚ªùQ>§¥í=ppˆËÀBü£ƒ#H¯yAä»!Àp ZÎ…›©k¦!i^*+Eœu©Ã·BÇ ¢Áˆ|…LM/œ>.µæÿèàRÁkAùQèBz(üT#v +Øu©Üæ$2¯Á¿ŽDJSÍ®²<AAA~:8=Lðµ>X.cZ¡N@Î¥‚ˆ½ÄÇ*:Yš"-m­n:AA)ÐÂÅ— À0œðU$UK…0€RHškz¢Ë…¡Õ¢®…«B‚ ‚ ‚ ?|ù<^J ¹Šk5Ae%aM“²E£ÐV\HaY~JEï€ ‚ ‚ ?#°\¤šÐØ2'{y+–É"¡Nº@€¯¬'VËTTóF%åL!tb¡‰;CAAŸ ±Ž‹`þˆJ߯©]]Ñ@â çÒÑY ršÚ С…´nž¯Í† ‚ ‚ Â`xËëZI²3ÃU§V$dïËŠ…µ¢Ÿ¨¼‡¶yÔÕýLjÊ3fÅ‹IM‚ ‚ òcˆ2¡§ä-]RÈ€4!Ö|ìY$š5hˆhV¥tüÈŽð©©©R‚ ‚ ‚ü|¬šPe *Ò–ÐBEµ’Oâ Œ.M—ΣP«¼Õ˜AA¤ÀÃŪWIXDš$¢|L€è«ÅæÚÅ&AAùe¡r˜.8”/Šå€°¬†=yÁL¹tƒáP­\—ªEâ[E¿#‚ ‚ ÈO!„îKέ/ME/Ëgv¨‘¸¼Q±Ÿ9pÂZ¤˜ia"YÍH"h+_ÂO»/‚ ‚ ‚D„U‰À¥HÓuŠ ™«%ÕÍÂwSF)¯äkÐ9+*&‚ ‚ ȯM—á'N–Zä'„êaZèƒz ¤†Y–• ]V*— !âÚÕ X¬±ÍÏ*À ^ØK; ‚ òß1t¤kpÈQ©AUh0€`€SÉZÂÕD%[Cš ¢@µTË%(Ä9ÖŒêà‚ ‚ä —a£úôìÞÙ©“´!Lðð¾vã&0 S©S‡Q#†2 [7®Ü$SLðð.W®¬×D7ÁA~[Ä©9KaÙ!@)DMD)"B0[W¤Ö Q³$’€V- ‚ È?ÍŸ}zyMt“Éd?q÷šbeeéܵ³Ô ANÎ.Óƒ¨h\…ì"ˆqANë² "–)*ÓXÉðjû!‚ ȯLzzúº ›C¯\MûœÖ¶M+ ㌠û» oÞ¬Éý"""Ûµmýèñ“À]Û¨ÿ«Wñ½ú >hmeÙßex3»&÷îߊŽ)Sº”·§{Ý:µ§Íô}éë7ß×o~-›š[7®}÷þýÒå«n†ß&„4mÒÈÓ}|áÂ…•~ uèèèÔ­SÛ¦fõ˜˜Xj:Òµ['ç®U§PîÊ¡i^µOYè•••5}ÖY®Ìž¯‘‘aFfæÚu/^º’–žV¯NÉ“<¬­,@üMŸêݾmaùÏ¡Õ=T„´&Pí-Jæ @¢éÁªyо|n57÷¿Aä'e濈¨¨‹>´·Fõj·îÜ¡ö£ÇÇyáÌqωno“î?xH퇂C7jHÅ% :ÓårZXñ¡ªF ,ËÊ%k©¦‡œÞ¥ÿ0„0„(if¼ —c­š/"ÒÍ ]ÅKK"‚ È/ÇÛÄÄK—¯ÚP¦t)èÞ­‹ÐÔ§g:µk€±‘‘cÇöƒBêÖ©ý%'çÈñÓ§x n=ºwkP¿ ØÿØñ“C/‹€× wîÞ 9¸×ÂÜ&yºÿ9pHJjª¹™™ØMLà¾ûÐãŽÚµla¯Üž'4Í›››«é)Ç>[·qK箃ö§–¤¤ä‹¡—‡¤ƒ¸ÓºCçØç/*Wª¢—A |œX³Ð¥ÑeAêÞ¢¬ŽÕW¡pê\q@ÿ•NÉYUì‚ òëñæÍ[†aJ—*)m°âcÒл‡ó¹ ?~ütîüûævBS©’Ö¢ã’IIÉÂ)%11IGGÇÚÚŠžR9›˜˜¤ä¤ÌŸ}z…‡…Þ¸r!øÀžÄĤ9~ó¥y@Ó¼ZžrÈÑc††½{v,¯ß¼Ç®=mílí7o•žžþæÍ[Ú*~‰¤à (±§œ¾Á=X@+øpÐ6šþAÑ¥V®9ÏâX­§Z#‚ ‚üJX[[Éåòø× TwŠ¿ V¨P¾–MÍ#ÇO\ ½Üű“®®â+â„7o„ã× -ì›ò{¨¥e ™Lö61ÑÊÒ^Å¿¦FÁA Ô*Y²C»6+ÿV“ìñÕ·iMóæææjzÊn®£¯Ý?ÁsùÒ…… k+K†aN;\¤ˆš¤ð¯ý òŸ¡zmr· «æŸMú ,CŸ1òµ‹ýkíH¾‘šúÎÖÎáÇ҆oË—"œ¾»D^~½ÜÜÜÙsÿrhÓ±ï€!Ò6äÅÊÒÒ¾™Ý\¿ùÏ_Ä¥¥¥‡½|5Lê½{8ïܵçÁÃGÝ” t ¹s÷^FFÆ®€ÀĤä–ö`nn+“É TÉ’Ô«»pñò”ÔÔÄĤÅKWØ5m¬%D€eÙ7oÞž>{¾J•ÊÒ6å)Ô¢i^-OYGWgîì•*U3nâ»÷ïÀÊÒ²Eóf¾óü_¾|•••õäi„·ÏŒ/99J3!HA„¨S×JV|l›ˆü 5š BhEîA'LóÂ[ V®º ‚ ÈÏ@~}ì ½|åÉÓˆc‡îݽ òoX¤€3gÖŒJ•*ºyLêÖëϧ‘ ë×—z@K{†õÿz{të²fý¦N]zœ8ufù’ÅŠ—ý®]oÖ²ÝБ®à?w¶‘‘Q¿AC iaaáû¿éâT Üw€æ] 1¦x±¢ó|ÿ'õP™ø^Â#&ö¹¦yµ+¤µ¢:Àë„„­Ûwݾsþ¨WwìèQææj>—§¦¦–/WVjýùéÑw€ïÿ¦Õ®e#XRSßuìÒýÌñ¢E‹ˆ¿:æÒÓ*KÒæ@.—¯Z³þèñYYÙMÙNìU¼x1©“ˆ…K–ï? ÃܸrAÚŒü®ÐKÔáÒAúvêÐ^ÚüO¢zÇi¢¿Ëp-¿çJص¤ä”YÓ}¤Íð%'§S—S&MWÀÐ~]!ù…¦wMïb­Ú;¦¥¥ np,ø@‰b‹¦¾bèf=Ó}¼…7ßg1±ý 522¼tî”àêvóù—IIM]¶bõÍ[·rrrì›Möšhbb"u¸{ïþêu#"£Ê”.å9ÑͶâ3˲£Ç¹ß½w÷öÍU«T€½ûnÚºÝÈÐpêäIM›4¢n“¦LwìÔ¾uK¡ã¿O«TU úçQô6!;3cøsOq`šBøò{œ6æD/á7a‹X³,ÃÒP5ýG áGQUâ\ê6ÕТfÞGáù„9Ö²Eó[7¯_½*33kî_ß³äâ'%îåË´Ïi65kH~€bL­;v9w~ÍÊ¥Aû¾ä|™6s¶ÔC™É^ÃÃB—.ò—6 ¿1ÿè%ªüšZ'--CqˆZX–Ý ÈÀ@ÿ¿Õ¿-šÞ}4½‹]8}<<,”>zõpþ£^]‰ªÍ}%T©\é`Ðaáô`Pp•Ê•DíÜJӰгó|ÿ¸ÿ`ÈÑãâÖ)Óf¦§§îܶ?`GrrНº¯>r÷šìرýñƒ‹æû]¸xIܺgï~Cá499eÃæm[6¬î3Ù×{åO9§§§û3Ü„þŸ&uj¸‹ ¡ÛœsAf X²H¡ò˜£XK!Èbºq¹zLˆš­¿WO ¸ŽILMMœ:u˜ç¿P¹ýWæò•°fÍš2 “’šêç¿èνû–%,Ä˫ՖÙßwàÐá#ÇvoßL}ÞtïÓ?xÿº”[S4×ü×dW»… :¾b…reJ—*SºTFFFzzzö—/›¶l[¿f¥Ð«À©Ye•Ké¬8BsDx¬È!„pÚK,Ž !­L-‚QNxÝM€% äK¾ujjêÉÓg›5m"møu¹t%̾YS˜6c¶¾¾~Ðþ€¥‹æ9vBpP[f¿c‡v/^ÄEE?£>GŽŸhðG=¡@’0¦M5ÿ5ÙAÝ?~JNN©ÉGû*”/ghh£É_ AĈ/Ñc'N;úÔÑ §ŽfùúÑ?#Z.Ë ¡—<ÝÝN ®eSsœ»W\ÜËÀ[wnÙpùjØy>”¢ö®¡MjïÐðkPT7¿~œe‹ç÷îÙ½‡s×ð°P×Q#„.j‡]¶x~xXèõËçùÏ;vüä©3ç´û«Ý˜CËsD W/ž9y$È®ic‰=`Çæï˱¶¶BªÂUõ7¡ý]ŒrêÌY==ÝÖ­¤Ö¼ô¥0 éÞ­ËCÁpüÄézõꨭè¢e7Ÿ@Yþ±,+è Jnnî½û‹)ÚwÀûÖ}çî=Ú$—ËgÏõ÷˜0Ž–‚¡”.U*öyÜë„„ðÛwŒMLL.^>røâŤ 3––á×# JWt¤Œè¥c€î™,¿{¢È“‡¨ÙJvî ,†ü^Nž>Óº½cï~ƒÞ&& ì_žOŸ??ˆlÒÈ6þuÂÝû¦x{/V¬t©’ncGSZfÆÔÉ%KZ›˜˜¸ÿ:!öù‹Â… µhÑüÈÑãÀ²ì±ã'»vv”Œ)Ì|Íÿ)“<,ÌÍ--KLòt¿zízJjª&;íE·0011<° ó‹¡—ÓÓÓÀT”ƒUÈÔ4-KJSõÜD@r‰þÙ§—M͆††½z:¿{ÿ>%å+—埽{Ö¨^ÍØÈÈ©SÇÌÌLOw·Â… —)SÚ¶aƒÈÈ(Ð|רN-Fõ× öØçqÃFmÓº¥·§ð-–q$h†©VµJŸÞ=/]¹ªÅŸîE2súÔ Ê25íÞ­‹}3;-ÏA-h£ éâ䨚╗¾ÎÝ:_¼tùÓ§O‡‚÷î¡øšB׌6±o=l¤kófvß·›Ïbaa^£zµu6§¦¾KNIY·q3!„>G´´t™Lrdöÿ¦ž:ä`ßÜc’]ŸºmÇnkk+Éo^¢„ň¡.ƒ‡ž3oþ¬éSÏ]¸(“ÉÖ¯ï:~¢C›ŽÞSgdee‰ý ¼„%„¥É@…«pãô¯’âex-NÔeŠÐôÚ‹¡Û˜ÓO5ŠIÕÁå–|/Û·;wêØþÀ]µmlÜ<¼²³³¥¿"a×nÔ«SÛØØ8))ÉÈÈPøHWº·~\K™ý®NŽ'NŸÉÉɹuûÎç´´V-[HƤ§M5ÿ5Ùé©êtYƒøïÈç´4ᯌª¿pŠ ’K´xñ¢ô€&êeegk¿,‹ãüõ ô „²¾~Vv6h½kÔÞÕ_ƒžªn~ZÇ‘ vسç/2¢E›¶vK–­ß)ªþj7æÐòÑ‚öw1x%Ù“òÕ¾bŠ+fפ‰ßüÅ™™™MK?„çËn>?ο9@ W¿°ofG)Z„ûD122$„tëâT£z5ccãaCéè‡ß¾óüù‹AÁÞžîbgJ¿¾½Ïž8r$h_ÍÕ×mØìãí¹uÇ®råÊž8rˆ•³ƒ” f,Dê¸ýb¾&}•r®€% «8sË€°¬œåÂÑ,04ƒ›–`©z4´ð…)a¾2ýW!„˜/> _ßÃG޾~P±b©Ç/Çå+at/®%Jdff½{ÿžjëø„ê ¥Ì~ãF õõõ¯\½v!ôrû¶m øÕ˜b4ÕüÏÎÎVk§½T·0(R¤°……ù“'OkÛÔ€ç/â²²²ªTáÖd¨ú §" ö£ér•úi@Ë]óÕ©UQÝü¾kwïÞOŸé»à¯96022 ÜwàôÙóR'j÷"Ñò‘_•[wî®^»aëFiž®rssçù/¼pñ’••-©Š»×ä®Û´j)møEÑþ.Û6¬¯º䡯„^=G¹º¹wÕvd´îæó/`mmµt!·Äðò•0}}}›šÕÅåÊ–NY–eY–aHDTTrrJ{ÇnBÓ€ÁÃöëëî6V°,Zº|èàAffÅã^¾ìÓ«‡±±qÓ&""£‡‚†ò&BXÂéc‘Ué?%¡ágEšp‹©«Bt¸ôkÂ0@h›¢Ã»qBtèCŒü»„µ\.÷çÿ,&öË—/‰‰IÛvì*^¼X™2¥¥~¿2™ìÚõöÍì t©’uëÔ^´dùû^'$¬^»úh)³Ï0ŒS§Žû^½$äˆÇ£©æ¿&;í¥v ƒžÝ»í Œ~ö,5õÝòU«ëÿQOX·¡ÖAÄhºDÅh¿,¿Š¦»&/S«¢ºùÅ÷#Ͳ¬©©©®žÞ£ÇO÷K=”Q»1‡¦ç(íŒüB¬^»aˆË©U+’"ëjâ2pÍúM?¾Dê'BË»XZZúé³ç{vWèE˜ç¿pìn!£–¾ªüQ·NxXèÀþJxX­»ùü ìÞ³/üöŒÌÌðÛw-]>Ôe Ê‹Ÿr¯ÎÁ‡>ˆÌÈÌܺ}—\&·mØ S‡öB–ÿÉ#A°{ûf±ª½|%==ñc{(W¶ìÕ°k™™×o†—û©Š&‹‹J«AqÓP} @ÑU½™8=.įUÐôÙK“]; ôoÛzùÊ¿cbcMMLkÕ²Yºh¾žJnӯǽûK”°¾ïöŸ;{Þü…νúѪ Ÿ<¥vß™Ó6nÙ>Ásò»÷ï*U¬8Äe€øÕÕ©Ó¶»*V¨ Ô“Œ)Æîì¥+þî7h(Ò¤q#O÷ñÚíÀoaý¬téRÂC]¦}Nsuó Uþ{Íú5+—ÑÓ¡.§ÏôíØÙÙ¶aƒžÎJZ T÷²ŠµXÖ*Ò¬yÝLxåͬœóa”î"­ž¨Iñ¸b»ÈßøÅ´ïØ &übÄ,_µZOOܘü\©™c~ëßêüžäã%ú­ä×Ôù5‚äu6ǽzå?w¶´A‰°^´tEnnîÔÉ^Ê^RþZ°˜aµÕåä—á«ÄŒz>zæ•-ýÉ 0@€%ü1°,°„Ðf„%„–d1á¡§b8»º&ä»ÑTöëGø'ÆD|ä?¼DókêüAòÎÃÇ«‰²ú» _·a³ëø‰m;õüsàõ›á0m¦ïÓˆH_¿ù¶vCGºzLòÙwàСà[;‡µ6@àþƒ]{öµoÝa¤ëxqªkõjU¿úµ ‚üòP¥K%¯`£ÚZƒ<¦f††UÉXÐU›YEaYn"…eYÀ²œŠW7z#¢‰C{¥ýçŸAò‘ÿðͯ©ókÉ;ÉÉ)E‹*•k8vâÔ|?ßJ+îŸåëwòhÐ_sfÅÇ¿G¬.Y.“ÉhÄúåËW+V­Y÷÷òÕ«EF?;uæ\õjU©[ñbÅÄ… äw…“ÑÜ Õ´,0 #EPO@³9ß™ÑB@]v¶ ’‘Ͳ,g¦fé oT3 ò³°ƒÛÖ1|«?‚ òÝÐ’çЫ§óÚ ›RRR-,”6Ì“ «««§§kbb¢¯¯_Û¦&­k ˆ€¯}'5 —¥)TJsF%] :¼NÖXÕCiz,•ØŠ|nAAò ssóÊ{Ùª–<·ªR²¤µŸï¬•¯ýðñcåJûõíE÷å€wïß››e9‚ü>(‹^ª·©Þå"Ѽæ6—–M]jÍ J3¡ˆFA…ÚµjF*ï5­Õ`›ûævöÍíärù©3gGºN8yä¡¡!DDFÕÂ6òÛÃ¥:ƒ(FͲ\Vጄ¾°žåî¼Ø¦ÝD(DMDTôZØAA§e û[·ïÈd2iƒ2ææfÑ1±jÝnܼµzÝÆWñ¯se2™Lž-çWXÝ¿%ìÝ‹ ¿-¼¥Û¸0À„îÂHwuQU¼„[ñÈé.0,KXà57ÝYGè@í’QøÝfAùg©Q½ZéR¥®†]—6(ã2 _صëÍZ¶:ÒUÒTÿº…LMÝ=½[·w Üï?o¶±‘Ü»ÿPGG§QÃùí [ô˜Ð¨³ÊN1bUMcÍ t !’Ä%-RÛâ&‘ò\‚ ‚ä7cÇŒ\³nc ûf ¼X\__?<,”×­S{ÿžBÓd¯‰Â±žžžËÀ~.û ʶ»ÆŽÉ0¢¯¯ä·D,é·¹ÁQ}|™æX>}„žaãs¥å yÍ y!Qä‚ ‚ä ¶ êoݸVjýa–/Y 5!Èï -ú¡9)ƒÄ2 rSÁL3@aš‹\PÕà„Í„>KDIU£¤FAA~R!K8µ Š]+ÖÀœ;!@X*°¹Žœ°¦Þü¨Ò%´ÀÐ 6\Äšúr¿ jkAAäg„Bh<€° '‰9ù«ˆ/Ke6UÇ\› 4Çš+ÿà sÁAÞ´³XI£ªFAA~Z'–•­,—¢@¡¢Õ µŽµX.Ó-Íi-U5‚ ‚ òó¢^Ë âÊÔÀ%qˆ!ÀWád[* IDAT!üâE¾M³D&„pJþLjÊC‰{M˜/&5!‚ ‚ È¡Vàªê^.'„žðbšk]ú¯jO t 9wưX ›Ͳ\AÕ*ܪßAjjªÔ„ ‚ ‚ ?ŠfË„°„_mH³¬Y"’Á€Ðª Ü@šÂÕâÍbxÞS)ÙZ}wAA)ÈHòŸ•,ˆ¨Ÿ ¬¹S… &¬.C5¶"­Œh&"ÚÐÕÀ®X܈ ‚ ‚ ?)T&•Á|ʇ´j·ÖQÉ*ª ¢U.Å„ŠU7AAù9à44!ÀŠ0U¼ MCØ"ÝË«kÕª T£siÓ"£vÔîúˆ ‚ ‚ ª¤ÌPqËgD3¬à@€Êœ&Œ.="„Ä‰Ž•Æ¤¹8‚ ‚ ‚ü´(T50¼Þå4µ°)Œ «U%1Ðñ1JQgiZMUÝ ‚ ‚ ?jd0¡1dݠVÓ-*Æit›Ï‘Âeš(·Bh=lE_•YAùA\†:zì„Ôš7&xx/Y¾JbìڣϾ‡Ä–ƒCŽÒcq—¬¬,I>OIM€—/_yûÌhïØ­u{§ žÞwï? nwîÞ›àáݲ£cמ /MOO§vùY`Y.郈OD('w(Ì, , À•á†Jl‘ VÕ #–0„>XUýŽ ‚ ÈÏɇÇŒŸ˜ýåˆ5+ÍÍÌÀÝk²‘‘Ñ®m›Žïðgßí;vSÏÍÛv è×÷Xðþ¿W,¾s÷Á¢¥+”BŸ–uÛ²ðeð!„Ð<î!Hb„jk.Çúkpéúò²AAHOO_·asè•«iŸÓÚ¶iå1a¼‘‘a—áÍ›5¹ÿàQDDd»¶­=~¸kõõ*¾W¿AÁ­­,û» of×äÞýûQÑ1eJ—òöt¯[§ö´™¾O#"}ýæûúͯeSsëÆµïÞ¿_º|ÕÍðÛ„¦Myº/\¸°Ò/‘$$¼ï1ɦFõ™Ó}ôôôàÝ»÷ñ¯ü5·D hܨaãF ©óêKéAÅ ºwë¼gß~ùIàÖ rú˜¼BTY³Úåô5íE·’Q NK!„¨Ž*ñ×ÔAA~fÎñ‹ˆŠZ±xÁáC{kT¯vëÎj9z|ܘ‘Î÷œèö61éþƒ‡Ô~(8¤q£†ÖV–ÜiÐá1#G?| ]ÛÖî^SÞøðלY5ªW›5Ý'<,tëÆµ0uÆì´´ôÝ;6ïØ²!11i¦¯í›ÄÄ>:ÊÕ¡y³9³fPU ÅŠ-S¦ôÆÍÛ>~òåËå nß½÷#»,#È‚¨‡HÍ*«5—YE²ÑÂG%? âFú ™"‘‚ ‚üv¼ML¼tùêÌéS+T(_ÈÔ´{·.öÍìhSŸž=êÔ®Å0Œ±‘‘cÇöƒBàKNΑã'ºwí"ŒÐ£{·õ뙘˜ Ø¿„…ùÅÐËBåuB»÷¦Lò°07·´,1ÉÓýêµë4:yò4"++»KçNâ7wBÈú¿WXX˜ÏòçжӰQc/\¼$ê°wÿÁ;wï»+±#HG*eY'F+ì<„SÕJ Ù„iõ­’\iV]Š7‚ ‚ün¼yó–a˜Ò¥JJ¬ø˜4ôîá|îÂÅ?;AGGǾ9'¾ TIkÑqɤ¤dá”’˜˜¤££cmmEOË”.EJN_CWW777WlÉÍÉ"ÓÐűc×ÎŽ£ÆNx)ò óÉ^í 8{"¤S‡v>3fݾsOhÝ»ÿàæ­;Ö¬\ªö@–&|NˆºX5 „å*ñqê›×[i`e¹ 7ߢ("n«.µ"‚ Èoƒµµ•\. mǼ*T(_˦æ‘ã'…tq줫«Ø¬-áÍáøuBÍfV¼5XZ–Édoé髸×Ô(8ä…R%K¾ŠN?|øøéóçR%Ej˜¯‰n=»w;ÁCÈZcbbÒ»gwk++¡uÛŽ][wìZ·zyµªU”}ä'€+u§d’ÈZNséÔ¼âßž@SA”-„ c•à´B¸‹Í4R’ò"È÷“šúÎÖÎáÇ҆odèHW¡|‚|ú» ?qê´ÔZ`È˯—Ÿ¼_ã ÿ2V––öÍìæúÍþ".--=8äèå«aR'èÝÃyç®=>êÖµ³Ø~0(äÎÝ{»“’[:Ø€¹¹YtL¬L&€R%KþQ¯îÂÅËSRS“/]a×´1-Ù‘wºuq:~âô¥ËW33³“æ/ZZ±B…Z65$n®£F 4ÀÍcRø­Ûœœâé=5üÖíOŸ?§¥¥ yóöm-›š°fýƃA!׬ªX¡‚dù)’¤¹S©ª^+$µà-vÖei ¡ Ž&„°„°boBDê™Ð(5–‹”KU8‚ ÈOÂБ®Ýº89+KùæÌš±zÝ7I™™Ym[·œè6Nê-ì/_Ù°þ4—C G·.kÖoŠŽ~Vºt©åK+Z\ô›ç¿pïþƒ5ªWÛºq­ÿÜÙKWüÝoÐP¤IãFžîãÅ#¨¸ï@ ¨LGà®mmÛ´ÊÊÎ^·qËŒÙsLŒMêÿQoÅÒâÀ¹ÀAŒŒ<¼§úÏmßÜ®G÷®Ûw<})“ËË–)=sºO#Û™™[·ï€}Ð^úzzWCÏ* „ ? ù \ŠÕÒ€ ájÂ*û± Lï"eAL¨V ‚¶æT5 Tó¨S÷ß˲“¦½zÐãævM›Û5·€±‘QxX¨ÄX ð_¸äPpˆpêé>¾_ßÞ —ËW­Yôø‰¬¬ì&l§Nö*^¼˜¢ܹ{oÛŽÝ=662rhÑl¼ëh‰Ïïk7nN÷ñ>œ?‹‰í7h¨‘‘á¥s§`¦„……S§£F e˜oZç–ÿhzYļŠ½~ãæá· aƒúžÆ[X˜Ó¦»÷î¯^·1"2ªLéRžÝlÔ€½ûnÚºÝÈÐpêäIM›4¢ž“¦LwìÔ¾uK~Ô‚'bU2› (Ç\†UÛ@€eY† |°™K¡;¼êÉKŸ~MÛW†³pve­¦ß7q0(ØÀÀ@jýÕ‰{ù2ísšMMép?Â?1¦Àd¯‰áa¡KùK4ð­þÈoÈ?zÅj'¿¦Î¯qß–e÷20Ð/àRãW¢wÏîáa¡ô!ÈÇ­;v9w~ÍÊ¥Aû¾ä|™6s¶RÈóÞ7U*W:tX8=\¥r%Q;üÙ§WxXhXèÙy¾ÿ Ü0äèqqë…Ú—EÌÁ à¶­[Ú°sëÆÌŒLá%zðð‘»×dÇŽí‡\4ßÖ‡INNÙ°yÛ– k§ûLöõãÞ÷O9§§§ûÓ\ꄈ£É Ãëc`a¡¼ ,ËÈY¨3è*ä1ý—å¢Û œÚÁEÀ¹ca …“ógßÌ«øø à#Íó:b´´í—æò•°fÍš2 “’šêç¿èνû–%,z÷ì.8ddf®]·ñâ¥+iéiõêÔ™<ÉÃÚÊrßC‡Û½ $$¼éÞ§ðþ=t¸0¦0hÚP@“]í>â%|«?‚ˆ¯Ø¸¸W®ã'>‰ˆ477óötoÒÈ´^¥¶ ë?yú42*ÚÊÒrætŸ{îËÈÈlצÕÔÉ^tLµ7‘djq*H—á-šÛÝðPòkdeeMŸ5G–+óŸçkdd(bŸÇt/¹<&ù\ »F±²²ìÖÅiØàAôïò·Î¸ÿ`@à¾÷ï?T¯VÅkâ„êÕªŠ‘Ÿ…æ­Ú*d:sšÚì‹ïàÍ›·]{ö•;;vœ5cªÄˆˆ9txðÀþU*W€‰nãúôw‰{ù²\Ù²bŸ<î}ÓÌ®éÉSg?yjS³FFfæ©ÓçÆŽ¹rµô«0ºujÛÔ¬+i*˜¹L…LM»vž>k=]³~c×ÎŽ=œ»@áB…&{M€Wññ+”+SºT™Ò¥222ÒÓÓ³¿|Ù´eÛú5+ùñ .œ„¥2˜ ֿÂý—phNd ’˜aá3mgÂ5k#ÚWÏ€ÛÒœF‡%˜ïÖr¹|þÂ%®cF25•¶ýê\ºf߬)L›1[__?hÀÒEó;!8Ìšã÷2>~ýêGƒö—/WÖÛgº\.ïØ¡Ý‹qQÑϨϑã'üQO¨¾$Œ)FÓ†šì nŸ¡I-ßê ñ{ìÄ©ñcGŸ:äÔ±Ã,_?ZÊSËUz!ô’§»ÛÉ£ÁµljŽs÷Š‹{¸sëÎ-._ ;ÏWØU{Ñ&µ7 hø5(©©ïF`an¾t‘?UÕ <ŽÚaÙâùáa¡×/Ÿ_ä?ïØñ“§ÎœÌû\/_¾Z±jÍÜY3Î<2aüXñ ÈÏÅÕ‹gN ²kÚXbر¹S‡öc^°¶¶âŽÂUµ˜c'N5shÛ¹{ï…K–§¥¥ÀÇŸ’“Sjò_4U(_ÎÐÐ0::F©›2Zö¾aÒ½[—‡‚àø‰ÓõêÕQ[ªE&“=|üäÉÓˆzõêHÛþ T_M$§¤9~¡EsÈÍͽwÿaÑ"EûbߺÃàá£ïܽ¥K•Š}÷:!!üöccc“…‹—>¤x1i‚MA„*_–*fÂ?€=åE° … !r¹HÿÒª 4!„! ŸÎAøH7!„pÊ]Y+Dæï$ pŸ•¥¥jÚÖ/ϧϟŸFD6idÿ:áîýS¼=Š+VºTI·±\Ø>))ùbèåS'—,imbbâ6nLüë„Øç/ *Ô¢Eó#G˲ǎŸìÚÙQ2¦0 hÞP@“öúê>¾ÕA@åŠý³O/›š5 {õt~÷þ}JÊW®Ò?{÷¬Q½š±‘‘S§Ž™™™žîn… .S¦´mÑ‘Q ù&RZŒê¯Aí±Ïã†Û¦uKoOáK!É8Zn†aªU­Ò§wÏKW® Ƽϥ«««§§kbb¢¯¯_Û¦¦ûxWaA´0u²WèÙ—ΟZä?ïþƒ‡³æú@zz:˜Š¦ ™š¦¥k—_Ýûƹ[ç‹—.úôéPðáÞ=ß¾ÕA@åŠ-^¼(=040€¬ìlíWi±bœ¿¾¾¡¡B6Ð×ÏÊέ7‘Ú›…¢úkÐ ÅÉZ 2ŽÚáìù‹‡ŒhѦƒ­Ã’e+ÅwGÞç*YÒÚÏwÖʿ׺ 5Ço~ô3î;+Aò‚ŽŽNêÕ¼&º]¾–‘‘A× Š•ôç´4±Î“—½oŠ+fפ‰ßüÅ™™™MK?±ÓëW.Ø“˜˜4Ço¾Äá¿Bò²H›:;uºyõâ‰#‡êÖ©=|ôج¬,##CBH·.N5ªW3666d¾~øí;Яoï³'Ž ÚW³Fõu6ûx{nݱ«\¹²'Žbå,Ýp´À²,á<¨·\T›Ïý`XšC„†ª†ÓǼ Wz¢P¶ÂŸB†sþv¢ž=KIIíÑ»_ëö޽þ£\ǯ۰Iê÷+rùJÝp«D‰™™YïÞ¿§öønsk+K†aΞ8"þvviܨ¡¾¾þ•«×Ž;Ù¾maݧ0¦M h²ÓSµûhá[ý4\±b´_¥_EËMôÕ©Uqs]¹RÅñÓwİÁ'ݼzÑÓ}<-H¬µsÙ7·[¹lѶMëlÖé:¡ ‡üâÖ»CGþ³±'w¯Éç.\”ZuŠ)laaþäÉSzúüE\VVV•*J+)yßû¦WOçóC{vïF4("†aJ•,Ù¡]›ŸëK]Bˆ¹™Ù°ÁƒÞ¼M|ÿÚÀÀ \Ù2B+Ý›QÎ^´tùÐÁƒÌ̊ǽ|Ù¼YSccã¦M½ˆ‹û4!T-ë*‰ø¿#wD·Zä,‚P¦® ?—* Dñà—?êÑÐ!D‡w 2šæŸzšÊ÷o¦]›ÖçO§»`ÃÚ¿ÇŒ!õûåÉd׮߰of¥K•¬[§ö¢%Ëßøð:!aõÚ ÔÇÊÒ²Eóf¾óü_¾|•••õäi„·ÏŒ/99À0ŒS§Žû^½$äˆÇ£iCMvÚKí>ZøVÑtÅŠÑ~•~M7Q^¦VEGWgîì•*U3n"ý$¬:ŽêͲ¬©©©®žÞ£ÇO÷+FÔŒê\7nÞZ½nã«ø×¹2™L&ÏÎΖ‹²‘_•Õk7 qáêCÿC q¸fý&q~ÿ/†·ÏŒˆÈ¨¬¬¬È¨èe+W7kÚ„~ÅÔ³{·ÑÏž¥¦¾[¾juý?êÑ•‹óüŽàIû~ÓÞ7Ô­:°ÿŸÒ–eß¼y{úìù*rµÿM4½,ÂÓ—ËåSgÌŠŠ~öåË—7o×oÚbfV¼\¹²Ð«‡sðá£O#"is¹LnÛ°0rèå+ééŽÛ@¹²e¯†]ËÈ̼~3œö-˜PY,ˆf!1ƒ>¨ÞåT5—ãÁ9Ph¼™¢+g ·Å‹Ð|<œv'@XºaŒbRVåÃØ÷.]ü]¹wÿa‰ÂÜþsgÏ›¿Ð¹W?Zä1ÿÚwæ´[¶Oðœüîý»J+q ¯§G›º:uÚ¶cWÅ „"_’1ÅhÚP@“4ìSrÔo>WâÔÖÎÎ)Z´Èwø#ˆ–+VŒ–«4/¨½‰nß¹——©Uafº÷²•«G¹NX³r髸גqÔÜEa¸1Ógú~þœV½j•V-[<|ôX4¤F$sÕÿ£ndT´»§wRrJÙ2eüçÍ662’öA~-"£¢_ÅÇ7kÚDÚ7\†êÓ³{g§Nb#˲£Ç¹ß½w÷öÍt)ÞuëäääÜ ¿Ý¸QC±ç/C·®N /‹Ž‰-V´ˆƒ}ó‘#†RûP—iŸÓ\݈ôõ›okç diǽ|¹÷À!•¯}ªW«šÇ/Rä—„·Ã á?¨†;Ò$Âý ‚ÚÖ%D‡PO·fÈX` Ë•z¥Œ?¡ÎâVÂoƒä…C{¥ýçŸAþ9þÃ+6¿¦Î¯qD-ÉÉ)E‹ruc`Ö¿/_¾¬_½¢H‘›¶l÷ö™¾cË só¹³ÿç=uFõjÕž<¸v-`û†aþš3+>þµ8b-—ËgÏõ÷˜0®p¡B˜”âÅŠ ¥ä7„!|‡B÷ Êš \–šº /«‰8¡ZÍ¢VtæÄ1'³)„£± nlÎUõ/EÀn[Ç<ò­þ‚ È7A‹²9hannãÆ´îÐ9öù‹Ê•*6²m0 _¯)ÓRSß-^àgfV\Ú¶íØmmmÕ²…}jê;i‚üÞ0t5!*mi™o¦˜àƒÓœxÚYÎC—º²´“à²@ÓE8 -Hwš†MÿOg!\ÈAA|ÃÜÜü¿‹­P”]ìðæÍÛÊ•*@OçnÛvì®eSÓ¶A}±ƒÀóç/ïÞ®>òîý{só¼ÛA_"IöÂih……š¹ÂœðU¸`u‚˜°À‰f8­Lý8¥M€UˆhÄôÓgfff€Ë€~a×®7kÙNûÞ÷î?ÔÑÑi$ÚàA~?Ë^`0À2À2t`xÅL•ÂÚÊ`]Â0Tzs£²rBëjâ47¯›ÅšBû0ÒJ‚ ‚ü(cÇŒ\³nc ûf`llì>ÞÕ}¼’JnXÿг'„ÓáC\†q¡ÇuëÔÞ¿g§Ð$`fV<<,T8ݶcרÑ#ßÇ‘ßq€˜‹/óÇÀ0 ÕÓ€%„»_81Î+ÐeXV¡›iò0ÀÒÌlú“¦~pQoàµ5áp}Å¿‚ ‚ ?Šmƒú[7®•Zó•åKHMò›ÁeG ËyaK€¥¢šS¾´ÎwB€ïHº,Ë ,­c­€åW#r¢™¦g+Aš ¨ªAAŸ^ìJ¯HÝòZ›å7—´¡h%,èº]"iQ:0Ë2ÀåRÂEÂùÉ BS¬y- ‚ ‚ ?h”˜Šf±åE2CƒÎ4[–fƒú™ºA (ÁÒ8'¦…™ qá¢Å ‚ ‚ HÁ‡ð"V!‡ _²š;eXB€a¡%¨€œåš «+t/I¤ ¤VÖË,0@·† @hú6!tguAAù™IXª 9'w9=L€Zt8̲,­„ˆ.ÕÎB‘h…Îæ$7Ö,·Ò1Â:Š/tÿ˜/&5!‚ ‚ ÈÃ+bº9¡ \\šáëP•ÌȨ°@ÑÕQÖÓ‚ªal–à×I2ü4<ÜâH†aåh>­T­RYjÊ3©©©R‚ ‚ ‚üBù`Ø2,3[Ë–d7™Oåúo>ààñɯz¤rÆFí+_?~âû“*G×ÍgqNqõ¯n»Ç¾c÷Øw×½ö¯<Öš·Þ~猳ÎÛï ñãÿê/¯½®¡¡¡r†RÀg7v}_{ýdäÄïœüç¿Þ#·ï¼ýÖ#ÿrrH©jqâwN~âɧ+™ùäÓλǾS§M¯8´qkùÆ÷?x¼|GK~ÕÕ-*–,]zÑÅ—4þð}¿pèɧ1ùÃ)I§Ìé3fŽÝcß}<$=A¾uvÔ1¿½íŽª¨Enb_]2 `ˆL:I'ÊæFVÑ‹"?cŠ¾Îµ¹nÝr];SàQ!ï-[Ö°|Õ’æf¯PäÐF†Ù0ƒ™ÁLƒ¥ß„‰ˆ™=ÏcþômÖGþå3~xZåè&`öǯZ¹jÔ¶#+¬ƒÏ✉ÿ;çÌÿ;çÌ—ÿýê¹ç_Xy¬5wÜu÷‰Çw娑 ëê~rÑ¥×\wã%?½ r’R@·n]}󭻎ÝŸ‘”Ú8ýíÞûsÙlåè& åñÙ§’Û¿¼öú3?êÛ·Oê8\ó«-®ÿÓ·wéÜùÖÛ~æ9ç?ýøC-¿J ºõƒ?šÍ~dØÐ­çÌ›L8ö˜£Ï9óGQ½?éƒ çœß¿¿ªH¥›ÎF"jåúÅÔqI¼nœÇ`E©%v›-ú׌ÑcøÖ;w –,‹f}²jæ'K>YØ´t54›bDÖ·ÖX æd?¹,Ò%tòŸ»<È«5òò+¯î¹çîÆ˜Åõõgûã}¿pè1ÇøÂ?_J&465ýêú_vÔ1û<þ¬s<ÁB÷=ðÐñ'}7™3oÞü]÷Úþür79g2ñß¹Ä!_:ò’˱bÅŠöÇ;ñ»¿ùííß?õ‡û~áоõ½wß›X:WkÚšÿ›¯ÛuÜ.µµµC>êˆ/¿ýî{åSª£8lü¡ =QúF›ØH⩪O«ß-^|È—Ž|úïÏÊœËñËS~8ÁZ{ÁÏ.üá”K¯¸jìû~ûû§ÊÑÙ|ï5á‡É97í¿ñ¦¦æ§ÿþÜWŽ<¼ò0múÌC:°¿~µµµGå¨%K—.^ÜÊnx{î±û²eË'}0@cSÓߟýG«góñðý[m¹Åy?¾ÐZûÅCš5kvòìǟzzçw0 Å9Ó~rÑ%«V5üåî;îþÃm ÖýìÒ+ÚðÐÞòýï=õè}ဠ眿tÙ²äP«V;ÿo¿3|ØÐŠA¥:ˆL6sÚ)'ÿöö;›š*)Õ1´ú¡OïÞ—_òÓ«®¹þ£Y³Ÿ|úﯼúÚ—^lŒùÅe±ÍÅþø¿¯¾tçí·°Ö^rù•gqz×.]*O½Q[íÿûsÏÀþûVØŸçž¡®nQCCÃ?ºýèíúôé]9 0†Ž:â°zÀSO?»ÃÛ÷ë×·rEÑÄI|0ùÃvؾòX‡´é|atÅb—i ’žã_2—ª€S©7­Í{¬œõØC—]òÓ÷'}påÕ¿ªœ±‘Z±råä§ì6n윹óÞ~÷½óÏ;«g› ø£Ó~ êêýó¥—/úÉÿ 8 ¶¶öG§Ÿ2gî¼™ÍêÚ¥Ë>ûìõøO`æ'Ÿzæð/¯8gò,æÎ›÷ÖÛïœîY}z÷îׯï¹gOø÷kÿY\_ßÖ¸<ê+G±óN;ÔÖÖžtÂq}ûôþçK/§ÏÙRûóï½ÿÁ·Þ~wÂ&Ù𣪅ԥþôç¿UPªhë;€qcw>þÇœsþWÿꆟ_ú³^½zV>p×Ý0 ÿ~ûì]y`c·Ú7þÐ#ö¥ñ™ ¨<|ëÄü øÒ‘GïwÐø—þõòE?>¯­ŸÏyÄ—ÿù¯—W¬XñÐ#~í+GU½ç¾Æî±ïn{ðמ{´ób:šMæ #ÃêR²-ÿ_M@)ÆÀד 0€gê—655!_4žñ|CY²a„H´{)Q˯ψçyÇ =ýÔ¼öŸ×7ú¿‰W_{}‡íGwêÔ©®®®¦&׳GßlÐ ¹1wþ|ãÿjrÑCCCƒ´|þ¥ñO?û\±X|óo­\µjÿýö©8§Ü Öyž—”´7ßl ¶5.w  7 8°å%Ú™ïýÞqçÝ·üúºÍ L•êhˆèÌþç¿Ý»hÑâÊcJmhí|GðÕ#X°`á6ÇÝy§²‡Å>úhÖ?rÞÙ*lìVûÆ'8åÃ)S:â°Ê€ÓÏ8»gîO?þÐKÿxæØcŽþîN_´¸õ¯={ôØc·Ý®¸êÚ¦¦¦Ýv-+o8ö˜£ÿûêK¯¿òâ#ümáºˮ¸ªbB‡µÉ|a,ÑDÆÈUŒŽ;ÀÒ-cƸkrM#~ccžŒG0L2äKgI\ wÙ† 3¬ë4‰Ëà€MwSíxù•W÷Þk}ûömjj^²t©dë9óæÉ„ýûcž}òÑnݺ¦`×q»d2™WþýÚ‹/½|ðÌÆd$çLëׯoE .ì߯€OæÌ•Á|>ßê¸múô|>?múŒ[~{û®ãÆvª©©œ´Ñ‰¢èµÿ¼¾÷ž{ØlÐÀ1Û¾æW7,]¶lî¼y¿¹õ6™Ó¿_¿}öÚóÒŸ_ùñÇŸ4770ùÃó~|Q¡X`ŒùÒ¡_¼çþ_|é_É×Ðô9Ó ¸ãc®¾ö†Åõõ Ö]{Ý{ì¾kï^½Ú—G=øðco½ýNccãŸÿzϺEûí»šŸ[µ:ÿ–ßÝþàÃÝ~ËMšªUµøÑi§<ûÜ?æÎ+ýEQ©Ž ï¸ëO ëê.ýé…?¿ôg¿ºá¦3?’‡ôîÝkÚŒ™Q8ôƒÿûêKòë™Çð—?ޱѧj¬î¯ZÕðìó/|õ¨Rìðó+¯>팳tïÞmÀ€þ÷=øð’%K›ššï¹ÿÁ0 ‡ mób¡ÇlÿßW_:á¸c+ĘyþüÏ>ÿ°j»âh£ÿÂ(×#cL\‡Ž¯K$"Ï/Û¾xžïû¾çy€] ÜmŸÀà 0˜9"k­!"™ˆ¬1cŒ¼8Z˜á:PˆÁÚ ¢”RJ)¥ªMªÚ¥]"#½©Y 0Ø 2¬efkÁ.XW`ˆ8)–KWHi–æj¥”RJ)U…$øÆÅåÊ£±Ô!‰ÌÔ ’ƒT¬Ý$ù-y0»mœ£ÝuT:©, âæ+¥”RJ)U5$ìJ–uV’m*ßW^vG&°T™IŽ–k"·nHe@®¼@Î'qeCGÏKökÓÔiÓ+‡ÖX¯ž=*‡”RJ)¥”Z7’’K !-S5¹º´dk"I‰™@,õåT°vOî#å©!†CúH "·ã9AöV/Mmƒé?¤rh}´dÉ·«¯UJ)¥”R›’ïU9´ŽJÝÔ„xù;€³l:Qd¤[ƒÏqa›ÈEc¬+òx\æNN ¤’·!""cŒ„iY„h‚µRJ)¥”R‹„\I²®Z²2±¤hŠÈwG»líûDñž‹\ü–G'SeµjšÉg,‹øJuL]"€™ÈxäS¼–´% °1€oMÆËvÊæ:å2ÙÀó¼(²ù†|SC!ßÐl Ö—µçyÆ’wz1iñ^êäYÓÇ⯔RJmŠ:ù8~H°koSëã•:{Ç´bs„Çeß\ìn†v1/×Eûš½ž—ù;Ñ-»fO~-_×Ì7ŽËþ¯>Ú¶›ÜÅÌo´¿›N^nÏ íb&Œ4FSWØsß,tËÐ÷‡ùcz0þ·ÄÞ1-\Ylý;ïÿ–ØåÞ¿¿÷ÄWí>d 7e¹µŠ 8m›àùùѦ»Ð=»ïžðX>“s£ï ¶ìlf7D+‹|ýÅ‹¶Ï¼¿Ì†¾¾•áÛ…æòJzcˆ»fÇoæèJ¯/ný…)Õ‘±«!Ë¿DDL€aK yì^&çgr™L.dCT,†ÍùæÆ|±¹,‡ÖXò3™ŒÄe"—ª%-3Xý`.íES‰´ÿC)¥Ô¦îìm3}\únaIž÷êëîaþ»ØøÂ@ïʉũ+lÆà®=s#»™ÉË-€/ôÞYbëš]ýâ ïʉÅ+í¡ƒü‹Çd~ðZþšIÅ(Ý rþvAs„ o ᬑÁYÛI͸3ž2З`í0À»kz`³ZꛣV×^"k¦¯t×S½·Ô>57‹—wí.™ƒ®çs*õY|¬®Güå­–~Ú~þ5óÛ3F›×R'ôÆö6•“O͉¾º…7¢›y¶<­~q·]wSãá¨-üÞ9úÏ" `i[u&`AOZfOôÈPï<<ø_½m«\-ÞZbWù'ÛS–ÛÙ n&·L)4Ð;ik`'ÊzØ¢–¾9Äß«oåÇLCˆ‡?ŽŽÙÊ÷[+Jmljºä:÷ìÜ¥G—š.5ƧB±Ð°¢aYýŠ•KV5¯Ì‡ËÙmd­ekÙ‘;ÖJгIö!g¤jÓœüE»t«e‰ZÎ鎂Ü|j}ÛD¾Sn"oSm@ú1¦>#¿ú 0»/“¹}÷ìÐ.F¦[zmQd‰KmEmûïó¢oníÿq¯Ü¾ýÍeï¤aãÁÙáν¼öË]»KÀÕï›#¾i×Ìõc3õùÊeª[bƳó¢~5ôLyˆ«Þ^ðVaóZsÍΙ¿ì;oT¦!*ëKI<1'ÌzøÂý”Q›„Î=:×Ôæ4®hZ^¿ryýŠ•KWåòaÞÚÙ"²6²Qdm(ÑÚZ¶6bkäÀ>@®` 0\3uY|&­%CSj)GéÚöÚš=cúã÷ýuúäIÌ¾í¨¯žøþƒ6«œ´üv·ì “Wó%ì3"O}î›­_ú½æäÏzdè{Ãü1=OôúâèwS‹!|y3ïØÁ~s„[¦ߪwÿÑ.Ü>óâüèÕE•ùJSSSXÃ|d ‘µÌKG‡4zXŽ€dÛqw"»ß]›41Øw ;NÕî÷¤¿:À€MJܱv–ã[CÓ'pÝ¥víÖýôŸül‹Á[4mÊ^záÈãN¬œ·! êDµÚoGûŒ¬¯§^_çQj]lÀÃõõÔëë èïýòýâì{ÄæþÙÛ'¾’çvíß½wÕÄâœF{òðàò3ÿZñF¡K€+wʼ³Äûw]à¬mƒŒ¡ Þ.¬,ò±[ùŒÎz³ A!ýÔi­¾ Ñ#C?L[Á¿›ZLþþ-çyo©ýÎÐ`Hg#?Ï:°¿7q™Ûž ·°&Öñm¶eMNûÛ‹›ùäWó5>ÎUùµLu(ͧ’Ün¹£Çò"·ó’BÔÐÍ»f/x«0c¥ÜÙìÓÏH°nçí·ú:å¨!lÕÙœ¿]° ‰_ZØÊ{TÇÑÿt}WhÙ1²†êš9Ù<\­¹W뢽úz¯/²:Èÿp¹•Þ†4©ÂÞ1=\Õî_R,ãïó¢ñƒ¼©+ìþý½IËxQ‹SðC»˜a]Í3óÚ=݆pÀïàÞò¿¾Øþi¦kçhUÏ,8À{}Q„$ï¥Þ+C:Ó¬U¼y-õ¯¡¾9jЏ1ÄùÛùû(\Þî…¶[b¶qè%0[kÉÖqYZÞCV‘–YÉC&“,V-笼6Ä ›LJO_¼HÊZ[¹b™Ü0†®¸å÷G{ü¤·ÿwý¥?mnj*Ÿ¸töihóö÷íêñ9ÑÔ6á©9Q· õÌ’,ÚÿÛ)Å%y^ÜÌ·M-îÒËôȸÿHM_ie_€œ‡;¦Wy^#¿»ÄnÝ…ôÎÒî}¼›>,.lâÆwÎûט-j©åS§µ|2¾E-]½sF~d“Dä<«B~}qtà@ ðžŸ!Þw ­·°&Öåm¶cµ§PC#»™ßM —yAS+»òªŽccúT’»²£Gcˆg‡õyÞ­iç5 Þ(Ä2BFÑ¢1â‚Å”öÎé!V÷iØÖë`3WÚ'> ǵ± …RªÂý³Ãñ‡=³÷ì“Ûµ¹éÃV~Êyô–þÂ&þÏt/ü}^´[¯K@‡òŸš[ùmè°Í½ÇÈ=¼îš]2o,ŽÖ䄟§[¦¿þRó1/5ÿbbqdw:{ÛLå À¼ÇÈݵg¶oޤ€]Ÿçé+íñCüꙥãû Ôø´8Ï÷Ί~µKfÂÈàÆÉÅ=ûzaâR{ÅŽ™ûöÍýdtíÀ—ÂZ1³[æ# ÙÊÏ0eÈZ¶,¿¤3„Ù…à|¤ÿÊÁ€dð4r3ÜOI å)ÊmBÙ_]ÖB×î=äÆŽ»îQ۹˞|Ïn[¶¤þ£iSFn¿CùÜÏÛνÌËmSü‰¬{/+æg zµ»h¿\Ù  !A~š  h‘5 _ ¸kϲ3õËÑìU\ñÔi-_†øÂoEOÎ)ûÄNŸçùùÑ9ÛwNǨn¦³OÒç·¶û´´.o3=Raµ§í•¥æIãG«»3¨b#ûTBk;z´óZrxa_;©ðí¡A׳Vñ㟄­âö? [}{öõ¾¶¥7°“Éy ½(J©ÕúùŽ™M|Ò+ù¦ˆè_½sæô× ²¥¥Ø¼–Têœlßòÿ¯>:}„Ÿóðv½Ý¥ü¯¸ÒcM„~9š028cd°Úå\>cúJûû©á;ej<´üjùùÑ ó£îúú`ÿ—;gN=ŸpÕÄâÉÃ[wË-ß7;ܾ‡‘oÇ}⮀ìÐ/w.|«ðµ-ý9üó÷šÏ•9tÿHk;wv²¼ P}2À@éO€ÀŽ×ÄsÙØ—?ä”Üj“r´{`š<®•k¢¶s—ž½û,Y¼¨b<›ËUŒ|þÆõ6­.B”ø‹ö§Õ533Nx%ß²§yµOÝÒg„;õ4—ô⪸ß2}ž·—Ø‚ÅØ^Þî}Ì¿F ¬ñ[(Xdã/ÝÖ¦žvßæº¨ÏsÎC×€ä“9}½ˆêhVûñ¼†‡miçclµOÝÒj?•ÐÚŽí¼”U}c±}cqûöó®Ü){Ò¿›×öíwÏÐy£‚«Þ/¾»¤Ðá°Íý}úiÅz£5º‡9ikÝ×´iÇÅc2ÏϤ«jãÖ5 á]Íï§¹æàG? OâèjÒ—ÖmÝÅôÊÒŸö.ý%ù†q™G>“nã OÍ®Ü)sçô6¯s`Æ‚&þ×ÂèÛCƒëÑá‚õš``i”PC³Vq]3'kËŒëm ÓÊ/ìþÁpÿþYáÒêDOÌ ›"¼U éÒq¿R1G€K³\‘jÙ¥`¢ÖjËåw X·‹ÝÌl-¤«0Ì$¿àÒy •=$kéðcðöë¯6¬Zùïž°Åà­·Üzhå¼Ï—GØ©—ùïâöê@ŸbÑþ´EÍüúâèÌ‘Á N”õ0¬«¹`t˜5zê–"Ƶg¯â+vÊHö­83^\¶¹·{ׂ5~ 3WÚxµ>úæè[[Ç[3m½M?\¾cë?{Z­ùMüárûƒá~·€ú×ЉkùªÔçfM>ž×ðã°-m}Œ­ÉS·´ÚO%´¶£G[¯¡Â=͉[ûjÈ'BÖ­ýÛÏ¡!ä±M7sÄæøÇ«j´µk«æ­GÌOâ¯Ó7ò*±¢ÈuÍ<~×=C9‡mæù­²H}?úç‚èðšå—¬kqæ…¶R5€IËìá/4?Üv!–€¾9Ú»Ÿ'OÔq\0:غ‹ÉzÒÅ|w˜ÿ¿z÷C¹ä?…!œ¿]0¤³ÉôÍÑqƒý¥žÛÈŽÜÂß¾‡Éyؾ‡9yxpÿì0ÝŸ½koÓɧDæ6òØÞ^ÎÃ=<¶c²ˆ,"f Ë€•»r#ƒ–asŽ˜#F×Lܸ,Ñç§+Ñ,«…0'i$»S¸‡È\™|:{ìÿ…°X|þ‰GÏûî7»të¾×yÜ7=oç¤m»›ÅùÒgÛrõûÅï óoÚ5ÃÀÛõö÷ÓÚüÔjÕõì_<&Ó=C7Øûg…E‹Ñ=Öè©[bÆÍ¿;Ì¿j§ÌOß. èDçy~~tô–þÇ <5õ7Ë5y œNܵgnA3?5'Ó³E^hW«osÝ]=©øÃm‚ÛöÈÖçù¹yÑð®¦c­ªl¤ŸJ²£ÇàÎf^“Mvôhõ5Tx™ÒÅ\²C¦W–æ6ò/ß/JgËZ½ýºf¾kzxÞ¨ ³O3VÙ×E#º­Ý§¤ªCº˜5ôf¼ðÚºnlæÉ9Ñ?âJŠ Ë3OZfƒ1=Í;åkãl”.·ðí¡Á-»e|¢9öª‰…–{ѯ/‡mî¶¹ÇÀŠ¿¿Ì¶“Î7ˆgçE§lãoUk–ùõÅöo3+_že¼¸ :u„?¸³iùƒeö· òeíÕºèÔm‚Ñ=Ìâf~äãð‰9¥±Î>44øéÛ®ž}ÿìð¼QÁÝ{åÞ[jŸ™Û¡ öÒ:M¤Ë Ç7‰»²z^:—`wî"Wov‰:¹L1µîˉ(­YM$‹ l"ª{êàá£Æ456456üqøÏÿÏÍÕwüP'ºúýOGZ ÖGlîïØËìÔ³lß“ÓG–që”OùDJ}Î^<¼WåP»ö¬þ±*{ŒýÖÉêÌË75^=÷NÆuj€I¶@’S}уa¤[@IÏq‚–yr—Àq—ay`‹¿×±„ûòçÛŒëí½±–?A^_Ö×S¯¯ótX{÷óöèãÕxÜ™N¼¼pc~³Õk~®¯§^_çQjmèjf®,}oÍyøþðàŽ=²÷ì“ûÙ˜Lß虥?í•ݯ¿ë:cdpÅŽC8oT0´‹™02xì·/:âå™ï˜V g¬´Ût‹ëjJmšÖiW™N>÷’Ûñ¥:>\r²¥¹!" fIÏp›6ÊÏÓqÙÄw 0LÄò¸IV Ùhœ’ÚKös¶¾žz}§Ãzg‰=e¸ÿÑ~s„×Ù?N¯üV¡:‚ øq¸¾žz}G©µÕ3ë®Ï­®•¾$Ï×~P¼`tfÆJ;¬‹Ù¥—™ðFÁ2®™TЉÒëv–g^^@¯µ¼0]©‹k¨K®%”äþJÙڪݠÄð˜ëcff·_ú˜(Ý#@’wœ¿Kƒ2¦Ÿ“êsµ²È×LjñýA©ÏاÞÑC©u!k¥ëßyYîÎáßöÎmQK³Wñ»Kì#‡ŽÎôÈÒï¹%/ZJ–g^«Í ”Ú4ÄŸ5I9—KÒ˜÷`# Á~’Ðã‰2#=èN@ñúÖD&=3e¥m¥”RJ­›%î¸ï¶í¯•þÌÜèk[úSVØ÷–¶þäö—gî–A}q\©MÂ![)Æ=Õ­k€RKwHüŽ7e4KÅZŽ»J5³›œ “ìT1»µO¿Ö_€RJ)¥>)Ëí.î›k;k¥áÌmƒÿÖG#º™/ÄëÂ}CwÚ_žyë.fêòÊÓ*µéõ@¸”ªWT¹«"|f "ãÎÈ€„u eu)k—€˜’­•RJ)µüg‘½d‡À#D\Z¯ýÓ‹‹ó¼E­ùÚ–Þ5“ŠE‹¯oå÷ÎÒ9o†u5mŸ™¶ÂÎn`K ت3ÉÃÿ¹ J–²é‘¡?î•M¯ ²Cs‹. ¢”+-W®†[ƒ‰aIJá9 W/¦¹C%Iò–_É$ +ep¥”RJ­ÓWÚM¼s/ןyýÅ9öâ1™?í•ûÁpÿó#Y¯ý¨-ü_¾_hŽ0q©}hvxþèŒìuÿàìpç^Þû•ViÕ¶ÝMÄx§¥6œ*33Ã2[†µ°–-³e¶®œMïà ¸›2ß—Š·ô‚ÈÉ «íŧF¼vµâ驇$³ãq¥”RJ­wÏOÜÚcq@S„;§‡w–ï32q©ýúKÍÉÝ{g…÷Æ;5N^nOkmM›¥>ü…ÒCŽÞÒÿÓLÝ_Kmê¤wš“4Øý[Z)D‚p:$KØ–ÇD«ÙÝ0ýøò>@NÒH­”RJ}&Þ[jÏ}³õ+×—ËÞýlϯTu f¤v[ä¦Äm¤¡šJ L“ÌŠ§Ç/Vâø‚G´–§SˆfYN[)¥”RJ©êÃ`’Rr:Ôºõ>Üb!îbĸ˜,ó“T-eæt°&©c3s*K»Á˜ãy iÅZ)¥”RJU+â8[S¼K¢ · ¶rÛ]jŠ“4˜“T̘dçEé¢ff71µdµü "r­$)I¾&"kõ¢¥”RJ)U}˜ ÂÉm.žäàòÉÉÉä0û©‚4Åi»t?Án%a;¾®±b¢RJ)¥”RÕ'ÉÄRl–ô›lš˜¹ÔלÙ%dŠ[A¬µD J27ìÒ³ Åãiœ´š´ÛŠ]2{æôÊ¡5Ö­{ÏÊ!¥”RJ)¥Öâuð\f03"ÀKz8Ri—YZGÒì#ÉØ€üÉ÷–8$™]n²I2@ñm³&ÑúÀ1Ã+‡ÖX}}ý‹‡÷ªUJ)¥”Rj¸BqjA â$d Ž—áK—°“ì*Ñ©-ÍAp©Û,Åë$„Ç9:™™JÚ·R,WJ)¥”Rªcc±lB^y¥%øX¢/!)W—¦ËCåâE°•¥bŠC³;QËÈœºœQ&S‹‹•RJ)¥”ªKEãäªC×Ëáònj–벦¸µ0Ìçc7&1<¾Y:=Jãn§™4MÖJ)¥”RªÚ¸<,¹ØZŽ¥ï&·-]a™f0K5Ç{8J <¦“3$Ý?2˜äs7Y)¥”RJ©ªÄ²©8J.ÿ¶å›[î¼H ‘ ìŒôzDÄÖ2ƒˆä:G9MÛϨ”RJ)¥TÇæÊÌ¥Šr|¡¡KÁß*…^—“‘îà(ky@ÙcâÕ÷’sÉhr\Æ­»©”RJ)¥TÕJå]`¯€lŠ×!W|ff$—û »Ë Øté;–Jâ-—«Žs6»3*¥”RJ)UuÚª“lB\U–´_HÚB$Xƒã)éÅ«¥w;‰ÒÒ’:ÈD©}Ô!-ÜJ)¥”RJUâ`ÄYwé¡ëøHGéx€e)é!bë–Û“)Éïå·JâVnf¸%³S|ÝckQJ)¥”Rª“¤\–e“;Ä w&h‚[=Ĕ͂©]C.C$–#â­‰ìª×ò8†›IDb¶q­:~¤RJ)¥”RUE²µHÇe%À²…KÈñ…ˆ®¿ÃÍñ¥áZÊuäjÏ &"ªHé(Þ†ã~¥”RJ)¥ª”¬B Ö­w8»¡xíi¢ÒÊÓÌLD¬eñ< ÞÒãQªP‹$L'wHœâ‹"•RJ)¥”ª:.(#þÍÝ•ºsZ‹ÈK„Ty»å:ÖŽ„ëäÑ•AÛ‘DÝê!¥”RJ)¥ªÒŒáêÇqÄM‡éTê%0âÝI.b4¥R5sÒàánµ¦í#J)¥”RJU+v¥kâ|]Q ŽKÓdÀ­U¬­Dg"""IÚqYºåéKÚ< ”RJ)¥T•Èìò³KÏqqÙõUËbì¶I¤¸E$Y·Ú%éÒm7‡ñTrn«h­ÙZ)¥”RJU5ÉÍmq1X’r2Mº=˜}ÀDT–°Å[62ˆOBqˆoñ”­];©”RJ)¥T‡gÓwä2CW¯&Û8 »r}äŠÖ aiaË")R»eCˆ™ÙH6`­+QÉYäºÆ8fÃýÑ"k+¥”RJ)U5â¾ ˆ¥n\ºˆ±|Ž+:'“ñ:Ö¥¬Ì²[£Ìg–A,'.50[&W¥fÄ—¸•RJ)¥”ªbâ„×…ôx°$c¹ Wð&Ÿ+c¸Ëé F\&0ƒ’Ÿ©å±Ì`Ã¥%²•RJ)¥”ªé4¯iMñ>0R¼n1¯üÔõ‹Ìl¥h“CTª'½ì~cf€A°är½RJ)¥”RU¤˜SuäVrmY{SÜšM®æÌ&ÝÝ!g`Fy›Ý#kÓÝ @DdZy^¥”RJ)¥ªÇ¿ á–\¾NÛV6KÖ±–´L©rµ¤k¹#[Ò³4a'En+ØR.WJ)¥”Rªê0ÊÒ¬´P®-#î˜ ' SƒAHÇó™ÙÆÕªÝcäúEÌn/>Då§æÒ”RJ)¥”ª~RWnËrr»4ìË}†, â ×€IÏb†Ü•Ï)—ƒ©¥”RJ)¥ªD*غ ²ì[.ñ¶<äRª—ä6[„[ÇZ¦¸¸,Uêô•.‘3'Í!%̈—¾n7×+¥”RJ)ÕA%·Ô…Á Àõ‡$¿•FJ.³ÛúÜ•¤)q–N³+ÊÕN+CJ)¥”RJU–Üì’pžd£7”Œ§î&ƒ>3À$‡ã0íva@b;»6ëÊ𜌡µó+¥”RJ)ÕÑI .5k$ÑÙmåĹ·µî 7Ä€ï.cä¸Ò$#s‹NkFëåꤞ]y@)¥”RJ©ŽŽiªŽ{›ãu>H¼Nò3YÌCn–mI”Nf¸m y`*ŸËeŽDfy4dZÙ™•RJ)¥”ªLHjÌ©ÔëZ¢e»l,· ,a[åöÈÕš]@G‰+Ûdp¥kW¥NjØIÆVJ)¥”RªšÄq6éýpýÖòo)íºXÌ‘Dr÷@€üøa dFŒKÍ× 6 &I¿uRg†ni®”RJ)¥ª’e–, vmÓ£YVû\h.ï‹f€A`XÀ¸Šµ ·ÈÅÒê! '`—À$­ WÏ.ÝVJ)¥”Rªz0\š•ÖÒ`{\z–‡X¿ÔéÁŒdWEYD†[sfKf·³¹„zéQJ)¥”Rª¥kÄÌ6‰¶ –j3QRÖCœì}.|ùƒIÕénë33dçÆ8ƒ3ˆ`] ÊϪ”RJ)¥TõˆSµMÝ\ö-Ý3µ H6¦$;û2äfÉñÎå‚€¬ätfȃãÚ6AjÖå;:*¥”RJ)U6ÎÊRP¶ävQt#îO¹DQ*Ò¥„]Já²ALYŽŽI[î(»m@Z¾K§UJ)¥”Rª:”JÔÌœê±N—®Ýà²qêêÄ/]–A.—Òz)m3»gpW:J A–ËNæ»ÙJ)¥”RJUI¸qP.ßFþL‚.ǹ—’C lÜcÝ"3äÜ­`ke=†ìC© ÝK© íJ)¥”RJu|®šÌDÄ0(µy»n1IݩԜD_IÕ øâE$‚;1KLwç‘Ã’œ €,·—œXþl­›D)¥”RJ©*aÜ¿°\JÔ,C‚±”“AÒéW•­äe–`Mò/KY;)Càx¤íÒw’³5N+¥”RJ©ª–ŸSwX~‹¥B/Çåfœ“¶ ƒ ¶ˆ/Lob.Ѻ´#ƒ“Ëå40 ¼Š¥”RJ)¥TÇG0Ì Èe„,ÿºÆi±q-°›ëø¥1Ù^‘˜.n3‘‘5øDú¶+f[Ár¤Õk¥”RJ)UuL²0 W¢6`i¼vÇÊU¦í¤H¹`ˆJëù•“ýÐ¥t0Z!D)¥”RJ©ja@²ß!³e0`Hº4,åçÕ³é‹Ó$€»¢5äRƤDÍI—‰{>Yx/¾ R)¥”RJ©ªaàIÖµDÌlÙQi¹i¤vki;ír²¥y%¶ +BKq’×]]\fA²t[˜T“ˆRJ)¥”RÕÁ0o»H¬/ BH:­K‰7YäC‚we°Žã¸ü™þ=Á@º<$xÁ•RJ)¥”ª">ṵ̀`b"Šw.g¶—°e›qlr¥cœ}I£.k""Àº D°  µ*4»5øˆp+i»¼]>Q)¥”RJ©ŽŽØ3`1"‚À2yDœ\Oka™™ÝF‰ÒŠ-01ØOµ¸V@šªApîdŽT§‰–;ïpÞ2~+¥”RJ)U|Dˆ,H.bôˆˆ‰IÑšÁ®‚-õe™b0¤Ì,gaøef˜å_ÄÝÔ ³¥øŒqqš¤þÍDHoĨ”RJ)¥TõÈùµ‡E[´Fˆ`É€ŸK{.²% ÀƒaXvMØVÚBˆÀbò¥ž-­éMp÷˜-‘T¦å. "fÙ&†Á’¸¹"£+¥”RJ)Õñuòk-GaT m1ä0â0¢ÈrÄ &²ˆ ¬[íÚ0,3ǃ–-~R~Nb1®µÃ2³g×Om]˜vâÖÉÔV‹ÖJ)¥”RªêØ(4Æd¼\ÆÏZ…\ £b1*X #Š"则ãÅC,ƒ,ÆX“…¬¾ž™ã‹ãvj –èœh™C€ëIH‡‰æj¥”RJ)UmV†+dü¬Gïùž5ÊZ/ЏXäb(¿lÈ$ !ž¥&í1‘[b0|@º°ãzu’°¸%EJÉÚ´q‘"µš¶•RJ)¥”êðšÑPä X,xäyäùð=ò<2>ù‘ ІT(ÚbÄ¡,‡²€ 0»Š58*_Ó#ÉØ²I:XÖüÊ51˜H®‚„œ$O»Vk¥”RJ)¥ªJ‘òŠ!š­ñÈLÀ÷MàÏ#c¼Œïù‘Í£BÄaÄq+6EGÌ` b²~R®Ž›§]ªN˜™!³ÜNé¸îëtËuüX¥”RJ)¥ªF‘ ž¡È‰¸"ßl=yY“ Là‘ï2d²~†Dœ‰¸XŒŠEZZD¬Ed9òÁ‘kå`Y•̲nH)'Ë rõ"€®²ÍÖFDˆÈ”‡l¥”RJ)¥ª@DQ„È“-ÉÉÈxÆX*r³‰È°À ¼Làe žçr†™FÅ"‡E[,r¾€BÜcMˆKÔÒó!mIs5–{®+@Ü5âzEÊ&+¥”RJ)U" AdYVªöDlŒ!X2 CÁ¢fžñ“ÉzOL`ß¾õ<ö|k#"’¥Aä Ç$%“»m%P3–E°]eš`ˆÁnŸôH•RJ)¥”ª"Ö„ 6â2Yf2ƒXö‰›ÈÏAd¼¬‡À7¾G> Lγ¾ÏlÁncF¹úôÌ`Y[*ÙÌ®&-…kukW³¬p­­ J)¥”RªÊXÏ‘%†…5 À0ÀÄð Áºô &âbMsØäqY<ļÀña#Äì1ÉňDAö„qYÚº®X×3€ˆAn¡lf"¯ü*¥”RJ)U˜Xög`-À–˜a`@-’h"2& ´¡A±=Ïzž |pij‘%?Œë8GsÜàQªEKuœ°<…ÄoÀ¦g)¥”RJ)U"D w¹ ‘u¥‰AÆÊºx$[Ë*y.~²!,ƒÈƒ6°`@Z:`¤ „ä$àd#F‰Ó`rg•Þj°k9¦/*¥”RJ©ª#eb2ÄÌV:3€ee ËåA`YbÃdla@&dò­µ [À0˜¤uÄ5L[¸jtü¬LD ·ŸÔÌÁ享%h+¥”RJ)UMâh‹8ÍJ*N²- bfHVŸfb² &é’¦D>s陆’ˆ,‹R—ž#Á ""9µ‘‡zØ IDAT¹ŠR)¥”RJ©*#Á7]M–ßHjÖnH†ÜŇÄ$ƒHöÙº­Ë#Eo™ÈL® ¤ImÚÅk×ï­«‚(¥”RJ©jÓ²ŸÙ•˜’{]Î8ÎÑ¥#ò,`|’9`YÔ¾É-+’ŠËr[ž[‚4³{.˜ÝêJ)¥”RJU NíÓ"\-Ú‘ à¸ç#>좲eJƬϮǚ–ŽìR.w·ÜrRÕv)\ÎÁ ¸“é:ÖJ)¥”Rª*‘+3sÒÛ‘äå¤AØ­= H ¶–¥O`öÝã$W3“¬'" ÙU¦ãG3LÉò%Hž^SµRJ)¥”ª>®8ì:1˜âÂq|8IÕE¬cñòy`iñ%"KíY²±+XSeT&€™áDä%0\;¹«”RJ)¥T5’d›$`tÝ* ìš>*ò.Q©±Ú—¬ Õã‹]Æ$dËÔÌpQ^ºGâ(îÐVJ)¥”Rªê°\@˜º–Qn¸ˆ+)›%*K$Ž ËÒ âÇy¹´¾‡ËݱRç4»GÜå2)~:“®¹§”RJ)¥ªM\Š–<Ìq’fA·l€Ø•”“Š31@ÄÌ Ÿ*2—²5@ŒÊ«#ËÄAž"b+ït WJ)¥”Rª:HnN”ÊÖ UeN4â ™Á$ êùŒH*Í$ˆ2ÁO&sâÂ8 "by2Æ0³ë)QJ)¥”Rªzز>hÀ…^ð¥ÖŒøP)ú2fò™™Ù™t5’P­)>ÇëüIa›fNí2£”RJ)¥T•I Ä©q…ZÚAä*F¸îh<.¥lb°25âT;µ`ãÊ×@zF—¾‰ˆäÙ¤û¤<é+¥”RJ)U’âr¬l%=»ã¸ëêψ+Í®³ÃúqHFº\ä8»Ë’1—ªKéZNëŽ(¥”RJ)UE’†i÷€tø-Å\JÅ]fw‡“í3GDFÖçK*Öɲ 2B À”‚¼¤j×bi#ÑT­”RJ)¥ªÃJ]Ù&[¾ÀUšË Ù®  ÄÊarû”û”T£Se餷:U—©Ó¹C,‰¾¢ã[)¥”RJ©ê'\Š›2-FÊ—†˜>Üu‡É¢|F¸f@Ât|©b$$2©Êµ² C¬‹‚(¥”RJ©jäÂs’¡[´\—¤.]0["b–å@e‘šd£˜ŠÓ2ËŠ|@z›F¶ Ò¢µRJ)¥”ª:®¼Üz˜.,ëæ $­ÖZ>âÚ7Çëè•fÇ7˜%ŽKøff÷!‰ÚLZ²VJ)¥”RUÇ‹[ Ör$=çff–}Ç%3?¥KÅêô}ÀÆ&g&™"—22´b­”RJ)¥6F.§ú­™å:Ã8<ðeYÉËR’Òv°eôdœÁDˆËØî±•E”RJ)¥”ª&íV¬9©+·’ªMf@¼¶[ÝC6•àæ2bXÄKÄ š%‘DzÉ"}J)¥”RJU/µã<ìö —›ñ„Ҋ׀짪ÌIŒ–G¤ëÏéœN$åi’"5Éó,ÊZ´•RJ)¥”ªVŒ¤Ú È•«Kq7©[3  ëÿ{owÛQÕyÿÖÉáÞ Abî%$dbHÐlQÆâжض1 3¢44´´(ÝtGx¥™D›vÄFB”îfT[¤™çV ‰$†D ¹‰yözÿX«ªVÕ®½ÏóÜÜsòü¾Ÿ{Ï©]µjÕªaï½N=µky‡}çå PÅ °ÞCâÓib¼¼L¦;N!„BÈÆaë4àN/’¯ëî®@²PS£M^ëæ#}+lâY1¤œÙ™N‚¼ˆ¶›ŠB!„²øÂѱ˜‹ À}ìÚ×õ=ñJäR±•C4÷ZUˆÀöQ )IÄýôìª/Êò>»H!„B6{ç‹yÂùæ6å\|mìÁBhÜcZ!À`nðRUÓð™è…š´xÞHµuµ4‰„B!„¬?æX#M>§yèj’Ú$ǺøÈ€%tÛÝÚ㳛ŀ°;µ(Ô¦·mÕ‡½¿Ñ…U!‹$I!„BÈf qõ´;ÃæÖ*Òb[(²å2Ž­ìȓͶ+ˆƒ=¼8^'ŽÝy$­¨63LÄ’!„BÙ$z.¬Å×]£'n1ƒícmÇ Ø,÷BD²£lú¤š·¯²*'œB!„ Áýh¨mWûÎC³®:PÖzX꨹ÈÑK¶°9ß>?íeªÙçî–G!„BÈúâ.¬­zÖ2³Ü¤Ï£ªK{äP6°ö¥$ øl´‹¤Ý}n‘!—`[ôu'Ê !„BYf[·v :ܪªª¶+ˆM@7¶€T!‚²§µûàAØ_sîñ„B!„lªöÅ:€O=æì¶Þµæ7%*èÒ[lÝb &êzƒ'=˜· `hyv²uÍ !„BYwÌi¶‡ µìd ›‰TÝÍùÖ>- @ti޳„µÙÁN1 Øþz®0}@|eˆ¥œ°&„B!‡/ßpï7ûÎÙn¼é‚[–Ùd–Š¡öªËv9¦øØ¹5Ióë}’œÖ„B!dãP(t°' ãrê2{-º°7'BýùB¸_¬ª".¶„—Y[&U¸3íâš×}8IUöÅ­ øjkB!„B6 _âaïi‰Øü²í’¶îPäÙæg÷Ø^ÓxÞî4çµÚÙñ¦@ò»UG«N!„BY{Dò±ˆ¨jšAöIgO Kþ(,ãtwC™«vo\³?Ž‘|ñ¼ÞšB!„Í%-r®žb̉1—ào^Lrt²m‡k Àb‘S£3ݳB!„²Ø,u>ôYj…í}—Üÿ-ްçÙ¦¸mÆ:=±(M/lŸjKôyiõ¶EI±†B!„MAuÈ~uå.û‡ªd_·¼Ý¥ò~E º૯¡(;ë™{퀔$s²Å!„BÙ`l¢ÙyˆmRdÍÓÌ@r‰ ¢ºTJ.˜Cî‹ü °÷1Z!„B!›ÂÐNût±ú›¸B¤LW‚cÝKv;‡ódöX@Uùü"!„BÙ8UÔ[G›_ÝFxhd/ÞŠB!„²î$×6LEw椚}ëà+–Š­(–¶Ø3ÑŠ´ɃÎhž®–N*!„B!@gÖx;»„,’W=@ÑÙêÓÚù8¸Ë£i…¯8¡KM!„B6ž´ŸÇÈímÈo®òRUi鴏ލOUÍþøˆàRO‰B!„²®Ø|s~Ï €&¿ØÈoœ€[œ-€@¨m·æœ}ñµªê0—ÛâƒL.°&„B!›‹ú,±€¦m=rbñ¨;aUUÑ%’_ìγŠ/Ý6÷Ý2ܸƒ@ ƒÒ³&„B!Hv“R-‡®¢C€f9M»‚ÄœQcú00ß}‘g²‹¿N!„BÈÒúÐv$šB¶·Gå—° ÀRu+íþ‘£Ý[NE )€Šo hråª )ò„B!„l­o ¥ÎQHÅQ¨Ä^i®À I›ˆ‰UzŠU•¡þ_€Aù–B!„²¨jí3§ø4³ÜÄ<Éu,Ã0ÙùÕí ‹g-6_ œ°&„B!ˆÊV½Hf…{›æ¹]l™Ýb ¾Ýos£e:ZaKAõî|„B!„lÙ—õ¹äõ!…*ë2ùûeš\þÆôk.¸'‰}g¿_$!„B!kŠ µ9æî ÅVlt0ß×çšmµõ8!'ªm¶I©zÀf´'J$„B!d]±éèa´B:QÖkŒ|æR–ª¶éÜY÷!æ¬/DÄžjÌ  *þˆælGÍ#„B!„¬?¶ÛÜo@ÍÎ~2´„ÍùÍ^¯.T˸æZ1? öŒ¤/°Î"N¨} ÀIJoB!„BÖÂc‡ZÏWyêÓ½gÅ2$ ¸á†ܽN[]+ a[?ñl2B!„²)D_ÙBŠ2Ù]Ü*œ—ˆØ—¯±ˆB*a—êôêr»áƒª@Ä„ý-Ž.Á™jB!„r‹"¹Äª…-Á–™©ä¥ùÔADÍoFÊ—P DjIþ¦F¸KO!„BÈ-…â᪠1xÎí]bPäœþáì+­ù"¶®»yž1—ÁykB!„²a iEG&9µCöŒUÓ[yžÙXf_¸rŠM{š¦®Þ“ÞqžÝ¾ÓœB!„ÜÐå1N86GÙœwÒŒ"*ù}æbN5Äg¾ !„BÙ4TUlŠYWl¬¤yÀ1¾ ®É) M»¨êȳÖöÑ'„B!dƒP¸[ë ¡Þí䢌f½†íc­€Ø3Š¢ ¨ÊðYiµéêò¤Òb1“eB!„²®Ø[ÆÕ7¾ HaOПEN‹8ŒôæÅ4ó¬¶z;;ÐÁOÓâc¥ô¨ !„BȦ’æ‡Õ}_‹K43Ê3,mA‰ùÏù+DüýŠAm«]Ü[ûÜ„B!„¬=eiF'GÛ¦´³ìK“Ì/%üc“œÑ•ßÞ8#C!„BÈZ“|Ù4—¼CßvÙzÔUþ¬T·±ÉK&„B!d HÛJ/  P!ØÞÂŒevžs”˜ö é Ay øzl ½#†B!„ÍCÝV¤çµö¥U¡€¤U–joq)ñ øS¾_ŸtüqTË6}¹°üI!„BÈæ¢ vù¨½\w‘[XÍ‹V󕇴+€AMP}˽ú 4¢’ŸQ4uU˜6!„BÙHßû®vh5¾ý0;¾¶QµmQ-€mò1Xjp¬±×£ÃŸF3šÌ&„B!d³é;¾et¤L-—mø’ÜRu+ÏygAê}Bœö8¬á2kB!„²‰Œg«kÌËõ-÷²û«€?õ˜ðëìÇoÙÉ õÔ$7!„B!kμכ^ÍX½BfŒí$R&ž#:¢•€¦7¢#&Ù{„\|é m,!„B!7 ô¥ëöÑqt#†-lmaØ‚nak [[Ð-ÜÚÂ0@¨BE1r€KØf¬W8Ä™žoíȪ9t¿ö{ÏùÀu/ÿä!ûÖGâ#ÛÆB!„2Á¾…¼þŸîmc[ÆNl# Ø.zsSÖKè:é S`¡Uè¬Ë]¸Ý¼ñ»WVŒB!„o<œâèÚîé*[)RaÛ~DU€X¶3ã®Dyß‹ø´´…saM˜B!„MbPŶÙ®ãk‘Ë8Õl;{`ïTô¹n{§ŒG«+U¨`Õ*L!„BÈf!Ò¤2´µ±ˆ“Ùæ—7É lË·¬ÜnU 8Ï!)†MF(1ùä‹B!„²Y˜g+îïæÙd#E‡AêÉäâÇÚEüþ §kö¡K–ÉB!„²y$_ÖÝàä/kñ†ƒ¿b‹¼ô”мÓu• Ñ!/qØÖó„B!„¬)­7ÜêÝ㥪 RÖ4ñ<ôyÄd·µ'!„B!ëÈÈ•M'÷©à¥EØsŠŠ´RÚ_ºxtÕŒ „B!d£ðÕÑíÕø½“´5Öæ4GeƒÐÈHN´9jMÙJÂ6¸þúë?ù©O½ìh !„B!›ÁàŽ5Šc¬öD‹*ÞðTØ2ÚË@íçð´§ÜMÙ†Nv73c`&‰ìfÆÀLÙ=Ì ƒ™$²K˜3Id—°1ÐÈ ª">+]bgÃKßX/$%zq}²C¿ ]µÀ…Üâ™dfpxp„Yf‡ÙùÐä[瘮¿Û ­eGdÇXÑýIlB!„B6ó¡evîy1`P èÿ !<‰&Úr8xÊÓúmog \yå×üÐG^}õßµ d35ZÈfqà 7œÿâ—œqÖ}î“Ú´rîŸzÑÅÜÆB (û—Ý`Å0¤ùPm¥‡»Çæ÷𼇗õ²ëBYQ2ï™ïM˜“íÒûÝâ¥ö’Ö–C9<™§þÔÏ<òá{ä#æÇ5$"3Fï¶áñ¾÷àSŸþÌïýÖ;òÈ#otÅz i½™:ì¶i¯»•™îßÍÃ+»_ÕöÈkã Íÿ úÖ BFÑÉ¥ ¶,زŒ€EÒ/Áï^µ}&ÍýóœŸýöçñÌg<=_†¾øÅÿwΟ²oß¾·]ð¦ZöFñ¤§þÔ÷?ú̇=ôûÚ„dC>üŽÜïüþÇ~Ëef Ì$­k;r~åå/ "›Ì̘IZ{r¯íÝ»çŽw¼ãþ«ù½þžV¨æsŸÿÂ=ïq÷#<²MØåÌ ƒ™¤›ƒî©Ò'ñ 0sõ¸å33f’Ö˜oØMgW°í1³“Wn Ìý5gØ’ü‰Š¥ÀúÑ»ÿسÎ<#']{íÁ×ÿÆÞ÷\sÍ×ï}¯o}úSŸt‡<áÉO;ýßñ±ⳟûÜÏüÔÓ¿ç_üóPàÚ±Ãc†µ9O{Æ3ñð‡>òá~åÍ£ejTl(k>üáXäŽz|GÂkÂÊ›ÎTÿvo.˜¾ÕÅn‡oxÐì;£ãa=‡'¤,òÙš—â¥Hue:KV=Ïvånz‹Åxø[/|€w_üÇßvï{Ø¿?§¾à…ç_sÍ5¯yå+þë+~éò˯8ÿE•gÓmSM IDAT墋/>çìÇýþïþæC¾ïÁç¿ø%ªú¼çþ»»zʳžùŒw¿ãÂÆ7šb;åþÇÿü‹{öìyï¿ö?ýÂϽó¢‹sü/¾ø%_¹ä’—¾èüßùï¿~—o¹óóá…¹_Þñ΋~òñ½àMo\¯zf Ì$­ë9r¦˜ëÉŒq3IÄu×]wÁ[/‘»ŸzªÅtûè…/xþYg>êQ|Ä»ßqáãûã&Oän®/å+¯~íëŸóìg¾ù÷ç çžý'ïùŸ¹Üñ0ËI›ÅŒÝ3Iëà _ðüw¿ãÂw¾í‚Ÿÿ¹ÿ®‹.¶>úÞÿ‹¿þë/}þó_0™w^ôîûÞçÛ»Ã0{Ié^ØÇW•uã´Óîó„sÏyõk_÷áÄb²Û})cf Ì$­9ó7nÿZÒ-欟áp šþ0ï@;ÍÜÅV`+0¤|0$m9¬é™Ç>ÉÁ^eöªôo$g<âaï{ÿÿþïÿþßöG~Ô9þÒK/û¿ýØÓžú¤oþæcöï?ö©Oz‡þìϯ¼òʵÃ~ÿY÷¸ûÝöîÝûè3ϸꪫþv•<€?xË[¿ïá²ï{ÿ·Sî%—^úÑ}ü§žú¤£>úŽÇîÙ³øË¯¸â½ïÿÀ3Ÿñô㎻Ãmns›óÎ9û’K/ýõW–zÖ£u¯o½çb±HjnVfÆÀLÒ:±n#§MNÌŠ5ef Ì$mÖkgœõC¯zí¯½àùÏ»ÓîˆöQ>‘§r-X.—Ë#¼Íž={îy{œwÎÙ9ï! ³5efÌ$ÝLLª‹Å┓Oþþ³Î|ÿ?à›n{Ûïúνã]ï ªïºèâ‡?ô!XuIÙÎ…ý†Ê§· ˜3IkÏÔMgª-õ–sÖÏrx†G÷ƒd¡"Ùn”©*Ò¿òæÅí±3»FlÃùþ† ªGuÔpÿ—¾ü^wÿûö¡?ýs‹ÿêå—qÄw8pÀL=þøãüÍW/¿ýíooïŸ}Ôí,fÏ­n຃×%9—óßÿè'?áÜ|ø?ú±©rU]Ïå—_±oß¾£Ž:ÊeŽ;€ª^zée~äÇ~"kpÙes×NPàÀþýS6ÜÌXâm¶ÎèúW”äsxfTĘ5£_e1úè£\zÙe‡DäüîoÝîv¾&;²+ȶX«‘3Åü¨ 7 GuÔÏ<ãé?ñøsßþÎwñˆ‡ï¨ò ˜Éõ Óø Ó¨ªü'ïùég=ç¿ý†½{÷62äæâk_»ê…ç¿øçž÷ÜÓî{Ÿ[ïÛ÷æ Þú'ïùß–ô€ûßoÏ­ö|ðCúÞ÷ð{¾ûŸíݳ³—L_ØãÕã–4TN»ï}žûïž`}—ƒß”to:3ý;ÅNoF›Âaª["Rûä±½íwHXN½éÀB1ØÏU áA5…1¨úüšGÔáäÄoßvï{]ôö?üáúyüqÇ}Û½ïýŠWþ×+¯¼òò˯øÕW½æ¸ÿ1Çà”“NzÇ»Þý×\ó7_ýêë^ÿ1W—cŽ9æ _üâÖÖV›Ðc¦ÜÌ?þ^ßzÏW¼òUW_}õ¥—]ök¿þß,þÀýßõ Ó_üÒ—}ù+_¹îºë>ý™Ïþü ^øÿø1/9Œ¬ÕÈ™‚£b=¹í‘GþðýÀoÿîo¸á†C룩\ÿç/þòõ¿ñ†K.¹ô†n؆믿~°÷õàúë¯WÕ#os›[-—ŸüÔ§ßôæ r’ˆ<äûüæ þð½ï{ÿÃú‹œ¹¤Ì¯·°¡rê)'ß·i£éÞt¦ú7Ê4ìôf´A†áaæ@ 4ˆÿŸÃv a uvÇ-`ÿ&r)Íی̡ð™öu`d‰ÕCüìsŸõª×¼î¼'= "¸ÿiO<ÏŸ-ýɳûâ—¾ü1?öØã;îÌG=ò/>ü—þëöû¢h°øõ/ð¥/Å[Þzá©§œüË/ûÿbaHB1bªÜ¤Þl{öË^þ+?þøs÷{ì£Ï|ä§>ý+ëÙÿö§ó·÷ß?ïç¿vÕUw=á.ù‘^.—ɘqeo6fìX«á1ÃÈÈ›äÄÃ3£b=™±lS†Ç$¡×Î:óQoúƒ·¼ãñȇOöQZ ”Ãn®oÿ¶{}îóŸîxþß^ñ·wºóž÷Ügï۷ײt‡YÖ¼A̽Ž#¤nçöŸsöãþóù/þûø‡SO9ùŸ~×w~ⓟÊ}È÷þÎïýþ 'Üåîw;5GN]RP‡xÖ7W•f¦ë8<¶ÍÈr?‹1q)°¤éÄã?¾Màð d!d2Cwx<æqçøêe—\wí×ïô‰SHð…ËÞÔÙqî!¸YÈÒâjÇÛÝu©üûjNz*L!„BÈf¡ÉéÍ_ õEÖåÕã=rNÀèïÂ9³øB!„BnÉ(lF9¯Å@Um–9ÅtÖE+LF†é]A|ßáDÑY­Bv3ÝÏáAfºŸÃƒ€#„Ì2ÓýdÇÝ/Pµuo:9Æq¯“´Tc‰oäPûF–EÖ“™10“Dv 3c`&‰ìf†ÁLÙ%ÌŒ™$²KX5ò|²Ë¥°¤Í= ž¢6?íñqÿË%W{B!„]9Ñ-j[ƒ˜÷ÜI¯ÐYcXý˜*ŽpxY8<È<!d²Š01mhÞ‡TÕÞ.‘“í`á!_02¹ÆZ5= yøà &3c`&‰ìfÆÀLÙ=Ì ƒ™$²K˜3Id—°z ´>ïЉàª\ŸíF-£–о_tÕª @!¶èdai†é³Ã^Áêj‘[:3c`&‰ìfÆÀLÙ=Ì ƒ™$²K˜3Id—°­1`Bö× •zÛéŒhÙ‚Z¡Gî ` …ÅpƱ¶˜žgß­÷~õòË÷{l›@v—_qÅ­o½oê/!»2G™ÃƒÌ0?< ÕbNµ(Ú«EÄWÙ‡⫦…Ø®|* µ]AÒÊ#M9œÈ{î ^d'Þ&ÀKxžSO>ésŸÿâ¾ðÅ6ìn½oßï|§}ûö¶ 8úöm,!8<È,dŽ2‡Y‰B›¥":˜« dwº`ñˆbp¯ZUËà¯öŒ;š !„BÙpFÐ(N¯- PóŸ}Yd™ßzÞ1õ’óùõà„B!„¬-É3.´ñ­«Ä0!-da1ñ1}§y;äeÛ„B!„ly}G:Šžmt£9æ[¦í«o$‡î”B!„rs¢HãÛìó̺ w²¥d_ö|âì‹G§|B©OV·©·¾Í‘yÜyM$!„B!ëF^í\ª;k ëE’÷\„!7g^KÇTßÀ”U 7¢AªB֤͌^㛪X¢e4°p\¢—Ïî>V6'2¦2ÆÒjOCŠÉWÃLUa²ÙHŒ(u,{NeQ€E)X50Û#×%2ÄUm.©AÆåÄø;·•¼v‹íDç\々Óa¬ÑŒymöqdK9Æ/X½T¸X2&¸.ÓÄ{GÝìmã(²q“–Tƒ|‚ÑÝ @lÏd¼i4<²ÖÓÓêXRÛ¬YIH˜Q«æ©ðˆ:o,6‡k[mT3ؼ=c±1¬éC€üÜ[¦”h_ ´ž=Ì4W­.¢±9ìeª* *ªÀB¡P•d¼)Síë 3>°òLeö‡SC{"(Hç=Ih¨¬¬Óò5édÈÅ$QQkçï±PÿÚSYøÞI5Á³)qmÄd“¬<<ˆ)ñ똭< kÃS/5¿[ºWzK5%M¸üJìdÝ&+d ›rS¤[|¨žxr`¬;ϾÈém—I£l¬fQiàº}ÄF¡kkñ®âVµUFKeüÞ,=[«l£r¦@ …Žå¢=KŽ$’y;adÃJ|0NäÒvLôõWÃ\âz¥›/û]Ík”Ki0ç®»=…`€Ú–,Kž›pìBŸ šnë‰ùˆlÉRÑA -Ôɨn…ú¦Ÿ#zÝ]Z;Y]Sí1Ê…‘/¾=tÚ“ uô–OXtU'VtjÔ ©%G49ƒªtc×qâ†ð¼Á\Q]#‰¶Öu÷GVoT´z¶‹øtf­ˆæ‹¡ÝØÇrÝ–( Þð9e…f±Ñ£f^¹…WÐ&o_ªO¯µ?V„D;§Š¸u£Y@³ª¨>^`«b{°£66Àä7f“€E¾ Me¬•Œ¨bÓI£òWþ›÷€ÚUVÿŸÕ¾‹ƒ1×ìŽÂ¯‰*^£… ô£ŒìZɲ2.fζnÑö©FhªØ% t¦;íJ5À¡7çø^`d™i\mÈv*í¬’SlØøöè’M!6D[MíqŸ˜Qû–çòc¡~ÜdobûA^/§é·iJŽæ‚‘ðS1èIyv¤´^OŒc[´Ú Ʋfkì£.º œû«S☱Ð|¹›Û°¢*%cÛcE>÷MDÆh÷Q?‡G“$\7é,(ÕÑ<£Û`ÀTÌÌÊ/Ám`ê”,d»f \¡¢¦`ôé€Ô}€?Pµ=ÍnS1M`}6W³0bj±t HJ bí¬TU ,l•ƒv6y;ű„ªªˆ(†…-Šl&{›¼Ï—=K’¨¸¬±îv¨ÄæYÙT±ž)P†žÅÌiÀÊä¡ÕñÐrÕô{Óè&(Ô¯ ½Ç 6Êñ8si®ù†«lnÔ¸e9¸}\ë\ƒ$æõÉóá|–‰zm§D'Ÿ\!ÃXç8¦K+&Ð62Ú¥ößïÍU ĉ E§––ºòªml¯!LUžˆm­ÑœeµÖk£[…–i&£7ë FÍ›˜µd¥Zä~êÆº;b·„IÏÀmkUlÔéGÑ •ÛS嘲³0n´n‘~ÅóŸ³E¶LÅOSš½Sšâtj—¹4¤"V=‘)“ÆD#‹ž±Æíq(ùðkÎxBgŽ(ëáÜ7JüN ùp™s©½©€#Ú¸IÆuÇT”‰†"hQMFP®Ÿöç>µ_…ƒ”³_‘§![…åP‚Á'“@}ÀwÇiaúáÅ‹ ì³´>R!6w”¾$-þ0f©¡(&”$M_‹ª§„©îiÚ3èz ‹ÌÝŒHmZÍ€[JW7­Ÿ›ùÈ g¨óë-Æ4aÃÔÚ“‡ù©pŸ#7B®ï˜j*Jí¿ÿ¶Ë1øD$oFRà ™j,»ÓGLX{NWÔK4ÍE«Pµ5߉"—”Å Œ¶3Ùå¶^ÇDšÔnÓÁŠN[µ€ä4ä† ‡V‹- R@‡¬4Vr‚ùÁÜƤí6½ç3¹!oÞÞ¡iÌ.ãö¬Ä [FmÒȇCoËŽ%Š-¨OÀ›A>Më×éTëÒ&Ö¤‘Ø2!6œæ’Öu ÊkBãXÀ.~R…¨ÿ1DB8vºëÅ”úÁÚ|FxÌ„:ÎôøøTZZ™­j<$šzÅp1ÕÚwæÊØÒ¿ˆ·q;ó>Waeú_pÚ¢ ÛD<¬øŸ\6ršÚ²\ˆ >YˆN%l˜Ù‰²Ã+€zÄäðlsŒÅä}rêCÉ ÏáÙRx%ØLjÆê\Ÿw–Þ [ëÅ–´ð"fW/šÿˆL±;, ¦YÂ…”+9&bauá-(òvòѹ›y¿·ÝQÕ±ó³8…;¸*Eˆ]aŸMLƒg¬¬RŸ›í)E]ʈx^dmÚd¬HÞQˆZ¤ˆ*c'¿ŒNÊt¼#h–ðg,—UÖp™Fvõ ê-¡@ÇYšAÔ¢¼î\»ûø”FÄÛ¦C%\5_=ÆgQ«HUyÈ6æÕ|2qîÒÔY;[£@Þˆ7ÆÚ82U¯•KÅaßf¬©¶m\;ê¢jýíœÑi‚B´?gÚÁÄFµþ®¶öºab3·…õÖ¢LèdÉ©pE[ÞˆÚÎñ$ß ¼ñ{¤îˆçƨ©×šó{|™ŠÆ×æÅe’\òöÂ>¾æ8#ßœåxYèkðœ;hA©áXç ±o( K Ì`¹¥‘æ8«‹m87‘Ðfáod¢Ïš?FÆDºf4áȸ"Mx¥’x­P«3FiV!~Öx\MFËó7b7êFÀ:ZºVev”Ô0 4eÅpÌk¶Ž%»Ýd–¤¨Â~°ð33È…°´^ni"S³·nÇT‰Âï›"5Ž*¹ÂE¡iTexÉŽÕ˜ ¨²ÁæjlÈ46›s™ RW•RHCQvÙkŠ0ªJÙŸóa"š‘,ïwÁT]ÆE )ñêÈ -—ò<ÞZ‘ðx­vš6©ÄŒccd}36Uè[e±Q3€Za R[¤KY(Wh¸M–>«õ7ö”RR(–Ø„1‘½K_Išó@Ø y¸Wuì—— eX¢Pµåâ^ÃéèXmÄÎ)— ¢cm‡ZóÕtý‹¶ÕïWöåf{ážyM$¹p‰˜j¥ZÛ”Ôv8ô¼–³m£±ÆÛOûcPb\âJ²©ñ.+qž&*F•˜¨“÷±¤ØØ “Ʀ»FŠ•àçŽj(HÓvÑkªKÉE‹™Ø´Råna6¡£Ð%$ï^a%ì¾·(Ê‹m²f¸v¨ˆO°fSš°8…úÄ@OH÷e…×´©["þ¨S {ƈÅžXh¾ÙH±Ÿ¶GM›(Û*ÿÈSã¡®øvÂù° «"ý lÂÒ  •[ŸØÆÜ™@µíŠê~â1Þ;MôXi~ÍA¾æ¥_œ1\Î0D«0g#W9a] ß­£jÉP“öÇs*l@`¶ÍâÛddð9 þ £é ›º]b#”pv¬¤¿LÕe‚¢Rý0[цGN:Ž­Óʌ؆™±fæç¼ V–xØ2ÜŽ­”ºÄqÁ¥AÆi-¹¬¤&²A‘º¡Sìô0^ÉH× :4;¥¹`¥šÝ»T¡EÙób²î hjÔ2¼wÒµÁz¹W~l ¥8ó ?©Eó%N¡Õ•Y@þ‘éJ;y‘ÕXbBU½Ž%Òkì+F¾½jYUáû‡@ƒàˆÅmNl Є31¢J´y~ÓÌ$ZRÏêÔ^+,™fZx2EmÆ9‡ ÔIDATÉW‚ÎjQ1¦Q¨¹ñh¯]!¥á&M‚µƒ©4)…EŒ©ÆÜHeŠhÚc§µ¹×Ç„¶°ŠZT KçãáU*çF¨èØ4Ò Ÿ”êZJ+‹qö %£ëHOx· ¯jSQ(7‡5²%t»ÔÉ €Tâ3Ý€Ž‡ ©°º‡Kp”ns"¢Å'ȱ©,£Éf³Éžº=£«øUM< ±Ö^á J’]%GulP(Ä‹³K¹]¾çHy.-ÈWU3´(Ô‘ùÈšScTIAêÒ4´ŠŒv w˜bNj«¼P·•çôîHæUi˜Ó渀ç¶f®2.©4-°®Õ[;TQ; mÁ¨Œ‘eU„Ì §"YuGñ9Ø‹›FÅ,mjÞÍ9irŒ®{@Ꚙ0ÇXQä˜úÊØÑ™¢Ì¤¬]Ò¿@JŒ +˜½J #©Ž1ÛE;êV"ž)—ë#GRBàFØIšó‡xìÊòMwdJ7 0yvWŒe*%Nßóok:ôÚk<ÆíWê¢SÆ|«gÓ/öíG À‡™ª7d0b™yÄß²9,MýE¡X”éíx;õ‡[c£^ʘñ=uóˆ — ž±¡FPʉ7Ú6t…ï4GéøLA¾“‰«íÖ&ÚfaKrµu±%·ªš À~0Á/—~ÝÀJŒ£Ü"³Õéùžh˜ÕNáu‰ìç£W-ŵa;4UFTTlèN¨ä;™„‘ë ¦K7WÉcÓi%,˜ãÉjú-JVÙ:£Bݽ;!J}ÅJ’œ½˜†p "eþ/_IÆÖ•¼ÙÿS@R;È”š1iilGT‰™›QKtj3ÕiYÝa) : ‡6?ê#2Šx,Gï ’Ö׆kÄÖËš ÚR¢U=Òð+å¢8É´ÎZ—ˆY^›uaùÚâѹʜ£±sÚ Lÿ®h.}L:lëvëBâÿ5$µÂÓf¬¢dÔ ¼öÆJ)U1³evó§ºÄã˜U˜„ý “É~Ù¬‘v Œèw“Ý>rÖmõ—ÑÓ6& òê¢Ã9TŸéBZ+§ä ±”ÝA­èvŠ›"ލE¨ŠÔ¦z9cu³'¦ÊðÛ²”­Q$\î@¹ì¨ýjiÙƒO…)¬.J¾WGðöB3„«H¦¹^g¸Oª?®ÂMú±ýì²¼›'­ºœnMt 0}êÖcþ‡aÁ.ûÛ£_;+¯I°®Í®CöʺרaŽî¯ù.#ɱþ(ŒêW£på&9mú—(š«ÊŽ 4Wl›ÉP,8Z½”š¤î¯`KU¦W:–ú±ë.ÙC¼å÷®ˆjNZA£\Ï'¨oZµp©²¢d\iÔ€ÅÛgéêTH'Wó9"²©ÅæhYÔ5ÝocmÐ}(Œ3×1µ5;¹TöiÇNÍtÝ·Küq@».:´+и/è™6_•ÕÄá; +€z„‡ðtÁ½K‡Çög¢ºFìÆÖqD«oƬH¾®Ï²-eu›®V:¢É2w8Õ|cC»?ašÞìHxR[ŒXÑÍ3S¨ª¾²‚|³®Šj•g‹‚Ú(ØÙŽcŠ “Oí9¸Ý™ŒS§c抦–:¾+3RY¨š¿giEßlA[D{ùšÒÚtU2cÝCT¥×Æ•¡DS~xXܬA¡P³?åOY™®Ú¤¬P°€ä+æ`émãLµŽk°pîš…bÇvJk³ Þj˜…ˆBÒk5͘¦ÄÖ¤$à SåÇvæ˜Tz;ÙàM‘ÍP·ß¼ádGT®^A3/V'Îû[|ʬ&V Yˆ‡£Šd;FY¬´½+ …¤õ;c… «L=S›ì¯Mí¦¶HŽíPG*±ù˜Æ‡ÎsØfC Õscˆõ­æøÀ‚ß=u\…„úÿ@žUÂ(iŠ,Ö´d›}4f ‹—¨ˆ§DOÕÞ1Ý.°ëI5gbéÖh3XªåüóÎcÎnÌ$_Ä{DÐ)Qaå¤F Ô†è Y_A°ƒ ²19k쓹þñ„ªuâAÌn{Û豘³î¶ÞbRÛvMŒu®‚Hr9)ùçê?:Θ$™Þu½’sL?iÛØ­–J·Tƒ¢¶6Üá ŒÚ3×É“½D‹Ë?Z9qŠ—"Æ0’¾ƒ=N g(eOCLC˜Ù Ê0þð(ÐN-‰i;Ed®Wk $]g|hÒ™^¸t‚éxI‡ÄÇVÌ?öì0µØ³Ôø“‚?ÃáØIØÔn®gª¹€D$}â.Ï:“Ãl›ž°Ä¤@4;ƒMžwÈ@ž‚œR!*ÀÆ­2±FÌÌ`"â<Æ“ÎãUû9Š3ÑÀ¹ Hz²PŠ3ÛþJöc Ó•fØÂþ’<G€éZ1‘™`GÃ?yñ—u¾HJ{ l¢F×!L[“¶y²æÌ%f¾uøNÆ^@ñ\¡¸ŒŒ›„ÛYz‹wu0ˆ‹Œ 43}#Î SFàI3yßm q°ôsÜO&1(êIFŒ¤: z‡al÷â“$ú—ࢠØâvв‹dœZ1€(1µ×]¥@¹Å7Àõ»TAb"²WŠ\LÒÒøW8ó‰’ˆ(`¹Hf`0@QdtÉÔJÄé~QmÌ Ss Ûá‘Àž‹¬œÅåÒ-u)Ù=Å~äQ¾Nw É)¿$5<3“´Â–ef&{ÁŠq’\«‰æÆ•lçR&ÜŒíäë!ÆVMd{ÉÙðJà»ÈKcó¯M¯šÀ@²ÅbËm-Dr7ØúÃcÁÜëM3%Ll ">&Py¹ÉÝG3]ãED¦Ç YIÊFŒôì–&9²Z"„N å\£bZ¶ØeÒ¦I# •h‰¹Î$™ª¬%aÛrn¶JÚDò¿¹m±ty—:7›Œ–Û‚ÄÌ„¸.çg«Øˆ™L‹•wŸw 0“©d„8m‚ÁT`""¿´Óál–¬¤ã²ÛHäZÊ%y‹ 0×! mbff€ÀDrm`SÁæ c‡MŒÇò ë[çó|ryÃÌni —^jà0’½´2"Í€mºI`6A‚s`\fò™(a—ó¿˜b]T2¶;ì¹½_Øc„='#JÖI&ÑHs¢m6ø†üŽˆ˜ÙKŒLyëù®QöÌ¥§{-Õ‹ck$À7ÄÔÈÆ”Ï» œ›V;û½Høæ¶)eoØÊl|oXþoÈEÆZ‰Þb1ÑÁ`˜µC±L8¾U )ucÜÈÕkXFó’K€™äDp×C¶Zë åwK|å¦ QÆÕëá_ŒiÈ]@`Ì ’— )`U‰¤­ÆsöS\Dqm¾W’ØØxbui¢OÆÀÌQ o[3[a;ºdPËoÛ D˜L“`ZC"4"oއ1›,À´)y½ÀDÄf,åE‰´ (9:O±ùïcÚéL"’D—MD`wÍ¥ ª%ƨƒ_3àn;vì ±ÃÒ-²zàŒ¦Ø>¢`$4ÀùF3¤„»ëH–3Ü"õ&;ŠÝ/—y#&@>´X%öÏ¢ßþ¶wÏ8M¬k`m–çïžÎV;àÛ˜î¯ Å?‘¡â Ï03¬×½ž0Bl?9&Üì»É@D›l£þ,Ž)è·ÓSåNý°ù¿9˜f#)G`ù$ÃY—V1Š loVjØN+eÒ¥„Šƒ%‡ŒdÒšÄ(H%h‹Úܬã¸wÉ ©×¿ÁpPÆšçø6Õ@Â,»Q–ð 'NûO†rÊ„;í©‰t ˆUZU)TG²TèU2¿L{È΃R»û8Q/èñ…¾‘`@:Ÿ»S ¿HÄ<›ia„…;1Ng 0Ë1$ÍI$z–$—ÁäãQA~‹,‰zCŒ;ƒTŠ—*B2«ú. ÉÌ÷¼;`ÀlµQ!xÊO÷p“Ù»ºdâH{3is˜[*±Qà¹ÂiÌôEpËdWĦD`Œs2‹_Â[eºÉ“‰3m™y#ß¹ÚÒ5•L²ÒÀj»hc×–¬ÇLÛ‘ðCÝF°˜+ I¶•¹ kañ%¶e ƒÅg’i¯7hꃛ°3qÜq{ZqºÉ®ƒ2ÇWfb@)2!líK›XoäOx¾Ì@ÜݰÇö”‘¬?’ÁDušVüÊJ×Û]Åa ==ɈÏ,˸v%ê̺?“u­ y}?3`»Ø¤3ÁÌr ŠÀˆìÅþ+Ó##‚™@ßÂSæ‡6™‰ÆO6ø-2–˜¨ÚT*e|Sìü @š`,¥¼}Ò¢°^äawª3gÛ ó™;ζ­°+¢ÆËâF033Ån\:2‹‡³"BG§K¥S20úò^GÛ±´ €¹ÏÚ’<ÈÞO’÷n×Yõë"‚|²ŸÛVJ‚ˆ@nÄäg9ŒÁEÚ(EIf M6>ÓÜ$Y¦I;ˆäc^"מ‰ ³M2‰¶Ç*’z,ÆÐtãW’ubD™®¼\vE ¡Ü/å®îTí¹0 "s娄,ƒ–ß £×]E~®¹–ãXƪ1×|} '0É^ä2+KyÄò\a:ä5L˜ø.E¶—R.)P/ ÿ˜ãzà+´ˆƒ¼ÆJ —(óHP2Ã\K²E¾`B‹Ç ´ÝB¯ —Ìȇ¥Ùx/›Øi…õDг[™öšâHW!éN•;ðÓÓÁà”¤šÖEQ$ßy¢¸Ý™‰)U… %f&»ÕŒp?ŸãIÜ®\šöÚŸeEZUF³ëIÒwâ_4‡µúµœÈiÒÃ>NaÿTnIVHÈ²ÌØ" e£¶oÌ ¢ÌJmäVjäÝ„+râ`“ çÙ?ØŒª¼¹¹ú–°ÄvB³Ã1Q6åA·w")U ,1]{¶eÏ`A£–!1…z%L aq¾;'ó?ÛC_ƒ'FAÀCÙÀZNý¬Bî1ÊJô¦ FÜUïÒÿ7rA œå…äadä¢)¨✺ L)—b3ÝGS¹²‰Aò9΂´HbPñÉÀåwó ô¢HGÈÕ‚|Ñ>ÔïŸØ”"^ ÖV“­ŒS3ÜfpóB˜ÃÎaŽA²âY€û¤(žg°ü=AnquÄ ’ÅO .d~-NŠmVRTlV…Bfûm÷eDIIø £–î"OfÉ©…$²ÿ>b†3ƒ'³Ñceˆâ»2q1ÅE1Ž÷N­"6ưùøÎL”-½ ‘15mKˆ[–%p{u™Dë #¬Ê¸°‡/é›ûaʘ,¬Ÿ¥Õ¬ar»M÷…+%½ìw½Ãø'NÈÃÖd!뚌âÏw% ºBsSø'Z—ç2¢<ћ˫4ùG¬$Ò)¾K™Í¨"föþ ”¨|L‘:pÕG×]"SÂÝ'^ìes%/(h x£•¬o²™5ú:Cý&‡­“1•e*õ’€¬È$wbfó¥7Ñžº, ¹ù3˜ä¯€n—3ŒúÄÉüé&'$ÕfÀ˜Å21€ &åÁvϱåR:e„,{Œ°éÄ&Û•6S¾øbgŽÌ ?I‘˜N®3Ñ`M·“º?„8À=G"v~^lñ ã;÷7@îÄñWКBømL÷¸–¶|\È êT C¬Ê6ÝžFD¯˜‹ýžŽleöò±Uà ²M,@Á C¢^ûažÍEÁp÷bc¨ù³‡KµqvØKŒîº H"}Z@Ÿ%®Þë ¯2§É6Â[抈;F7³¯Ê(ò­¿¥ùÀD ȈHb¹ÆDlÄ‘h–ÄkÇh SœpÅ:y1;13‹cUA0˜È'jÜÄÖq¦"27wð´–C'±üʳy&šLÀ’.þ‘_òg>xH/6È‚‰»rÚR¦5Š8¢•ƒŽHL.*ÏErågÛy0¶\ÒV FŒ½K;‰ÓCîWé>1,í!S»X È…è=³ F9œƒæ< ÑADÛMÞo#n r¥aM{m=q¦;r¥Ò`+åÅîÔ‡ˆÜ_xýÁ`Áœgffòž@¶6ÀV+†%ºÎ·?Äø'LÎÆˆÙ¬=Û’‰n–D2Ï7ŒÛÅæ®‘Š…±…HèJ4:y5H÷fBD wÃ…þoG†Ýlã¯4q…«Ná©ò­Ó æë²8[;A±8Ï78ÛxO<´Þ•uˆ6{›p%Gk"F9 BèX""’{¯)•·O•”\D Š"Ã̶0j­­D’—P ˜ú­‘Dä¦+@Dy–ˆyÎ¥T€#3jóµD$OuDb‘Q`.€‘5±šxBšÀÌÁ 㟊UN‰½¥™\f¶a‡½ât ÙôT'2dæ1ö…ÉhÓt)éGÔ¡ªlâÙ Ù(7oÿËU&uºë’H?™cc—ü‹À¶‘ˆ¼Ñê~›Ä:W˜ãµ ‚Fx•Èð¯…÷²ýœ¹;µ§ŒÒƒÙTŽ&9%ìL(1 ™é!¾œ‘$yXc%àaé;9–| 6eC§äÚqš ÙF0S"Aú2SJHéšfpÚÜàÔ'=t™ÙO ë$òüÙPœ))íYˆaœ¥'Ófg´D´éR Ì÷c³uH}YS¨Å}äÉ"¶–Ã¥éh¦Tºw “…Ôœ½éˆ"òóƒ¾w˜¾w>N®ÆÕ—lw©=l¹ËMd8GÊ"S¿$åí Ò-$šûš§.¶ˆ LD y–¶‰™ˆÈ8Ík‘ìDd'cÓK»Rä·ç‹W—t®±Í÷jâêŒûÓ¤Ùî¦x’ònŸ éú$±~ª…€'Å"ê=ê8›G1FV˜a,¼kÊÓc"5,¶d˜çM‚q5’b¬„]æ4Jlƒ°;ÒÃ@ä2=cÞ!2ž)* ;ð’xCœ‘Og–ëüÛ™k‹±6p£ÁÉ›ò@(áð“ÝqYÀËbùŸüð1ÛàÄÙZ.bb™7(˜€·>Ã0‰I‹ ̃)Ž.L]D’BîV¡»²`æˆ"2Ÿ3Û«/®!wšˆ Ö’¨‘¢ ¹TÓCZ ó)5ÈõƒãD œD|èŽ}\)ßCÜçüBÂdy‘\̱æ‚‹ãú‚?GÄ)Åj°˜{ùL `$’:cmÒ(³$¼¦¹b@þpnî〠².ãB7²—,)R‰®ÍD€m8Áó¤)âc suJÒ&«×¿³X\Š9P¬/$Ç\&D0!6 ` g¦¹µÁ¾ÂÂà»4t¯™Mº+Æ 6:¬H,*<¼‘®€§¡tâÀ:¬ÏØdf†ë…T).7¶Æ—‘Aè²Kff–O!¡€?dz¾c¦žx? fâ “—.PYf"Ëw²%—eØ–0H>t‰C’Ù ˜Ù”/&U ©6Üg6ÞͳÂ`€l,RbÄÊI~ìÝÓìAЗyï>ÍNÊé·W—½GÆ8yIL; ž~Qk\*†eô£hÒYþ£œ·«ÓÇäþ°Þ±Ë ä$ …­åL÷ˆß}™˜"M²wâ”@xˆ¢ˆföo=%! ÉînKA–Ü-2̃µò_œ.ÿ¤LËTÊe‰Ø1,g䱉‹ X’RÆX|ñà˜aªv–g‡Ø) Ý.>’¡‘<8YžWAlšh×G¢Ô -¬ ±v¶" ~lˆ½“k’ Êž8§˜¼d¿Qàj³°¨#79%úÞSC¶¦$¶^!›n„ý ª~ -Çys–®€1Ìò7?i¿“ή‹ˆ(˜«EЉ¨K(Ü„ +Í0³ªåÊN8ÖbÇC2Ë|ÈÉ*`I{Õ¶&,d«He…‚%BðbkËU`ü5N0vqg™”¼f¾šb*B'xØé—½iÚ\r=K‘ýŒKAlðTûµøÇ Û"$Åò_üÚ#ŸÄ°ÀŒÀâ_¡¹+Å¥ŽÍÙôÙœo<¿˜"I2Ž(þI×¹’³nQãaÓŠÂöH†Ad…ÌÞÖjà¦c—fntq¢?¦¸Vz¡ß ùŸ¹5ÎK°ó œ‚Àò8X#™ì<)$öo[ –afjdÞO|$ôIŽT¿lÜ™UÅb‘HÔ+–ÚDJ]Ëë»ü«"Y8n1Ë/f°y*1±2á1IÖ-’ˆ~æ"JM1"m“QúÌ,a{Ë<Þ–™ä—ˆã "Û4{O""L-"»÷˜çÅÃlB7ÖxÏîÈ~LEº¥EDSÍ+o°[ ³{Tž•+7Bäâ!òîan¤)ƒ’dø?(2ým7¦§ìÚ¤{Uö\:µv>1‰I¹çÜ6u6¯ŽFInR¿ÙÆzuÆd$eR¸îxí´T])lAwE,ýdß̉Ÿ ™¡.eÌ wšï7Àl_F²/¥#Pž`Žÿà`Æ­R¼´o®P›lQƒ2[©XKNŽ`ìI&’Ø#É|Ë –Y—Xª´…-ör`pr.Kˆe…³ ÒIÒ?¥àäo1޵S%#ášúÁ¶rÛ ÅI×Bl'A0²ñ³Ÿ!ID¢Á¿¢3›æü\²±?áÃD—',LøÝàZ!*M’ÿ‰È+åÜë•åw®d›™7 AetɪK%ˆXu£w¹K»N”¸{ À`†ñ6%?ÚÙcÌ^,’ËHâC')I€{3I`o¥IM^‡ÕÂ-Å·‚$\-~0õ¹(P.ÀX.Y…­ÓÒYÃ|Ê i:R-ñt˜‰È2’O€™¿ÜÔ˜&È)Yg‘—lË.½ñÌ^°EuBdã­tUÌD ff3 %‘L2Ĥ( w©û¦$œgÜ"dFœ°êÌ$ÆñŽS±Œó–ÅvÉ¿D(ìŸÄRëkÓ_.#8NVèN¬©pÞ2zB8ÖaTøÎñrc2½’tƒÁYE5„&`Þïf+b†Ä©1Ékç] £ÄÔÄÖÆø„i™ØVÊ sÄ®Â0$é;"‚ÿæp¶£.¶7£®Ø?ÉcÀÖâúP06²ñ?Á¸€I*„8B\øšMé‚!±¾+‚(œcÅ1¾ñ‰v8;SEnœqB´"뤙5Ä ½n š™>NCNÀÎ"d®@²d¤ˆpIZêè6"Ñ,BÌÌÌrë,×E, v§" ŒˆâòG¢¥¶9$§~–;ÎH“Œª<œRfÉ3bˆsÌAÆ5Ò¸áx‹EôdjFjP¸S#CÒAI© îÔ8?ÓÔ@IJ§#­.K€éA¥œN®5¦]ñyé¦Ç$5…ÍN@ž 2bS!LO°\Éú¼3F¼''¼>’¤‡ ªêíÁ·*çÕ~ø°ýäÎôµ¼ÃÂDOuÛAE=0÷Dizè Dƒ ïìôþg ¦iDdB@ßëJŠý€#–ö0f È7–ÀÌl´›*|óÌ€I [“³%Î,ëˆÓ²ÃbjžÁäÖ£–˜zŒjwÜSuAž«£t©°#R‘ô˜—¥¢^Ì.ž…S!®™%Ï ¾d¢ú\‰i9Š?N//H.MPjâM›çð:Gþ-ôÉÌfE`D çWiñRÒ)ñ]˜@¶¥!ëdãI–‘B&€‹ÈeÙ„*"dE°$€Tcâ4‹Ä„y‰Ù’J b$2‘@ GKO ؽԹИ¥hœøt#mŒRAW]¡XŒøŠâñ&ÐSEV¬3ú@Úà·'“ÒLa؆0EœBwPX“'Ë™=`׈÷M2Þœ-iÄÞµêFrÜ.×Äô•¤8Ïø.*„“qòq,îù;‰T›”¤øIaýrnê2HsP½õ g>V4p†«žã ;ao­ã*• wrÁbWõ€Œ`Æ‹Ìꮃ¬m™õÊH2Ž‹˜hMªi΂8‰(b®…ý”E_¢ÞÇUfrÓ7³Ë2Xc]ì`w•8ýþaØPï<¬ð²qV»$YK–ÒÄúÔÁŒ"kÒY¤]Ùp†“Ť Ù’ñŒ9e©)Œ4˜å¹I•u-=n}2ÛUg©$d/õƒ£d(åµÛ'b0vñ.=¹ýÄb€œ›ªE' ›à´qÉfޤ\=F°7,§ÚXÈÛÇ·a•ožˆÓ ˆ‡â»F/1‘›) ÈØ Ó<—Â`8/^c©…aO¡—h¤#ÃNãÔ0ÍÈaBÂæ¨ÊôjÜ"À„Ü$§qy"– 2-R<'ºj͘dëWµ•H5DÛ`_À˜—Y¦0ž¸˜b•X³EˆhÿüOÕ üö&W$ÍpeÓ[.Ãu2ÄïqGDz>z”ÜþŒS$°NAq˜%×@ž9Š"¢¸amç ·ÒÊo‰`äù§™ƒ2¸ªÜ)¥²V!Š·¬!¹+¥<™9QÈQËfQEQEYEÙeò±Äž¤n+u.7Ô#°&€¢Ìì=:žÙ[”tëÙ;q®(Š¢(Š¢(+%ßOžPµhaö:`ðºéÀZÖ ë³¾cck÷§œE øùŠ¢(Š¢(ŠÒÈ€º@̉XS‘¢feš.¸ÇËQ[[&)Š¢(Š¢(Ê*MX]êæ0?ØhâN]`½dIUÕ¢Eµµ5±Pi”•å*›4©¨lÒp a†¢(Š¢(вBix€×p aƲ ÇÙ¼‘çµÀ}+Qddw5‡!5Û_&Ѽø¨Z¼¨¢²²y‹••F¶–TU-˜?¯ªjqyyEÃ5„yŠ¢(Š¢(Ê ¥á^Ã5„y C6v¤÷X &D&Û»Û?Ü©±½o·t]SÛ¢]«òŠŠÂ{L2¨¨¨¤4ý—Ÿ@Ôp až¢(Š¢(вBix€×p a^]d­D›xØ=#9Åá2ó„O‚Y”öþõ`vÉ^Y9 *¯\šå•DDËBƒ¢(Š¢(вRÑð|íDE IDAT¯áÒH gù©ä¶‚¤¿Œè›WøFÈ™yw¤áajiˆþ†kPEQEQV*à5\C©м0Ï)k+ˆä†q69g[æ½Õˆ–†põe¾6rôk#G…Š¢(Š¢(ÊRÓð¯á’)aô,1o=«0uE4Ë›´YÞõ £Ó¸ï>ú1·³!4Ñ2ü®[üÓ#N<Ý?Ä]i R6(’™Ø‡ dEQEQ”eE:À+â!b&Ëùø–-šWxÝU—rÀ¾—þåüî½ýæk¯Ú´×Æœ}Æ)믻Îé'÷ă÷]}é…RJôGôGôGô§Qþdx%þ ‰ƒŸD<çkˆ ¢Ð?µ²VŠ<`^ÕâC$ú€àq{îXؽ;†åW¼ë:¨»EÖW3ÓÍÉïLÉ#O:ã_w&¢ê ç8‹hðùtÜ8÷Qf¿}÷ý¿ßÿ~ÂĉI‘¥¡–ñúëoì¶óŽ·LšÜwÛ>_ýÍô™ñ_Î|ê⪪?^pAE§œrÊàSNüÛ?®÷Jg°Ãv}®¿á¦~üaÝw|ê ÇŸzæM7ݼzçË^~ù•Q£G3T–QEQEi$ ðJ¡xˆ˜™ˆ¬ 3 \J¦l±â˜À:Ž¡ã ™‰äq×&°.‚˜GÛ‰ƒB6e¦{‰Dæ'Kò_wÞäŽyèÁ#OìeZLñFY •Øa»múöí{áÅ—,ªª62NØ?%Àï¸LD¯Ž}Óu×´hÙb—ú=øð£”+—ôÎ:öبûéCΞþë÷û×µ¿ªmÛ6³çüZDá‹/¾ü픩 zùµ‘x@Û¶mgÍž P>ÊÕDõx½¢(Š¢(ÊÊex%a‚´B2‘HwX=HWG˜ùZ â(½Ùú­ rNIÁRwævVZ©øg€‹ªÝò³g;2ËèÝ«çápõ߯™9wA˜·´Ì™7ÿÓqŸž|ÜÑ•••ŸŽÿÂ¥·oß®¶¶ö§™³ÅûÓ~™)‰qÉ,fÏ›Ï UÕµ**t}ZQEQ”U‡BAZ) K¤!ecØîé` Ô‰Ý b\'’S— W^¢hòÄÂí&ÎÚt´}äIƒ—Ì›iw‘'ýH5Y‚¨úÈ“KÊ¿î¼)X·Î ö×é²öSN¼îúëøiº¬HX²dIeE…œ´iÕ þA]2ôò«o\zÑ_xèa¶ýEÀ¬™3ËÊÊ:¶ï0cæL«wî `ÖÌYT‡Â„å’ž—? x銢(Š¢(‘tŒ–¹H*dxi ¥“" ™×ga6t˜°=ML9`˜¸Ù’Ïça"o3À É*¶3Ir‰´´Í¢¬VW¶j¤,™73H¦t†بZJuòàawÜ„”ÑàNtìÐþ‚s‡Ü3tèW¦Àmt¾û~j¿í·ýê› Íš5=쀼MDÅd¤¢¯¾xð¡‡å£(çÊþ<}ÆW_}üчß9tXTVvÌ‘‡}úé¸Ù¿þ ¢‚ ƒ{:gΜ.k¯U–+«­ ?É(Š¢(Š¢4" x™dx™‚¥[_8"ü%e¶1^œ3C‚psää0`6¢"΀ª%’¶^â)"Vž`Ãë2ÿuòª¹3’i)1IHipe+[uH'&„S*·ü¿ÍÛµm{ö™C\ÊåW_÷Ù_>øð£§ž|â7_÷ó/Ó_yõµMzöð ê”aŠjËš‰ÝpÓ-GyÄu»ŒÁã>û|ØðábY ž}îù“N8n÷ûOþî»?_re˜­(Š¢(ŠÒX(à à5\C"3Á­US¶œÍ0¡/Éî]ÈZ+­¶Í-0y~ Ì L[¥ .²*nh·àþn={/˜7WN.œß¾ãjI‘R™9ý§fÍZ4\ƒŸB\Cù?…£ ¦à(_ ΃ˆ)Gùê|YQ~ SS™‘Í’¡ü â(ñrxâ<å—ˆÀ”¯!Î`IãÒL…Q¾Š)g+ET»8_V 8å«Eù¨BrEQEQ ð®AŽgLÿ¹jÑÂ]'HDÈû‘nê.0Á² ¬ó(J¬œçl,nÅ Mœî¾»˜Ò]’×§P€Yão°?…©œ£Ì/R¾,~Ú†‹’ýÄB2œ10•qÔÔž—Ud}$ÉVhÃqC>gõPY>2Ѷ¢(Š¢(Jã¥á^Ã5„©¥ï$&,ÿ8ë¬þב.Z5µÕ9yö\}¨©©Ž¬AQEQEY©hx€×p ¬<'ÒÂWš£dAWEY”[²hqÔ”råõغP]½¤jÑ¢²¨Œ–…EQEQe¥¢á^Ã5BbãV´) « ¬X—AØ.g[íÖ–\yyuMõ’_«œh‰E¹ò 5\C˜¡(Š¢(Š¢¬Pà5\CÌæ[ˆK F>XUY`7HÁ@¼,—+Ë¥ª¨ × (Š¢(Š¢¬T4<Àk¸†$È“:Eæ!xn[‡ÛÏí‡Áñ&of¶O³Î1ò(l$Ä[DÜ&yâµ¹_ÉÄE‹‰Š¢(Š¢(в’дi³ø„ï]/DdÞa“L2Ÿnm‘Ä€ ­EH…± ã]‚À3|F·¢(Š¢(Š¢¬@>úDwL€ÙÏá§ ,QtbQ9ôˆ…(‡†l(¬m+Š¢(Š¢(J£¢à s=ƒÜœh! ò¶ªt•U+Š¢(Š¢(œ|˜÷ÖIÞ¢7Œ®½­Õ†¥¨AQEQEQVfî© é5ãÒãßâUgG{ÛI‚˜:]‘¢(Š¢(Š¢4väºbÀò]E›ÃY[5Ü 53ç\ ˜b ö–°Éê` õÈ¿„.hä­(Š¢(Š¢4:2^N6™MœT‡ä¼•hO#Áäˆ Ð‹=aD´Ê5ÌZ\sòû5‹kÃtEQEQEYT”Ñ}¨lY÷û%Š–¥d2á±ûM6Ê.]™Çí…pÞ½ÎÑ„ëö ” ;L,ÄÉïלܭbÇÕ£0£d&ÎËØZ®(+Šï'Oì²Þaª¢(½~ÚeP'¾ŸUÚ Z.”®,/Î=îð÷ðÞè‘aF£bÕh…¢¬„#y%4I)‚ß_Úw+9ÚAËœùs瞸߀÷0ùۯü‰·Z̲DÛw 1!ãÍ‹ K‰x Ü—0…ªT pÝE|óÅøMþoËÓ/¸È%Þsõ¼õæÚë­ÿ×ÜèÉ®D\vÎ?~7EŽË+*Úwì´uß~»ì½_.—< nþÛ¥ã?Ûo÷‡r˜§ü–pCh·}Ø÷ð£$ñ;oýÊ‹6ìÕûìK®ôå—uŽÀ¥Û%²ü ¨S³²2à÷¯°n×î\}Ÿ²Ô,˜7ï采ÿh쯳g—åÊZ´lÙcÓßyÊ¡\ èpÂ2õçJ 3?rï¼5**+Û~—Ýö>øpIÿ÷ý÷|ñéǽö&7óÈÐÝjûŽr.€ùsçž}Ì¡ŽrÎÖÛ÷³úV5Ü—á­Ugâ¢dwÌæÕŒ`B.—÷•dKTncs/®Ö»$¶í¿ë7_ŒÿüãçΙݪM[‹.üäýwl××Pz%C.°Ÿ¦ýxí…<ýÐðùsçxÌ ¡¢eÔË/ì±ïMš5›;gΘ‘¯‡Ù+ˆ¥Û×Þû@˜Ô–¥ᢟ†¡ûn¹þ³?tèý š?oîWŸ}úÍçãC!¥dŠø³áµ’ðÞ¨‘#_qæE—Ïž9sØ­7tݨgÞ›Mþöë‘/Ž8ïŠkêü<ÿ€ˆù‚1­ÿ EÀ¿ì€ä›³‚édÈŸ°¯¿ ŠÏæèóð½-Ο?fԻÞ]½dIyEÅ–Ûõ°`þ¼ç{øóÆÎž5³mû›mù‡=÷?¨I³fž“˜ÏçÏøóŽ~¿Åì™3þxâÑ.»éŽÕ~·æYG²`Þ¼=ö;hÂW_|?iB‡N8úøñøÞ›¯ƒhó­ú~òéQX8þˆ?üه̙=«}ÇNÛößu§=JVV[cÍͶÚzÔË/~ðöh¹÷»%™²²\‡Î·ßy·îà’3OöÃT#_1òÅÍ[¶¼þþ‡EÉ´©So¸ìÂÉß~Ó¬y³=÷?d»WöÊ2¡M»vsfÍzóåvÛgÿ×F<]]½DRœ@‘ñ_dÌŸ{ÜásçÌÙmŸ¦Nžèª"#0“ôØ.bT*‹7ËϽ¸Vaü!ä§—83çkk¿øäcëuÛ°¢²²]eÇmvÜy›w0ô¦¾7ê­ûîxìà³|?i•çŸUV–»öÞácF½1êåf͘޺MÛž›m¾û¾µëÐ!s81£ô»L#¢ˆ?áuVÛö®»è¿`ÓfÍoþ(Jî¸Ë´©ßèÖ³×ì™3ä´[‡ÝzãNö^·k·Pº(¯x&=–PÔÓúïð;nùnâ·:uÞv¥\Ltam2|6¸¨—`,UË*³ýŽ#ropÌkt¼ü)/¯Øj»¼ûÆk’"ÿ×gۦ͚×ÔÔüã¯|ãùg·Ø®ïµ÷ï¹éæ/?óÄ —_ä^’Rø<ŸüáÉç]°ÍŽ;Oûaê—_Ô¾CÇËnº3Š¢·_eìÛ£ÔÖÖüã¢?½6â™ß÷Ùö÷ük ºýûþ{zW¨(‹Àœ‹®»ù®'FÜùøs—Ý|GEÿvïÇï½ à’nëõû-ôÛ}À]OŒðCŠOßsä©C?éÔY3fÀGï¾½`þ<¼=ÀÆ›m>sú/ÝwwEeå?î~Þ_³Ëzo¾4Yé3ê¼Ë4.ŠøÓ§{Ï^w=1â®'F\|ý­M›5P^QŽútÜŠåw]ºøö‹ñ¾üÀkwyöч8Ï>,-ÊÔÉ“2ÇR?ÔÖÖÜtå%_×À s/ÿû” ß„JW˜€¹Ð<^‘}¬µù×»;Õÿã””/xƒSбÝλøï?L™ðÍOÿùQ¶íËG·/>ýxÚS‰h·}öoÚ¬ù®ƒö0ùÛ¯'}ýUR‡!*dl½ÃŽ-[µ^gƒnˆ¨ßîZµi³ÚkøyÚ|ñÉÇÿùþ»²²Ü€iÚ¬ùŽ{ 0ê•/\˜Ôòó´ÿ|úÁ{¶Üv{?ˆ:v^­GïÍŒûžŸ•f»wm×¡ÃÆ›ý€|>?ãçŸB eU¤¼¼bÇ=Î3ûÆË/^´pÁ.{ïEe.·”ñ_dÌ7|Pc»{|–¹½¸;ï~S¾§uâ~þ=ìÞ0Û£^3óGWV–«ªZ<öíÑÝ}û_O;aè×1óº]»­³A×êê%cÞ|ƒ™?z÷-[õí·há3§ÿòþè‘ÓúiËí¶ß÷ð£B)fÔy—itòg(Ì™5óæ+/^´pATVvÌég¡4­ lµ}¿~»¸ûŸ×<ñ¯ûö<ààæ-Z¼öÜSG>ä•§Ÿ<÷¸ÃÏ<êàïº-Ÿ¯óq(4–Šøá›ÏÇËÀØeï}›5o.|[I)|£‰º0C¶W€ÚDD”s1²ÈÈ)™¸Ýb‡–üKÞò6yKàÅlQkvY§Ëú]¿Ÿ4á7^kÚ¬€ÕÖX³ëF=Ìšþ €Ê&M++›hÕ¦™5ã G¬¢Z´j@öK5iÚ,W^î²äš™9ýµµ5§²oœU[;sÆôß­ÝÅ¥ø¼?úÍ÷G¿Y^^Ѿc§~»ï)q3¿üôãcÞ9kÆ/U‹‹äì™3%S´lÓ@™ÝÎUÊe¬¬ì°Ûž/=õï©S&µlݦώý6Ôe5pü7dPeŽíúÚ³Ì Ð‹k•!su&õš™·Ýi—zõþäý1_~öé7ŸV½dÉ{£Gnµý=7û}¿Ý÷ºïæ¾õêKëlÐuÖŒMš6ë½ÅVee¹-·í;öÑßs€¨¬l—ûdÆÖ¥˜Qç]¦ÑQÄŸ¾Øâ… oºò’Y3f8üÄS%·­ Ñ!ÇŸ,_Q­©©¹òü3wØ}@õ’%Ï<òÀ'ŸÑiõÕ¯»øÏ]Ö[Ûþ»ÊZlyÔ\×gŽ¥"~Í'••Mš6Ъu['°RÁ̳Β÷¼½€ÈFÆq`FËIL’—ð!³ÕD)…íúïòý¤ cß]^Q`›þfW»ŽT-^TUµ¸²²‰ûnÛmQCEù|¾¦¦ÀÒý©Wê*¯¨¸éÇÊÊJú¾Bæ½á³Æ>ùÀ°Ê&M.¸úŸ«¯¹ÖCwß>êåòùZÉÍšÊo™fÍ›o·ón¯>ûÔN{îU^^ágÿK7æK™c»¸=%Òôâú Rß™¹}§Îý÷Ô¯A³fÌøó)ÇæóùE‹Øb›ívïüá±ûîðû?ô‘Ëíø³Î;ôÄSÿ3õ»ñ}é©Ç_zêñÝ÷= i³æÁpª¯« …ü騭­¹ãÚ«ä›{ìwÛ(Ü=öüãTWU :䈷_@÷{uè¼€§~ }ÇN?L™¼`þ|ž?®´lÝ@E™c©ˆ~= À’ªªÅ‹5iÚtýÜ•@EZ’«%-ÀÌv™Ùß B.Èf„o‹ñ•$Ž¥Dº¥[n·Cee“E Ì3»¬,×g‡$½ç¦›¯¾æZÌüÒS/Z¸àå§°n×nl.u^ãw¾÷É¢… ^yöÉ ·6Þlóß­Ý¥zÉ’'‡ß¿xáÂÙ3g¼?úÍÛ¯¹2”«‹šêjQT–Ëå¦ý0õã1ïø¹-[µ0ã—Ÿóµ&P”Ž:î®'Fì±ßAAzññ¿tc¾!#°¸=%Òôâú R¯™ùê?Ÿ;æÍ7¦ÿüSMuõœÊÌMš6Û`ÞrååÛößÀw'Øjû~¾Ÿ4á_·Ý4ãçŸÖY¿«¬³6iÚT6é^f¬2ñ§cÌÈ׿÷ €­·ï7èÐ#\z£óØS&¿üÔãG6¤¢²RÖÔ'|õ…l¼^³Ë:¶îÛÀ·_ŒŸ2á۪ŋßxþ9í;v’?°KEüÐ}ã^V[À+Ï<¹pÁ‚WŸ}ÊÚ²AŒ$Á³g%RbCò¡×…ž øÑ²¿ðm2ÕhÒ´éÿm³í;o¼ ÷[¶lmþÄœËåλüïÏ=öУß|åé'Û´o¿óÀ}öÜÿ`Û‘1‡Ÿ|úƒwÞúöë¯Løê‹íúïºß)+Ëwùß_xò±qcßóåZ·iÛ}ã^{O%²ùÖ}úØ{Ì›o\uÁ9]7êÙcÓÍÞý¦ËÝyà>?|7ù«Ï>=ùÀ½{nºù /‹K*J’âãéÆ|CF`q{J¤!èÅõ¤^3së6mŸü‘¹sæ,YRÕ¼E˽7ÛëÀCÛ´k'¹}wÝóå§ŸÈçómÚµï¾ñ&ÖZwý {mòÈÐ;ünJE]7ê9ðÃeY1=œJ7c•¡¸?…êêj9xoôHy_Œ<¤^·ÂÉ×ÖÞë Ûí¼[×è¾ñ&>쩇ÕÔÔôÝu>ýúØ|ëmŽ>ýÌ7_zþº‹/¨©®nÙºÍVÛï0è#ä/íEÆR!?”•åÿõÒáwÜòêsO}4æíwÙÍŸÐV‚ù½ô ßÉ1@¶¹Ãϳ„{¤²¿äÈD F^¶‚Ð~Á½Ýzö^´pÁ¢… žyìÁ@|à‹ŸÝ±IX/&Î S”È÷“'vYoƒ0UQ”ÆÀª}ý^ó×ó'~õå®{ï·ß‘Ç„y–U»ËJDàûÉwê]¿Gf† }"€_~šVµháž“-%’&!²q2 \ëŠå)±b] ³w„$Oä¸_Š¢(Š¢¬p¦ÿüÓßMÉårú,sEY 䫊aœí`† ˆAI1rDä¾êè®P³ Ë“¢F©¢(Š¢(+7ÿíÒÏ?þ°}ÇNûqt§Õ׳EÉ" £³ ™™Š—•mÑÈÉ~ŽŒÐ:€À¯CÖ-«(Š¢(Ê áŒ?_&)ŠRÌLdbeBêywò&¼o*fF⹜ÏÎ 1Š!½­+Š¢(Š¢(JcÆ‹¨É=¨ÃÆÛvy˜Z—²n`û£(Š¢(Š¢(¿5 GÂ9¶v[gm¼v¸¯C*Š¢(Š¢(Jã&Ø·JØ‚äs¬K€aUé^kEQEQeUÃì±.[;‚-×õ ¬ýÝkx­(Š¢(Š¢ü‘5g÷•ƃ`_L¾°ùÅð¶x/'fΜ9g¾ÆñÊJDë6íæÌš¦*ŠÒÐë·Ñ¡]u u›v3gÎ Së y˜Ànõ¸h4+ïuÉ„ PCW‰ÐÒçõ _Ï.a’¢(Š¢(Š¢a\‰¸ìÈ(ñ®<…ϳo^,iSGR‘Y¥–»áû[+Š¢(Š¢(Ê2Å„tÁÇIŒàíŠDD † Öà ë ±0CQEQEQdþŠîm6²‹“ñkr_^d‘1é6!'âÇÓãzEQEQEYɉÜôÊrQiÿ© ~V¡H9(.bõ³@QEQEQV"êP[ŠÖu“È.VËf4¼VEQEQV dkG=ŸÊa¤ëXK-Ïç“SS§·'DQEQEQA+±nÆ*v¡-€èHÖ%®<§Þf^g EQEQEYy‘}¸'~D ”²n”(°b]$ÄÎHÌHREQEQ”ÆBüôè`¡ºØ*5øOɬ êÖ£(Š¢(Š¢(«²í¢ˆŽJ£à¼îÅg¶?Êÿœ|>¿m¿]¶èÓwô[ï„yËR©¢(Š¢(ÊŠDÖ­mÄKòÈQj_6 ³Ñ$ZÖqõM·Üöô³#DQôÚK#ÂìßÓgÌ´ßÁçsæ üô)ß}_UU {·®~z½(¤¼%VÊÌ{ÚúôrÚ«g¡wßžQ”ÆG}¯EY©rÎùïŽyÿÀý÷=ïì!~ú[o¿{Á…—TUU5kÖlä+ÏGQ¸Ê¶Š‘ÙÞOÇ¿ç¾ûÇÿ¢¬¬là »>íä »w Kzd*IóΘ÷žyîùÏ?ÿrί¿–——·mÓfÝuº\sÕååååµµµ}ûï.·T-Z4_wuN<þ˜­·Ü"©c¹ð턉÷ þɸÏ,Xø»5V?ìƒöÚswÉ*Ý…$ßzçݳϻ n×®íË#žž6í¿×\wçŸoÓºõùçœÙç[¨©©|Öy5µµ·Þx]yyyPp…އÁ^¼\‘°‘qĸ@ºÐz´Kg¯\û?KÇàÓO}ã•®¼ü’0ã·Ê°á¶oßnÀ»é_ó-€Ö­[uîÜ)È*BÊ Qb¥DôÂ3OŒ}wÔZk­  [Ñ(\Q õ½^e¥â›o'èÖu?ñ©gž;÷Oá|À&÷, ®2d¶÷ý><ùô!'M¾÷®Û®¿öê±~tú™çÌž3',lÉT°¤ºú/]væ9œ>}ÆUW\òæk/>õØCÇuxm¾VbÇÉS¦HTý؃ÃÞ{î˜ IDAT{d¿¾Ûÿü‹?þù¢|>õTˆeÍÂE‹ž~vÄ©'ðÌãuø¡“&O¹ìÊ«§NýõqEÉí¶é3öÝQòsÓ?ÿ!ò;îз¶¶öìó/¨ªªzöÉGÛ´i}Õ5×IÖW]3}ÆŒkÿ~åJU©ˆ–A™¡mJ,Phu˜âk÷=ÈŒ0_YZfΜõÔ3#Îrz.—ðÐ#=òï'æÌ™³a·nÍš5ƒ·r<öÆ?øÈç_|Y[[Û½[×3N?¥WϳfÏÞuÏAååå£^{QÆë‰§œñɸώ;úÈ“O<ÎWþŸiÓn¹ý®O>·`ÁÂ.k¯5hà^ƒîY¼ÒW^{ý/]&µ·jÙ²ÇFžsÖàuº¬-)–,YòŸÿLCjW”ÆHp1*ÊŠ%sÎpêgýèãAüåOç}6þóSÎ8 ÌÇ{ômwÞ-¯¸êš+®ºfȧ~ÈAwÞ3ôž¡Ã>pÿ?úxâ¤É½{÷JÔ±ÊQ¨½7ßvGmmíûí³Áú먨¨øõ×¹Œýh×wJ”PXIÀ?o¸ù•×^_§ËÚ·ß|}“&M´k×vï½öÜ{¯=Eà‹/¿@Dk¬±zEë­·.€Å‹×ÔÔTTTxš–=Íš6=ÿœ3åx›>[ßyÏP -B}\QŠäâÅ‹¯¾öŸÖXcõ3N;yò”ï&Mžrñ_þÔªeËöíÛI~çÝCǼÿÁ}wÝÞªeKWpÅÃ$á,Àd3ˆü“‰r’IP‡Pf\¯ÔŸ=øp›6­ØÀ÷ ½þ¦[W_mµ'{hà^{¾3æ=Ý»uðô³#NrÎÌY³>ôª+.ýdÜggž}þ¯¿Îm×¶m§N«««§|÷=€Qo½ýɸÏV_­óÑG(?ïO¾öúÈëþþ·×_qÖàÓ_}ý™3g¯t—þ;ÉçÑQ¯¿´CßíÞû`ì•W_ã,0å»ïå“·ÖÊ*€½(ÊŠ¥Ðœ`ȧÑsÏ¿øî˜÷Ï:ï‚ÚÚÚ¿]qÉ1G~ÁùçèØ±ƒÌÛ‡¸ÿW]sÏÐaG~è‰Ç3yÊw6í½I²žU‡ÚÚÚ"í8i2€ß­¾:€éÓg,Y²ÀìÙ³]q¡¸Ÿÿ3í©gžpìÑGHTæË¯¾С}ûÊÊÊ9s~}éåW °ÇòŽªÌüŸiÓn¿ë;õÛAvq”è ”&y×½÷O›öß(Š.¹ðÏÍš6­­­ðóôéS¦|÷á‡÷ßq‡çžñ‡½þW¯±Æê~Á•ÙDZÔDD‘Û{m!ÀlÐ6Û±m¶ ä=¹©¥žÌš=ûɧŸ=êðCËËËÿûÓÏÆ?àOçžÕ¡}û¶ßNd6ìÞõçŸùç73óàÓNY­sç>ت²²rî¼y_~ý5€nàÛo'ÔÖÖÞrÛÎ|z“&M|åù|~ÒäÉê™wß}¯k×õï¼õÆÎ;©T„fM›þaë­Lú£Ÿ>yÊQÉÇYEi¼ø×K˜§(ÿ[ŠÏùÝ»uÝm—kkkÏ<÷óçÏ¿äÂ?÷Ýn[Sø@—µÖ%×Ýpó3Ï=ü±G~êIŸÿ<ŸÏ—••mÜc#¯žUŠâí]w.>øð£yóçß|ےعS¸ã±¸Ÿ1ï½/ëJ›mÚÀø/¾Ü¢O_ù¹ø²+EFëé3flѧïÎ{ üæÛ ë­»î™gœê©YŽÜ7ì-·ÙaÐþ‡Œyïƒ-þï÷—\h¶D—è ” 9a⤇y À¡¸YïMlؽÛá‡ôÀCœ2ø¬A{ïµé&›\}Íu—^ôç7G¿µç ýûí²Ç 7ßꊯLâÇèr——±IHH/@›ðÛÃEß¡¨²´<ðУ-[´¯I½÷þÕÕÕíÛ·[wÝuÌ;WdºwëúÆ›£-Z àô3Ï‘ëV¶mÉ_U6Ú°;€o&L|ê™ß}?uë-·è·Ãöò(ŠöÙ{/#žñ¼ þºû^û>;â…â•VWWðá#Ž9a§]l¹Íüõb«­ÖY„I“¦X{­5 }^W”Æ‚½(ÊŠ¥øœ`ûí¶ÀÌ;í¸Ãn»ô—DYøX{mX¿9ú-÷ ¶EŸ¾gžóGò]:ù[åªGñö^qéE›öîõò«¯ï{ࡲ$TQQñûÍ7Mê¨C‰Ï¬Yfá¶Ie½zöûî¨æÍ›Ãî¥\²dɤÉSœsÖà±ïŽzöÉÇZ·n5yÊ”û†=kYžsÔácF¿~×í77kÖlì‡ 6\ÒKtê’Ìçóûûµµµµë¯·î)'ïJ 9ãÔ‘¯¼ðÒsOíµçî^zÅ3N<å»~ì†k¯>þ˜£|ø±ñŸá„W$^ $žá!)ÅqÒþÆÁt1JE׆”h*A©?sæüúø“OzÒ òW¡™³fÁ›7Ç~ô1€¦M›¬µæšUU£l´a÷ ½+.oÙh£îÆ}6þ•×^Ïårçž=)åþtÞÙî¿Ïc?zúÙ“&Où÷O °G‘Joºõö~¬{·®þëÞÕ:w>á”Ó?7¾gòƒ»ü™¬[Wýæ¢Ò¸I_/в‘0ºÐœÿÕ×ß\qÕ5òЉQ£ßþéçŸWëÜÀÔ~°¶]±~á™'\‘ÃŽ:îÛ ?ö¨“Ž?Ö%®boïúë­{÷í·Èñ·ÜþÍ·ØoP«V­\¡¸·±a¤I[ü~ssæüº`Á²ãâ› kjj¬Û¥ €ÕWëÜ®mÛ_›ù5ÁåD.—Û¬÷&¿[c 'Λ7_Ktê’|â©g>ÿâË\.wéE©Hý¡oúŒCÎ9ÐÀ=Ü߃;º÷&½ºn°Á÷SùMÐÆ3ƒ"Šò…bç$²€Í3À`޽|¥A<øð£M›6•…d=7ÚÀÿ™6qÒäI“§Ü=ô~]7Ø Š¢­¶Ü"Š¢ 'ý𣪪ªI“§Ü3t˜ìÖ‚Ý òÕ×ßÌš5û°ƒì²öÚiå—^yõ¿ŸxªiÓfû¸mŸ?è½ÉÆÅ+•ÍU­Z¶lÞ¼ùˆ^÷ÙçzmÜC “¦LЭ›n°V7Áõ¢(+–"sþÄI“O?óÜE‹]vñ_wì×wÉ’%·Ýq”úeú/ª«—¤wŒþüË/(ðçþU’ ½ïŒyïö»î™>}Ư¿Î}ìñ'~ôߨjËSO>À‚ ¶Ú¶ß}ú~2î3_RJvé¿£ì”øç 7;aâ’êê?þÉŠõ—_~%’ë®Ó¥¦¦æåW_ŸòÝ÷eeeì3ï–gŸÁ«¯½1gίsçÍ{è‘Ç&NšÔ´i“ýöÙõqEIÓg̸õŽ»œpìÑé‡ó.\¸pÈÙܸGÁ§€Ásæü:oþügG<¿ÖZk®$_Ê"o‘ØlȰÇ`€íãðŒl¢ErV¥Ã2ÉÕëÔq¶’RyþÅ—¯»þF9Þq—=<õïGZ·Îø´´ 3wîÜÇžxê„㎮¬¬””?l½å ÇýēϜpÊé½zölѼùÏö/JmØýÚ«¯:lø¹úkEEùë­7hï½ú︃lݺÕk¬>mÚ;vìpÜ1Ge*?ô ý‡ è¾=0wî¼N:{ôÇsTñJ=ꈟ~úeÜøÏ=á”mûüAfê{öðÞcÏ8ó\Ñ à–Ûî¼å¶;¯¸ô¢ôwŠeå'}½(ÊŠ¥ÐœÿÃ?ž6äì¹sçþùçößq‡õ×]ç‘£^zåÕC>`ÃîÝ?ôàG{âÖ;î¾õŽ»¸ÿîTUUÉ·;u온f%ÝÞ^={Œ|sô!GS]]³Áúëýé¼³ØCÖMÇ}öy>Ÿ///ï¹Ñ†Å•TVV½ëözäQ£;é4fnÙ¢EïMzm¶ioÙ"¬ì9hÿ\.ס}ûþ;õ;ìà7î™XŸZ|Àþ÷ðï×]_½¤ºcÇŽî¿ÏAì¿Öš¿C}\QDÀµÿ¼iÁ‚÷ì!OJð©­­ýÓ_/nÒ¤òòKþ*òç5øªk®0è€^÷¸þW­$ßcñ_KžÆæJ°D½¸Í"Lí·¿—¼¶Ñ'L³=6¿Av‡y·uëÙ{Ñ‹.xæ±mºaà‹ŸÝqé·ÞΜ9Ó²Û*ÆwÝûäÓÏ>ûä£ËcwòrU®(«z½(Š¢¬bô{vf:=øèüòÓ´ªE M>Æy DÞu¼_%+'`&æÈ|û° V¹;qJ¥S¢ÔÁ¼ùó}ü‰Ã=hyÜÈ—«rEYÅÐëEQå7Ž‹håÍ‹ñ)Ù‡å…?N†êñÖX#èåCË-F¾òB˜ºŒX®ÊeC¯EQ”ß A|KDöäõ {É>$x’Hú‹s½jPEQEQ”F@Ö“õÒ)ÙHÙû†sÙ=MyW9ƒåíŒy€ˆe¡;ocz6Û¬¥¥×¬(Š¢(Š¢(+²+ƒ%˜eÈFÃYÑvŒ¿3Þs¬%VL¼Ì.ÆIrÇä„m5l¾ÃëVEQEQ”FÙ=Àî‰!Ôõ>D’/ˆ‰l¢9`×§ÓÇÞ·#ý|EQEQEidD^XMv)ÙÆÚD²ðœÆ0È'ëQ<ˆWEQEQ”F@Ô’,`ËJv2 !²{³ËŠÖõzÅdº"EQEQEil€xçÞ0}G¿õN˜·ÜX!•*ÊrâèãOÞ¢Oß;ïf(Š¢( L¸lCcïÐîÀv¤O‘ýJs2JDÉï&.§ÐyÜgãzä±/¾üªiÓ¦ÛôÙúÄãŽiÖ¬Y(ô[búŒƒö;ø¼sÎ4p€Ÿ>å»ï«ªªtïÖÕO¯…”¢^•¾öúÈ'Ÿyî›o¾Ís~ë-·8kðé:u …å‹óì1qÒduï )ʪÈsÎwÌûî¿ïygñÓßzûÝ .¼¤ªªªY³f#_y>ŠJ~U\ã!³3gκãî{ß~g̼ùó×^k­“N8¦ïvÛÖY*àÓqãï¹ïþñã¿(++ÛpÃîƒOûöÎ: Ší‹ãç& `wa=EìûYØŠˆbüTTv>» 1Aì; AQD)“vç÷Ç™ QyÏo8sî¹÷²ûfØïž=÷Ü1Õ«U•:ñ\½výð‘c=ùðñ£žž^±¢E+”/·Ð®žžžL&shÛ‰¾Ã€©©I…òåGÚ¤‘­òùû÷vŒúôé“™YñíÛ¹ŽNŸ`ÞŸ‘öP­HHx³pÉò{-Rd²×D»¦ 77w‚‡w®L¶zÅ===Åÿ!œxæ²3(Šê‰W!‚PnOä)D² # 6‹„!\DœoÿgD5À®€À>½zì Ø±hþ¼­\½Vêñ›±}çn3³â;Jì‘QP¤HaKË’¦¼£ipMäqR–egÍñ›ú¿Ùuk×Ú°ý`àîJ•*^¿.õCáš‹{IßÃjÔ@aüDFE@Õ*•ÅÆ ÃG&ùLgår¨SËF­vüÙQû“’’}òôYÿy¾û÷ì|ýúõ”i3£ŸÅhï%áÆÍ[cÆ»?‹‰Ý¼aͲÅóÃoÝ?Ñëý‡R?€/99ÓgΙè5%99ÅÞì‹gOí :x L.£R2öùsúißîí7®\håÐâá£ÇS¦Í”Ëó¿ÜÚƒ‡\Ý<®ßð9=hÿžôŒÌm;v >ßòŒ´¼€š4€L&óœ<5;;;äÐÞ¢E‹ø/\B‡šç¿09%eñ¿‚¢ªÓ»\–†(ÔÌËbÁDY-ƒ¢!@Ô,^TdÅQ6+»ü(‹æûуòåÊ99v<tX¹ý÷"5õ]Ðᣞîãuuu p_àþƒ>|¨^µ* ä ‘ãð[·wî|ôø‰L&«VµŠÛx×Ú65ß½ßÁÉYOO/ôì z½Žru»{ÿÁð!.cF þ:!áïµîÞ»ŸžžQ®lç®]œ»:iŸôôÙsÓgΡ³.T¨fê^Ê—+ ûŸ<ݶM«Ñ#‡Q‡CÓù_óTdîØzùJê»÷•*VXð×\k+K¸|5lWÀÞˆÈ(†!U«Tq5¢^ÝÚpáâ¥ÉÓþ§¯§×±C»k×o¦gdØÔ¬ÑÊÁþȱ/ââŠ)âí5Ѿ™Ní])úuäûÑtuuó¿}ǹkçé>ÞT?ËŽ6dÍú´ã<ÿ…óüº»دïúM[6mÙþgŸ^·nßy[·nm¥9~ 4=ÇK–%&&õîÙÞÚ¥J•Œ~såêµ*•+ié%aÕšu2™¬wÏî•+U}}ý?Ý ¿Ý¡]‰çÒå«NŸ=W¾\Ùµ«–@ñâźuqêÖʼn:<~„’%­†©X±deeåææêëë‹FÊ._ “ËåU«TndÛ¬,K|úôéÓ§Oð-ÏHË ¨ID?‹‰‰}>kºOáB…ÌÌŠS½¾~ã–k7nnݰ¶p¡B¢áÿc´ï–(Fò¹GÐÜt†Æ±%Í‚‡ÐĈu´BЋÂÚ?Ìý+Uª(µþNìØ½§hÑ"];;ÀúM[–­\mmeuh_@×.NW¯]€jU«@pÈÑqî^©ïÞìÜâ?Ï÷îý='üø©x±b%JXäää<¡—¯Ü½ÿÀÚÊrˆËÉàÞ>ÿ;{îÂ’;uÔcÂø3çΧ¦¾Ó>iû¶mÂÃBÃÃBCÏlé`ýf¸ßü… “ɶïÜ /^Ä99÷jֲݠ¡#ï?xÈ=%ùï_óTXËreM›4^¿f!äiDäÙsç`ïþƒžÞSs¾|Ù·{û_sfß¹{o‚ç¤× „aœ:u˜âí‘‘‘~ëvص+—.ª_¯Þ›·‰;wÒ¹4Ý•Â/ƒ ß–«ËÝm,!äȱa×nxxO•ÉdÍ›=tðÀ©“½ÀœþÝî×§×<ÿ…›¶l<°ÿ¨CcŸ¿€zuë(Ïós#“É4=Ç7oÞ^¾­ì©ó§ÏŸéO-½T¡éd¥¬­ 99åË—/ðþý{‰[üë„ ÃG`ØATU«òäi˜›™|øðñä©3е³c¾«j¨Y£:¼MLJJJ¾~ûYL¬µ•%•øy|FÚ_@M@&“@bròóç/nݺӶuË#ÇNìÚ³wÙ¢ù%KZ ƒ,~!|·i e^ŽA 3JZYŒêð!„!ÀÂBÓE!ù¡§)AÁ!÷<3r¸´á·áÝû÷‡‚C쯧§÷æmâöà3ÉÃÜ̬e îR®^­JbbÒÒ«X–0ÎÕÊÒÒ®icƒOŸ??‰ˆ€šÕ«@TT´L&û{Ízð˜0ÞÐÐP<¸\.‰€A‡Ã®W©Riýê––%´LJ(ÆFFM›4€—/ã "2Š~ µ°0ؾe`ÿ¾‘Q^S¦Ñ; Aþ+Ä×<ðºKgG»¦­­,õõôÀÂÜ99÷çîY¡|¹m›Ö›™‡~üôîô#/‚ü›ˆ¯yˆzö š4¶€¤¤äÏiiP¹r¥ ¡—¿|ùR¸P!šŠš›››™•43ŠÊqÛ†õíXX˜—-[bbŸ@ÕÊ•@û]‰ ?ÂW¯®öÍ€eÙ6­[vlß–iàƒ^«pñÒeØ´e»­ÃD¯) “ÉÚv¢ßUþhyŽô}ÊÜÌŒæ7>‰ˆ¤Â·‘mC-½DcsÌóY¯níSgÎõèÓ?öùsÐ××oP¿žÄMxû340€Ú65ÃÃBMLL€O­üòå ýâå1!<,4äо"E Ç>¾uû.Å(ùÄ«Wñ}¸\¿¾lñüг'Z¶°‰}¾|ÕÚšÇg¤åÔ®ÜÝÆ^8}üä‘ .Nþç;ÏÝmlìó»÷ì[¾xþˆ¡CvïÙ÷ðÑca–ÿøµÄ hY!‘Eº—vaÕm£€Ð‘m®2ˆTÕû^ºx~ùrå¤m¿ >|{NWWw’çP|¼=ûôê~3üvpÈјØçûuíì¨eÒ•«×îÞ³¯ZÕ*»wl¶²´é:þÞý‡ô“kñbŨéR% !á +Z”~FÿÉ5ÿ61‘~o^­JˆŽ‰==½òåÊÒ|'SÚ1üÖ–e š5m’œœBß\i¯g11ÂqNN΋¸—P¹r%à–Ej¸+äGÐ~u=ˆœç¿V™½tåmb¢•¥%¼|eùˆõñÃ….Š~6bØàÑ#¸ŒØ_-ϱ©)Pi W¯^€¦M•/WVK/U*U¬°qíßôxÅßk#£¢{÷t.\¸°²!Âè˜ÛõàÇééé@ nDF?ËÍÍ€ åÊ€µ•eñbÅ>~ü¤vÕà²uÇ®ääûæÍíš@õêU/^ºLÿšAžŸ‘–PÈÑ¢’SRܽ&;wuêÓ«GßCêÖ©]¥r帗ñ v‘è÷kÐÂJ-âÍ]Ä!keYLU³Æ'C@Ї´%ÐVi‡¼±yëö£Ç–/Yô;«jؽg¯‘‘ $€Mÿ:áYLlLìó[¶@•Ê•†iÜÈ–a˜èg1á·ngggÇÄ>ß´e;MÏ>äiDä»wïüÙ§\Ù²ªƒûúÍß0ÈÈȸ‡sWz§Õ­SKû¤4VW¸P!“£ÇOÞðjת 5kT/U²$ܸyëÍÛÄ»÷€Û¸1ænA~G$×< <›ššX[[]É^¾\Y]]]»&uuu“žFD¾Š½låß ÃL™äQ¼x1š"ê UªT€qqô}‘®|Ò~W"È åêz;~â¤ÌÌÌ9³f´nåðåË—5ë6Ñ^IÉI“ó…~ƒ/&1) Ô}Ýÿ+!yŽM›4ÖÕÕ}›˜ø:!áÉÓˆƒÁ‡ÍÌŠOõöRê£Ò+==½qóV¶vwï?€«×®¯Ý°)99åãÇOûÚ³wÓÆÆŽ%Ò¾mkšb±tùª¨èg_rrnݹ „±~òä)õ¬P¾\nnî©3çž¿ˆÓÑÑéìÔI4Lþ`bl ¯â_øð1úY MþîØ¾h}F’ç®åüªÈÈÈp÷œR«fÍ ã\€öÇŸÓÒBŽ+S¦´¤jÍ…„V¯fEr—âÌ,× ™  K@‡?—s’œ°@X Âö1Ü?r5Z~@R@ffæî={ÀeèjÑÓÓ;uì·+ òéÓ§}ƒ@fœÑ IDATFb``@-M›49|ÈÁC‡GºŽ¯mccjb’È…T£zµÅóý¶lß9Ég†¾¾^劻uiÛº%íX¤Há’%­ÞXX˜:XíàýûöÚ¾3`ëŽ]Ÿ>}.QÂbØAt¯–I‡ ôömÒý‡†tmn×”þ¥®ec+–.X±jí‚%Ë23³ªU©¼xŸ¤8(‚ü›¨^óTXÓeï •+U€*•+-]è¿aóÖ1ãÜ ÃÔ²©áí5‘™¨°VôŠ€*•*/²‹-bnf_»+äGÐtu½z?ÎÝóÓ§OÓ¦LjÛºe¥ åÏ_=yúLÿ?{W¯Vu`ÿ?÷î;¸zÝÆÕë6îÚ¶I¨(•M¿½)añËî3 úË—+»ð¯¹ë6nî;`ˆ‰±±ƒ}s×Q#$edU{ÝðH.—ëééÙÔ¨µmj^¸x©ŸËМœÜÊ•*úx{víì¨6„d``°eÃÚ]çC/ =ŽeÙB¦¦uëÔþ£^]ô¥ ÖàäÜKWW×Ü̬m›VþìSë¨#ä:fdNnî¥+W»õ,TÈ´R… ÇmÛ¦h}F’ç®åÔ®d2™ÏŒY††sgÏ #{{Lð_¸¤³sïÚµj.[ä_@*îi²,÷ƒ––%bq À Êš˶{Û†±;K”g!,Uê"£ô÷(š¼¨ªMÝÌŒôÌŒôÃûv+7B×óY!­Õ¯Í ©©©´²Û/ɺ ›‡„Ú«iùððŽ ¼æAV!©ªôÏ!£ émBvfFÿX•e£¼à¥Ag„°„!м^SyÌ!α&D´ÍŒD3?‚ªùQ>§¥í=ppˆËÀBü£ƒ#H¯yAä»!Àp ZÎ…›©k¦!i^*+Eœu©Ã·BÇ ¢Áˆ|…LM/œ>.µæÿèàRÁkAùQèBz(üT#v +Øu©Üæ$2¯Á¿ŽDJSÍ®²<AAA~:8=Lðµ>X.cZ¡N@Î¥‚ˆ½ÄÇ*:Yš"-m­n:AA)ÐÂÅ— À0œðU$UK…0€RHškz¢Ë…¡Õ¢®…«B‚ ‚ ‚ ?|ù<^J ¹Šk5Ae%aM“²E£ÐV\HaY~JEï€ ‚ ‚ ?#°\¤šÐØ2'{y+–É"¡Nº@€¯¬'VËTTóF%åL!tb¡‰;CAAŸ ±Ž‹`þˆJ߯©]]Ñ@â çÒÑY ršÚ С…´nž¯Í† ‚ ‚ Â`xËëZI²3ÃU§V$dïËŠ…µ¢Ÿ¨¼‡¶yÔÕýLjÊ3fÅ‹IM‚ ‚ òcˆ2¡§ä-]RÈ€4!Ö|ìY$š5hˆhV¥tüÈŽð©©©R‚ ‚ ‚ü|¬šPe *Ò–ÐBEµ’Oâ Œ.M—ΣP«¼Õ˜AA¤ÀÃŪWIXDš$¢|L€è«ÅæÚÅ&AAùe¡r˜.8”/Šå€°¬†=yÁL¹tƒáP­\—ªEâ[E¿#‚ ‚ ÈO!„îKέ/ME/Ëgv¨‘¸¼Q±Ÿ9pÂZ¤˜ia"YÍH"h+_ÂO»/‚ ‚ ‚D„U‰À¥HÓuŠ ™«%ÕÍÂwSF)¯äkÐ9+*&‚ ‚ ȯM—á'N–Zä'„êaZèƒz ¤†Y–• ]V*— !âÚÕ X¬±ÍÏ*À ^ØK; ‚ òß1t¤kpÈQ©AUh0€`€SÉZÂÕD%[Cš ¢@µTË%(Ä9ÖŒêà‚ ‚ä —a£úôìÞÙ©“´!Lðð¾vã&0 S©S‡Q#†2 [7®Ü$SLðð.W®¬×D7ÁA~[Ä©9KaÙ!@)DMD)"B0[W¤Ö Q³$’€V- ‚ È?ÍŸ}zyMt“Éd?q÷šbeeéܵ³Ô ANÎ.Óƒ¨h\…ì"ˆqANë² "–)*ÓXÉðjû!‚ ȯLzzúº ›C¯\MûœÖ¶M+ ㌠û» oÞ¬Éý"""Ûµmýèñ“À]Û¨ÿ«Wñ½ú >hmeÙßex3»&÷îߊŽ)Sº”·§{Ý:µ§Íô}éë7ß×o~-›š[7®}÷þýÒå«n†ß&„4mÒÈÓ}|áÂ…•~ uèèèÔ­SÛ¦fõ˜˜Xj:Òµ['ç®U§PîÊ¡i^µOYè•••5}ÖY®Ìž¯‘‘aFfæÚu/^º’–žV¯NÉ“<¬­,@üMŸêݾmaùÏ¡Õ=T„´&Pí-Jæ @¢éÁªyо|n57÷¿Aä'e濈¨¨‹>´·Fõj·îÜ¡ö£ÇÇyáÌqωno“î?xH퇂C7jHÅ% :ÓårZXñ¡ªF ,ËÊ%k©¦‡œÞ¥ÿ0„0„(if¼ —c­š/"ÒÍ ]ÅKK"‚ È/ÇÛÄÄK—¯ÚP¦t)èÞ­‹ÐÔ§g:µk€±‘‘cÇöƒBêÖ©ý%'çÈñÓ§x n=ºwkP¿ ØÿØñ“C/‹€× wîÞ 9¸×ÂÜ&yºÿ9pHJjª¹™™ØMLà¾ûÐãŽÚµla¯Üž'4Í›››«é)Ç>[·qK箃ö§–¤¤ä‹¡—‡¤ƒ¸ÓºCçØç/*Wª¢—A |œX³Ð¥ÑeAêÞ¢¬ŽÕW¡pê\q@ÿ•NÉYUì‚ òëñæÍ[†aJ—*)m°âcÒл‡ó¹ ?~ütîüûævBS©’Ö¢ã’IIÉÂ)%11IGGÇÚÚŠžR9›˜˜¤ä¤ÌŸ}z…‡…Þ¸r!øÀžÄĤ9~ó¥y@Ó¼ZžrÈÑc††½{v,¯ß¼Ç®=mílí7o•žžþæÍ[Ú*~‰¤à (±§œ¾Á=X@+øpÐ6šþAÑ¥V®9ÏâX­§Z#‚ ‚üJX[[Éåòø× TwŠ¿ V¨P¾–MÍ#ÇO\ ½Üű“®®â+â„7o„ã× -ì›ò{¨¥e ™Lö61ÑÊÒ^Å¿¦FÁA Ô*Y²C»6+ÿV“ìñÕ·iMóæææjzÊn®£¯Ý?ÁsùÒ…… k+K†aN;\¤ˆš¤ð¯ý òŸ¡zmr· «æŸMú ,CŸ1òµ‹ýkíH¾‘šúÎÖÎáÇ҆oË—"œ¾»D^~½ÜÜÜÙsÿrhÓ±ï€!Ò6äÅÊÒÒ¾™Ý\¿ùÏ_Ä¥¥¥‡½|5Lê½{8ïܵçÁÃGÝ” t ¹s÷^FFÆ®€ÀĤä–ö`nn+“É TÉ’Ô«»pñò”ÔÔÄĤÅKWØ5m¬%D€eÙ7oÞž>{¾J•ÊÒ6å)Ô¢i^-OYGWgîì•*U3nâ»÷ïÀÊÒ²Eóf¾óü_¾|•••õäi„·ÏŒ/99J3!HA„¨S×JV|l›ˆü 5š BhEîA'LóÂ[ V®º ‚ ÈÏ@~}ì ½|åÉÓˆc‡îݽ òoX¤€3gÖŒJ•*ºyLêÖëϧ‘ ë×—z@K{†õÿz{të²fý¦N]zœ8ufù’ÅŠ—ý®]oÖ²ÝБ®à?w¶‘‘Q¿AC iaaáû¿éâT Üw€æ] 1¦x±¢ó|ÿ'õP™ø^Â#&ö¹¦yµ+¤µ¢:Àë„„­Ûwݾsþ¨WwìèQææj>—§¦¦–/WVjýùéÑw€ïÿ¦Õ®e#XRSßuìÒýÌñ¢E‹ˆ¿:æÒÓ*KÒæ@.—¯Z³þèñYYÙMÙNìU¼x1©“ˆ…K–ï? ÃܸrAÚŒü®ÐKÔáÒAúvêÐ^ÚüO¢zÇi¢¿Ëp-¿çJص¤ä”YÓ}¤Íð%'§S—S&MWÀÐ~]!ù…¦wMïb­Ú;¦¥¥ np,ø@‰b‹¦¾bèf=Ó}¼…7ßg1±ý 522¼tî”àêvóù—IIM]¶bõÍ[·rrrì›Möšhbb"u¸{ïþêu#"£Ê”.å9ÑͶâ3˲£Ç¹ß½w÷öÍU«T€½ûnÚºÝÈÐpêäIM›4¢n“¦LwìÔ¾uK¡ã¿O«TU úçQô6!;3cøsOq`šBøò{œ6æD/á7a‹X³,ÃÒP5ýG áGQUâ\ê6ÕТfÞGáù„9Ö²Eó[7¯_½*33kî_ß³äâ'%îåË´Ïi65kH~€bL­;v9w~ÍÊ¥Aû¾ä|™6s¶ÔC™É^ÃÃB—.ò—6 ¿1ÿè%ªüšZ'--CqˆZX–Ý ÈÀ@ÿ¿Õ¿-šÞ}4½‹]8}<<,”>zõpþ£^]‰ªÍ}%T©\é`Ðaáô`Pp•Ê•DíÜJӰгó|ÿ¸ÿ`ÈÑãâÖ)Óf¦§§îܶ?`GrrНº¯>r÷šìرýñƒ‹æû]¸xIܺgï~Cá499eÃæm[6¬î3Ù×{åO9§§§û3Ü„þŸ&uj¸‹ ¡ÛœsAf X²H¡ò˜£XK!Èbºq¹zLˆš­¿WO ¸ŽILMMœ:u˜ç¿P¹ýWæò•°fÍš2 “’šêç¿èνû–%,Ä˫ՖÙßwàÐá#ÇvoßL}ÞtïÓ?xÿº”[S4×ü×dW»… :¾b…reJ—*SºTFFFzzzö—/›¶l[¿f¥Ð«À©Ye•Ké¬8BsDx¬È!„pÚK,Ž !­L-‚QNxÝM€% äK¾ujjêÉÓg›5m"møu¹t%̾YS˜6c¶¾¾~Ðþ€¥‹æ9vBpP[f¿c‡v/^ÄEE?£>GŽŸhðG=¡@’0¦M5ÿ5ÙAÝ?~JNN©ÉGû*”/ghh£É_ AĈ/Ñc'N;úÔÑ §ŽfùúÑ?#Z.Ë ¡—<ÝÝN ®eSsœ»W\ÜËÀ[wnÙpùjØy>”¢ö®¡MjïÐðkPT7¿~œe‹ç÷îÙ½‡s×ð°P×Q#„.j‡]¶x~xXèõËçùÏ;vüä©3ç´û«Ý˜CËsD W/ž9y$È®ic‰=`Çæï˱¶¶BªÂUõ7¡ý]ŒrêÌY==ÝÖ­¤Ö¼ô¥0 éÞ­ËCÁpüÄézõꨭè¢e7Ÿ@Yþ±,+è Jnnî½û‹)ÚwÀûÖ}çî=Ú$—ËgÏõ÷˜0Ž–‚¡”.U*öyÜë„„ðÛwŒMLL.^>røâŤ 3––á×# JWt¤Œè¥c€î™,¿{¢È“‡¨ÙJvî ,†ü^Nž>Óº½cï~ƒÞ&& ì_žOŸ??ˆlÒÈ6þuÂÝû¦x{/V¬t©’ncGSZfÆÔÉ%KZ›˜˜¸ÿ:!öù‹Â… µhÑüÈÑãÀ²ì±ã'»vv”Œ)Ì|Íÿ)“<,ÌÍ--KLòt¿zízJjª&;íE·0011<° ó‹¡—ÓÓÓÀT”ƒUÈÔ4-KJSõÜD@r‰þÙ§—M͆††½z:¿{ÿ>%å+—埽{Ö¨^ÍØÈÈ©SÇÌÌLOw·Â… —)SÚ¶aƒÈÈ(Ð|רN-Fõ× öØçqÃFmÓº¥·§ð-–q$h†©VµJŸÞ=/]¹ªÅŸîE2súÔ Ê25íÞ­‹}3;-ÏA-h£ éâ䨚╗¾ÎÝ:_¼tùÓ§O‡‚÷î¡øšB׌6±o=l¤kófvß·›Ïbaa^£zµu6§¦¾KNIY·q3!„>G´´t™Lrdöÿ¦ž:ä`ßÜc’]ŸºmÇnkk+Éo^¢„ň¡.ƒ‡ž3oþ¬éSÏ]¸(“ÉÖ¯ï:~¢C›ŽÞSgdee‰ý ¼„%„¥É@…«pãô¯’âex-NÔeŠÐôÚ‹¡Û˜ÓO5ŠIÕÁå–|/Û·;wêØþÀ]µmlÜ<¼²³³¥¿"a×nÔ«SÛØØ8))ÉÈÈPøHWº·~\K™ý®NŽ'NŸÉÉɹuûÎç´´V-[HƤ§M5ÿ5Ùé©êtYƒøïÈç´4ᯌª¿pŠ ’K´xñ¢ô€&êeegk¿,‹ãüõ ô „²¾~Vv6h½kÔÞÕ_ƒžªn~ZÇ‘ vسç/2¢E›¶vK–­ß)ªþj7æÐòÑ‚öw1x%Ù“òÕ¾bŠ+fפ‰ßüÅ™™™MK?„çËn>?ο9@ W¿°ofG)Z„ûD122$„tëâT£z5ccãaCéè‡ß¾óüù‹AÁÞžîbgJ¿¾½Ïž8r$h_ÍÕ×mØìãí¹uÇ®råÊž8rˆ•³ƒ” f,Dê¸ýb¾&}•r®€% «8sË€°¬œåÂÑ,04ƒ›–`©z4´ð…)a¾2ýW!„˜/> _ßÃG޾~P±b©Ç/Çå+at/®%Jdff½{ÿžjëø„ê ¥Ì~ãF õõõ¯\½v!ôrû¶m øÕ˜b4ÕüÏÎÎVk§½T·0(R¤°……ù“'OkÛÔ€ç/â²²²ªTáÖd¨ú §" ö£ér•úi@Ë]óÕ©UQÝü¾kwïÞOŸé»à¯96022 ÜwàôÙóR'j÷"Ñò‘_•[wî®^»aëFiž®rssçù/¼pñ’••-©Š»×ä®Û´j)møEÑþ.Û6¬¯º䡯„^=G¹º¹wÕvd´îæó/`mmµt!·Äðò•0}}}›šÕÅåÊ–NY–eY–aHDTTrrJ{ÇnBÓ€ÁÃöëëî6V°,Zº|èàAffÅã^¾ìÓ«‡±±qÓ&""£‡‚†ò&BXÂéc‘Ué?%¡ágEšp‹©«Bt¸ôkÂ0@h›¢Ã»qBtèCŒü»„µ\.÷çÿ,&öË—/‰‰IÛvì*^¼X™2¥¥~¿2™ìÚõöÍì t©’uëÔ^´dùû^'$¬^»úh)³Ï0ŒS§Žû^½$äˆÇ£©æ¿&;í¥v ƒžÝ»í Œ~ö,5õÝòU«ëÿQOX·¡ÖAÄhºDÅh¿,¿Š¦»&/S«¢ºùÅ÷#Ͳ¬©©©®žÞ£ÇO÷K=”Q»1‡¦ç(íŒüB¬^»aˆË©U+’"ëjâ2pÍúM?¾Dê'BË»XZZúé³ç{vWèE˜ç¿pìn!£–¾ªüQ·NxXèÀþJxX­»ùü ìÞ³/üöŒÌÌðÛw-]>Ôe Ê‹Ÿr¯ÎÁ‡>ˆÌÈÌܺ}—\&·mØ S‡öB–ÿÉ#A°{ûf±ª½|%==ñc{(W¶ìÕ°k™™×o†—û©Š&‹‹J«AqÓP} @ÑU½™8=.įUÐôÙK“]; ôoÛzùÊ¿cbcMMLkÕ²Yºh¾žJnӯǽûK”°¾ïöŸ;{Þü…νúѪ Ÿ<¥vß™Ó6nÙ>Ásò»÷ï*U¬8Äe€øÕÕ©Ó¶»*V¨ Ô“Œ)Æîì¥+þî7h(Ò¤q#O÷ñÚíÀoaý¬téRÂC]¦}Nsuó Uþ{Íú5+—ÑÓ¡.§ÏôíØÙÙ¶aƒžÎJZ T÷²ŠµXÖ*Ò¬yÝLxåͬœóa”î"­ž¨Iñ¸b»ÈßøÅ´ïØ &übÄ,_µZOOܘü\©™c~ëßêüžäã%ú­ä×Ôù5‚äu6ǽzå?w¶´A‰°^´tEnnîÔÉ^Ê^RþZ°˜aµÕåä—á«ÄŒz>zæ•-ýÉ 0@€%ü1°,°„Ðf„%„–d1á¡§b8»º&ä»ÑTöëGø'ÆD|ä?¼DókêüAòÎÃÇ«‰²ú» _·a³ëø‰m;õüsàõ›á0m¦ïÓˆH_¿ù¶vCGºzLòÙwàСà[;‡µ6@àþƒ]{öµoÝa¤ëxqªkõjU¿úµ ‚üòP¥K%¯`£ÚZƒ<¦f††UÉXÐU›YEaYn"…eYÀ²œŠW7z#¢‰C{¥ýçŸAò‘ÿðͯ©ókÉ;ÉÉ)E‹*•k8vâÔ|?ßJ+îŸåëwòhÐ_sfÅÇ¿G¬.Y.“ÉhÄúåËW+V­Y÷÷òÕ«EF?;uæ\õjU©[ñbÅÄ… äw…“ÑÜ Õ´,0 #EPO@³9ß™ÑB@]v¶ ’‘Ͳ,g¦fé oT3 ò³°ƒÛÖ1|«?‚ òÝÐ’çЫ§óÚ ›RRR-,”6Ì“ «««§§kbb¢¯¯_Û¦&­k ˆ€¯}'5 —¥)TJsF%] :¼NÖXÕCiz,•ØŠ|nAAò ssóÊ{Ùª–<·ªR²¤µŸï¬•¯ýðñcåJûõíE÷å€wïß››e9‚ü>(‹^ª·©Þå"Ѽæ6—–M]jÍ J3¡ˆFA…ÚµjF*ï5­Õ`›ûævöÍíärù©3gGºN8yä¡¡!DDFÕÂ6òÛÃ¥:ƒ(FͲ\Vጄ¾°žåî¼Ø¦ÝD(DMDTôZØAA§e û[·ïÈd2iƒ2ææfÑ1±jÝnܼµzÝÆWñ¯se2™Lž-çWXÝ¿%ìÝ‹ ¿-¼¥Û¸0À„îÂHwuQU¼„[ñÈé.0,KXà57ÝYGè@í’QøÝfAùg©Q½ZéR¥®†]—6(ã2 _صëÍZ¶:ÒUÒTÿº…LMÝ=½[·w Üï?o¶±‘Ü»ÿPGG§QÃùí [ô˜Ð¨³ÊN1bUMcÍ t !’Ä%-RÛâ&‘ò\‚ ‚ä7cÇŒ\³nc ûf ¼X\__?<,”×­S{ÿžBÓd¯‰Â±žžžËÀ~.û ʶ»ÆŽÉ0¢¯¯ä·D,é·¹ÁQ}|™æX>}„žaãs¥å yÍ y!Qä‚ ‚ä ¶ êoݸVjýa–/Y 5!Èï -ú¡9)ƒÄ2 rSÁL3@aš‹\PÕà„Í„>KDIU£¤FAA~R!K8µ Š]+ÖÀœ;!@X*°¹Žœ°¦Þü¨Ò%´ÀÐ 6\Äšúr¿ jkAAäg„Bh<€° '‰9ù«ˆ/Ke6UÇ\› 4Çš+ÿà sÁAÞ´³XI£ªFAA~Z'–•­,—¢@¡¢Õ µŽµX.Ó-Íi-U5‚ ‚ òó¢^Ë âÊÔÀ%qˆ!ÀWád[* IDAT!üâE¾M³D&„pJþLjÊC‰{M˜/&5!‚ ‚ È¡Vàªê^.'„žðbšk]ú¯jO t 9wưX ›Ͳ\AÕ*ܪßAjjªÔ„ ‚ ‚ ?ŠfË„°„_mH³¬Y"’Á€Ðª Ü@šÂÕâÍbxÞS)ÙZ}wAA)ÈHòŸ•,ˆ¨Ÿ ¬¹S… &¬.C5¶"­Œh&"ÚÐÕÀ®X܈ ‚ ‚ ?)T&•Á|ʇ´j·ÖQÉ*ª ¢U.Å„ŠU7AAù9à44!ÀŠ0U¼ MCØ"ÝË«kÕª T£siÓ"£vÔîúˆ ‚ ‚ ª¤ÌPqËgD3¬à@€Êœ&Œ.="„Ä‰Ž•Æ¤¹8‚ ‚ ‚ü´(T50¼Þå4µ°)Œ «U%1Ðñ1JQgiZMUÝ ‚ ‚ ?jd0¡1dݠVÓ-*Æit›Ï‘Âeš(·Bh=lE_•YAùA\†:zì„Ôš7&xx/Y¾JbìڣϾ‡Ä–ƒCŽÒcq—¬¬,I>OIM€—/_yûÌhïØ­u{§ žÞwï? nwîÞ›àáݲ£cמ /MOO§vùY`Y.郈OD('w(Ì, , À•á†Jl‘ VÕ #–0„>XUýŽ ‚ ÈÏɇÇŒŸ˜ýåˆ5+ÍÍÌÀÝk²‘‘Ñ®m›Žïðgßí;vSÏÍÛv è×÷Xðþ¿W,¾s÷Á¢¥+”BŸ–uÛ²ðeð!„Ð<î!Hb„jk.Çúkpéúò²AAHOO_·asè•«iŸÓÚ¶iå1a¼‘‘a—áÍ›5¹ÿàQDDd»¶­=~¸kõõ*¾W¿AÁ­­,û» of×äÞýûQÑ1eJ—òöt¯[§ö´™¾O#"}ýæûúͯeSsëÆµïÞ¿_º|ÕÍðÛ„¦Myº/\¸°Ò/‘$$¼ï1ɦFõ™Ó}ôôôàÝ»÷ñ¯ü5·D hܨaãF ©óêKéAÅ ºwë¼gß~ùIàÖ rú˜¼BTY³Úåô5íE·’Q NK!„¨Ž*ñ×ÔAA~fÎñ‹ˆŠZ±xÁáC{kT¯vëÎj9z|ܘ‘Î÷œèö61éþƒ‡Ô~(8¤q£†ÖV–ÜiÐá1#G?| ]ÛÖî^SÞøðלY5ªW›5Ý'<,tëÆµ0uÆì´´ôÝ;6ïØ²!11i¦¯í›ÄÄ>:ÊÕ¡y³9³fPU ÅŠ-S¦ôÆÍÛ>~òåËå nß½÷#»,#È‚¨‡HÍ*«5—YE²ÑÂG%? âFú ™"‘‚ ‚üv¼ML¼tùêÌéS+T(_ÈÔ´{·.öÍìhSŸž=êÔ®Å0Œ±‘‘cÇöƒBàKNΑã'ºwí"ŒÐ£{·õ뙘˜ Ø¿„…ùÅÐËBåuB»÷¦Lò°07·´,1ÉÓýêµë4:yò4"++»KçNâ7wBÈú¿WXX˜ÏòçжӰQc/\¼$ê°wÿÁ;wï»+±#HG*eY'F+ì<„SÕJ Ù„iõ­’\iV]Š7‚ ‚ün¼yó–a˜Ò¥JJ¬ø˜4ôîá|îÂÅ?;AGGǾ9'¾ TIkÑqɤ¤dá”’˜˜¤££cmmEOË”.EJN_CWW777WlÉÍÉ"ÓÐűc×ÎŽ£ÆNx)ò óÉ^í 8{"¤S‡v>3fݾsOhÝ»ÿàæ­;Ö¬\ªö@–&|NˆºX5 „å*ñqê›×[i`e¹ 7ߢ("n«.µ"‚ Èoƒµµ•\. mǼ*T(_˦æ‘ã'…tq줫«Ø¬-áÍáøuBÍfV¼5XZ–Édoé髸×Ô(8ä…R%K¾ŠN?|øøéóçR%Ej˜¯‰n=»w;ÁCÈZcbbÒ»gwk++¡uÛŽ][wìZ·zyµªU”}ä'€+u§d’ÈZNséÔ¼âßž@SA”-„ c•à´B¸‹Í4R’ò"È÷“šúÎÖÎáÇ҆odèHW¡|‚|ú» ?qê´ÔZ`È˯—Ÿ¼_ã ÿ2V––öÍìæúÍþ".--=8äèå«aR'èÝÃyç®=>êÖµ³Ø~0(äÎÝ{»“’[:Ø€¹¹YtL¬L&€R%KþQ¯îÂÅËSRS“/]a×´1-Ù‘wºuq:~âô¥ËW33³“æ/ZZ±B…Z65$n®£F 4ÀÍcRø­Ûœœâé=5üÖíOŸ?§¥¥ yóöm-›š°fýƃA!׬ªX¡‚dù)’¤¹S©ª^+$µà-vÖei ¡ Ž&„°„°boBDê™Ð(5–‹”KU8‚ ÈOÂБ®Ýº89+KùæÌš±zÝ7I™™Ym[·œè6Nê-ì/_Ù°þ4—C G·.kÖoŠŽ~Vºt©åK+Z\ô›ç¿pïþƒ5ªWÛºq­ÿÜÙKWüÝoÐP¤IãFžîãÅ#¨¸ï@ ¨LGà®mmÛ´ÊÊÎ^·qËŒÙsLŒMêÿQoÅÒâÀ¹ÀAŒŒ<¼§úÏmßÜ®G÷®Ûw<})“ËË–)=sºO#Û™™[·ï€}Ð^úzzWCÏ* „ ? ù \ŠÕÒ€ ájÂ*û± Lï"eAL¨V ‚¶æT5 Tó¨S÷ß˲“¦½zÐãævM›Û5·€±‘QxX¨ÄX ð_¸äPpˆpêé>¾_ßÞ —ËW­Yôø‰¬¬ì&l§Nö*^¼˜¢ܹ{oÛŽÝ=662rhÑl¼ëh‰Ïïk7nN÷ñ>œ?‹‰í7h¨‘‘á¥s§`¦„……S§£F e˜oZç–ÿhzYļŠ½~ãæá· aƒúžÆ[X˜Ó¦»÷î¯^·1"2ªLéRžÝlÔ€½ûnÚºÝÈÐpêäIM›4¢ž“¦LwìÔ¾uK~Ô‚'bU2› (Ç\†UÛ@€eY† |°™K¡;¼êÉKŸ~MÛW†³pve­¦ß7q0(ØÀÀ@jýÕ‰{ù2ísšMMép?Â?1¦Àd¯‰áa¡KùK4ð­þÈoÈ?zÅj'¿¦Î¯qß–e÷20Ð/àRãW¢wÏîáa¡ô!ÈÇ­;v9w~ÍÊ¥Aû¾ä|™6s¶RÈóÞ7U*W:tX8=\¥r%Q;üÙ§WxXhXèÙy¾ÿ Ü0äèqqë…Ú—EÌÁ à¶­[Ú°sëÆÌŒLá%zðð‘»×dÇŽí‡\4ßÖ‡INNÙ°yÛ– k§ûLöõãÞ÷O9§§§ûÓ\ꄈ£É Ãëc`a¡¼ ,ËÈY¨3è*ä1ý—å¢Û œÚÁEÀ¹ca …“ógßÌ«øø à#Íó:b´´í—æò•°fÍš2 “’šêç¿èνû–%,z÷ì.8ddf®]·ñâ¥+iéiõêÔ™<ÉÃÚÊrßC‡Û½ $$¼éÞ§ðþ=t¸0¦0hÚP@“]í>â%|«?‚ˆ¯Ø¸¸W®ã'>‰ˆ477óötoÒÈ´^¥¶ ë?yú42*ÚÊÒrætŸ{îËÈÈlצÕÔÉ^tLµ7‘djq*H—á-šÛÝðPòkdeeMŸ5G–+óŸçkdd(bŸÇt/¹<&ù\ »F±²²ìÖÅiØàAôïò·Î¸ÿ`@à¾÷ï?T¯VÅkâ„êÕªŠ‘Ÿ…æ­Ú*d:sšÚì‹ïàÍ›·]{ö•;;vœ5cªÄˆˆ9txðÀþU*W€‰nãúôw‰{ù²\Ù²bŸ<î}ÓÌ®éÉSg?yjS³FFfæ©ÓçÆŽ¹rµô«0ºujÛÔ¬+i*˜¹L…LM»vž>k=]³~c×ÎŽ=œ»@áB…&{M€Wññ+”+SºT™Ò¥222ÒÓÓ³¿|Ù´eÛú5+ùñ .œ„¥2˜ ֿÂý—phNd ’˜aá3mgÂ5k#ÚWÏ€ÛÒœF‡%˜ïÖr¹|þÂ%®cF25•¶ýê\ºf߬)L›1[__?hÀÒEó;!8Ìšã÷2>~ýêGƒö—/WÖÛgº\.ïØ¡Ý‹qQÑϨϑã'üQO¨¾$Œ)FÓ†šì nŸ¡I-ßê ñ{ìÄ©ñcGŸ:äÔ±Ã,_?ZÊSËUz!ô’§»ÛÉ£ÁµljŽs÷Š‹{¸sëÎ-._ ;ÏWØU{Ñ&µ7 hø5(©©ïF`an¾t‘?UÕ <ŽÚaÙâùáa¡×/Ÿ_ä?ïØñ“§ÎœÌû\/_¾Z±jÍÜY3Î<2aüXñ ÈÏÅÕ‹gN ²kÚXbر¹S‡öc^°¶¶âŽÂUµ˜c'N5shÛ¹{ï…K–§¥¥ÀÇŸ’“Sjò_4U(_ÎÐÐ0::F©›2Zö¾aÒ½[—‡‚àø‰ÓõêÕQ[ªE&“=|üäÉÓˆzõêHÛþ T_M$§¤9~¡EsÈÍͽwÿaÑ"EûbߺÃàá£ïܽ¥K•Š}÷:!!üöccc“…‹—>¤x1i‚MA„*_–*fÂ?€=åE° … !r¹HÿÒª 4!„! ŸÎAøH7!„pÊ]Y+Dæï$ pŸ•¥¥jÚÖ/ϧϟŸFD6idÿ:áîýS¼=Š+VºTI·±\Ø>))ùbèåS'—,imbbâ6nLüë„Øç/ *Ô¢Eó#G˲ǎŸìÚÙQ2¦0 hÞP@“öúê>¾ÕA@åŠý³O/›š5 {õt~÷þ}JÊW®Ò?{÷¬Q½š±‘‘S§Ž™™™žîn… .S¦´mÑ‘Q ù&RZŒê¯Aí±Ïã†Û¦uKoOáK!É8Zn†aªU­Ò§wÏKW® Ƽϥ«««§§kbb¢¯¯_Û¦¦ûxWaA´0u²WèÙ—ΟZä?ïþƒ‡³æú@zz:˜Š¦ ™š¦¥k—_Ýûƹ[ç‹—.úôéPðáÞ=ß¾ÕA@åŠ-^¼(=040€¬ìlíWi±bœ¿¾¾¡¡B6Ð×ÏÊέ7‘Ú›…¢úkÐ ÅÉZ 2ŽÚáìù‹‡ŒhѦƒ­Ã’e+ÅwGÞç*YÒÚÏwÖʿ׺ 5Ço~ô3î;+Aò‚ŽŽNêÕ¼&º]¾–‘‘A× Š•ôç´4±Î“—½oŠ+fפ‰ßüÅ™™™MK?±ÓëW.Ø“˜˜4Ço¾Äá¿Bò²H›:;uºyõâ‰#‡êÖ©=|ôج¬,##CBH·.N5ªW3666d¾~øí;Яoï³'Ž ÚW³Fõu6ûx{nݱ«\¹²'Žbå,Ýp´À²,á<¨·\T›Ïý`XšC„†ª†ÓǼ Wz¢P¶ÂŸB†sþv¢ž=KIIíÑ»_ëö޽þ£\ǯ۰Iê÷+rùJÝp«D‰™™YïÞ¿§öønsk+K†aΞ8"þvviܨ¡¾¾þ•«×Ž;Ù¾maݧ0¦M h²ÓSµûhá[ý4\±b´_¥_EËMôÕ©Uqs]¹RÅñÓwİÁ'ݼzÑÓ}<-H¬µsÙ7·[¹lѶMëlÖé:¡ ‡üâÖ»CGþ³±'w¯Éç.\”ZuŠ)laaþäÉSzúüE\VVV•*J+)yßû¦WOçóC{vïF4("†aJ•,Ù¡]›ŸëK]Bˆ¹™Ù°ÁƒÞ¼M|ÿÚÀÀ \Ù2B+Ý›QÎ^´tùÐÁƒÌ̊ǽ|Ù¼YSccã¦M½ˆ‹û4!T-ë*‰ø¿#wD·Zä,‚P¦® ?—* Dñà—?êÑÐ!D‡w 2šæŸzšÊ÷o¦]›ÖçO§»`ÃÚ¿ÇŒ!õûåÉd׮߰of¥K•¬[§ö¢%Ëßøð:!aõÚ ÔÇÊÒ²Eóf¾óü_¾|•••õäi„·ÏŒ/99À0ŒS§Žû^½$äˆÇ£iCMvÚKí>ZøVÑtÅŠÑ~•~M7Q^¦VEGWgîì•*U3n"ý$¬:ŽêͲ¬©©©®žÞ£ÇO÷+FÔŒê\7nÞZ½nã«ø×¹2™L&ÏÎΖ‹²‘_•Õk7 qáêCÿC q¸fý&q~ÿ/†·ÏŒˆÈ¨¬¬¬È¨èe+W7kÚ„~ÅÔ³{·ÑÏž¥¦¾[¾juý?êÑ•‹óüŽàIû~ÓÞ7Ô­:°ÿŸÒ–eß¼y{úìù*rµÿM4½,ÂÓ—ËåSgÌŠŠ~öåË—7o×oÚbfV¼\¹²Ð«‡sðá£O#"is¹LnÛ°0rèå+ééŽÛ@¹²e¯†]ËÈ̼~3œö-˜PY,ˆf!1ƒ>¨ÞåT5—ãÁ9Ph¼™¢+g ·Å‹Ð|<œv'@XºaŒbRVåÃØ÷.]ü]¹wÿa‰ÂÜþsgÏ›¿Ð¹W?Zä1ÿÚwæ´[¶Oðœüîý»J+q ¯§G›º:uÚ¶cWÅ „"_’1ÅhÚP@“4ìSrÔo>WâÔÖÎÎ)Z´Èwø#ˆ–+VŒ–«4/¨½‰nß¹——©Uafº÷²•«G¹NX³r髸גqÔÜEa¸1Ógú~þœV½j•V-[<|ôX4¤F$sÕÿ£ndT´»§wRrJÙ2eüçÍ662’öA~-"£¢_ÅÇ7kÚDÚ7\†êÓ³{g§Nb#˲£Ç¹ß½w÷öÍt)ÞuëäääÜ ¿Ý¸QC±ç/C·®N /‹Ž‰-V´ˆƒ}ó‘#†RûP—iŸÓ\݈ôõ›okç diǽ|¹÷À!•¯}ªW«šÇ/Rä—„·Ã á?¨†;Ò$Âý ‚ÚÖ%D‡PO·fÈX` Ë•z¥Œ?¡ÎâVÂoƒä…C{¥ýçŸAþ9þÃ+6¿¦Î¯qD-ÉÉ)E‹ruc`Ö¿/_¾¬_½¢H‘›¶l÷ö™¾cË só¹³ÿç=uFõjÕž<¸v-`û†aþš3+>þµ8b-—ËgÏõ÷˜0®p¡B˜”âÅŠ ¥ä7„!|‡B÷ Êš \–šº /«‰8¡ZÍ¢VtæÄ1'³)„£± nlÎUõ/EÀn[Ç<ò­þ‚ È7A‹²9hannãÆ´îÐ9öù‹Ê•*6²m0 _¯)ÓRSß-^àgfV\Ú¶íØmmmÕ²…}jê;i‚üÞ0t5!*mi™o¦˜àƒÓœxÚYÎC—º²´“à²@ÓE8 -Hwš†MÿOg!\ÈAA|ÃÜÜü¿‹­P”]ìðæÍÛÊ•*@OçnÛvì®eSÓ¶A}±ƒÀóç/ïÞ®>òîý{só¼ÛA_"IöÂih……š¹ÂœðU¸`u‚˜°À‰f8­Lý8¥M€UˆhÄôÓgfff€Ë€~a×®7kÙNûÞ÷î?ÔÑÑi$ÚàA~?Ë^`0À2À2t`xÅL•ÂÚÊ`]Â0Tzs£²rBëjâ47¯›ÅšBû0ÒJ‚ ‚ü(cÇŒ\³nc ûf`llì>ÞÕ}¼’JnXÿг'„ÓáC\†q¡ÇuëÔÞ¿g§Ð$`fV<<,T8ݶcרÑ#ßÇ‘ßq€˜‹/óÇÀ0 ÕÓ€%„»_81Î+ÐeXV¡›iò0ÀÒÌlú“¦~pQoàµ5áp}Å¿‚ ‚ ?Šmƒú[7®•Zó•åKHMò›ÁeG ËyaK€¥¢šS¾´ÎwB€ïHº,Ë ,­c­€åW#r¢™¦g+Aš ¨ªAAŸ^ìJ¯HÝòZ›å7—´¡h%,èº]"iQ:0Ë2ÀåRÂEÂùÉ BS¬y- ‚ ‚ ?h”˜Šf±åE2CƒÎ4[–fƒú™ºA (ÁÒ8'¦…™ qá¢Å ‚ ‚ HÁ‡ð"V!‡ _²š;eXB€a¡%¨€œåš «+t/I¤ ¤VÖË,0@·† @hú6!tguAAù™IXª 9'w9=L€Zt8̲,­„ˆ.ÕÎB‘h…Îæ$7Ö,·Ò1Â:Š/tÿ˜/&5!‚ ‚ ÈÃ+bº9¡ \\šáëP•ÌȨ°@ÑÕQÖÓ‚ªal–à×I2ü4<ÜâH†aåh>­T­RYjÊ3©©©R‚ ‚ ‚üBù=õä çyw& ˆ99œ¢‚¨DA…M,aÄ®÷û£ª{zzg]xÇÙîWÕÕÓÍtõw^¿z•Ò4D$Ö#"€™¿QC0C4Ȭdƒ¹ì&Ib6¥”RÄæ5pY ‚ ‚ BK‚@ 6Nc³ªýñ„r}ÕQˆ².‚Pj ¬_¶_‘ÌøGrüÑŠDvÂGš(sQok ‚ ‚ BëÀú%msu)Ëë´$²‘ÕfC—IÙèjë‘6jšfzF˜ 6¾kRƉmŠ"vq§M·C;%AЂ ‚ Bë‚@¶Î5Û¿0ù­#C M`ê2" IDAT˜#à’² Ùø£³Ùä¬V`0³rL*=v”C€"&xŽÒ®âvmÛÇ:´' ZBAAA„Ö†¯ªs"«Éë Ö b;àKmßh¤¹k&9‡Î&kˆŒÜV6Ÿ)@€£´£à*J$bíÚ¨m©}›B×E*•¬^–¬Y™ÏQ.‚ ‚ -ÚLÐdÖ@š&¶ÚúªM¼GHX[ŒKˆ”K¤À û@¥5»ž"]w â…nA㺮"¥à-_™^Y›\U›L¥Y³Ù• ‚ ‚ ´x¬s€y7“.—51`pPÏÖ±ê(4\Œ[H™`“—st»6ñÎíÚ*¢X2©“ÉTmCª!©ëëu*Íž&¦„Ä(‚ ‚ ­+“Ÿ9°r °ýàÁ8¦ý9ýmŤˆ”R J‘ã’CŠ4!å:ɶ‰t×ΪÏÖú÷mß¹CA].¯\UV¾jÑÒº²Š†ªéÚ$RÚñØÑÚÉhxž„‚¬ªªª‡í¶gMÍòhÁZò‡ÓÏz~ò”¨U„u@.+A„›DÇh<ÏLäE1H#pcCA™|xÄÙüz„ìDJ)ÇQŽRŠ\—G+JÇÜLû¶j‹îôëÜ¿_‡âå+ç-¨XX¶jie²f¥W—r“™XÚ‹ypX3´–Á‹‚ l‚l÷ A„õÉ&Ú1íëdã¹&‚uf›³‚”hKÉ("¥´ëz‰XºM"UÔAmٽÀ¾JK ½Lü‡«fÍ[¶hi¦¦VÕ§c`$ˆb¤\@±fhfÖš5™Ùd~wÞ}ï>¼&=û|´Æ&ÍQ¿;qú73¢ÖucC´i˜pû]ÃvÛsØn{îºûÞѲ|Lýò«ó/¼t¯ý>ø°£o¹íŽÚÚÚh Ahœá¥ÃvÛóãO? ,'ŸvÆãÿ~Â,?2ñþ#;$(„ÖÂɧ1å¥W"Ff>ãìó‡í¶ç¬Ùs"E›6|ï6w´àU^^‘»ª—-»êšëö?ø°=÷;茳Ïÿîû™‘ ð;°Êœ3wÞ°ÝöÜcßÃÌ­óÐ#}àÁ‡Z…/r3ë­2 ˆTXIäԔɢç—)"7®Ò®‹vm :v,èÐŽb¥’NMMíòUÕ N*Í­qfÅ f3L 6ñ&LDÌì8óϳ>â°CÎ?÷ì¨u3`Á?®Z¹jð Ñ‚u`C´pÙÅ\vñïøÑ%—–åã¡G;ùÄn5j¤Rª²ªêÂK®Øs¿ƒŽ=áä·ÿûnP¡®¾þö;ÿrè‘Çî}ÀÁ^rEÙ’¥žzæÙOùcPgñâ²]wß»¬l‰Y Ú *ÀÿÍ}ÀÁ‡ø›#®½þÆ+V4o?áä?þõ‰§ŸuîžûtÒ©úzÚôl[ùhªþ_ï¾c×á»´mÛ¶OïÞG~È—_OËÝNZ ‡|Pmmíä)ÙmÀ&úÄSh}ä½#TTVø›#^yíuSçúo}î­õ•Wûîû™ãÆßù̳Ž97hs3¡ù¯¯oxåµ7Ž:â°h0{μ÷ß·{IIÛ¶m9êÈêeË*+ó̆7j·‘55Ëg|û€ºúú×^+okŽã Ý~ÈàAæÎ-k‘l>#1)6ÁÓDȆPg`c©6ÚŒX jªß6mIcáËæÏ///_µ|’éxÒ+Hé„f×Ó¤5´f­5‡[XÅn–}=ÍvŽ™ŸÃëo¼uào?îÄSþrï}›U´À{|ô«Q#\yÕµñxü¹§ÿ}Ç­7¿zrwÍuã\¸ðo½{ÊsO÷Úz«K¯«µþõûÏŸ¿ x˜õâ˯ì¼ã=zt´æÏW]»jUí¿{豇\º´üêqã›·xö¹FŸþ§—_xfÿýösñåËjj‚¢¼¬¶þ_~Õ¿_߈QZñDüìÑg<0ñ¡ºúúh™ ´ òÞºuízýµÿwó­wþ0ÁK¯¼öÁGwRêÆë®8`ÛkÆ^ñ¿Þ}dâý´Ö×^Ó…çŸÓ¡}ûhÓ›4«=ð×Þx3s÷Ù{Ïh°ÏÞ{¼ñæÛååµµµ“ž{aû!ÛuëÖ5Z PŠŽ<üÐgž}À˯¼¾ÃÛ—”G+žçMŸñí·ß}¿ÃÛGËZ$›OÇhÅVÓŒzö_Æ«ª€Cª7¬­Õ´oW~7·¦b×%ã )·!‰ú”fM`ÒšM쌿ÚQH@¯U}á˜s§¼0éåÉÏ^wíÿ}3ãÛ›&Ü­±‰²båÊ゚9bø°…‹ùõ´Ë/½°KçÎ[”ö<ïì3M…òòŠÿ¾ûþU¾¬gÏmÛ¶=ïœÑ -ž÷ÃüíÛï±Çî/Ny3¿ôò«‡rp¤Í`/-^<õ˯.¿äÂn]»–”_rј?þ¤²ªª)»Ùê¨#ßy§Ú¶m{ÊI'wëúßwß·Ù˜æë?ùô¤©_~=f³ øZ Æ/õÏÇÿ-„@SwÇí|âñÇ^|ù•n¿ë†qWu‰n xô±õèÑ}¯=~-ØÔYí?ûüäCsp<‹§ž|’‹ýæˆcöÚÿàwß{ÿª+.mêùü‡òß÷Þ_±bųϿðÛ£ŽŒ”>ñÔ3ÃvÛsįö9íô³vµ[3¦¥±ÙtŒ +¨³Ê6÷Ÿš€¬”‚RP6& GU-«¯¯G2­4帊Ò¤3<#¦í>Œ‹Ú¼6Žãôï×÷œ³Îüø“O7ùF†>þt‡í‡´iÓ¦¼¼¼°° KçÎÆ¾Ei©YXTVààÃŽ=ÔÖÖšÃ~sð+¯¿‘N§?ÿbêÊU«öÞkH›fÕ°ti¹ã8K{Ë-J±)»Y-íÙÃ,(íÙ³ñŽÍÔòéI=òØ}¹c‹ÒžQZDtÁyç<þŸ'+**£e‚°±iæŽàè#_²dé¶ýû Ûy§œÍ|~øaþ3Ï=éEc¢›:«=ð゚ùýÌYG~h´pÎùuéÜ镟}÷­W;ö˜?žyNEeþþ¡Kçλ1þæÛêëëGìšãÞpܱÇüï£w?ýàçŸùÏÒ¥å׿9R¡Å²ÙtŒ¹"šH)3ŠÑb Ø„C›RvŒ#@6hÄ­«K’rŠÉ!EŠ\YâûÂmd¶"Å m#M|78 ÁÝÄ8¡Þÿà£_í¾€âââúú†êeËŒ¶^¸x±©Ð£{‰Rêõ—^èØ±CxC»ß%ðáÇï¼ûþûí›ðdm†)))ö?l—Œk)BMÍòof|{јs»8á¸cïð¡éßÌØg¯èÀ»ï¹oî¼:uê8jäÈSN>1ZcS䫯§w Â0nºþÚnžpÄ1Ç—wûíÑGš‘ÅÆ]}åćÿqþE—U/«Þ¦OŸSO>1;ì7=úØã}z÷2ëEÚ sÓõ×Þq÷½Çÿþ±ëð‹ü‘ÑMÙuø¡÷ýíï³gÏÙb‹Ò»n¿¥s§NžŸêˆÿ<ùt´@66yïŸOýòŸÿ~⑉÷ì¼Ó'Ÿtüc¯~ìቅ…'Ÿxü 7MxòéIlkÆ/ ^~õµ¶mÛìù«Ý£>wÞzóÝ÷Þ÷ÛãŸÎ¤{m½õÍãÇåõm¯–'žz执ž!¢Î:í´ãÐV÷“f³è­ŒõƒØåëÿÎ!4¢íΞM ãnf0ØÊs¥#Á9Žã(Çe"›¹[•“+Dˆhù«{÷<´¾®¶¾®ö…§þåïÆrØÛ “÷)ˆלªªª^[oµ¶Zîºç¯±XüœÑ§G ÖõØæ 'ÿñ÷'þî ˆ4ÁÚÖAAøeØ{rUc zÜ©g(_²8Y_wÛO 8¤6(2©÷L °²&"hëx@dS3XƒY‘CJ¤=h™´öÒž—ʤ“^:É™4{ip†à9`&°"(#«n(ÈæIÞ¤xëȆhSAaSÇ:ž™m&=2jFn“b"(cmb°Yg֮ɓGð9 Ø †Ô`fO{¤'R¬Ld‰C #щÌdé"¬×‚gŸŒzô× Ñ¦ ‚ ÂæGâÏ“†6~kk·lf"r}“ïÖf †ì~}¶¢›µÖš‰ˆã¥VŽKäøéC„M„?öPÔÔ,k[_A¡Å`=ÖY71LhP@hs[Ùx¯µ•ÙׯD‡ÿ3`êP£Û${ÌlË4kVT¨š ‚ ‚ ´ Œg¹Qð…6vÀhd«‘³?nÄ š-3g£FrÑÖL ¬3¬Á&3‰ ‚ ‚ ´6ȼ‚ &@™˜R+imVdüÕ P „=Ö_07rTû¥Y3l 1X¢AAA„ÖF(œÚª]"eb3BµÀ`€HamjæÖ°Â:R@qà,7Q!ÙZ¢«AA„Vˆ¾¾s9Zê*2’F5ƒL!E…µ­dÞ‚Ùþ¯}mÇ5R¶Q“ÄÖAA„Vƒ»FËZAk”mHß*ë^¶¥Øx™É”æk"›7$*£ëL{F®³™ÐÑq‚Ä~M2köœ¨i)êÒ9jAA„uèäl@HcUMÖ/m´5‰Œ‹™@lüË!am·Öá‹ò‰¡Á0q$‘ñœ`æVÏVmÕ½OÔ´ÆüP]ý‡ÉUQ« ‚ ‚°9ñÎaEQÓ:’¦&øéï ÌfÒq³ ‰{ñ–ƒ)›OA„Ê«‹2W ‰?8+]›±–žmh»Îjâì$€ŠÔØ!ñ—f™ãU&¹{íÙÝÞÕù ÜðâOÞÄÙ鄃ý{8Œý°R/¨å{¿Ïüexü Rç•E€£¶r»Ä麯­Î6›´qñû>±«¶ŸùIò°·­€¾bH¬6{¾Ï‘ø‚Ð2!_èÌDÊ!—ü\Òš4ÀJ®Vq'Ñ&QЦ žˆ9Žãy:Y›¬¯M%ktJ»ÆAí8ŽRDŠŒ‹;œ Ä„x˜Xê`¯á2_Å ‚ ÂæH'ö‰íÚUµuñA¹~hvºÁÃÝßWz;©¾íÕûå^ÿê¼O“¦~Ï6tß®‰3>N–7ðÝÃ_Tyƒ:ªÞíUYþÛ¬ÌwËõ¥ƒc}Û«1Õ˜±Y+ô%Ÿ§:Æéô~îÐ. Œ/ªõC³3+Óùï¼_Tëå)Þ»»3e¡õvØÓ™¹\Ï_Åœ½mìÍ2ïá9Vt/¨åÇæúÜ'éá¥EÞŸúŶn§Ôz+Ó|ç·é«¶S£cŠ~×Ëûeª!ד^—Á£sÓoá è@ŸVæÿ`‚Ð’aëC6ÿ1Š51ä°sân¼ /ˆÇâ1E”Ngê’ uÉtC:“ÒœÑJ“Ç\&²ªÚ¨e›¤ÌÙ¹h¢Ä‚ ›; Š·s1îëTu’w/v†tVÿ«ÔöëéÜ4==k…Ž+<:ª``GõÝr à×=¯ªuyƒ ¿.unšžž»RTê^34~æÇÉ[g¤{´¡p(ÈåÛÅ<Œù,¥Œ]8(øŒ#0ãõÅÞ=]#¬]…}z8ÎÉØ¢-ÐÛ« /1k欴㩦-Ó//Ê\<8#zj~föŠœqV‚° @dÓߘ•RD G9.91åÆÝxA,^s]—©d:UŸLÖ§2ÉŒ—Ò`+Å ¬Ýœt¾\G01ÈúAÄÌFd›÷°Ú6"XA„Í„n4¼«:óãdY=xmqV¶¾´Ðû~¹Ðàá%ÞA¥ÎwËuLaßνßgýį.ò¦/Ó&-ÈìÓÝÑM…н¶ë¤þôQ²:Éœ•¾g×Dç8-Kå¿ó¾Qæ×ÛíßAÍZ¡Gvs\‚‰ôè#UMlàÐ-C·td4ÆOK-®ËÖ||^fXQ¢ÞãI?F=Üð}ö f®h²qAhÉI­EfÜ åR¼0ž(ˆ' Çq˜ÙK§kkkÓÉL:•öÒš3ÌžMÒG ­5X»fN°Î‰æP°ÁÕD 2'†ˆ›ˆHb¬A„Í•âÒŒ%õyn…¾OÀË‹2wKLœÙ¹HyŒÏ*³Ò9¼íÒîZ}Ü5A#ðpß­ Ia]äÏ«ô¯KY+ô=w–è¤ËÓ  (N•¡ÆLwŒÑYÜã{»S«SÚ¯˜Ñø©Nצ£n4£Å<üX«ÇOKÕ4ñ‘¡…ã8Àä@9ʉ;‰‚X¬ OÄ”RÚÓ õ ©ºT&™Î¤=öXk±"6>hf03Ê…Ƥ¬o R³ ´6¡&>ªnì´A„ÍòV„î…dôn˜ðúOµ™iÈp†¡4A¾”V°3º*ZЀqK‡‚¦í2ÁÎÜh‹iÓDV[oê:ûîችº;Qk‹aC|¼Ûv‰Ðs=·)⻺iáoµÈeûËSÑÀÿ«ÔçŒmÙ–Ú¸8 §3¬«ŠV¼¼Ð;z+g@Gõz®Zýu©³]'UèàÈ­Ü®ôI…°,…^íÈ!XRÏ3jôèþ±ÎqêZ@gô}Q¥›rW¦Vëiþóv±™Ëõ‚Z[“ûf¦÷ï露۳ %lÕ–~ßÇݽ8ú©Í๽c{¹nþC„MÂöíº´kß¹}aûBåR*ª]Q[Sµbeõª†•ÉLJ³G:ÃÚÓZ³Öl1+Z¡ fÌCÎù¦9ø¡]jì¢6mÚRMÀ'¬o6“;åfr˜ÂFD¾cëÿF²™¾BÜþmjA-Ÿ82Ñ·½2Óù¸ÂÓÀôe:âÛ~m±÷ûmÜì^°gwuÝ×)°1iAfç"白 nÛ%`Â7éïÙ5~ç°xU2š¦º1Ìx}±WRH¯æŠø©UúÊ©©-Ûª[wŽÿëW—Ž×z9q)Sföë!—Œ°YЮs»Â¶êVÔ/¯Z¹¼jÅÊe«’µÉLRë ³†§µ§=O댑ÖZ³Ök /€]€¬Ã`Ø`êùLVZ ­T6h$ û¶×–sç¼øÔ¿ç|7ƒý >úäÓº—n­´‘x`Dâ®ïVÓ…m Ì®/ù<ÿÐï5Ç´cÆÐ´XÖý0…Ž\J­•ü}þfOè´Ô¥ñÀ÷©ÌŠïó™ ÀP—rF7~¬åÇæF¿œß-×g’maYŠo±v—ÏSó3OÍÏ3ÐpÖ ÌöæÚ¯rŒ Nz?çnžý‘M"4®ß0‰ wè¢bŠæ­ÔÍÎÉO"pãNñÁÔŸ¥æ­ŠÖ1“ãÜû}:xþ°u;ºgx¢Áñï6hFU’ß^âýû‡L‹º˜ÎÞ6öëÒì§¿ÏÎLþ)ú…éQH'öqwè¢L[¦š©J2€ÎqúS?whå}ZéýmVº.‡lá×ÛmðpßÌôÔ*{ÒÆn§Ìû¨"úÍoQÔ××gR™LÒÓ)OkfMD3ÖìÁ´ãv"Ûw&MD v­ÂöUµ}g?¾: ¸¸}šIÇ·†ÌùîÛ;ÆíбÓ9¾z«ÞÛü0{æ'ï¾}Ä 'Gëm JÛPÛšGÛ@¬¯]¯¯va]؈ßÃõµëõÕN+ EÝü[‘³çß øÍnJã£ò-/6yF÷w»$èÂÿ¥j3|RŸØ5Cc§|˜ Æh†9lK7Ùìå>TêÂúàRwþ*î^˜•D&Ý!ôï ®¯hàHÐF祅ž™³)*u>,×÷ÏL·qé¬mc—Ž]15àÏCb«28ïÓ”"\8(6f`ì¦éé¢ßÛ½äóTI!]8(vÊI{”8Í-\UXQµ’=(­Ä Ö€Ö€úÂQÌV6“™'‘ýlzÌìi£›¶¶š:ú=#•笱qÁšñä#3éô‘'žÒoà`† 0dh´ÒFbxWçóJmúÉÒ64~Çxߪ:ÉÎJY­áÿömœ´ÿîá‰i˼~íUŸöª¢ïþ.=¨“:|K§Ð¡÷˽ûf¦M›~¿MlDWÕÖ¥o—ëf¦ƒqßÁ®oÛ%þúbÏ\wO|Vé ê¨"# áàÒÁqE˜ðMàoÚ9¸ÔÙ¿§sÁgÖ»PRHŽHœþq²¼›:„0ŒJÜõ]úëj  k‚•8þ½†ÚÌz8Ì€Èa®I³E :w@lP'UÙÀ¯,ÊœÑ?vÒûÉ>¼ÐØd.%fäÑM†ðD!÷|ŸîÃá[¹c4w¥ž8;3wåj?ïç¼zh|—"Å@E¿±Ø{j~f=|ï#Špõ¬mýMŒ5»çùgõé½ k3ü—ïÒáa‹ëBqý}·DÄøv™·±ž µzµSSfÌÐÏ—fÙ"Ñ%N•Éè¿Ji:d çºi©vžä€Ï«¼=K“Ö°ÀÁ%êŸs茠› IDAT3§öEªyŒï–ëÙ+ôÖíÐÒõe„`.¡Ú ¿±Ø»xp @— è¨.ø_Êú?>/sËÎñ.‰LBú©–Ë깬ž jã"¦è¸Þ6÷d£…ÀIÀJj­¡™™Dlå´!äZt²o1‹ ¸A©/° ãÆ¶ß²’fæ Þ#rj|íXµbÅ‚¹³¼9å…ÿüý~fôÙvÀ±§þ±Ç[E«n †wU/þd/ƒ}º;·|“^P«ßÒ½hPìä’ÜlÒþ‘Ýœ›§§Öé3úÇ®ß1þÞRïüÏRíc¸i§øWÕ·å€ Å⊮ü2µ2ÍÇõr¯»ðó”é‡Ã»“÷c:Çéÿ†Æf¯à¿ÍJ¿¿M;Ó–éÓúÆú´SæyÖ¾Ýé5vz‚faMXÇÃlŠ5iö²íb• |ÆGÉB— ŽöeB‹b“¹”Ìrã=–§¹™ÏLÒ£îÝ5qåÔÔÜ•ºw;µG‰2º™ÃÏû9M©"ôj§.ß.¶¤žß]šç×”æ¯F`³×ÐyÉ{Nš¼óN=€ÀÐ8bd )oà`òpaÍù¨ÜÛ½Øù´B×y|P©ûýrmbÂ/ìCs2«šý‘¢¯-ö.uf­Ð{wwfÔpE£¦8„¾íU¿êÕÅÍ6·1ا‡s@OgyŠ?­ÔÿœgÃ9òÒ%Aûöp>­ð|ËCÇJ@Ÿv4oÙ–ºRqÕ{\—ÁåÛ¹ÿù!³¼Ù¶-ÖĬ}ÑK`ÖZF[ûnisL “Ä„„€È*g"2ɪM›Ñ±‰ ÓƒtP)T¼ˆ5é™ó±rEYPŠÆß÷÷Ã;qÆ—_Ü9îÿêës+nÚ¹Ô·½ú²ÚÞ®^\èÍZ¡“^^èuŒS—™¤ýÌLW'¹²œ•Þ¥HuŽÛ“ôâOÞœ•ÚÌ Pàà¡Ùé•i^\Ç_WëmÚ€® Ù͹çûôÒz®Ëà‘¹™î…j«¶Ôx×a cߪ-MØ9nÙR hgU†?­ôöíé `ŸΛeüyš:„5a]³VÛlBØQýmVfyš—Ô癕Wh9lJ—’Y53zÔe0iA¦*É#º©f>ü‰B4#ÃHkÔyœÒ˜¹B?2'ƒÕ]†M}Nš1o¥žòSfxi(V燂C¯æ0÷‚Í„èÁGYÝI[Í968O/ÈdJ<±GÁ®ÝÔ=ßçyÊyÌÖîÒzþd ¢^[ìèæ´ÑA¥îË‹¢·¡C·t&ïSðÜÞ·îÿ¬Ò[“Iî›™þÝ» ǾÛpãôôÀNtÑ x´`ßÎä} •(. ãÀ®Jòœ•úÄ>nç8uIЉ½] ]ªLò“ó½Ûw‰»û»ô¨bÇ!L_¦ÇïjÏ‚?‰%ZðPX­=f¶i>¼ kó Ó˜´fÍæe"C˜›êø\„¯~ŒC¶†}JJȤh– Mö"«¡C§ÎfaÇ]wkÛ®ý¨}xâákª«~˜=sàö;äÖý¥Ù¹H}»\×ûB÷ÞdÌ+5›´ßŒìòô`ž&Hk$()$ŽÊyÌTR@ Vqd×a Ã~=œi¼´0ç·óf™wñ Ø#s0¸£jç’‰ó[Ûy³.‡¶DXm³E jð~äAh!lb—òÍèÑÌg@(åðÒz¾mFê}cb˜¿Š_ü)óÃ*nþ2Ìû9G;¿ÝÚéÙF8`bQÖŽ&µ]Svp“›lF4u¢ž) t&ìOu,ü²Ü°c|I=ŸòA²Þã{ºvŽŸóiÊLiiز-Tšœlžå)þ¢Ê;g€[ààË*½KîO\cM„’30vþÀØjÓ¹üòxŒ9+õßgeÆï/tи·|«Ì{»Ìë§ßõvoÙ9~Χɤ‡›§§Ïè»D"­ù©™í;+s;žü“Ù>F·ì;5õÛ­Ý…u|ô†‹Ç*uŸÏ7sgKÀ¤÷`ò¥o€10ý ˜À~N<{9»æÙ‚‚¥Fd»’<ý€Ù.OÁšÐ¶]û.]»UWVD쉂‚ˆå—gxW•7 QÀÏHÚ¦¼™qÒÉÆ1Í«Ýucþ17³SuýŽñq_¥Wùñ–áv¾¬Ö)aEÎÈnê½¥^Jk|)„ß]t\6š=Ìu¡*É:ÄÈ\Ìáñ"BKcµßç5ü6E3ß±Õîº1«½”oFf>r{ÕÏ*õg•)"ìYâÜ´Sâ”Ööð;ÅéÒÁ±›¿I]jðpè–î%ké±Î¯óóëȼÆÍÿÞ>QD¶)jÔG­™¶ÒY²»î9mšáš¡ñ7Ë<UµiÓ!Fý;¨¿Ï¶ÁÁ/ü”9©; ƒ ­Û¦½*JÐ?•ý‘|×ðøó?f‚hã//ònÚ)þÈœ&Ç90cI=¿·ÔûCߨhqÂzM``YŠŸžŸ9¸4Ñ£æ¯âòrË ïªR³svŸÙß}z~fYŠKÛД…™zS«¼>íײ§úaö{EsDÕ²½¾‰òù–sWØn+»™Yk˜¨@1¼£ÎѨY;;îD_~úQíª•¾ý€­zo³õ6}£õ~YÂNEê•Íù~FÒþ0 üi¥wÁÀXiJ8è×A]9$Sk´ëÆxŒÛ¾M/XÅãwŠíi‡ï,ñÝÒÙÍÆ`aÞJ½o§­‹â:uÿ÷ØšÑÔa8o@ìúó?{Z-eõüýr}f·cŒºÒÉkù©„_Œ5ù>¯á÷°)šúŽ­É®³ÚK ùfôhê3DØ¡‹:y·G!¹EH8 µ?ü¸j3œalÛQ¾åZ>^Í#‹9¢ªÍ3ͬXd?€Á¼»Iľù¼‚3µç;{–èIòþ[D9e÷é|YóÖ#Ï,ÈœÔÇ]§y+aEšËøàR§Sœ º…ã*ü°J#t?úïï°·ÌË䵸à³TSªÀŒ}ØÛ Ï5íˆ% ¸€~U☵®Û¦½J8èÓ^ý±ŸûE•}(œ E¸|»XŸv*®P\@'ôv—¥xQ8b+wûΪÀÁöÕýcO/È„ã³wíªÚ¸ôÎÀ¢:ÖÕ)p°Ce¶m™hx³†f@›U3Š‘Á ÍÐ Ù{ÌÃó¯hk7)úÜà¢&€M¶Îþ&€}aͦ(0›:áç±ÛÞûeÒé7§¼péß¾c§Ý÷=àˆ~ï8Y' ê¤*“Ù‡³M1á›ôŸú¹÷ìgàË*ý÷ÙM^Zy¹óÛôq½Ýk†Æ;ÅéÇZýôüLZcHç5Úuc˜qï÷é?ösoÞ)þ_¦z´¡H;o–yÇlíþX˳B¿,×äþ173f`ìÑQKøå…™¡]é…fÉ{˜ë΄és·=¸[¢*Éo,öúwP-+G¨`½”ÌŒ½Û©Åõ:˜Ñ#ïgˆðMîÓ^]»C¼(A‹êø–oÒ&²e­¿¼“¹tp¬KsWé+¼×ø’ÌsäXrÄtD6Þ@x“ÍëH²G:p{“ ,²sçúž8z· ÝnÓ§½êQHŸûù€×–;†Å_Zè½å{R Ô(=óŒSÚE}•›g“äú¯Sè»oDÜ%ZX§ožžj<ýúâÐ-C·tX‘âojt3ê|£ðúboô¶n¯¶jyš?­Ôÿ™ýxšñÎï¬nïvª6ÃßÖè±SS¦[û¨Ü;kÛØÎª²Ÿÿ13eaö;ÖÎ¥SúÆþïKëÏ~zAæÒÁ±Çv/˜¶L¿º¨E;ìÍïc‚ßûˆ}‰\÷&{^Xç^Ò4ü’Š › À&1eAÞ6 3ÍYMd’¬"*ù€þƒ‡Ö×ÕÖ×Õ¾ðÔ¿lC>‡½ÝpǰŸéžPS]}ÝÜvQëã´¾n†±Q†Ä­¯]¯¯vZ»©‹ÇNxïgޝ6ñ{¸¾viçîá‰ç~ÌüwI+|nUÀ9«V7«§9Rmp³!G û÷J»–]´ëDˆÊkDëEK-'öqKÛЄo~¦É+¬ßÒݱHíÔ%gÞ“sÄ4ãþ™?sG‚ð óÎaEQS³ì=¹jò>ÑããN=@ù’ÅÉúº ‹ l¤0ÊrŽˆÊ\ÞfˆHõô DDFQMn[0å„|½(qŸ»¿M€á]ÏÖò òúb}íz}µÓbùU‰³[7§ÐAïvtJߨûK7åƒm½lÄïáúÚõújg#í¢sVíÓΰnfØqðÌv8KiÆ­3Ò=ÚPØcÝLzæå)­åÀtAØ´°uÁXB³@öÀ¿îÙwT[#‡jYA˜ÙÊm4úU]3½Cð6›\“Â/ÊÊ4ß:£ÑýA60?{FC¶[ªj¤³ï޵u‚jÁfÙe»°ùàßìÈøªÌ90F&"3G±}DÌÚÌ.eMÄœ ª4÷Ny5˜\é§~˜4¹á™›ùϯ ¶jK Vñ×Õúù3c‡Ä;'hü4›ò¢1Az浚¬@6‚> @® ¾dÙ\Õ{U»B÷+ša£ßƒøù­‰TØî£B}µ ‚ÐbhBûúªÚ>oôÕáÐ…¼6ËX]k›.Y5ìipSô‹ Im6|ïµu]3ƒT®¶ayˆêwˆYKó¹Ò_]äývkwæ =mYþÈͧgîGUr\6 3•¢Sï"(”ºƒØNʨ6kSn» Û…†úãÊU1‘ÿ‚ -_æUÕ¬ œ[RÞ 2Wöz ‰»—§4k&eî¶:W[Û»s^f.×}ÚÛÒfr¥á‚A±ÿUy:ªýü‰uaoè–æÓ3oÓ^ÍZmV6&5^ ªW(:«"\f ("e[dÀˆu qŒuî/ìÀ®bÊå ‚ -…Grn?™¿¬Á|^IÅÐ^%E]ºd« ?—ªªª1(¿uQ7@ƒTVBG=Ó!m[ôI…¾v‡˜Cð8›¯ýá9éÊ$oÕVývkçÖé´Æïz¹]tñç©~ÔUÛÇg¯Ð jÀ²zµ#³ù—xA*›ÎqúÇî‰pV:«û$%ˆ ˜«qM¥µÍÁÇÄP bóÐ0£ÃØ¢,ò6¯ ’†6npA¡¥Ã¶³7÷³j»ûŽhU½¾(**ê„ÿÞin¢¦„‘ýWhŽ9+õ’zÞ¹ÈÆgÞùmza¾fhüŸ»œÙß}«Ì3ùÚÜʽå›Tƒ‡éËô³ 2—‰›¹î'-Èì\ä<³W6+H^uRã«&bHas€m‡ØkÕä÷ÑZi‘`’ê±?_ 34`M}×x¼É¶ ó[9ðL›ÞÖ¬šÀ¯Ú$¨íÛA„@N·ìk:c´ï¾ªÖ&›žtãÖ " (Å ì=•ó„pŽÓú±¹™“·q?«L¨÷ðÈœÌ#¹óŒL_¦÷n6tçÉù™'ý™¿[®ÏΗÓfYŠ{;»É1[»ÿœ'ók ›;æÂãÀm~Èf 1×kX$æ¢6‰V3»axûÆ#-Œ(W¦ƒAZ¾ÒÎöáÒ™o¡Ì¾/+¤¢WË´eú’Ïó8\_\÷õ†m_ZÄŒÐl‹€Y4r›PMÙÓdjùÕˆÁùgÁ w­õt"Ø)[A„–E¾Î9ä®f»Êö!¦uZ ë›ì¹µ§Úü»Øß3ùï¡y‚ l0‚8-«–³VÓ]&Øk8{!› ¶<"¬m3¹yDUkÓ‡iVy ‚ -P×mµuÖnäµieŒ>gÌ”—^‰Zêêe{ìsàòåË£¿<þ¹ÍJjÿ-÷„·¾“/›Ä6`ÐVï²QÛ ÖÐÌÌšÙ3½ l7±0¶©CaÕd°•B yÔs`"¢°xAZ ‘^Úêi­ö½ªÒ¯˜ýv0Û»s£A6*ÌÌ` 3PÑ L4~h¹nl€ƒßÁPX$³ú‰L¾ÚήøMP ¶™àp¶ ‚Ð"i¬Ûr-°k"dú73}ì_3¾ý6“ñzm½Õo9êÀý÷VZ\rùØÏþ÷y°:|Ø.·Ý2>TÞÚ` r€sF%ÜèÚØ"Â/GÐ323@Fý6 ›f«³³ùÌ•KDþ”æZk2ŠÛ^Ñh˜gƒ9ýo´ `ã%7­ æÍ‰šÖ˜Ž$” ºÜL÷¼7j>×é'Ÿ~6öêëN:áw—]rAaAÁGŸ|v×_þZV¶äÔ“OŒV]sô‘çŸ3:jm¥03³?#ƒÙŒN²÷ͨÚac@?žUæ_$x€\¥¡‹•™ý?Y›‹@cæ¯?x%gVs«žÍÃWÛ£Ø@­IϰïÐþQÓSUUõÎaEQ« ‚ÎÑÐÙw³ µff­µÖÚó<óîyÞì¹Õ¡6ÀÌwÜ}ï!¿9è§üÞX~}À~Šè¦ ·ÿúÀý»—ŸvúY#v>mú7sæÎ---½à¼³‡l7@}}ýć}ÿƒVÕÖn?dð…cÎë^R à´ÓÏÚmäˆéß̘9kVQ—¢ Î?{Ø.;‡÷ØËjjî¹÷ϧN%ЮÃw9÷œÑÚ·Ô©ªªžpû_O›Þ­[·£?4°7óaFŽØuú73fΚ}ÙÅì»Ï^Á&ë‘ItrÇq¥”yWJ‘R °˜f!x/‚ð `Ŭƒ Oƒ8Ù›±‹@® ;ÁlL™UÕ°ª[ùWºÑÍ”­ª™»€sWA„F ªóbäu|­,øñ§%K–F?öÛwoEôùç_˜Õ^œòÇ?œ2é©ï³×ž—]qUMÍrãoºuáÂE¹óÖgž||«­¶{õ8í·ÿÚëoŽ>ãÏOzòÀö»áÆ y÷Û˜kÆ_U[ûðÄû'>pïÒòŠnœ­\sÝøx<þŸÇ½yüu¯¼öF`oæÃ¼ôÊ«gü鯼øì¾ûìÔ_ï0³ÖÚ,DÎ|S4_*ÂúÅBí¼L €ÐÓ=_Gž‹Pe6hVG€ ½HT®ný˜¶•¥Ahi„õYöNÛ_›Õ¼R¯¦¦@·®]ÃF¥T—.]–ÕÔ˜ÕÃ=dǶoۦ͉ÇÛµ[×÷>ø°¢¢ò½>¼ìÒ {ôèÞ¶M›³Î<}ñ¢Åó˜oêsôl[Hyø¡Ëjj*«ª‚–ž™ôÜûh^ïðÑâ²²¯¾žvјs»w»à¼³?ùô³ªªçú¢ÅeÓ¦sÑçuîÔ©´g3O?ÍØ›ÿ0Gqøvƒçñ"8±yO{ÄÞøŸ@„_ˆÀ{l_L6ÊZkûÊ hƒ•Ú!ìšËÝŸ3† í\P¦bÎïëi3e³hÛòв ‚Т «=#þŒW5L§NTTVvë–ÕÖZëêêêÎ:™Õž=ºE={t¯¨¨,[²ÀQ¿=!°([º´OŸÞ‚ ‰8€T2Ïì$‘믾žæ8N÷î%fµ´´'€òŠŠ¢¢ìØ›ŠŠŠ‚‚‚ ñÒž=ÍB󦤤8lßh­‰ìœÁ»DzBËÂêa˜ß¶æ tmXËÚŶ\c l5wpµs¨³ ÛÿŒÑ†^•A„MÄ9V{yÙz«-»—¿öÆ[ƒŒo¾õާõ.~ltÙ’¥AÑâ²%£vYRR¬ˆ&?÷T‡‚¢u¡¸¸›çyKËËKŠ‹,Z´@q·ná:ݺukhhXVSc´õâ²2coþÃü’ò6ïÙ‘--ö3챘’Ìù`³"»q EÄ&_n@Df¬‹5û…F€7½_AacÒXO–ðj¸šˆÆœΔ)/?ò–—W¬X¹òµ7Þºó/=ù¤ãÍø?/LžòÕ×ÓêêêŸxê™ŠŠŠ=vUR\aÿ4ÒÚ‚ ‚ ‚Ðjðã2fRs8šxÚÖ±Nç 2ÃÏcÕÊlfk4õ™›†³A ÌšÉz©1û.nA¡óÅÔ/£&A„Í ¾BöýÇãÁF›ÑˆY‡7¹•áV§3 ¾7šÀ T|à¤6Û2ƒgSd ‚ ­ãC1ËÎ;í˜[Eøù˜_)O² -аösZ“?Œq^7ª×ÜÐøEfÖÆiícŠ(ëb=ؾ13À h²º^Ah¥ˆìÛÈY„–OV0‡üÈytmNx“šMÖçÌ*tÁ³iœãÆf» uô×6‘ʳ_AAAh°ÿ‚·dõu`lšœZ&µQËrWumVŒà6êÙaNnm"°»\AAZŒ5Ëìg»³ÁÏÑGOVƒ$Çs™YÊúªí6fü"ƒf›Äñ‹(·iÎn ‚ ‚ ­ãWn6é>ÌrÖìšu†I b×€ ×b†Y5"Û¯“-7…!‹ ‚ ‚ ´BÂÖzͼåFÞæŠ\ År¨Ðd‹°y¬M+——:<Ò*ræ 8$ 3üÔ×ÍêzAAAh¡7…Á ÀƇoÙ€‘l ‡•Àl§>·.i‹1˜*¾–;³#îjK“ ‚ ‚ ´Øèf«„ñ µXS`­F—`2ž˜¶³Ç0`d;Û0ë¨x,DÈ×¾ ‚ ‚ ´tŒ ÎkÒÙNåøº7_ô†51àÚaŒì{ºhdniÍÈï®üÙÑAAAhé0`‚ªýØf?Ï#¯ý À$ó0‹9B[ #ªµy143³¶Šœ@`q"l4´y·íÎIxAAXŸŒ>gÌ”—^‰ZAÖ &0ÈÙi_äMUü IDATfÖ ­¡¬¡Ú_†i&f"1˜Àä23Y_³èþ.˜²œIfà«jóN›ýA„MˆK.ûÙÿ>PXXاw¯3O?m‡¡ÛG+m0N}îQGvЯ0«üõîÜrA„õ‚/‡¡ƒØfã?†•¼VíZYÌ&XƒÉWÀ e6cfóÇTõ7`0C3 ­gÆ-MDŠHRÚlÚTAØt8æè#ß{ûµgŸþ÷¶ýûýyì5Ëjj¢5AZ7šÙoÀ8§—à¬ÿV4gW[4“fbë±6æFg¶ÂÜÌ)ã€Ä&¡5ÃÊm[[´µ Â&KÛ6mFŸù§ç^xqÆŒïv5ò´ÓÏ9b×éß̘9köe_°ÓN;ÜsïŸOJ ]‡ïrî9£;´oà´ÓϱëðiÓ¿™3wniiéç=d»Áêëë'>ôèû|´ª¶vû!ƒ/s^÷’bS?h¶Oï^3g;iÂí7M¸}ÐÀüõîÑçŒ9äà_ò›ƒšiá™gŸê™gk–ÕôïßïüsÏê߯oÎa‚ ä‡aÕlHI¯ÖqlÕ³ÙD»ÙHf³*š´ Æ{øfMf;³9›*y‡5 ‚ ›./½òê ã®4p€Rêü /-((xxâýÚÓão¾õ†'L¸ézSí…§Ü0îšþýû>ÿ”ˮ¸ê??Ú©SÇñ7ÝšJ¥þrç­:vxô±ÇÇ^=nâ÷*¢H³‘P0y[X´hÑ}L¼ûŽ Ûöï7{ÎÜ7ßzG„µ kHØG̬ikƒ8@ä=ô5sŸìl13¼Ñ÷H‡^€q{MXÀÚ°ÑÖ‚ ¦Lm]݃.,,4h€±uÄáÛ ¤”Z\VöÕ×Ó.sn×¢¢âânœwö'Ÿ~VUUmª~è!;î°}Û6mN<þخݺ¾÷Á‡•ï}ðáe—^Ø£G÷¶mÚœuæé‹-žÿÃüH³f5/Mµà:®ëºmÛ´‰Çム<{ôéÑ-AòáË`Z¬Ëšš6/ßlÍ»Î.@¦61˜æri£Ó™ÍÆþ.‰`uus=  ‚ÐzyfÒsÏLz®   Oï^7^m—ν¤¤Ø,”—W8ŽÓ½{‰Y--í  ¼¢¢¨¨ €ž=º»Y®¨¨,[²ÀQ¿=!°([º´OŸÞ5Û Mµ0jäˆkþïÏ÷ýíïË—/ߦOïcŽ>²ï6}ÂuAã§û`üÇšì,ŠÖbÿš!Š dÐ!±íO“££}Œ›[rL7® ÍìOR#‚ lRsô‘çŸ3:j Ý Š‹»yž·´¼¼¤¸À¢E‹wëfJË–,õ+bqÙ’Q»,))VD“Ÿ{ªC‡AQ@ø“ïöÍ´0jäˆQ#Ghæ7ß|û¼1?7鉂D"RG!LÖEÍÌ¡ë°ëÚZ«C£”‰åМ‹Ö9C mÔ‡"©lEv¸~Î&‚ ÂfCÏ=†n?äλﭪª./¯¸ëžûF fÜÕ^˜<嫯§ÕÕÕ?ñÔ3{ì>ª¤¸xÔ¨‘7ÞrÛO 6$“ßÏœ5öêqét:·U(**š;ïÏó"ö¦Zøü‹©þý‘E‹{™ŒÖ:™J±Ü›AX=Aº=»ÆÆs â”Øæa öÀží1»vë €Ùz˜æ´&2a f€BÉ„“DE» ‚°Ù0îê±÷Ü÷À©M„áÃv9ïì3ƒ¢C9xâCΙ;o‹Òžnº¡S§ŽÆ^qÙ£=~éåWU/[Ö§w¯“N8.‹e›ó9á¸ßÞrÛ“ž{aÛþý"I¬ó¶0tèö³fϹ䊱••U[nQ:îê±………á­Aò`U5ûó'ZÙk$±QÆ~!¾dB³ 4è¬JbL^š3ù¢&ä'«ç#ôxŽŒ° ØðÐúºÚúºÚžúW°¡á°·&ïS1®9UUU½¶Þ*jArÉzYظIì{€yÆhðOçì=/þE‰¶Û2TÚM–ø¥€-ª†À;¸cóN‹jÞ S—ß„B!„ ]7ÒCÏAì!ÆŽˆ¨(zæ´V¨÷`›Ù’ÙKÈÍÍl¥(º™›YUû‡°šZQuJ Îi1ÿ·ŠÀê „B!dؘÑÙÓñUn•ÓñzpR@®†Ö€:q:(Ný"lgËBD Qéš?Û–v¤"[àTˆy¦íPˆˆª½&F¡¦¸5Óè„B!„ >wg:í÷V»Uã:ÞÓñžôœöT¡"½…@œßíºP8U F§‚nt?GY,€_ÚáTÕ„³_Oí¼˜ö„¥#¦©Ö„²ðã»îÎM„²AãzãEQŒvfŒvÇœëëªñÞªU½•NÆ{ÒëAœöT5lââ ( çz¢â`;†h×Ϫá!ŰœDM:GmiðkE"¶Â„ºšB†Ÿý÷Û77‘Õ…¿¥2üaüGŠ‘ÑîXGFºnÇ£2æ:½ž®Z¥«Æí7®b BL<›Oº£"Ô‰BÑlvðWG… Ào)R*ë¢ÏCŠÒ¨¶ !„Bx–cé*YµjÕˆŒt¤Ó‘NÝŽt:Rt¥Ûs#«d|\V®r«z:î§ã¶ž ) ê=ÖÐ^uO¨±í%éPÛóÃ<×¢P{ Vš˜žöK­ !„B*VÉŠVëÊå®èHw¤A·[Œt‹NGŠ¢3Úít{nlUoeOÇ{–bK¯§=U¨ƒ¨¸ntW‡ÅÓ^UÇ DUUX*ÿ¦tüêëtÉuÈK!„BÈаJVèÒ+¤èéªq¬Xî:E¯3VŒŽ#év )¤ëŽ*Fz:ÚÓU«z«V¹qçÆz=8‡žÓ^ÚóK9´€íÊUÛ7¤Ôɶˆ=½ ïÙVçz"D¤¨ŠlB!„B†€žôzèuì•äR¤è…“Uº¼èI¡tF:£#ÑBF:îFfªŠñÞªU:¾Ê­Z¥+VbeXc-.j[óaË<ââjjG~U€°jį©$&„B!d8èÉ8DœÚNÕ=-ŠBà¤P"=+{Ë‹ÞH§èŽ£c‘®Œv¤)F::Òu#]×éh§ë\ODlk{Â1ªdñag‚Z¨m‚í=Ó‚Bêß“Þ3#!„B!C„+Æ(´|ÈâT¥è(Dí=1è2qEÇŒôFF;cŒt‹nGºRÈH1£ãº]Uõ/f´§USÏ µ}°Í“­ê}Òæ¸†8¿wµ¨Ú×\ B!„B† ×q€öĉÂÁ  P@EÑ)Ϋ_¨ˆ®Z©Åòñe)lóîHg¤¢ ׃@ ª{QD{°wÂx-íüª8¿f€ˆBüFÙª"j !„BTÔÞ5®À9@¨¢@Á¸“Bl ´ˆ`ÜXµ-:Úé¸N§éB{ ¨¶åGaÂ:èh þ•{í¹ÇŒ±±W{ôãK–<ºx±·÷Ê=vßm£6:ìЗ/[¶üì3çmúŒgl·Ý¶ûï·ï}÷ý Àü þë'ÿýÖsÏÚr‹-æÌ™}ÞÙgÜùƒ.^üX¥ôýª#„ÕGp çL÷ZÎÁ©¨ƒó^d¨ß‡ÏYTËâü‚l¸ˆbâü®UØfØAbÛ¾}aňºPT’‡BÈE§ÛO-ã㫺##ñð™³fY`llÀÊ+ípÖf›Y`ttdlllÆŒáptÅÊ•.\Ôét¶Þz+³o»í6.Zd‡ýèW!„¬6þM‰¦xá¢Ù{ší5.€-­¶S˜&‘QêcÛeOÛÀ¯TÌbâÚD¼/Gƒ»„B6(¶™;÷ÁЇO<ñÄþðä6s·N’¬&sæÌîõz,\h‡=4ÀœÙ³ŒŽ®X¹Âì/Yrô…ùBÖ™³ØÄmÜÏ+í¨Í?~™HQFÀçñ©ÂÿÚTŠsêœS ŽqU¸žö(¬ !dCã¨#¿é–Û¾wÇ÷—/_¾pá¢Ë>rùN;îðì½öÌÓMmæÎÝçyÏýðG¯X¼ø±… }äò+>ð[l±9€ÝvÝåÆo~òÉ'~dáUŸødž³Æ[lñëßÜßëù—šBÈj¡öKz¼>PFªêTãbhKUËW].–3{ZQ“² æØ6ÙîÕ6‚[Uíõ1„B6$^ü§ü–sÎüÔg>wÌq¯;íÌs:Î%¿¿ÛíæéV‹÷½ç¢6ÚèÄ“ç<ïÌÙ³·¼è·›}Þ©o^òÄǽæõïø«wÿñÿù£j¦^Âkîüá¾ìð£çynG!Vi„7,zT½6î©ë‰:AX<ÐP1Q­ªª";w§hù}9"ˆHÿ¾æÅ8lUˆÂö´†H!(º÷ž´ûÞû,{jé²§–^÷å/„4žcn_~ýKü»Õ`ñâÅ;î°}n%„R%úD,?#¶é“ÑëõÆÇÇ{½žœ¿`ÿýöMK#O‡ßu÷vÛÌív»N§ÓéX H°WCß¹ñ›·ü &„< ^|ýâº=áÄS,|xþŠeOõØEôÌýPU[""P[? ç5s˜Z…Š-Òé*z‚ð«°Í®&´}`iBe /¨MbKQªj) !„B"ÔoOP[ @ p\ù:ÄUJ_ *]s^ˆØVýñ}ŠATÇ_šC^¶ûúDUMÞ2C!„BÈÄ޽ɦoE~Ù³BM(€éq…*D´ 8KÚóO5&háÝ×@úF¯¾EèYmª"jnnB!„B†‹è\é«Év{Aîzÿ3‚§Ù¯ìpÝ ’‘º«ƒ@Ú]’}ú¬,IÕµëc!„B"Lòjü@*~K™+‰ÜUõ%tWµ'RØs‰åÓ!‹Š¥7Uí—8À–‘PUB!„áCÃC‰N“Í£ý²ŒÒx‡2~Z´8;îJôF'n鸶:ñŠ[ )ÎG©)úlÅ7!„B!ÃAP¸eDj–jtiRtáŸ;” œ 1W4`b:<ªèwÝ)ϵE9H!ÊMA!„BÈ0âÅsÔе%×%É£‹@U'"ªðk¬TrRŽˆ(j²\Õ¿“aM¶ DBè´&„B!C‡w/7‹éб²šC—r8çt|ßöÑ+S‡€ªÉqߪ곘ELj«ÐeM!„B†ï,nÖ“Z‚nVUA+€nª¥Kguz,´ðÖX²X{”QA5!„BÙñ¢8Yo­jÏñ, kÛz˜^6‡4]ÛA`CmŸoW¨Ø‹ÒK­m/O'„B!d¸hõXkô+7¨jLB‹@µ ì€íw÷°—Êði€(ÂÖAA«)òÉÅMú!„ /?¾ëîÜD!Ó /µƒöï ·`HPîx 8@ ÝÄËe´åHýÏ©N1÷´˜“Z¬Ce‰6!„¡dÿýöÍMduáo)„ /Šèm†âÝÕ¥Ü~kEÂu]\Áa?ãr¨Â $Yï!éÓÁ1^¾L¦ÑN!„BÈÐaë4àE/‚ÖõrW …êßÔhÎkíÂÔ1ÂO…9ž.äŒb:$Lˆ;h¾©!„B!C€_øQó‹I\^cWµ®ß¯4v½ø¢ÉkT!ÛDáB”ˆ×éQªåò>»H!„B†{ç‹)áøNss9—Z[{°šî1­À™ îªjØýC( €÷D h(ÅçM©l]-Y$!„B!ƒ kçsðCWœÔ–"Ö¥Ft¡Nlwko2Š€dwjQ¨¹·mÕ‡½¿Ñ'V…!%!„B!æ«§½6Y«‹Al¡HϧñØÊŽèl¶]Apöðb}trìÅ; aEµ5Ã’X!„B!ÃD“„5[}Ý5š’›ÅÙ>Öv¬€y¹ ‰BÙÊ“Š7Ú!n9¿ÊZÄUD8!„B!C‚×ÑPÛ ¯ª]¶®:¡\ë «.= &‘S•laßÞ?í7ÊT£æn¬BÈpPÿ£%yú°W |¼„µUÏZz–³øvTµ0}¬PüË^àTj\mâ¤ê£§¥x÷ÕW[@!d„ÿ¯÷üôg+V¬ØvÛm^þÒ—¼ú¸cÇÆÆòtk”·½ã¢þç.8ÿ¼£Ž|…Y~ó›ûOŸúÌöÀÖ~ÀÛËÒMR—)ñM!dá?üÑYçž¿ÝvÛ|ìŠÿûµÿöÞ‹Þ¹téÒ;¾ÿƒ<ÝZ`—wºöúâáµ×ß°ËÎ;%ñ„²fà™® ÚD÷A]Ï«`(€®Â‰õ9ˆ½]1AD|-@YZJÓõ±)e.B!ªzÙGþñÈWvæ¼SͲÓN;žzò›*‰/YrùWýè®»rМuæ¼MŸñ _ùêµ_þÊW—<¾d÷Ýw;ç¬ÓwßmWË–-»úSŸýïÞñäÒ¥Ï{îÞo9÷ì­·š“—rðA·ÜzûÏqï^{î±lÙ²[oÿö)o>ñcÿ¤Åö+ä¤SNá!ßóÓŸÝ{ß}[l¾Åyçœñ‚öpükßpá;ÞvÀþûX´èÑã_÷†o\Í&›l’TH™¦(êlïê¨z”ÞkÑÂÞœ…-õ€×Ū*â“ШÍÕâ’âÔ !6¨jû¡Ño­ §é:lB!ƒÍ$Ÿ¢ûÝïxøáG;ôeyD÷¾ïO.]úé«?võUW<²pÑû?x €|ðÊ«®~÷_½ã†ë¾rúi'ßzÛ·,ñþîÒ|è?|éW¾ôùí·ÖEïyŸkòÍ…}Ô_»îßÜtËmû<÷9[Í)õwK!7Ý|ë¼Sß|í5_:ìЗ½ÿƒ—¤_“Â$ûŸ²Ž0QÛ0Wx7¶:uÎÙ*KåEpHb© 1ï·½P1”äµýïwiªLç÷Q­.I!„2´h¸–(cÉ’%fo¹eQeþ‚ÿõ“ÿ~ë¹gm¹ÅsæÌ>ïì3îüÁ/~¬Ûév»Ý™o<::º÷³÷:cÞ)-zô;ßýÞoËܹ[ÏÜxãÓO;eþCó{ÿoóBGõŠÿøîÿû‡?\wý ¯<öèho/äÕÇ¿r¯=÷˜16öªc~|É’G/Ž×;-}ÞEY»ˆˆØ‹\Ê5!ª°¥âµrTÌ$yE9€n“\öh|FÑ«qÓÙ!»‚Dð1„2舔kÿ2D¤.ìfÍš`ѣΙ3;‹JY¸pQ§ÓÙzë­ìpÛm·°pÑ¢½öÜã½ï¾ðÊò‰'žØeç^}ü«vÝeç? à¸×¼>-aÁ#ìÜ´~ú™³f|Ð .½ì#Ë—/?ðûÿΚ½½gΚe–±±Q+W¬L“­c;6ÒEY_m]yŠ1F¦ádBUü›ƒBNg[ñzZP16ÓyÍ“5!„A¦Eùí°ý³¶Þz«›o½}ïgï•Ç%Ì™3»×ë=²p¡-Õxè¡ùæÌž àE‡ü¢Cvª·ÞzûÙçžÿµk¾¸ÕVs ‘ë¿öåM7Ý4+§‘W{ôYçžƼSÒFNµ£c£+V®°ðãK–T#×:-LYïHÕé`aUøm­ƒ@"¬-‹4wáÝåû^Ôù, À)z¶Ú#¬'QhYœÚ»cÌ@!dhWrÛ.øDäüóÎùú7¾ùñ«?õàƒ-_±âþßþîêO}ö[ßþNšl›¹s÷yÞs?üÑ+/~láÂE¹üʃ|Á[lþ£ßõ‰O~桇æ÷ÆÇs+V®Tç¶š3çE/:äƒÿ<øàò+~qï}½ç}«V­J LyÞsŸóÛo:ᵯNS-Àn»îrã7?ùä“?²ðªOø' ×%±«[:ÅBÖñ݈ªêBQò©x‰ìàBÀ°ÿUD½ÇÚ+tµ€H©Ä­´¨â-J¡€Ý÷¼ù !dh°ÉÜäÍêYl£¤;èÀ.ÿÈ?|îŸÿeÞ™ç®X¹rÛm·9ôe/yá!eÉÞ÷ž‹.¿òªOž'‚_pÀÙgœ`Ÿ}žwß/õ¶w^ô裋ŸµÝ¶ï{ÏEm´€‹ÞyÁg?÷ù·¿ã]=þøÎ;íøç¯?add$+pB¦ZȼSßüÁ‹ÿá¸×¼~î6s_uìÑ?úñÝyеC¿ŽöÆXBȺDUMÖš´öFh*u͵l+:Ì̆¨ÊV/ý…7ØÂl¨_äa…¥3BzóK×>7€Í}p÷½÷YöÔÒeO-½îË_ˆvã˜Û—_ÿ’™qò,^¼xǶϭ„Bª¤¢Ù;]¢÷ž4œºÝ9×ëõœsããã½^¯×ëýö÷ì¿ß¾1;yšüø®»wÜþYN§Óét»Ý¢(:NQ"R…¢¼®ëljnBÖ/¾~q]‚žpâ©><Ų§þüá³L•ZZÍ÷äq@!Ékyº€ÂþÙû¿ðªà=!EDQHÜËBȰ }œÖ™…<}{µÑHYoTKÿ´ªBl´æI®M˜5ù«@×^ØèèPhxí$ªfè IDAT à €@Ô–¨(‚B…³ !„ ¦ªSÿhQÎñ9™µ…ˆEaì“2¨:@Uƒô žh„Ç +”žm¨-1ÝuÎR ìð¡Én|I„%–×*Q¨D¥€XB!ëŸ~ÞèFcúI©·6ˆÛ¢§'o$„¬ œsªNÄÖlÑDsJu­ˆýT˜ t /Å}¢xÛÝo…úUÔšV`·» U16!„$UÕQÞ™%UÕæU%k–l!µÍÓ(BȺÇy±ÆgU ŠÂÄ®˜à-E¶wh«éd„O{AŒéÝئ}‰½üû %òi€ùº­„B©*l›ùm…ÝÚ#ö³…©§ DÄ‹j/š³[S¢x†ªy©èªja @Ô²jØhOBa¾")BqÁ·¡fôG„B†…¢(z½ži>.³^HØA[B¯•PQ(T!þACÀ–¦’Áb>íF]ÜÒQŸ;UñÚbZÌ;]–ª!ƒPUBÈ’¹¨-½¤Þ{‹¢˜9sãÇ?¶ù››…<]¼xæÌ™QL[?§Ÿ²0!d¡É㜙¦1A<ÛAßníhƒOQ¹ÿƒ]â,l($„ !„ ©žn$n""’¬®Þn›mxhþý¿û]%5Y-6™9s»mæš»º+­³ïGøž%„¬ R¡,j¯cLl’ܘ¥šL €®_…Ú#Õ;9ñs„ü ¤þoªésB!ƒ„$îêLs§‚À¶s·ÖäÝ1ö*™^¯gFË’ûm’Ï ë™ô3 ˜hît:V}Ä·ÀX²ˆ/.P/в^ÐðØ¢&o€¸Ú‡‚Ý(`ï‰l)ˆ%´h’ªét¶t= ~‰·ˆ•'±B!ƒIüˆ:Ï\׿@UÕˆé-‹}šÈ®‹é XR§XeŸ"b:~F2c<4Ò2 !ë›R'Óš—̆ó»R‡XÑxûÚJ]f;P[q’ªõô¶÷F‰ÕðŠ™ìM„B€Ê|žX¢=а>!¦7-÷ Ñ ­cšô3Ë»a _ gŸ¦•DõlÆTRgE¥%¤Ô-„uCp!צ/˜ÑSKPA»•Ù¼ÊNgÕx ߣöá"ZÛ˜„BÈ!U…m0†M@› Œ‚Ûd´Åšª¶€¥‰¥M+am ÛgÔÓF”ÔÙgJ,3-–²¾pAêDZw«ó¢‘Lo‰»:!ÖMÑ^cÇpœjë T•Ï/BÈ`"é³1‰»:~FUEsü´€ª¦~ëhχÃK?œ¬EÄ%µÒ,i9Y˜²ŽqªÊÖÑ T'³4äQ£* ]ŸTrŠØtÚ T!”ªšB©­‰Æe‚Ïs£OÚbUÕÂ@Øñ:–_¯¨n:êJ7Z,PT_øbhÌ$µ¥‰ò:S„µˆÀ¤r²6#Äò -N¡Ù\×ê8w´†X –î`‡Ù-!„a!Î禞ÍÃNGƒÎ%µ¢ÑŠÊ¾ZZŒÃB£´Í4±¢>ŽÔ9*éÔnBÈ€ ª…ý3S¹â%o˜ñìG21Y¬]UÙ=®‰û9ÜÿÎæhLËû$‡z%„ ©­‰ì3êiÑcݨª³Ï4ÐH{ìÒ®zcl*‘ãg ¤Îl3fª:ýLY˜²nppP•øNq½~1€B%¨íúÌ&€µ³=¬Í."¡ûK_¸í!e}¥ò˜fQ ð J´ˆ376!„§EC£ªüD¨#vÅ„ !뉆;‡´Q»¦«7z,ÅbÄŒ>ƒĬ ÅBŸ%û~4ÊÁ–ôÓÆ>iaªé !ë–8¡¥bºrÛö™ô• tU{’>~hNhq! ¯žCÑj+C’ ᣓ´ƒBÈÑîÀ®C¥8ØK„ 6ïÙ¹FïuŽŸ*E ›[£#ÂÍ…rù# T¼“ÿC!!„a!Ó‚œÞ§•4!ÉèÞ nÓ¢µ—–{ºe#:¯Õÿ X¸e¾ÐÖXB!CI?¥8Íw¿n!„ #ÉË“Akº×w¸®Ò}H˰ˆ- ‰òZríµH™‰BÈt€Ê’²aZ©Ò9 â°™RÃäç³tUýºÀ?—XËG*ä@²*[ª±„B!„ &¬E5}Ô0*Û°]‡O·ñ,q×D±©cËPæJÓ–ë°5&:Û'%„B!d¸p^XÿZQ py«>A8²C±0§¶ Û.‰MD×þÞW–’^vB!„2Li›¸¢|Ò µu"€]E/M¶Ø³¤ÊÔ Ñè®–†XB!„B†€¯ñdv )‚ªvP4ì õníxœÈåšGZáWœPRB!„¡'ìçQ“½"ˆ<ÐUUAX:-¾Œ´<T5êñ‰¤î—„B!„AÅüÍñ=/t±oê€[œ-€@Ô¶ÛK|Î~ñµªj&¹Íž¤i‚ ¬ !„BÈð¢ÞK, a[Y*ꆰªªhN ‹½xVñK·M¾[¦¯ß^ ¨S*kB!„2„D™ÊrèŠ9 ИNî iδÄða(`Ú½ˆžìR¯B!„2„äÚŽDCÈöö¨Èâ2ì@Wµvÿˆf¯–C.¨ø­³ R^ ZH™žB!„a"×ÖаÔ9M¤€ÂA*±Wš+Ð$”&bÉ*å”…¨ªƒú8å[b!„BÈ¢ªUÍìÁ³œÙ|”-êè&@Â$²?RÄW7æ/\,•µ˜¿è°&„B!CˆJ¯ºHdyüÜ>Y7Êb }%º o“тҭ°¥ €êî|„B!„ QËz_rÕ=BJ*Y»I"ÿ~™,—czi5 î£Ä~F‰ß\%!„B!Š 5sã ÅVl4`Ú×ûšmµ×Åzꎎj[„m©T}À<Ú}j$„B!dP1w´«­”ë5jš9†T®ªmú/Öý‚ë…ˆØS±¨ŠÿDc¶=òH!„BÈàc»ÝÁëfÔ$pÔÉÐ2lâ7ª^-Tp‚nºæZi~@íI¿À:&ñá€Ú‡ú,û&„B!dPQ yìP«¾âR*÷ûôêYÑM"Èpü¼[]+ ɶ~â³i’‘B!„a!ÕÊR”ÎæTâVÂq‰ˆýðk¬¢P…J²Kuxu¹ÀËp§*±Äþ-Ž>=Õ„B!dƒ"HbUˆÂ–`K‹+¹kš:I¢¦›òÅ(œh¡åßÔ/é !„BÙP(®* ÓÀm²· §ˆ9ý‡Ï`?š b뺳çcô[B!„!Ã…‘ j]Tƪá-Š ÑÏlt£®ˆb+=¸©+ïIoϾ-|§9!„BÙÐè8~G­Jã¸+HU=W±‡3£ˆÔÔxž†B!„'}-Œu“\ìœ&²]ArDи›u›ÉtB!„B†ŠwØdð¤Tu&„»å›Ìƒç3ŠIjqPxymYzØ&ê7Q‹&„B!d˜òÖ¤lãKÍ=¶0$9ª„ýR¯ˆÓÕ >™F TRú |ë"!„BFLŪÿçås}‘sTÃ5“…ýR-½ÍR¨¢ I¼Ûkϰ—=Z0Õì„B!„ ¶ã‡3ﱸ¹7Ú§ ¦x”Hèð‚; 29`rYÕ2Hü€&+QbiTÕ„B!dø*6UÏ^§ö†åÕúº 'XzÿQ +iÐã ¨–ÛôÅÊâ'!„B!Ë€h²ËGUåz‰œ `5­¦•]Ø€SK¨~˽êhD%>£hÅUÂTØ„B!d(q~ﻪ Õôí‡QøÚFÕ¶Eµ¶É‡³ØDXb¯G‡±NÍ™M!„BÈpÓ,|ËÐ)¥k¹Ü†/¤ëªö¢Ï;& ºOˆ'?NVŽp™5!„BFêÞê*¦rý–{Qþ*àŸz xuÅ©Ç[¦â¡îçä&„B!dÀiW½áÕŒ•WÈÔ±DJÇsŠÖÈS@ÃÑ‘ú2Ö‘ÛŒçVB!„BÖßx`ÅŒNƒÐMqp=ôzp=h½z=hÏ{=8uP…Š¢&€Ë°y¬'Ä‘&m푉|è>uÈØÉß_ñÑŸ¯¶¶ž‰Ÿ,Îm„B!„ôaF!Ÿþ£±ÜšS±U‹(`»èµ¹¬»Ðâ +ÀB¡­’»dÓQ|ùO&<1B!„BÖ=šˆâTÚ:¯tŠ^0*lÛ¨ à€nî÷…¨"î;b&wK[8V–… !„B&œ*&-d…¯»©«ÙvöÀÞ©è}ÝöNoV_ˆ¨BT+aB!„B† œÊ@ÂÔF‘:³M—o’A¹-_·"»UR<'QiØÒ(…K´8!„B!Ã…)[ñz7z“`Nv©:“K œkŸD‰ïb¼F ]f !‘X!„B!ÃGв^½¬¥Nônb-5p×ÇTˆ;]W"4ä¥ “z¾‘B!„%WÃͦ&RyÜUUAÈωBoG,í¤ö!„B!d©IÙš;¹™ªîšÁžST„•Òþ¥‹éÆâk „B!d¨ð«5RÙ«éω±”¶ÆÚDsZ˜SZ€8@b¤ù¨5d+#&ÁÊ•+þ‹{—/_žGéÁØØØÛo·Ùf³Š¢aù‡Ç4‡Ãƒ´ÃBZàð -´£¦¨}xòX®ú›SÁnúé¢l Õ2ˆÿ×ÊÏï½oÛí¶™³åì<‚L-Zô»ÜQdÖ¬gæqÓÒGiôÐ>< S¶uÿôüÇ€B@üÆ}ˆáºZ@ª¢Â&º'Yë²§–qXOgfÏž½|ÙŠåËWä8<¦=¤ŽÒ‡i¡}x ¨ø×¸Lì*NÐ*åË~qµy¨›ÂÓàfÊÞVƒèä¢Êǧ;-c %ŠLZÆ@K™>´ ƒ–(2Mh-Qdš0ÑPÿD¿J!ÞÔ¢ÒŽÅŠBýv{+ @[ÀRÏuÒ¦Šz›B!„aÄdrPÃ>l?TÂ{Èëa TÌ’¾ FÊb* Èõþ(¼ÊN›B!„BÈp༰F)ŒÕ^€h¦R ÷ [F{x¨Šâc&¡ÁÉô¦e ´D‘iBËh‰"Ó‡–aÐE¦ -c %ŠL&3²4¨ªˆ÷J—ÖÖp×o¬—DšlÍDA?:ѲÁÓ28ìЗå¡ ñðìwñþ6‰ßpi-QƒÁÀŽœ+>ú¡$É0Ó2Z¢žxÕÆÆF·Ùf›?{í«_ú’牪üê׿ÙkÏ=fΜ™GLsZ†AKÔú ñVMâ×$é Ð2{lø´Œ–¨f}éL &=Ò„Q$§+7œÉ_Ãåß™¨è Lq w©•«Æˆ&õ¦á ™|ʵËÎ;ítý _#õú¾±óN;Í_° šjírÜ«Ž=sÞ©¹uçe ´D 9k™–1Ð5ØU[±bÅ7¾yóß]rÙÎ;ï¼ÓŽ;䉖.}jdd$·’¶aе~Ø oÕuÄ]wÿÀ~ûî39{Ëh‰háKg`é3 úÙ'7ªj7æ”ôðº¸R^|oŒßÇZ¤Ì^†%yýLu¯‘XXZê¤Z<‹QÅApÛ·¾ýó_Ü»ç»/[¶üöoû¤ÿòŸüŒ5oÉ’%W^uõïþ/yÁûqÚ)ÏxÆ3œð†7^ð¶·ì·ïó,zôÑ?ûó¯ýÊ—6Ùdæigœ}ðAýìþç¾û~¹ù曟uƼöß÷ý÷÷÷ýòW—\öáK.ûð^{îqùG.ËÚPÿ{}¿z(|âÇ{ì²\~Ï=?Ýrö–Ç}dŒZ¶lù§?û¹ï}ÿûK—>õœ½Ÿ}ÎY§o5g€ÓÎ8û _ðÓŸýÏ/õ«·ž{΋ÿô“ ŽA- ìÈ9û¼ó_qø¡GîgÞ8ZúŠ!eÀ‡G ñªŽŽ{ô‘W^õ‰ßÜÿŽ;l>×è¢÷¼ï?üO7|ýÆ7üÙëÞôÆ¿Ènäƒ:°ž À×®»þš¯^÷ø’%»íºË™§Ÿ¶Û®»X~ÿÀƒç_pa:Ì’Öm8 Ôi¼UíÊŠÈVsæ¼âð—¿þ„׉ȵ×ßpãM7üŸþÑÒ<üð#ñ¦“ÿù³ŸÜz«­úM)Ùxøêµ×Ù PŸ=ú•CõãWò´SNÞ7Iwßý3NéŠO)ñ€0á—N¿ëÛøå‚þ_FÕj‡‡57<hÂ5Äîèô°êÃŽiE¼û@ãR¼`T_˜¶‹ng²éÖ>EQùŠÃ¯¿áën½íöç>gï9³gÇØ¿ùÀÅK—.ýÄ•—ìò,ZôèÅ—T”M#·ÜvÛÉ'øo_üüË_ö’‹/½LUßuá;vßm×·ŸÞ­ß¼!ÓFý˜L½ûÁ¿ýÜg®~ÿûÞsÓ-·Eûß_zÙCóçè’‹ÿõŸ?³ý³¶{ïû>¯Ë7oºåÍozãu×|yTuËh‰säô£eT &-k‰"V¬XqÝõ7ˆÈ»íf–Ækô¿yï±GuÔ¯¸õ›7¼éa)Ó¹1׃=ôñ«?ýÎ ÎÿÚ¿ýëi§œô­oÿ¿Xo}˜Å¨á¢¥Ý-QƒÃþæ½·~󆛾~Ý_¿ç¯n¾å6»F/}ÉŸþþ÷üú׿±47Ýrëó÷yÞÖ[m…Ö)¥qb¯ÏS*ƒÆ¾ûîsÚ)'üêOÞ}÷OÌeSª¥Œ–1Ð5à´é4^_‹Ú`îúÖÔðhBÃÿLÈÝÌØ l\ÈçJ‹a Ï<6öDÍž(~]rä+ûÞwþáø÷¯ã˜£ŽŒö þï{~zöY§o±Åæ³goyÖé§ýà?ôØc%Y8î•Çî¹ÇîcccÇ}ä’%KO”ÀW¯½þe‡eÿïŽ;'Sïü îùéÏÎ=ëôY³fm3wî)'höE>úÝ;¾þyçl½õVo¼ñ©'Ÿ4Á‚ßþîw{ì1Gíý콊¢ŬWZÆ@KÔ 1h#'´Š¥e ´D vÕŽ<öø«®þÔß¼÷]Ûn» ¦xâÜ/W·Óív»3gn<::º×ž{žzòI1ïj ³¥e´D­'úݪEQìºË.¯<öè;îü€gl²É 9ø›7ß @Uo¾å¶Ã}9&šR&3±¯ÆP@RñÔ"›€Ö1Ð5ðôûÒéw}-vùë[Y3㯃=H¡"Q g…©*Âÿå›'ÇÔÚUcâ{ ª›m¶Ùìÿ¡^¾|ùŠý÷Û÷?ü‘Ù.ZÔét¶š3Çš:wîÖY¸è™Ï|¦%0»ÿ40k³MÍ2:2`Åò!OYçU¯<æŒÓN‰‡ÿ}ÏOûÕ«êËY´èÑ3fl¶Ùf>ÍÖ[PÕ ðº7üe, ÀÃ?²ã;(0göì~mX´´Ä÷Ù £ƒ7r|A!} ·ŒŠÔ2`4Ÿ2€¡-ØU{â‰'>zÅ•Ÿûü¿°ÿ~EQ´\#ÿçÂpÊšÜÈýr|нóí¿úÓOüïÿî¼ÓŽÇ{ÌÎ;ïdy‡Yš}xhiöÀú­úÿøî¿~éß|hþòåËìý콬͇½ü¥_zÙ©'¿éžŸþìÉ¥K_ô¢C´uJIÇ’»ÖA!<Õ¡2°<ÿùÏ;õ”7ÿã?] àì3OþóŸ×çZ7“Dûéô»¾öÕßï®Wõ]̰öLdM  tHÓ` _¨ÅgeÅLš¾Ò|rLЬáâ裎xëÛßyêÉ'¥¯Ò™={Ë^¯·pá¢9sf˜?€9³·0:6ºråJK¶dÉ1K?Šþ×§NK½‘-·ÜbùòåK–<1kÖf<ü°Ù·š3GD¾òÅ/lº©_“2•VI1P#§í£‚¬6Ûl³·žwÎ_¾é”oºùÈW>¥kEK®ƒ:ðàƒTÕÛ¿õí·¼ý_þ—ÏeiÈúâñÇ—|àâKßó® ÷}þ>͘ñµë®ÿÖ·ÿâØ¿Ñ‘Ñ;ðÃïÞqç‹ÿäÿŒŽ¢uJAÿ‰==6¤¡²ïó÷¹ðo0¸ËÁ×&_:-×·Sý2ÖÈðPí‰HU“§ým¿‡$Ë©S5P(œýú¢ªIØ©†0œª÷¯yC5DüðñÜçì}Ëÿþšã_•çn½õsŸóœË¯üØc=¶hÑ£ÿtÕ'<`ÿÍ7ßÀ®;ïüÍ›o}réÒG.üä§?›æjdóÍ7ÿÍý÷÷z½<¢‰–z#ÛÌ»÷³÷ºüÊ«žxâ‰?ü©Ïü_³Ï™3û…té‡>üàC­X±âÞû~ù±… IDAT×óU«V¥yÉd FN?8*“MfÎ|Íñ¯ú—/~y|||õ®Q¿\?¾ë¿>ýÙÏÍŸ¿`||¼çÜÊ•+½Ç€ +W®TÕ™o<Òíþü÷^óµëb”ˆ¼üe/ùÚuÿþÝïÝqØ¡/7cË”ÒB:{l`Ce·]wy:²i¨iüÒéw}Ó4Sý2"ÖÀð° ó  dˆÿ׆í @’%ÔQŽ[Àþï»KhÜf¤ …÷´µ–Øy(€‹.|ûUŸøä©§Ÿ ‘ößwÞ©þÙÒ7ŸôÆK?ôÑÞðƹ[o}ôQGÜu÷ùß.`¿_”%˜ýµ¯>îC½üÚëoØm×]þñÃÿV†(5ô«7om»àýâ/ÞtÊì-·<æè#~qï}V×o{Ëçÿå‹õ®¿~|É’wØþ„×½¦Ûí†ÆÔOv½ÑÒŽ-Ô¹þGN:BÒp˨LZZ6,ã/ÉU;ö裮ùêµß¼é–#8¼ï5 kA’ÊÃÆ\Ï{îÞ¿úõ¯/|÷{?ºxÛí¶}×…̘1fY‡Y,yˆhiô Žj?Ï™3ûä“NüàÅ—þáÉ'wÛu—?zá!ÿóó_ć¾ü¥ÿú¥Ûa‡í÷Ø}·hì7¥ :Ò»>›=¦:T†š–Äá1ij-÷w1úLGHüTÕ–/£ ž ORE€êvxMò©<!‰€2ºÝ1¾ôÙÇÚ‡Ê÷¿”ÖZx—-Ü}ï}–=µtÙSK¯ûòBŒç»ß»ãàƒÌŒdZqç~¸ËÎ;Í;7àð d"8BH ¤…Æáq‰§XøðüËžÚöv ‰.÷¦ŽÂ¹ ¤›…tÍVÞ^®KEßW|Òý„B!„ Doü¡P¿Èº|õx1' öwá˜Yü?B!„B6dæQŽk1PUó2Kúh…¥@×W¿ÆoM¢hX­B¦-—ŸÃƒ´\~ŽÒJËåçð S¾üUûP¯¦ƒ0N÷ ±”kt±.‡Úº¬‹ &-c %ŠLZÆ@K™>´ ƒ–(2Mh-Qdš0шþdŸ.„%lî!€Àù5ÿ´·§û_v¹ÚƒB!„LkLDç¨m bê¹!¾‚CÃëÀÄÙW‹~ÕÒ ‡i‡#„´ÀáA&"qL÷¡Uµ·KÄh;(|È/黯Z5< ¹æà &-c %ŠLZÆ@K™>´ ƒ–(2Mh-Qdš0ñÈ5¯k°ðEùòl7jñÐU8øøR©î¨€BlÑIaq†•g‡ix&>-²¡Ó2Z¢È4¡e ´D‘éCË0h‰"Ó„–1ÐE¦ “–Èþº¡RÝv:"ZnA­ÐàU°À]HRYn"ÖfIÃíÌØhlá¢E³·Ü2 ÓƒE>ºÑF3úý%„ÃcšÃáAÚá!-pxÚ‡‡¡ê &ªE‘ï\-"~5‘}( ~Õ´Sˆíʧ¢PÛ$¬<ÒÃ〸çžóÕ@ñæ/Ãíì¶Ëοúõý¿ùÍýy™l4cÆvÛm;cÆX€ÃcÚÃáAÚá!-pxÚ‡‡ElôSkp«jº@:¦T[„í·Xò¾k¬TE¶jE¾W¢’p›m6k·]w^¾|Ÿ!˜žˆÈŒc›nºY€ÃcÚÃáAÚá!-pxÚ‡‡ÇüÃÙ[Ç!æT.½Ýu­1¨:‘°îG¬tjòº(ŠY³ž™[ ÀáAZáð íp„8<È„(4[*¢Î¤2åt‰Ù…óªZUÝDO¬ŒJ&„B!dÈ©ýA£½¶¤–€š~öËB ÝøÖó†Ä5ú½ä¼}=8!„B!KPÆ%Í´u%2qH )Ì’¾ ¦Y4O†¸l›B!„á#®ïG©²Met¦˜Ó|ݰ}õÓdõE9!„B!ë@2UlÞç–u^dK™½Û¤‰£OEyŸB½³:Ýhã™'œxjf$„B!dЈ«KEë ZS³Çä~ˆ½yˆzÜ¿L¦ôj×·©Nå¶GóZ !„B TÂGbÑRsçû†$‡K_ßn/åñ0µgÒ:•ܸÿW™…B!„õγvÚ59JÔlî*ÎŽ£¯Ùï]í­Ra]ŠQ*~è2£úC$Ù^Uß÷³Ÿ„”„B!„ "Uÿ¯BL*#è[$êWƒRö»˜FmItÝcŽïÜ íKkÿrAË[m¢ ÷×fÚۆ¯M*ÍRœ4Xó_"¬§)·WÕóS¨Ší.jé­Ÿx“§¡í@böÞt’Eèi.&žcrP&»0"@Ø&;… cµ£©jëEK,vâ …¥0ªW¢‚X[¡Ù ï}áþr‡8;`øFd™)«Ìª¶ìuKÕ¨f·&ùÎøk“õ°u}s±YÝf€4d¬[¯c¬ÑZÒü²B›f…˜Y¡(lT”רz±úaGÒû\$C®­y9 MõÛ‚è×*…oD†T*µfäMjê|+*­Ñ2Ø X¯Ñª‹ww3V7:2úeLkW¨ cóZ°6í¹‹8ÑO‰JoBM¿\¬Îì˜1™[ª¥TQ1FC!y--…x,q µ"ʯµŸiŠzYM5[ª¦˜HC¡jGâo+vPÀôIµ©bwÐ÷{06Ãg ½Žêaß_cÚ [b)¿‰k­*ÄLÍÑ`2!Éê¿j'*Dó‡ºò²¶© k³z`çh…Y©My‚=‰óÝfÚ_X[ŽxŽkkJ,±á–Ïû¢ŽOç”D„:b'ÇoB¡¢&©úVfÙ¬À4l‡­¤ç¨@e/ñZ–¸†ïy-ÃþÐJöíò“NY,•vÁ7KS[+#ØFeË5*€0JZ.ÚÔR !%Bó¦B­ âcŸ\š‰æò+Ã\ÒzB§ýÆ’%=£XK†‰»lì6(Ôþ°dY¢oÂc}<4È.[S2?"sbªT $=ÔPí%ç~%¨Ñt¹Ëެ̩öQË…šŸÚ_É%çè{>`æÊ9ùÄŠ†3ÊÐГ5²œIQዱ~Ž}¾p|Þ¤¹¢6±Zäg]½âÍ#«iTäåLñîÌܬˆÆÉоØëé{¢ìüô Äw|Œ™ d±Ñ‘šÖ¼ò+¼r±4ËÛœª™¦Þ^óX’¶³_µm·ÚiÐXTZ|:ÁVªmB€) °z3, H|ã`lPį¡~«…Ô¨XÃMššâø7o‡ªTVÿ/$TûY Œ¶n÷(üœ¨âϨ”×Qjíšn¥qiæØÖ!!m{¿NÈN±‘˜ ±ÀðM;a1Àêwgý»@­eVâÄ ™ÌI{&J§6ذñíÍe6…ØÍKÊ›I3jsËcýi¥þ8ËžY2œýB^]NÓܧé±Ú±%l ¥Æ5BÙ-O£&k}z!¬™½• ª·¦¢OºXK<£Æ»Ê3\¿†õ³g¤…´\B[Ÿä» l:Fr\¸m­äæD}°ô…ªý¾aS{¬L!ö§¶¬{ÒY"V×ЃUhMÕ…<6ŠåÖL¡7ZM…ZO4S¹“̳æ°Ú³:§4*& OY±·“4&­wGc² uƒU'€”ã?Õ1‚¾¿Å!ý“GÃøndr©PöÃÚ¥¹Š~ wwSdjk 'ÆÊeh*lõi¬@h|ÍÞt®ý ™€¾‰P?úC±žz¾µ %Æ‘QñIÌb…küµÌ<ˆ}°Â¤ž"}óbÚÒ~4¤¨” žš+€Æßš€T~-‰€Š÷…X² ÿ_M­ ýÈÓåÇ‘ªÓ±– @/·eMUûÅÒ´e™ بßi ¤¿÷* Ík¬Hý¾Mÿ²¤@hBz•2ÐÌ©ìsäe€õ~µµ½¬+Êó…š%¯ZDªrAàËN‰Ç¾KE€ôS¾b ÿG{Ý—Üøü€†ÓKÃÖ˜ÂæÃ²´²Ô’p7W¤€jyû;A!æUÊNÙH²¹ƒ@ƒ%=*»,VV!X5Ê~DS-vŠX)¤•-¾µ›9sˆÖ+³3BY¾ï¼§fõêÛA~Ôð,‹óÁôÜB½ùŠÀ7Å!\³Úü¦ ?55a¿ äÖˆ³]xoñÅWOU]râN{%iÁåë†ÊV—´{&ìªô•JÖk©9k©Øµ:¹­/õs¬[*”ކ2¡™²Œ  œ?íÏ}j¿:)ï~EtCæ–‡ª8ïLõ¾qœ–ôxñé¢{Æ,¬TˆùŽÂ ä³'ÂêôÁÉ«*™¬qâÿ䢰‘#ÐЗåDä༳ 'aÃÌn”)Î`ª#&†[»£ž@Ü'§ZcR³ÂçðÙBxB0OjÄιzßY|CØz/íI q0û¢Ó©@ã±CSEì+YÂ%!W–ÄÂê÷ ˆ{tØ äó䑞²·Ä§1›zÏìÖS¥h®âgI íJkÃL¡ªAh…(?hð{$ˆ@÷µu‡©óHè‚2  SÌܱéS|ëýýD¤çNß÷ƒŸ›ƒ¬ü%ЇV™Æk»¬<)ßõ „ë‘KÕz8¹6–5¶"–äk¬c8i²™¤©y±;¡Z3ÐÐ WI -ëO 5¦–Z1¥Éh+UblSŽˆohÞÞô·¹¬ô*e‡Â²Èj P»+ü¡MJ­çÜØ˜Z_ei²U©×ˆ¾çÕœ:³¥- á¼v\Z­ˆ*8¬Qù2RhRIißÐhQöSü9X élù'$QN9¢§Je0ôë©vbùŽê[HèÈ<ÜBUí[ŽÂª2ÒÊ'b ^™>X Ö®õÙDµ8»ö†o3ÝóËQ9dž_‹C¸_”"I^ ûÌ,>c¥U*ÂàóÍö1eq!#Òû"–¦YÆ A%¦"*òû‘ÑÓßîdKø#–ËNÖpY3Œ(õJÔ÷„ b©Q:eáÕ‹kß>Þ¥‘âû¦JâJøÙ£~婪 Ù¬yUÞ™Ø655¬­¢@܈7µÚïÒ‘©êüYùTé°Ï3V©lÛ øb¼PU34o猆.,Qˆ6ûL°dµÄÕòKËç KÖòõ¡°«U”˜²_¸B^_j;ëN¾ ðßD¸é½Q»‚ áªe÷wý>²"²æI°;¿"½z Öó¾;ÓïÃZ¸NË9N•Õ+GÊÎé‹3Ù¢€ÀÁ Ķcrpf·9«@­çñ½U~ ÌÒŽïË5J}ä4öj¼jjãp*T¿Iýý„\ ,­¾›C±ï’„HÕŸk~ñ¬0 ’<ŸØësާÏÈ7±œN Í%øœSèAy†õ2 b?¡€văå[š’ÇâÒ>¬‡3#4[ø›Òçš4~Ô“ÒØŒ,œR?‘,é’)¢_/UKë—j2¬~^Ë™wÈÓ)±Šï?ìAz›š~ËJê§I j'Ñçœü5öÁšvC߯†o`¬ÕàïÕj¤ ¸íRÕT­%V-ÖĬ—*r (Ì¡£Ð.$î^a)ʰ×Þÿ¿¶kKn$Ç ÍüÌÞacïIa>o%¹›á¶Y $ÀG±(µ$Šüb›°ÌËK…@ì€5¨Œ2'N¢Olt(X…ß—éˆÍQêHekX¡@ò©Nc âHá#߈£€ú‡(ó¡Ê~ECOzàߔ㲕UáToX’8iÛzÇggÕÙí~bë!ÞFãkbÍó'ÎZNƒxWVp³!;Ø ±Oëh™,‘ÌyäÏíÕhgU]‰ÊþÕ”E«ªH*¥Ç:e¬gî°OC$ó¯áP¼ÞaîX–c ò›ö¬•Ra•\¡xädqi7©ˆmFNX.¾ íT³‰ÛÖ§‚va"5‚9»ñB–[¼§n!UæíP8ÍÔŠ·¼-ÛO­C…¨vâŽpFå?b)™ìðÍeŽû¬zT5–4ó8îs<¨à€ÀcÎê·ÉÈÛ΀þ £>ÃnC÷ˆš„,ÇÆ€¿^p‹å‚4©v,fy)üºfgê,|A³&èá|ÎRðÑã€7Êr;¦—îq;΄캉È= á€Â»áàö>Œ?bÙúê†æ§ –GúFéÞ  (ò3/®± ( žÔHÖ;¾6°—Oþk~8ÒǼÂ&µh,q m+³¾€xÈ´¥'/ +ªj1¦Ð"¶‹#_ŠÝeSUØç‡@oÁ_¯ÿüO‚ 0ÊZ.¢sçwÇC%«N¬=_˜ÜqW¾Ö‚K¬^ ¥¨J†A bè)¯LÜ•˜𤖂‚6æ–IÌŠym˜œO},@É¥(ËRÊq )çF tSSÀOø$ÃeÍÔÅn^´d­#'å%û u„³J‘&™Ç.5ÄŽ€‡‘Û¡BÓvHÜc/KpÕž-ÑÜ„Ô}£róéù¬[%À.šXAjÔðYÅUrÅ8 Pˆ¹ãRÎåû ¾#oE¿…FhSHta\1ZEYïRZ©£Gç¦Pk¸IÆ=WÖÒºÃéµ:>Zh.›e^ÒQ %‡ãJÜɤŒ\K¸{çVɤ>­‹Afê•ö)Rƒí jÛ[á„Èx…ž$š'5” Éó¿XI6»lû?Äó :(Ƙd$ø˜ )8BiÔ{vŒÍh5§ùîÖ VlR.y>j¯©^ý`@üýõk¸Vðý²TÄôRYàÃ/¹(^q·Ùm‰y››ÝY¬-&Ž ¢Åày§ûsÅXú.¸n:øêvkJbÿÔ/ܬ–òÆ'dC-Æûn,½47>í=–z] ]ÙV˜@0lÙ˜dd„…s7ñöM¿ê/âdm£ ò¶(Ôr”úŒ€ÜL–7½Dõ2 ?ˆ€~ãî†:Bª *Ò©ü¹Ÿ EO»ãæÃnË’"e¹y+øQþ:þ¶Ÿ l‹’}VG(X¾àcF€²ŠÆzxÃö´%üÂêöáçÙ…¾Ñ”¬þ}Ï&hO=ž \ö¿Ã9:úìÚØ:Ä®ì¸nT O8>ͱ4·ýªà¤Nä:fœšw>jÿL#-·`—CnžDÑ,®Àâz÷’§¤÷Wá¥bŠvåÀÔ®Ív6/r¶Ù½+ ©|ñÈŶ¦Ã6~§oƒòä¬ËJ9=GS}¸ìÉÉ*“v­.ªš#õ(É7 #ÃŽª‰¾ç.úýÆFÁÆC^s[tÞéq1‹e­Ù+¯nÚ8¸âS ǼȈî]Y$æ}W}À0.¨ó úM«+gÈŠlø‘ÃMrþήv'‡V1æCà… šœ+³jëÞoÛ´Šÿ»q—t6?Y*Ϙc§ãû·¨Wô¸eJ‡Æö'jÏ¡|F¾«¬ú/å»ãÓÒÁâæ¨æ†Úoc\˜öhUĺþˆ¯Œõœ~6º0š<]ÞÒ·‰aFo4¬jººhœL¡…]þGAܬ›«i<³U§&ØðÍÆÚ]–ç9?@× ÀÞ˜4?¤Zºü¨³L&ZúOLδÓÅ\¾ž‡´Ž®roàuôXDÍ.Ç•Å#—Ê §¦Æ—@ˆ|É"Œ `¦©E§à‰óÍú™œ[vÌËÑ5/#Âk.@þÞ,ˆu†’ ñ¯Õ$™áqRr3èÁož!qïó8sÀR4Ôøs7ì<ª_/,@Ò«áÔsʽ±R³nXgPP/W˜i>²»IDAT Ác¢TfïŠB!þþmÐÁ`úI­óïTO3‚fSs¡ä¡ €ðx¤p(G°*Œ0‚ò²/éÛ`¢ûÖhhC+¬|G ê¢7ĕ֥ůŽÅ›–0ŽåÛä„Ìd—B¡\ Z ¥Âz‡œéµ0bÐÕö,³¥ «>{p²ªóH§ÒŸæ÷pºaäûê:ñQá–Ç3Ê,¨ê£—YæË)Ýâ…ã4øœ+€]À’¶;ìa4ä3]“’¶ý|0áõx·*…€øO“Ö¤ñW&u]5QÙ‚™IICqI°Y~óâ\pÉà„C@JgwSL(ì?d3Š(  ~Œ#ŠÑ÷Þ¦½;×£¦Ó”ÌÕ·°3³ž™a¦Œ€±­q ˆžŽÀ6Þ]õÖo¿yÀIا.ˆˆ;ðÃL±_1ç†*¢÷ëh„FßòðâC€ø–ä·©ð·öî$àóÒ²Á‚p3fCOv‡øwtºÜCë\#»y9¬Û»G˜K~Ä*áA+l. ½•ÿM_š\Y`Û ”ˆ “7µ=©Ä‰@„ŽF»D®§,uðZÙ@RòŒÑ_X)5-~ –(åÇ Ñ¿B_V€Ó±êD'§À1eïü)9‚;вMŸjÅØIAwWûp÷'"–aìá`‚IP°ÇqÖð‰—x¸ô½¡Q6kª,;’*ÿŒ0æÖº/'¼ÕÁF™òlX¦æPf™rƨ }éKñ~‹Â–…j$šD ¯l#ÇÝeè˜#wœÔxD±jÌ6€ëVüKX/>n¡Î~®ØÚ:$=G•¶WÔ”Ö?cÐÄbÆ=²–'­uI½ßQ$(#s4 þ™ÒÕÊî—Û›ÖÂööÿ½Ô±4Z¹MÕ"R ^ Gµæp¦ê! ¹åèÞs\Ƥ̱´gR¥Ö-½“ý-S(¬s¼»6Φ”SÛC@ì©ü^,‚þõΠ9f"Ó*ú/?`”üÃÂÿoIEND®B`‚zuluCrypt-6.2.0/plugins/000077500000000000000000000000001425361753700152365ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/CMakeLists.txt000066400000000000000000000023661425361753700200050ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) if( NOT NOKDE ) #add_subdirectory( kwallet ) endif() add_subdirectory( keydialog-qt ) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -I${PROJECT_BINARY_DIR}/plugins -I${PROJECT_BINARY_DIR} ) if( CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0.0) set( CMAKE_CXX_STANDARD 20 ) MESSAGE( STATUS "Setting C++ version to C++20" ) else() set( CMAKE_CXX_STANDARD 14 ) MESSAGE( STATUS "Setting C++ version to C++14" ) endif() set( CMAKE_CXX_STANDARD_REQUIRED ON ) set( CMAKE_CXX_EXTENSIONS OFF) QT5_WRAP_UI( UI mainwindow.ui ) QT5_WRAP_CPP( MOC mainwindow.h ) add_library( plugin STATIC ${MOC} ${UI} mainwindow.cpp ) set_target_properties( plugin PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) TARGET_LINK_LIBRARIES( plugin sharedObject ${Qt5Widgets_LIBRARIES} ${QtCore_LIBRARIES} zuluCryptPluginManager ${blkid} ) add_subdirectory( gpg ) add_subdirectory( keykeyfile ) add_subdirectory( steghide ) #add_subdirectory( luks ) add_subdirectory( tomb ) add_subdirectory( hmac ) #add_subdirectory( generic_header ) #add_subdirectory( network_key ) #keyring module is handled by CMakeLists.txt in ../zuluCrypt-cli #add_subdirectory( keyring ) zuluCrypt-6.2.0/plugins/default.png000066400000000000000000000476671425361753700174140ustar00rootroot00000000000000‰PNG  IHDRj…ê¢sRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ 28#Ä0æ IDATxÚì½Ùdùuç÷ùÝýÆ‘ûR{u-ÝÍ^¸¨©&9#R¤K‹ã±¤/# ¯øeŒñ<ðƒç°ãmA´5¢¤!9ÜšÕ]ÕµdUefå{ÄÝ‹²²˜•Y•Õݤhª¸ˆ¨Ì¨ˆq?yÎùó=ç'Œ1|rûÉÞ„âÇùúæ'tQÅ'ðüÿ’¿i >çg˜7LŸÀó7Í0ó“€èx~2ЈSüL|L ˜Ó‡èx~|МÇóîO’9åýiáúP}ÏšÃ`>Žû™xHÇ`Ž<>zp¿?6ˆ>çãG<ë9÷‡?ËúŠ~νù0 = Oàùx¡9˜£‡}äþ¸CœÏIÀh@=çñ‹Àt*€>çÃó, sç˜ûƒÇö‘çŠ:¸P‡AP‡î O¸WGž«Oé… r>ÁãCƒsð»ÃîççÈáw8àÚàÚ6NÉǵ$66V)ÀUãì¸@¶²1ŒVh­Ð¹BkÌ…™Jr x Lqè‡îå @¶Jâ´KýOày1pŽZ›Ã®æ(,Þ¡Ã<‚’OP³¸¾¡\)a—\üz?)Ê!^àâú)NÙÁˆ¦ãS q\P8)þX¢•@2ÎÉ2I–ÈD“¤štœ‘HÈ€ü˜£8$q X !„8j}>q[/ÎQ÷drCî!PŽÀq=›pªLÅø8K†ú¥ÌÅ™H²NÂh#ÇÑŽd8̈º1Qœ“ÄŠDB¤ìupa’G,‘>âÊŽu_ŸÀóâàXGb™ÃÖ%BÇ¡äû”¯E°`S»l1cÏ‘ŸŸ¦~å!KÓ5¼…áÒ§± ÎðEîòW4ÛcòÙ7 Xc–1»›¨…ª¨ e…Å”ë?ìR«è³gÙÜòèo·a°A}sLo½ èIâÝ”¼/iï%ŒzŠá aœ ¢T=)áiët`Nè0<Ÿ¸­ç8KaàPõl*Õ€ÊÜ4õ¹Zxum™òW{üÜB…G{|fþ2Îr—inGëü}V»ò©‚Úv™"á}ª pVŽq: ijn–î0$Möô?0ôí^ÓbFä,]ó0#ÁÅÄc÷¦"5¶W=«Cò­„Þ†ËÞVB¿oä‚q*™ñcˆ¬Çñ ƒàü)vØ}}byNÎaksð@Sr Rò©O;4f—i,Ö©¾Yãü²Á|všùWµÕoòéóËÜA3×YaéшȞ°wþ"%B¼Þ€(˜fY®ÑÞiõvž_ Ü|@­×À¦>æAPÏ,5ÊdKu&FãVa”DÔû9 bH/ P/_b %Öæˆù=Íî†fk-f¸³³±·1¦³Ð™(‰dDG,Ñ+;º{b}>±<§ç°µ €Pê5CsÞgîJ™ú•—h^ŸÅþr‹«K;œåsüÅy‹áÝ?åï/,òh£J“›´Á7Vé´3Ò!ÌÚÔ«jg‡t¤Y¾±*AwìªMŸ”«NÊð+9L$=#p´d¶V'H:ìŸf¸ZðúÞ:cA Ýð)ÿzðßtxcÆãþ5›­÷mVï jë)í´ OÇå“>Éóœžã‚âÃ.ª:Ô]¨5§hÍXøÔ Ë_hRýòW¸x.AP¡ÌmÎð9¾ñÞ7yMLþr‡ek‚wÄ”IØBCEBQiRÛZg¯Ô¤ hØ6rbÈ-…Ý´T[„m,|e¨{6EÉf„$l4)§œ³+¯\dXR´\˜±èî¦Ì5]ÒaFCÜý³-Ì1÷î'Ü{ð¨³9Pt¢‚ácW–>¶@ê¸øÇcœOÀy.8'x N%p¨OW˜Z ™½ržùù‡,|ý2SÓ/Ÿûß*þ€/Œ=¡§X¿Ã™›LÙ.㮡³×árd˜hEÉʰ•¦–Ž“Y3øî€8OQ…Æ1}4á EùàJå ìŠCÏr ² …Á™ì2òÌûfïß aY„éû˜´ j+òªÇTÃ!›©òfÝ"þ9M^ä¸c‰«=L#£§çpŽÍý8Ÿ€sªçÀMU‡FÃev~–æÛpíõ³4¬Þ¸îuöp)»Wøæ»?ä‹í6­ñûÁéÁ9ÇAãB/%’IF0˜E0êæˆÔ &yÙEø`{…VH@§9vÚc¬ ¢,ujºîRž ¨„àϸ8–œd”Ê.ÖÒ4i¬Å\ ÎÖžÃZ q£Œë?ŸpyܦæBÄCA\Oå‚ÔInËùˆqÁÏKGàq¹ªpšó.sW\8¿ˆÿK3\þ•Sƒ‹¬'³¼ºp–?/zøô-^÷>ΦCYg¸eŸ&ÑÊÁP2ꤘí­ ñÕ&ÎËㆇýÚ"Ù’ÓZ"k¸n™Íâ•ÒH¿ø.,O† [ó,<a6Ò Þʀ袲‹uœ¥{¦L£\‚ç¶8Oƒ0÷Z‰³—-®~9¦ñ• Ö@ÌàÎÏ3ùËU>Ãî­=fW‡”FSLT Ýz½Oï^´A|z‰ñWæq¾Ü¢ý<—_YdóæMæ_ù;ü€˜KØ”ö is —ñ§®°²öˆZ¯ÏDt˜Y¶ñ­Åè߯,EÓô:>ñ­÷Û¤Z³³ì¶ á´ 4_¡–Î’lçØQ’÷ æl‡qâаs–‡ÕÐ¢æº ‹‚˜§‹·ú…-ÏO™¼òÃÞÌ XÃÉ¿àñŠª±ä2÷©ç^õøÔ§¦}žõQÊË‹³´ßPߨcv³Ç½{—z9ñHSo'$»C’6z¹†ü­KÈ//á~ùŸò—37éóC¾°Õ%¢ÁònÌì+«Ì’–’â2ʺ0ÎÉ›„ßXeêåyÚ¹&÷áRÈV_Ñüâ÷-IQŸ¥êøÔö:Øÿn ñNŠx¿@ýÕˆÞ•ƒÔ¢dØM…ÑU%˜(›l¬©äŠø3,ÎSà„õ—™‹æ—m^Ýcþ|%fɼGp¿Mù¯6h„6£<䜽ÀînŸÒ·×†d%…û»¯Púk_½ÂlZL¾ñ þƒ—C²µ]¬E‹UËA½³Ë´p(ä»±<¢ÛêÚ]Šït(=(pòÿ¥ ÔSG¥”ÿÏ»üêÓ¬ßßdÚ*PMCç7ÏàýNÿn‚óÜA}wLúÇ{D›¥/U™|æ ‰#`œa'ŠñvNÙ+¨ ƒ¯ ½ÿù[qê˜ç”Ð|åOÚÚW-6'¬®ž$C‡ZÓcêBÈÂgê\y»Âòóø i³ÐŽPïô ÖRo„ÛK©ŒÛl®ö?Ho_eôhü󯣨ñ ý&ƒËÜøÃÁ/¾µÈÚ.ÝÌ™}ôoè­vñ&® ›a¬pdŸ¥qŽyo…`{ˆñ#š¶ÂúvŸoÞgt®Jÿ+ÔtÆ êc‡.­Ë.ÖKkù:SoŽ)½î‘¼7ƒøVNz_RnXx±"t ŒkHm)lXø‡ÒÇ©?ÔjëyòÉgÁô7γ¤š‡Ïïx«õ3%æ^aé+gxékSLé îdÿÏî³(C:wG¸;šR5!ߌXßQÈó[SøÿíqÞÚã.5*ä”í*÷ÿÕ·ø…•!ݱ…so—`gŒÜës=Vø‰ÆÕa®TÔ•&÷ t’a‰7p±óœZIïdTîLW:ðh¸sp¹ÌÖC‹Ù‡}^­W¿þiB§ÀþÇ-6þõÖÿõ“¸Z§½mQÝÊðí¤CͶ±,æi™É‰ÜùåÃ&í蛉ŸxŽO™#E¿ƒ›}4Hj3Ós’…ň—¯öh½³¥Œ¯ÿ6´ß£û ÀD ÓË‘[»ìÝ“Ì5ÉßjRùÇ—i½µÄ;ìâí®Ð˜»Âø}—ñª$~§ËÕwýÁ»?ÄK*‘b˜kzJ3ІÜ@&J*”ˆ¶ÀÑ @hrÊ%r?§äkG@Ã#Ÿ ÉogÌê¥E—]£63f/Ïi¶%漡õïO>Ü#õ ¦7×Ä»µ^B1cKžòú9§´8Çå?+ãŽSÁýMYŸÃÖæ’£Š»ÃYÓƒs~â®¨Ö S-›å U®~q‘™qH}OÐZÄöë7z\6p’½6d³«ˆf}ìÿèõßmÑmÔÉx…9õ{«Ôßý.âû&/§fÏf¸±F8NPlKIW zÒ0Æ0¶,r¹†Bk€eac°ŠœÀ(Â4§ìXT,Cô&†éL3W7º¤ŽG©ÒÙ‘8¡!zoÌ™s;×CX—Ìe9E*У‘JŠÝ5PÈLc„ü`=ë¹ðœ2ivœ:îàg§Ñáþ¤¬Ž>tdL+ëÔ¡åçS凚Cí\ÀÜg›,}q3×g˜ ]âTàE6ê¯Rß“XR#·övR¢3MøúãßnR3 IÎ0\gñî¾»I­íbßê³LÀd;¢3ŠYÕ†]{ÒÐ3Š‘†HÒ4'¤mc”zrްmƒk®4øÂ¦d*™¦Q¦³„ÙAÁl]0—Y”ˆñ|ÃÔ‚E§dЉ¤.,Jd"à *í9–ØOV'ŽƒB+É8õjKœL<üHÏr‘í;8c#Rb޾“cƒ@‚ó2É¡çɧNòÉïpœ§ŸÃþ¿”@gò)ïè)çi!ÔAöÔ>luÊ͇™i͹Å×V „å’îåä·G46B„ ñ·ÇllOæ×—ðsšêEÃ­É o>¸Ïdk‹ÉŸ®p½ãl:Lw%»“©d½0ljMÇú…Ú—F¨ýzÒ“ÒÀ!pžÄfJí'0 ck˦œÔRI3’Ì `©›±<”œŸ˜¡Eµb!Z^+ Î2ÊÆ ¥&Ú*h$ $ý4'É%¹TO•&N´BÎ)b¬B*å²Mͱ)Õ5UåP­øØH¢@8Óh«‡;˜"id…Ò Œ¿…ci„ ÑÃYUâ…cÜÜE9Nn£”‹–Ú78CîGØvVq“˜ÂRˆ¬Ð¡°”FX °Al#Pi‚ÒÆ@&±´ˆ'š‰Lú “|¿øW‚'J%›ê”ËlËæÜ\™«2 «×lHjk9Þ–Á¤”zša'¡·‘}~Š©ß9G<²ü§ܯ}žõ¿ø·,™ÞO(G)ÞjÎ^gª„uFÐ. C¥ó#…_q¤¦dž±*´¸ <¾­(åPö]vÃf"ØL »CÁÅY‡¥ªC11´)É  ™ÄîiŠ‘A$ý\1¶l¥N.ˆžÆòœ”ª=¨V,¦l¦/VX8We¶,hVlœ\Ñ´-¤cHúUjH¨U)0h»ÀŒ§¨X.¹ãbû.yæ2rbÜ|ˆ[ºJ Õ™ç8•G8X“–-вNßj`‹ÂÞÁÎ÷°Ã"n+EáŸÇË;„¾"õKÔ·Ú­ Ì“÷7±·{ ×Ç ºŠéÐIúž~E=¾aàP™öi,ט{kÒùk<øãÿ‹I}o—àNw#Am 쑦»•‘ºIùëóÔ½U•Ѱl¬ùã­tY|°ÍK{ ³•po¢¹­àA¡Y—š=ƒCB¬£à§£9IëžÚ?BmZ†žô¤dW…lÆp¹ZpÙ˜ñzäÂ×*ènBØO™HØÅ¡£ä˜‹çô<·u8Îñ=(O9´^*1ÿj•Ëç-®\󘑚±FVª`Ë2­BãΗéøe$6eJ<¢ &f—سtÿ.×G’øÊ4QPfž¤C‘b —‚*í¸Çâ@Q Zd­3ì0Æ'úöwøÅ·>ß–8Cµ·ÊÙVÈ}*Ôn¼Ã§ÎÏðþ¦‹?ÎÙûVŒ_-Ø^/Xq k$=.Z@ØTçK´.•h~z‘Y ~£o yy5à N-„±Ù&Œö›>ÁùŒé•-¤ëÓëÚ¸+’3w¢‘œû‰à¦Ü)4¤¦ýœ“ÄWÏÒ?KCí±Ü—˜ŽµbœÛôdL¯lÓÍ =^òË–Bƒe'”E/6¬Ú÷ ìÁøñÕQx>”åyⲪ.Õy‡™+W^5¼þ+Mæ.4°wl¼²KR­âbi“à#tÒFxgð‚*µ ‡ÅXp&¼CG"©ÜÞ¥5ë²9|ªæÑO&¨{h]l³f—>C¶œpãû#¾ööuþÕc.pq|XÒü3íºKi£OXNpÏX,O7¨Û1Í<ÁŽt*Åþ_¿å;”k>õÅ eêsUæh²’ލ¥‘ÑŒ"ÉÜXÑD{ñ×T~©…\n1rl²H ¶côhL·_PÙŽØåÜÊ5w”`M*vôá‰üóYàp<YÕ”=¾NJHQDJ1A3”‚¡o³hÎZš#LJ¢=kîk‹Ý"g|LLhNÔó‰wÄIñN`¨,»Ì}ée.}¡Â«b€ûƒþb•­`' lC<ŽðÞßd~Ô¡(z ë)¼!Í5鈊Q—¬Ô"ÁÇAÂΈæŸïðf«Ê¨¦1­‹WØÉSò>x eÖCìÍœ 7#ㄹ…ïÑÌ5CS0¹·ÇtÔÇ÷,’Gš`1c=ʨvbÎo Ꚏç’g†Åsej{»]›I· ;¸–¡Rw©/Th¼½„g#¬½Œé8GD’’c‘džþFWj¯Ö¨V AÎvi¯WP꧈ o'&æÜÏ$÷rÁº„] ]`|Dl%¬ ÍsêqG“µêÐ ÷èâ UÄŠÈØŒÐ´m‹u5lJF“[Ùm¥ÙÊ2ÚIÁè·õ–ç‰Ûr]‚¦O}¦ÂìrˆWhÊ}®½ÊNe–ðý-Âшl¤h8qZ¡?¶( +,ífäï3Ô婈Ü>–Ì)1Ö¤ƒ³cU Î`Fma…ä¥ ;z@û:\È~b[>ñ£»7nÓZ^¢Uì¢s wúÌx6ã*Ù/ɜٯ4Ùž©±»½AÍóˆµÄ³,h®¸6C×b`ƒP ã@µéиPgñÍ«w·°˜î9¸C3q°’8Lú)ég›´®µ¨¾ù2ÛS x?\§´=Fo&”#ƒn›iØ( Ú-Îø±»J±8§Ê­‰8$Ö²­.C”IHSETúžbË2”\‰÷83—’a"È‚I¶vþŒÀýÔIÂ'³ž–ƒ‚ºÊY¨.O;˜<§øá Á_­2×èé€ÌmÐô\rNêc6“,ÃË8Œð Ä%i¹HËÆwkda@6Šð¿»GKvðƒ€´RÆAbdëXĹ!Dà%ãQ…Òƒ-¤e#Þ-xy³M­VA¨ «U¥\õ±6À³3Âê ÉÖ&•¶¤5‘D¾`Ž‚ªe¨ZÿòËåÙ*SB*ÎKÈûH¿÷PQ_öoæÔ÷:=I´b¿¹€ýõ×Q-‹dwû;w™¹=`üP¢7 :‰f½€ÍÇÁñð«:XYuU'YsBÍð8ˆ,>Ø~œyI!kð7Ú·+ÆóPR’f?:?Õ9mžÇ,Çì+ê,»µÅôR ..Ð4¦Kò™ivc½Rì²ER'¤+–4XÊÅ)UÛe.*ðtŽpmÆ¶ÂÆŠr‰ž±Ú¢¤ "“èILKÊŽ…öFÒfNG´­¯3¦!JdÜráM /)b_À¹Ê^;*àªî°A€EKjBËbAÙ¦>ïS¾b“Ñ¥§x*Á‰ FX0(Çq¿ =ïQ¾âµtÓ>A®ÉšÓ´u ¨3ÞË[YΞçhÔqÕæ”Vçès~p`…ÀÎÁ΋'ñ’)ò§’¨G»HŸÙ»uË#x\,s,DÙÇÞ3³ÚAÖB*'“Pv=œ¿h“ß2TûC*–²,„m1y}E,4 £ÁÒ#Êv(,2˜Á ”bÏ„ÖØÆ =‹ !Àh†–Í@*²Lc‘cdŠ3TØŽÄéKJ3!á#Íg£[¹Œ³[„„–Eˆ&ñ,슠Ú(¶ú|ªºÎúC²Õeѱɤ&ÈÝ\0 lh ÊÓÐ`´—m§Ôº’ Ö8‘d3“lŠN¡È}W•§x8§íF8Î.ø ž†`?~Ï£ÙÃñCô —'žU`tÀ<^º¶ N ì;mævG´ªìª1Þ9M1]A!ŽÑ¸“ ®ÈZ™<,A¢(CÖÝÅ}bßÇ.…dÆ#0šÔ€k‚8¥œ§hÏ%.5±ŒBÌ2D¡@‚µ= ÏË›#¢aÎH ¤½ÿ±­\₲±™òÄr…n;Æ[5,ÇSxx–Àà)ç‚S²©Ä}Φ Jµ›®Mkm—Fª¨D9~.Y‹ ù\ˆ»ìcÍ;ˆ÷·™¿ÛcV:tV¶)í 0ƒŒ½\²WhúúGàd'@óB“)NHäšcªÞÇAd ¯8iÆÏ±çö¢£Ð ´ÒÈ’‰ èIjrD'`ùDM›ìíg^m°uažÉÃ>s»ÛdFà|õ úgÆ>)ù;Cœ™2îÌ,,ÌcDÒœŠ1ì÷‘{ÂrÐå*,Î3i–˜l™"¬P1^žæá8û¯¾…w;ÄÜáw2Ò"Ï JÂ’5ç38[¡Ò0—ÚT´$V¡A) ŒÁÁ צYwiÙOiÅÀõTc 2±"›(Š«!áÙ`b(« Ñ$Âä6y¬HFŠR¦é†nV0”O/Ç ^°üY¿{HÇA¤yþÜN ÎóàyªñKJŠÂ%ígD—‘±[Ⱥaý{¸tù"Ñb‹xP°xwB¤z™ dÕiÜÌxÉ˵œÍÝ•©EŠLP÷}v6a¨ o ¸l)&&ÃÜgÊAFLÚ95ÀT-&iA°qmV0üGŸƒo¯aL›ÚjÎ`k‚Ø"Ⱥƒ,êY„33E1î!íòœJb PØÐË”|¯ìQÒîH2ŸˆØI wMr¤Ö蚃½Tŧ” C^1¬þõ.—Ó2JlÊ‚4ŒôÓ1ÎsÁyÑ’Ïé¸J<ÃݤƒúP’Œ£¾PJÈAº7bÜlÑ+ìE†ò®bz¦JïáÕÙ‰$ý6~žqæÂ,ÛA…q?aÐ;#Τ9âÚm“Ý’Leì!:({%’¥»GLÛØçKÜíz43EÉÑÈqÎtÉ&ÞíÐ\Pt§¯¢[³Ôç"ìÄ¢Ö3p,¬™ öù÷|€×˜BŰYbò(aÎr‰BfŠ43ûæ¼äb/V±g|Âv—þËIWWiÍÌR”Ú˜Á„a¢ˆ+.Ž[PžmМÓÜo'´v3Zå*½Íˆf"éš~¦?žJ‘Ÿ&Íÿ‘eƘg¨?Í üüTVﴖ瞢€tœ3¨‡ìl¥<Yœ-–My½GV±)î§„¾MV$¤‰¢¾Õ§a÷q£‚Y!È´a¤mXksÖq(l‡B€”ž1V=Ϧç4}Íø‡]^¯—°}6Kf>àï §”V2ÔV'ŒÔ_ØxFa pKxŸiÿv“(QTú’r”㎠¼T£cÉP bÆQ²q§-ðgK¬µSZ™@YRHd¢qr¬»ˆ…IhßK¸¬ ›j'BŠ<ÍIÅH|Ðâ¨g%?ŽÚO†¼8D/då>Ïrú>õøKÈ"Éh¤h«„ÕØãÛžæ%ÇæRZPq ð3&ZSV ãX$ŽÆ1¡ 7` ô€Ü•ŒµEÅHV®¨»®6ŽEhܲMPq( ÈMA¹¢´E3˨¼±À£5›òÓiDÑ/ÐEA>–8 òZșϕ(U¬t‚Jô^F5ÒÈAAe\p?UÄòÀBÔ\˜¯¢­°‘Ý”p¬Ê&CÓ‘©]¶qZîúˆ©³5Ö•Í ŸÐŠ%³c‰,4=)ˆõÓ²|Vðãëÿ+ô±ó"–GY“ING»¬¤e ¯ 3ÆPÒxh ËÆ6 ¶ÖcPæñ2Ü ,‹.b_@f º„¹e%‡¸â ªÝO)îÙ83!ùÏÍÓÀ½»ESÕð—jf±±5ÂKŠ¿w©_­0^–X”v8wcª{9º§¨L4Y¤éä†q¡IËAÕŽ0Ed€ë3Ü-¸`BÖŒ ®`KŠšG¥éâV-Æ«]–28»=AH]6¥&S)úCg?Ö þQ!zØÏŠyÄ¡¯8ÈL$ýD +‰-èZ†û…b ›’.p4¸Z#„²llmö]ƒaôã×¶°Ð` „Kì¿—+ÀrÀË%ÞÄàïd8دThþ¸‰q®ïÑb¹µ]»„éF8wG¤Ÿ9óõëT¿qÿÆÎÍ!—ÖS’Ý‚h#§6XCÃJ¤ØN ýT7-ÜÀÂ*4³Ë¶Æ’°âÒ \‰…²,’L! ˜ŠGá JyŽ}¦Ä£]I«î‘¬NXÒ† ‹DØdJ@—s¬ËúqïNóã~}çæÎüHô‡x ÈŠýÚqYì×JŒÄ36ξ, Û€ƒ|zYhÙûKE µÿXil,<mQ¶åIA%ÔÏT>Û ÇŒpS IDATú_]e;±¨nFxkCU§û`ƒÙ¥ ˜ù~D>âýb•G¯Î&mrè õž…‚Ó׬% ÁV¦º`ÂU€SÑŽK¼¹IóósˆF…ÊÎ6uEåÙ‘c§ž Ñ# 5Ð8©ƒ. F“ëŒBîWÏš8ú3q{žÛâPÜóTT@QHâ§$¨ê)óÛqô ²VM”ÑÔJf:$|¥ù ö—àÉ‚Š2¤+#¼»cöþ×È~ï ¦ií®1—–ÉMv'ô×ÇÌíÆô†ïgš‡‰¦­mÇàƒ´4VK3\ÝåŠÌ±7ú 3rÛ+Af@;µp-M)aΖ¸×ƒÚÈAn:"N%Y¡Ÿ ’æ€yÑî ÃÓ}ʇƒèœÎ>©ç$=tøø5×BM9ð’ƒûŠËüÿp–{7º¼4=Ëú÷vhíöi¡Ì° ›ö½ÁÃ1úW>Ï£þ; *X¤ÂÞÊ…w4pV3¼Ý”|Pp+U¬dš #è+…tmJF¢tF¾»Ã¢¶¨´âP°ÕyÕHeHH pV= Š…¸EäÛ1u•‘(EaØ_=þ¬[œcáy†ë:Ú΢Üìº&Ä3ôAÎc=´>л`-…¯OSû|•àµ{÷ÆLã¶còaF÷AÌüHX<Ìßèbþáuÿýÿȃ긄Al? õÃ6îÊku„Õ6؃‚wcÅû¹æA¾_åNK«ý€ÞµÑ–‹ @X¡öÈJ›™"P)¹6` ð,¤gcÅle´ X¨—]¡(È)Ô)²È?³–瀧·§½œX~Ò ‡Á9À m¼YŸÒEŸÖuCíKM–Þ¸B:¼>¢ÿ'™])¨Ö8Æšx¶–à PtX"Ÿ­3š ˆb‹ la96R%¸:ÇÆ SÊ$ŒÆ–ÆÍKX}A}œ¡â!CÂq°žjDü¿Y!Éô¬ÍÁ8&H~2Û/p¨W-¦Îûœy­ÆK·ÅâÏŸcnzûì<›£‚t­M|s`so£Oü`Äù•2òw/2ùÃïò.2\›Pþó¿àÒƒùª"è$l %7 ÉܰV(Úòƒ­.P¶ÆÆ(˜cß|Àœ˜Ðëu(|ÉN–c+M J Lá€Ò+°P¥3_fÇwICÉõƱíŒ&ŸþùE?ž˜çCÔJŽ›_|xvq%0´–mÞšañ—.2ÿkW© î±òí–ßï3µ™£WcüD`3MÞÝeœAúŸ_`ð?Žao›Æ•:ßùÓïòs+1­w:4QIK{J°V(vsÐÊ{³R ­5:dŸÛ˜í„rOÒôJ$X”BDZ0|’j Ë-˜l$Ì$9‰§ØgU‚ÛVOÁsÔ›¿UðœB;ò,xŽ‚S­ÚL]ª±ðÙi.ýܦ^óyeå}ÒÛ›LזּGyè qÄèÖz3¥ø•áÛ5LØØêRšŸgëæ}üG½–ÑèfŒbÅ\²’+JÅÎcpôÃù¡Už”ã sŽ b»ÆðìE¶·6h–ë¤õE&œ¨lc»û5¸Ä8›|£Ç\ššœbà03Û Ówñâ {a“ÿ{ø©Zm¶èvt®ßá¡Õ²CóBùëgXøÜ2_{ƒ¬1毋66SÊ|e±9ÈY䘇1£•˜ü·Î þÅÔæ3¿¸ìÐZr˜»¨Yx£àâµ×zNü(C Ùû6M—b,1ŽÏ£Íò‡}ì¯NÓûoæÍ9 oÇÔvnrn#¦t?eéAÓ)°vbn¦ð^Vð0l+E§›ë žîoÒì«#•pÐEJ³VCw°gBJÓŰÏ›+%—˜LaÆ9²7&]ªÒèÅÔÜ”õÞÁ¦¢V€%cøà<¿Ã‡ù[ Ï3À9ÎULLo,T™¹>ÇÒçΰøëŸ§rµÁ£øgL(ɰؤØm³è voÈÞé¢ñ,Ñý¼÷ÅW1(J—÷˜ü Kø÷8¿3a24v#ng†;©æ^&Ø| Îä8òPŽéIw¦„Bjr¥ÚB¥*A ËБ KyÕÇñ<4QRÀ¸ kÔÈçklµf–²dˆ“B/%pl\ÇàIù Á »·ÚÇ}û°²ŒÓœ—ó1‚st4[T¨×¦—*̾^bñï6q®Î0¢›™iiÖþz—+»©›Ó¿Õ'»Q¼\ÁùÝ%²O?äâ7ïráÍ%¾ÿ˜Y0XéãleTÛ)÷2¸iîæš-¥ž´óîÊ,ŽÔæ÷4) RÁp8 šY¢9ã«‚Zs™±Ü$™ tq<°rÊ\ÌdˆImÂsÓì¤6Óó5Üf I0)ðäÓ5¿Ÿ¸ëú¨ZžƒÿÿaÅ`§=™ãŠOæOÌ\®³øÅ:—~yŠsoû8|ìÞ&×nth¬Ìoi¼TQº7&¹¡›~cšñ!úÞ&Ì"þ_wyýûfD,w4á^Îfª¹• ->Îá®Ì£y¨'IÈ'šl½‡ºx†™dˆªT‰LƒÙü>&pK.Wà$[èRíÙ䣌æXbtLQrÉ¢êØ„öÓîŽë•ú©çèk=S†ú!Oæ¤]ïB ì@½æ2µ8ËÌ˘ûR™+oâï­*‹é-ñíž]'ïIò[md;gRòÉÿÉyöþÙ¯±QX¼±ôÎ]êý¥M<´iucº‰æ½LrO Öµ¢sdI~ŽÞ˜çÓQ?Pk”hÍU˜~³ÂùÏ¿Bù—§©d‹.Å2ª7û4zýr€iØMIƒþ/®RýgŸáÝÍ[|ª9MçÛ«4¿ß§õ^B±“íæ 2Á- ·‹ý±%Ç%Oêµ>:¯PæŠ<ÊIû#¢G u€S‚|\@'cÎXÈТV 7 Fyo»ÜÄšhŒ5ÄÛ@©A\ñ}×2øC˜J¼#ðk}>*@§Ü÷ýYŽoÅy¦ ³>̹ròÄôPõmšçë,\ŸbðŸþk\ã½õ‚f[ÑüÞœò€j$VzLº’ü.aþ§ÿ„˜˜¥|HQôèn+)îZJ³+qÃíIÂí4gõ9à¨gdÀŸh³äZ+˜hÍÈ·ðŸòbl©Æä\ƒÎ…j*@d3Ö#EœyÔ|—$ŠQÊ%ä,.—(ê>¥Ð¢îÚ”Ç~'$>ª«oϹNÇ?>é/Ÿ½èöÏÚ‹ª TË>Íe›…×9wm÷koÓc›fþ}.í8[Š`àô2ÜÁˆt˜Ó¿9Füj ÷Ÿ¾DÌ6 &„–EûC–ÞM˜ZË©v$ÝH±ª +ÚeUìÈJz^øqýhyªIC–:Œý%ßGf!@¦ûœMy%'h$¸½‚|+E¤³™¢X´‘Ÿ=Ãýû}>U\](Ñ]±Ù+•qödà§ËñÃ’ž²B§ R_ÐÒÁê-;<NÕbú¥¥/–¸ö¥«ÈÏZô³-rþ_.ï8Œ¥lßïàŒ förîߣgBìF_›&Eø‡ùÝ]²›=ØjQÚHñw"ÖRÁí\ñ°0liñÄU Ž“‚À³çØ<ÑaKH&š¨/lç´›óØ@GX-Ÿ´2±˜qñç=üÕ˜Éj‡ÁÚ2 ó>q®p ÿƒ¼úÒï~y±[0?RLåšdœ‘Kù”K=|N'|Nà*žN·÷»WÚ×QùÕ¿f°•@Ûªõ ÆGÊY'¤6>û8/讞J:P <3†…ëU–¿àÐøåŸçAþ/ù;¾â½á»œû†aò½{¼ž*ú*çþÊéøq¯m⻂¸á?Œ™ë†Ûej«J;)[¹àýBóP[lkMOîïÿ}X“søƒYœ~XÒÑVê\ &qAw(ØK&ó.2lQd¦§Xp]ÌÙ*ÅZ÷ ÆÞIP:lÌÎÓë xõ\€¬ì±;{‘ÁªÅÛo•ùAb1C¬;ÈáÓç{ð<Ý\ùÜ™=Ï€Æ:š+å%ú¹)M:xÃkR0ªúŒ>{&t'ûVý¤‚^xûë˜ÒC¨VK4Ï•˜;o1ýùeÂÍ[ÜÆ~˜RZ»ÃÕh}£D_ ’~‚º5"%ö?9Ëà—Ï2·µÎ¨QQ¯öß8³-÷ÒaÁÝ\s?SlÐSû#ö³#‰?q(ý8']ŒÃݰYñXÑKàÑÐæìK /×éÕª‰B[P_yT7bÒµ˜h-B- Y.ô=ŸèaŸW^Ži g^qé¦çɃLò'âðøÛâ˜@ßœëˆnê mò$u8T*6µE™×ê´®ÎÐ\QjTñþõ ~dmTËz«æb=ÅäOÏ5´ø-Çì¹YvhL7™¾Veñ­€…¯Ïqm· ÆÂµ-vîgx½õ±E7±èÞíPº?ÆüöÙÿ¯½3ûÑóºïûçœg}÷}Î É!EQ"¥H޼DŽ•ˆã$H“Ö‰‘A‹íE (zÑ˽iïŠÞÈÐh$M]ÄvÇK$Å–¬…;g_Þ}{öçœÓ‹¡¨ápHŽvŠðbæ%ß!øüžïó;Ûw¯\b¡jsx¬ƒu{JûVHíî o7#™f܈s6rÃA¬v›ãgTÇSvž¶zyÚ2”ã“æ<'Œ,fÍè0£{ X÷r ’I»Äý$ÇM2Ä U¼WW‡›È›ºá’®(줜+ú$¹¼Pcg·Oþ…ó¬÷mh±ûcD¤Vl·šÓOØÜOa0œì6 èAeÕ£¹X¡þ‹UÖ¯ž§üÊyš—K\òŠÈó«˜wïéÊÝŒó[1ÅÂŒñ‹á“žBm+<){â©™›%›Úr™ÎµU–^/ÒùýÅh‡ìʯR¡¿Ùe)[&¹³KɫἳCúƒ]Äï?‡øO/±];Gºµ?whlNXèfè Ly›þHr/×ìåš~bÖõ±ÿ‹ËǶ±gÎiËГçŒ#ÿ¡é0¤k¥l«ƒër‰âj™î,§í ‚ª"}¹Ez³ï °–±_AZs «?Oš7è•¶Xþü/±ÿõ[\ÿg_¥ B2?À'Ãé8¡Â}àUèrœò$s„ãB‚Ó€óQ˜LÁ³¨øÕEAçå×j¬ýÂeÖ^ÿEjþ9B>`t“ë—‹l˜%:³.íI¡'éY†îƒyerlX=• yÖø€‡]§ìS;_fñrƒÅ_~‘ ¿çñJg‚¾_¢6¼Åp#¡óÞ˜ö‡!‡‡Ù»wÈÞ¾Cñ^bþï¿Ä fa¿ûW¢ˆ½MÃjf‘ôª3M9lgû‰fçDÙÇfŒ. ³gÌN†´©KÑã7è£Ïç@’ç±ËP–Øv«Üh/"KMÊ•qY0o9L“+žpáÓ‹ìÄâÆª6r±HyvÀxoŠÑHºÜûô‡+¢?üüÉŒ%ÇÁ¾7À=˜Rîg RuªÙ哜HO£÷ï8¾gQ*Y”J4 Ô®Xùì*?sçÚ ö 1¬ÒZ_äÆV‰¿pì°¶¿Çþ!Tæ~øhºñ©Ç*ö»Žø›Êr•æå"ÏtXþ͹º4¡Î„Ù8cðÀË÷o±¿˜Þ;ôÿvˆõë/“ü›_£ré7øÆýÿÂçò ÑÌÔÁ³$‰¶°'!Û †™!ŠrTöqÍGã®wàœÖq>ê,ÇÑ/ï9ö™8ÓÌ& Ã~@÷ö˜õv•Ú~ŠWóHµ¬ú„Í)Ù/­`ÛU ÿõ]ÂÛsb©Ù+µ¸x{ù¢¢W¨Qò÷±Ë¼ªyù_¾Áª³Á7¿ýW\ÜUÔ·3ŠóT0Ò‡qIO² ãê‹ 8žïJ ‡bæºV¦¹Ð¢x¥Cù•EøJœ>šŒœ‹C2t“lr11 ½œE)(ƒw #àÌÇ'~•dQ;}^¯pýùer4·îïrñÛ(ÀܵiÍ4ó­Óê…eÂßY'yq ‹¯³¼¾FòÁÊ÷ժώíãݰÓL3R4¢êP²´mð”¦$4™k©ä „8îic¡Qà‚•g¨´--°)š4Ò„±& r‚àÑÐùnP$qÎ|,zs¶‹U+eñzgÑ%½°þb››¶ ¬ –¾z•ñvó§÷È48ƒKUjJ°ÍP/”YÀbaïCÒÂ鿸Bõ³¿DõÏþŠÅb÷\˜b‚ 'Nqš’ ÈmûÝFüêyüqŸü›c¢†Çþó Óe?%S?Ä9×b>ÑïÑÜáêW/2˜zŒÿ÷F!×÷Æt'z\b’SF¹ R¹(•”í€Èz¿’QnX8í Å…þÕ"+× µç3NDwëåõ:ïͧ¨»*‡1 3M6QJ ÛÁŸæ¸âIFmª(¥a$Žy2öQð<%´ä‘ÉrÅ¢Üqh_ôYû‡€ß.³Í‡¬×^¥¸ñ“AúnDz ÷c&Ý9Á›8o<÷áÛlÜÙ'ú•*âÅ«t?Ücáfçƒ>Í—Û„¿÷fÑfZ»D3Þc¯PcMvzŸÁwÞg-ëà N¦Ü±êó>k¥UR§F(r\•3gN­ÓѦ¶‹ê\dn2LoB%³™Ž¡·1ü`Êæûcö¢‡tÙ±ïqž3‹l£”]Ûpÿ¦ v±È IH¹iÃúLÖúû,ÿáïcgCöÕ.ï ˜šr±Öaíö˜Á°Ççß\f3Ÿ’þî"ÖÏ]ãp¿G; ¸ò»‚ò¹ŸÇ½¡©Þ=`<.³¾sŸ^baOG„¦‚t8”°ÅLk>¥ZÊÂj»Ù†5‡êz‰¬6¥s?`m{Ê0wYmžgþNHùæ‹¡m‘aSé¸d#MiÙCä)¦`HmHÚu„›PÉ©º3Î:a>•rQ–T–ŠÔW|Úõ=JÝŒfvˆ =øÖë‚ ¡;Ïè †m¹TÄ)ú4¯,ðÝ%Áäë·øÒR›½N™þï.ðÎ…Û|î·ÖÙÔEÚeb4ŸGÑeø\ C›äÐÆ[,³EF-i³: ©6‹„V‡}"šÌX¦Måà&ó¥ßšóº˜pit£%›zÓCþ÷®-¸Tã{"H{I–=6™N;É™NVw}‡ŠѺR¡2ÓÈûF.«Ë‰9Îù×ë¸6ÄßÝGÏ#T¾Ääy 16Ô,CT+qëO÷ùÔËØlù ¯¯ñÝ¿üo\ÎÙø”ÍÒ§^#&æ<Ÿ!m2ކ\‰ &i“Ååb‘]Âjm™5w‹F±@Ä ·‰)1¢•Ô)ûì;„oÏymrŸÉ^Œ$V¦É 6a¬©mF$¿Ö@wªŒ†åý€vA"q@?\’œáœÍzÂiì#¯‚Mm¥DçÅ ç^?Ç•ËUæÛ+³ ùD}í=ŠS‰è&ìÎ5ýyÊl¡€u®„¥F½_!¸¹ÏµV‰½÷Ç´¬ ïÝ!ŸZp؉B*B‘êgÂ>5Îñ=ÑÁ{ïCÎ{7"Ü?¤±âзWÐ[w1÷澿Í+[êÓ”èæÅy‹ÕïlpaIóîµ+ìŸK,—ét$ó½WÎÛ¢˜æX1šä¤ó„Y¨ŠYi0¹8rbP\ã[JJŒ›v)'Y[¢÷íï"Ö—ŠÄþ÷¡‘G9z¹ˆ•ˆúS.\z·§4Ә·öù\Óf7S³r²BÍœ]Ú,n°W¹„£î³zÎÅ’ЛP[k°ï?‡šÝDoÍ(þ`›OÝ;¤q¿µEe¿ÌÊ×·XGlÅe $õ*EH{å›S¦QŠü­sÌÇ k‰Â‹ ÑfLu”“†Üž$lG†~¦ËÝ:y´r¶¥º¶NðÓ€úx—åûm¬Ö:³Ã bNݲ‰¦kfñ¡J9:ÌI6¦¤ÑŒ’©±Sk±±w‡rÁp'§Úb©€‹¥„q+g\³8êcu „¨Á˜Z§Åþ\Ñîï±8Ÿsi ð“ ¿ Ù‚|ÓÐ’×Ü¥oÛð koþqjQŒ1£„j”“ãÐP’J_òJž1t {L$Û‰cC€•çL'9ŽvpÉñ³Â|Êb$h\ª“Ž$ÎÝ>m·€^©0.ÅœûÊùáÒŸqùψ¿q@f Ö-äªÌ\f¶ËüÆ6ë–Ãä]C«³(#Ú˜Sº~Û»‹ã.Í­€«›P+JR0L@Ï í™Á›n2 Ö4§ÍPJPè÷2Ôf.ò³öím.—$QÙ°¿QÝM‰æ.Y`rMþ!óI&̇/ l×Ã.U¨]ýõÛ\ù'×ùæ·ºü‚*31ec3Ђ0ÎÉlÈRE:˰nW{Ø*¤=H‰°ab²Èb ©í@EÏŒIDATÇ”F 2W8X¤Ä76åPƒã¢ÊéA@:ÒÌváÁ|®Žýå6îo¯`‡°&ø[3–µƒMpbɶL±ˆD|¶È¤Ó†­“ó‚-©¶lZ’‹‹‚ËV ï|͉¢u8Ä61£ƒg RÈ…Á(…Q@}¤•#‡ªyˆN-“¡ÓÇoPNƉFS@¦àÚ²ÌÁÖ‚Ùh†l,Ã`„?Ó4ãÚ‹Ô­j kÔ e¢pNVk¢J5´g“úUŠ­*S·Œ]+·*䶃5‹°Bg'fo¢Ù‹4ÓT?tk?m¥‚¹&OJ[`|aSíN°}C¿tŽ…Ï\äû•Ÿc>z›Ë!Î_àpÍSC½¿‡øþ>voˆÎ ¾§Ñ>Ø~ƒr3™kLâb~o¢î qMçæ>Õ혥ÃÇkÑJ],SAè õb•8 Éd…`n1½0úA@8VÄŸ_ÂúW—‘ÿñUò/.bY dEì˜Ú\mg¸¡„‘bc®¸ål…ŠæávÆ“˜ g7w`|‹™£˜MºX_û.—Šuì,@^\Ät3Â~FÁvH 1nÃAL>‰É÷4YÅf c4§Te7šSp#'G ™˜š`"ÁÑ!>“'È`Nz¸‡‰¥ä K±ïÞ£—fxŒí0RŠ®ETÈ´ ‡¤R5=J¯j,Ë`ª”›’Ý9²!£+‰q³G÷2Ì)(ˆÄ\#DŠŽsˆsž[-S­š Eäz‘äÍ׿ò~Ñš)^ü4ïÿƒçŸ~þ×÷ü6¿’ýÅ!AÍF®xŒ3tÛƒTá4 ýbâ<¥¦,ÜnH6OP³„òl޶FyŠ·µG< ñ"ÊeرCÃt¨IƒxÞ_µÐ×ËÔ¯N±äñ1Îóë„wØ»!ñ½éˆÎ@“5ÑD³+sÁ<ã±yàt0ú8Z`fòΔ)ÃN•­TÓzeþ\áG‚jÁçÐ^¡’õIœ-‡çÙ0÷±Ó6^?$#&‘Â?HTL, %¯€côAŠ-R!1y†Ét¿‡ Bl[kCnÙ}äRjÉœ8×$¶Ä$H­‰uŽÄ*û¨‹k¸ÍœÝœ•ƒÕˈ§†b¢‘ÆB<ô ;}wú‘¡­â¿ã¯Íq5ÍÈMoû?³¾ö‹,f’IœqϲhÎ^âo~øßøÒË‚ƒ-¬õßánÿ›¬.4ê216Ú XP²ƒ}Ôò—IÞý••³ÑˆâÅK´‡¼y@¥;¢òR“­»´U†®†ŽWÃÑ6îÛ8÷3^˜ôPà„†> 9™‰È±ÑäMõ“ê’ƒŽÚ‚ÔÊÉ•b2Œ‰­2«]ÖÖ Ü¯÷ifc6d/°RÞ¥±6¤n»Ü~å2Ñ+_àÞ_ôø—^!þëxé«ì}ø&‹sAÜO0ã 9K(ÌrdlpÒe¨²Dw,X_€†ÄéX¼„Ê——ÙŽXÔ)y3§ßXĵëØƒxsƒÂ(áçÇ=–8½ˆÞÌBõ4ÎØ §†7sÁ;¹â^fè&ù©«¬OÜyò|dÆ"·,&‘$•†xoF»-IãáYôpQ÷‡,v‹*jwÇèË-Â^ ]¯Pb3ü._äÿó5^ûêë¼—ßâRV¥v~Hp®Æd`sa±Æ H,²s¹]¢¹iƒŒ)yŠÂÆû¸ƒ åõ½—Zloî±Ð˜ÑÛéá&µr{9góo6èìÌÂaÌŽSÆIã˜ÃL‘ ÈDþ˜ÚâY¤,ähu¤sOb‹™'™ÞÓµ"^ˆwh'TÔ„4Üe@Ž»2'«Jzworù³ÏóîŸüoüöunÎïsñRƒÚ«~¨^º¬vØ,BLD#”ÿ*õ·þœ´ê‘sü$¥4S¾R¦qý{{,ê9‡]ÜÛÍ%S°ûö.í[sÜÄfšVqç ga!§‡‘ↆ”æv&ÙŠ†ÙÇsœ1Ýøaœ$‰&0.“Ôe¼1 1›ÑYoqXÈÔ6»„©bÊMVûSÔ–MGÿ1Ÿ×Šn1÷bêIo}—_ž$ì¦W©öS2áÒÿÞ‡\³ ¹Æ_”â’’ÑÞìsѵè.ÇŒœ"~’RÅ}g‹åŠÍtKàÝê³"4&ªÓ ŠÈµ2Û°úƒ>/ëAë9J½9^,˜F& r®ä0Òš ?½PÇ™†§R<òØä™"ò%sæŒLN/ë³ZH¸à–¢{¼X ™Ê=Âm/£ÿÖÛ¼‘kv·/SË2²¢Gï½›\õ<|¥p:M¶ðI™Ð‘—ë-¨°¾¯²Ò"âwXª˜ö$Î+¹q•ÖÐêú¼•³Ü›pmn‘ªóøýÒ\‘Îæ8ã”a¢¹ŸÁ]c¸¯ Û™a?Mèg<ÂÊ”¥úcß0#š&‡‘ͽâ íI1˜`– ˆý˜¢sƒü°‡ ? ô·¹Pq(½v“îáæ_þ€úµç˜Œs’CÍüÞ€kú6÷jI‘¤œó|FB†T¤Xvq‚ÕíQÎvé$Ššê³³ö"¥© 1EÜqLµ;ÂJVÙ%®–É߉Xî(ÙÐSj¢OЋ¨Ì4ù(§(f³Œ­z¡fú”ÉáqjÇ©§õy~£*"2•†¾ ØÏRze‹ >U/§ÙÛÆ¹°ÄLdXEE\õïãœ/X#âA̹V~’µïâA­^ÄJæÛ;X³.kSCSŒ¹ñ2Uk›È°·çT6ȩƶ\RåanÎY:˜R 5óØ¢˜ Ƀ 9Wìg†Û¹a[ö´¦› *gò8gR£<ôh:åüâ8Ñè# q¹êЩ۬Õ-®­¯ðbpÀgÝ57GöC¢ç×°ÇC,¯áœÀu°–˜„!v¦ðKE&[û”ÚU·ˆQyÈJÉÅÍÚ²f’ªkÓ•’Šï5žcßñ0ù„n¡Ng2¦^ôQR¡’ ;i ð<: Q¹A[i˜ãÎ2ì0ÇI4½Lðnžófï%†­iFÿ©þ´¢=É ä¸ `ÛT¬œŠçÒ´ MÛb±\`Á‚eG²\/Q‰çÔ;‚Z…$ IœŒå¶‡- ª^d?“Ô—*lHI£]$Pç`€Î •B­{lÒæâÆ6K…*ËÑÃg¦±sƒL%N¨`A¤Ñ‰á0Rô3Í1þ†®ôµ`¬r&ùǦè„þí‰éËÁcŒ9ÏsRbSt¡ZõéTa¥Xb= xÁ)sQf,NªË-Ü(D)ƒÿ€3™û%TËò¦3 Ó\ ³˜‚-ž…B¤DZ8B R ÁMRraH,‡B–¢-KçÇFH696ž8Š^B€ÉrP‰$K2SŒ2EÏà–Òl‡9½ôÑ'î´}ñc‡Çˆæ6”,(;Uߣ) i :¶C-OY«•(:.URÚ¯â`¢Ò‘¶‹WðYÆ“He(!‰ð¨Ï§hlÜ$FÚ.¶2˜$#O ˜jìX1M5ã$c˜kFÐS†¡ÖôŒ•`¤S•3Ë?–hÇ<ž¼üÌXì§ç¸Q“s @•ªMËqh[pÎX,’Ó Õ¢ƒçH¥1¶ƒ­ZØh¥°,0ÒÁ¨ , ¥QÂÝ –Ñ` ¹Ýö;¾Z#ŒËBjƒ~»$…DKq«-‚£xmDh$F‚6†ÄÀÃÀhö¥Í~ªé¦9ƒôc÷°ÓZµy ÛàI—¨º>àÛ6Ei(ûPµ<*hjŽEÍ’Ô”-C]ª6Ô‚cÛ`Y„Ä@#•BØnš0™ÆHI¨4Y®™iA  3`®ÓÊlW–DkA* ÁL f*cš>nŽp©²x†Nê1­àÙ6 | E!)Ú’‚%¨˜œ’”øRP#°Å‘¦£ FçX„í ´:ÚçÒš I" 5†H@  0šP ­„¢üc°$'˜”Ù)æ‰Ù`§ièÅGïŸAEµNå£6íò¨‘‘eƒmŽ‘ˆlëã4Wpüýë+Wûlä -Ž,ãòãªÐcE;Y̧¹jœE7u!ý8œÉ< éë™ÎgÎ'¢dðxPÛ“Àò³âv~VÝú'ªž‘ÅqZúÏiö)â)??«ŽÏRÈžE§ožug³Ÿô¹gxÝñ3–O¦¹U‚.t–zý]:ó ®ÏœåÁøD¾§}þØ›‰¿G ù±ïÇ\'ñ¸>ó½îgýÞÓúgº-ý¼ÿ¾ÕêïzÍâ,¿ÿÿ:€~ù?«5ûq^«ø çfüÿ¯Ÿ"˜~Ò¡(ÿ^GÍ~¸'»LIEND®B`‚zuluCrypt-6.2.0/plugins/file.png000066400000000000000000000262151425361753700166710ustar00rootroot00000000000000‰PNG  IHDR  Ûph IDATxœíݰÝu}ïû÷gí½W6;;!!á‡`áG±U‹ŽUàzlmO½ÇžéÅÞétÎt˜‰GÇ£ÇqÚ‡±ÁQˆHñÎ=wZÇŸ\‹b=È©£ØâÔRG!?™@PEHB~²Ù{}ï WcöN¾ßÏg­ïz£UU}âæ›o ŠÆÿu檪ªX¿~ý›6lØð½ªªþ¥ªª·=üŠÎÏ#äŠÒCfC€ÐWÖ¯_ÿ¦7þ(¥t{D¼²ô€Ñ©ªêëÖ­!@ß ô…-[¶œ½qãÆ/ÿ<<.,½`u"B„}O€PTUU±iÓ¦wNOO?PUÕï•Þ0àDÐ÷ÅlذañÆ¿\UÕ‡"b¼ô€–èDÄ'nºé¦?*=àPElذá”ҿ¦”<ëP¿NJé“"èG„ì6lØðš”Ò?GÄ¥·´X'"DÐwYmÚ´éwSJÿ?û©å4«Ÿ¼ñÆEÐ7Ùlܸñ5UU}>¥4Qz À餔DÐ7Yüü5wŠ€"DÐ7Û´iÓINçΈXXz À뤔>¹nݺÿ\z0ܪª*"âo#â´ÂSøÙOLÿôG>ò#@hÔæÍ›ß¾Õ.@ÿ褔DPŒ¡16lXkKïàWtRJŸ¾ñÆE¡1###ë"¢[z‡Ô‰d'@hÄ–-[Þ¯/½€#!@v„ÚUUÕ©ªÊ—^ †NUU"ÈF€P»Í›7¿%"V”ÞÀ¬=ÿݱÞRzÐ~„ZUU)¥÷–ÞÀœu"â³"hš¡V>øà%ñë¥wpTDÐ8B­z½ÞŸ”ÞÀ1éD„/Ç#@¨ÍC=4žRò€0øFC„  Ôæ¹çžû½ˆXXzµõÂt  „Ú¤”þCé Ôj´ªªOøÃ!@muº¬ôj7"¨¡[·n=9"V•Þ@#DPB-z½ÞËKo Q¾ ¨…¡½^oeé 4N„ÇL€P‹”Ò¹¥7…މ¡.g—@6£UU}úCúÐÿVz0xuñó?†ËhJé³"˜+B]Àð!Àœ ê"@†ÓhDˆ`Öp¬F#ÂkB€Y @º!B€Y @]ºñén¸A„‡%@€:‰àˆP7–š B€C @Sºñé믿þM¥‡ýC€Mꦔ>+B€ç  i"xrèFÄgo¸áCN€¹t«ª!0ä“!'@€ÜºUU}öúë¯cé!@~(¡[UÕm"†J!0„PR·ªªÛ®»î:CB€¥uSJ"†„ú!!@€~ÑM)Ývíµ×þÇÒC€æ ŸtSJŸ!Ð^è7"ZL€ý¨›Rúü?øA-#@€~Õ­ªJ„@Ë Ÿu{½ž @¿!Ð"Ý^¯÷ùk¯½ö÷JŽE7"n!0Ø0Hºqû_ÿõ_‹P4ÝN§#B`@ `uSJ"•$@€AÖM)Ý~íµ×þné!Àì`Ðu«ªúâ>ð@€mÐM)‰h @€m"B Ï  mDô1´Q7¥ôŵk׊è3h«nUU"úŒÚ¬ÛëõDô´>"@€aÐíõz·‹(O€Ãb¼×ëÝ~Í5׈(H€Ãd<¥tû>ð×—ÃJ€Ãf¼ªª/Š(C€ÃH„@!V"  À0!™†ÝxUU_|ÿûß/B 1ÞétDd @~f¼Óé|ñšk®!Ð ðÿ  ¿L„@ƒÀ¯¯ªêvõ ‡6!B ~àðDÔL€ÙDUU·¿ÿýïÿíÒC  À‹›H)}Q„À± ³#B `ö&"â‹kÖ¬!p”ÀÜL¤”D%0w"Ž’8:Ï¿&äß—ƒD€½‰ªª¾$B`öÀ±!0àØ‰˜%P‰ªª¾´fÍG @ê3"Ž@€Ôk""¾ôWõW—•ýH€Ôo"¥ôe¿J€4C„À!€æˆ8ˆhÖDJéËkÖ¬¹¬ôè y½^O„@€\D„Èi¢×ë}ù/ÿò//)=J yM¤”î! +Ÿah €2&"âÎ÷½ï}"„¡"@Ê™èt:"„¡"@Ê! Pžah€þ0‘R!´žè"„Ö ýåùoÑûÚÒC   ÿLTUu—¡@!´’è_UUÝõÞ÷¾W„Р¿Mt:;Em!@úߤ¡-À`!´‚“?ÿ‰é"„%@ËdUU"„%@a` €Á$BH`p‰Žl"„"@ßdUUw¾÷½ï}Mé!ðb@;LFÄ]"„~'@ÚC„Ð÷4`ff&Çcl/Ã5<"„¾&@ Ýnwa†ËìÎp ÓdDxM}I€@fffrÈ“®ÁàZè…éô#ÍX”á3\ƒÁ¶°ªª;ßóž÷ˆú†€TUÕø3 UUýkÓ× ¦”D}C€@3NÊp¯d¸í BèR:¯ék\}õÕ÷§”lú:´†¡/h@UUfºÎÍ9®CkˆŠ Ѐ”R–û±#ǵh…!B(F€@3^òw÷wM_äÊ+¯Ü×4}Zgaüì焼ºô†€†ìß¿ÿµ9®366öш¸/ǵh•…½^ï.Bnšó†¹òÊ+§SJoˆgr\VYØëõîz×»Þ%BÈF€@s~7×…®ºêªñ¿GD/×5i…NG„€æ¬ºõÖ[ÏÎu±«¯¾úŽ”ÒŸçº­²°ÓéÜõîw¿[„Ð8 ªªêM9¯÷¶·½íãUUý—ðLs·0"D Р”Ò©ª*ë5W¯^ý?ªªúˆx2ë…iBã4ëüüã—å¾èêÕ«¿ZUÕ+"âå¾6oaDÜõ®w½ëâÒCh'Í»ªÄEßþö·?²zõê߉ˆ?‰ˆŸ”ØÀÀZØétþQ„ÐÍ{Óºuë–•ºøêÕ«ÿ."^oˆ‡Kí`à,L)‰j'@ y£Ýn÷ÿ,9`õêÕS«W¯¾iÇŽ/Ÿý|’ÏDÄ®’› SJÿøîw¿[„P›Tzí°eË–mqÆÁ/´<Ü /÷«Çõó6ÇÕ{\?o›Ëqý¶gŽ›îõzüÅ_üÅæCÞ €[o½uôÀ¯éõz¯ˆWEÄ…qFDŒFôÕû®µÇõó¶ƒÞ¾;¥ô>øÁ~÷ÂŒ–ÃfÿþýñðÃÇž={bß¾}133‡ÿà°RÇõËŽ~?îXnßï÷­ŸÞW³9ndd$&&&bþüù±xñâH©ø¿¹v:µñŸJyÞ•W^9ÿôóÿ""âsŸû\çñÇ_6==½("ÆSJ‹žÿ½Ã½~ûôôô¬®Ÿë|Ïœ«Ã¯×›Ýw8>øö‡:ßÑÞ·Ãm;ÚóÍæ}Ô‡h ’¨…g@^ü¸­[·Æ7¿ùÍxøá‡gýàÔ£ÛíÆé§Ÿçž{nÌ›7ïÇäúøPUÕoýùŸÿù·f5 …µ ‡?nÿþýñ÷ÿ÷±eË–CžÈgdd$.¸à‚xéK_ú+¿—ëãCJiã¾}û~ãï|ç³³Ð"^„ zòÉ'ããÿ¸ø€>133?üáã¾ûî;æ/;ZUU­š˜˜X[äâ}@€@CöíÛŸúÔ§bçÎ¥§Ù¶m[<ðÀ%'ü×[o½õ²’J Ð;î¸#vìØQzp[¶l‰íÛ·—œð·7ÝtÓI%” @ [·nM›6•ž¼ˆûï¿¿ä—b166öùÏ}îsÝ"  Ѐ{î¹§ô`öíÛ>úhÉ —<õÔSÿOɹ ¨Ùó?ç …¿ +"âŠ[n¹å¿—‹šmÛ¶ÍÏù€òÓŸþ´ô„ˆˆµó7ó¶Ò#r P³Ý»w—žÌÁÔÔÔQÿ¤ì:UUµîæ›o~WéM P³½{÷–žÌÑJOˆˆˆ”ÒõûØÇ|9ÐjjæË¯€c´ö–[n¹qÍš5£¥‡4A€@Ÿ©ªjõÉ'Ÿ|×­·Þêç„­#@ ?ýû™™™ïÝrË-¿^z@ô¯—TUõí}ìcï\³fÇl |0€þ6^UÕ‡–,YòÍuëÖ­*=àX  ¯ît:ÿzóÍ7ÿ÷5kÖtK8ZÇxD¬=餓¶|ô£ýc_– "¸`ðœŸ8餓þuݺu¿[z À\øã0¸.J)ÝùÑ~ô‡)¥u£££ŸºòÊ+Ÿ)= àH<ƒï¢ªªþ¯©©©¯[·îºo¼qEéA‡ãhÅñîN§óîuëÖý ªªÏÏÌÌü¿ïxÇ;6–ð<íôëñë###×ÜtÓMSJ_­ªê›UU}ëíoû#¥ÇÃK€@û­ªªjUD¼-¥7Þxãö”Ò·ªªÚ[ªªÚÚëõ|Ç;Þ±=¥Tz+Ðr†Ï²ªªÞò‹oèt:qã7N}ä#y&"vEijUU=;ž?¦ªªCž¬×ëÍê¢ß>×ùf{þ¦Ï7›ûu¸k͹ær¾Ã9è:O\ýõoÕ áð¼îÏÿ[4—ü¬Él?¹Íu¾c½}]ç;Ô³KužëXÎ7ËÛùÒ=já»`٨ټyóJOæ¨Óñp‹¸P³ÉÉÉÒ€9H)ù‡€ŒÔ줓N*=˜ƒùóçöë騟švÚi1þüÒ3€YZºtié CE€@ÍRJqÁ”žÌBJ)Î8ãŒÒ3†Š\rÉ%ÑívKÏ^IJeËâøã/=`¨hÀääd\~ùå¥gG0oÞ¼¸ð KÏ:òªW½*^þò——žB§Ó‰ßüÍߌ‰‰‰ÒS†ŽýÁüA¼æ5¯)=øÝn7~ë·~+–,YRz ÀP-=Ú,¥¯ýëãÌ3ÏŒ»îº+vìØQz ­”R,_¾<.¸àÏ|$@ ƒ•+WÆŠ+býúõ±qãÆx衇â™gž)= Z¯ÓéÄÄÄD,[¶,N;í´X´hQTUUzÀP I§Ó‰ /¼0.¼ð¨ª*¦§§cïÞ½/|2tð'E‡û$i¶Ç½Øíæz¾£=n¶{†i_¿ÿ?›ë'èý²çàãFFFb||\pô…ŒŽŽÆ¢E‹^øu¿|Bî¸æëçms9®ßö €ÁàEè@6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À°™™™‰íÛ·ÇîÝ»ãÙgŸ}áíUUÍêöw´·›ëqM_g˜îGîCÎëíqN'æÍ›“““1þüY€æ ÈäñÇo}ë[±yóæ8pà@é90T,X§vZ¬\¹2:Oþ”$@ aSSSqçwÆ~ðƒ9ÿË2P={öĆ bëÖ­qÑEÅi§VzÀÐ Р={öÄ'?ùÉxüñÇKO"âÀñ½ï}/ž~úé8ÿüó#¥TzÀÐñ<44djj*>ñ‰OˆèC›7oŽÍ›7—ž0”4äK_úR<ñÄ¥g‡±aÆøéOZzÀÐ ЀG}4î¿ÿþÒ3€#¨ª*~ô£•ž0t4àßø†œÃxúé§cûöí¥g 5›ššŠ­[·–žÌ’ÈK€@Í~øá˜žž.=˜%¯ÕÈK€@ÍvïÞ]z0ˆ^¯WzÀÐ P³={ö”žÌÑJOj633Sz0G¾i@>ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² P³±±±Ò€9)=`h¨Ù‚ JOæ¨Ûí–ž04ÔlñâÅ¥'s011)¥Ò3††šqÆ1oÞ¼Ò3€Y:õÔSKO*jÖétâ‚ .(=˜¥åË——ž0T4à’K.‰ÑÑÑÒ3€±téÒ8ñÄKÏ*°hÑ¢xík_[zp£££qá…–ž0t4äÒK/U«V•žBJ)^ùÊWú®uhHJ)Þò–·ÄË^ö²ÒS€_022_|±Ÿâ‹Ô¡A£££ñæ7¿9N?ýôøú׿ûöí+= †Ú’%K⢋.Š… –ž0´dðŠW¼"~í×~-î»ï¾Ø´iSlÛ¶-ªª*= †B·ÛSO=5N;í´8å”SüÝ(L€@&Ýn7^ýêWÇ«_ýꘞžŽ½{÷ñ‘Ã}’tðÛg{Ül¯s¬×í÷£¾sõÓ}(yƒÝétb||ÜO9è3 ‰ã?>Ž?þøÞV÷'ŸŽëßãúyÛ\Žë·=Ç4äáEè@6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À0Ú¹sgìÙ³'öíÛUUò˜¹¾ýÅŽ;ÚÛ¹ný×mË}=ÖÛ»n\sX¯;66ccc1>>>«Ûõ ÉÓO?÷Þ{olذ!víÚUz1>>'œpB,]º4ÆÆÆJÏ¡ @ a½^/¾öµ¯Åw¾ó˜žž.=€_ðì³ÏÆc=ÿöoÿ§žzj,[¶,RJ¥gA« hÐþýûã¶Ûn‹­[·–žÀôz½xôÑGcÏž=±bÅŠõ)4ŋС!333ñ™Ï|F| Ý»wÇ–-[fýz`î4äÎ;ïŒmÛ¶•žÀíÙ³'yä‘Ò3 µ4à‰'žˆù—)=€£ôÄOÄþýûKÏ€V Ѐ»ï¾ÛÓ÷¬ªªØ¾}{éÐJj6==[¶l)=€c´k×®èõz¥g@ë¨ÙÃ?Ï=÷\é£^¯{÷î-=ZG€@Íž~úéÒ¨ÉJO€Ö P³={ö”ž@M¦¦¦JO€Ö P3?í =|C¨Ÿ² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€lÔltt´ôj’R*=ZG€@Í,XPz5év»¥'@ë¨Ù¢E‹JO &óæÍ+=ZG€@ÍÎ<óLÿbÐN'&''KÏ€Ö P³ÑÑÑX¹reé£N8!:Ÿ*AÝü­‚\z饴XJ)–-[Vz´’Ï K–,‰W½êU¥gp”N9å”/=ZI€@C~û·;Î:ë¬Ò3˜£… Æé§Ÿ^z´–†ŒŒŒÄýÑÅŠ+JO`–-ZçœsŽŸÿ  РyóæÅ[ßúÖ¸ì²Ë|g,€>ÖétbùòåqÎ9çÄÈÈHé9Ðj~d34,¥—^zi¼â¯ˆ{ï½76lØO=õTéYDÄqÇ'œpB,]º4FG}Z9ø›™LNNÆå—_—_~yìÞ½;ž~ú騷o_ÌÌÌòøªªæôö;îhoçºõ_·-÷õXoïºýqÍa¼nÄϾeúøøxŒÕí£'@ € Ä‚ ~ém³} uÜà×ÏÛær\¿íÄãúyÛ0äá5 @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À0šššŠ={öľ}ûbff&""ªªú¥cþõáÏ7ÛÛ;ßìÏ=¨š|_Íåºm8ß þùî÷óÊØØXŒÅÈÈȬoÔC€@&Ï>ûlÜwß}±~ýúؾ}ûœ(hÆääd,^¼8N>ùäèt|aä @ aUUŽ÷ÞßøÆ7bÿþý¥çð öîÝ{÷îíÛ·ÇòåËãä“OŽ”RéYÐj4==·ß~{<ðÀ¥§pÓÓÓ±mÛ¶Ø»woœuÖYž  hHUUqÛm·Å¦M›JO`–žz꩘™™‰sÎ9§ôh-y ¹ûî»ÅÀÚµkWlß¾½ô h- عsgÜsÏ=¥gp”{ì±8pà@éÐJp÷Ýw¿ðíu<½^ϳ Ð5›žžŽ7–žÀ1Ú¹s§o™  P³ÿøÇž¶h™™™Ø»woéÐ:j¶sçÎÒ¨‰P‚ú ¨Ùž={JO &SSS¥'@ë¨ÙsÏ=Wz5éõz¥'@ë d#@€l² @6ÈF€Ù d#@€l² @6ÈF€@ÍFGGKO &ŽO• nþVAÍ&''KO &þQ ê'@ fÇ|é ÔdÞ¼y¥'@ë¨Ù™gžé_ÌZ ÓéÄ‚ JÏ€Ö P³n·+V¬(=€ctüñÇ{ 4Àß*hÀ%—\)¥Ò38Ë–-+=ZI€@–-[/{ÙËJÏà(-Y²$&&&JÏ€V Ðßÿýß÷¯ghþüùqæ™g–ž­%@ Ä.n\ HIDAT!cccqÅWÄòåËKO`–&''cåÊ•^û ò· 499ú§_|±3€>–RŠSN9%V­Zccc¥ç@«ù^¡Ð°ÑÑÑxÃÞ¯|å+ãÛßþvlÚ´)žyæ™Ò³ˆŸ}Œ>á„âÔSOñññÒs`(ÈdÉ’%ñÆ7¾1ªªŠíÛ·ÇÞ½{cïÞ½/ü~UU³:ÏÁÇííæz\Óצûцûó:myËŸAºG:®ŸîÇØØXt»Ý˜˜˜xá»ÎõÏ>ptd–R:ä‹Ógû@ê¸Á?®Ÿ·Íå¸~Û3ˆÇõó¶a<ÈÃ¥Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€ÙŒ–ÃêÀñÌ3ϼð몪~é÷þõ\{±Û5uÝ£Ý3LûúýÿÙl÷õÛž~ê¸6þù”}ccc1222«=@½d233?úÑbãÆñÐCÅÔÔTéICmdd$.\‹/ŽO<±ô2xàâ«_ýjìÚµ«ô~nff&vîÜ;wüä'qúé§ÇâÅ‹KÏ‚Ö Р^¯_ùÊWâ»ßýné)ÁâÁŒ¥K—Æé§Ÿ)¥Ò“ µ4è _øBüð‡?,=€YzüñÇczz:Î>ûìÒS µ|,hÈ·¿ýmñ0€ž|òÉxì±ÇJÏ€Ö ЀݻwÇ×¾öµÒ38J>úh<÷Üs¥g@+ hÀ?ÿó?{à`½^/¶oß^z´’šUU÷ßé£;vÌùçâ/N€@Íy䑨¿é£éé騷o_éÐ:j¶cǎҨɳÏ>[z´ŽšíÞ½»ôj255Uz´Žšyñ9@{ôz½Ò u² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@ fŽ¿Vm‘R*=ZÇgJP³ÉÉÉ񬃯ØXé Ð:j¶páÂÒ¨I·Û-=ZG€@Í^ò’—ø2,€H)Å‚ JÏ€ÖñYÔl||<Î>ûìÒ38F .Œ‘‘‘Ò3 u4àu¯{]é £SO=µôh% 8óÌ3cÕªU¥gp”/^ì˯ !òæ7¿9N<ñÄÒ3˜£ñññ8묳JÏ€Ö ÐyóæÅÿñ‹€rÜqÇŹçžëµÐ  :á„âÏþìÏâüóÏ/=€±xñâ8ÿüócÞ¼y¥§@«–m7>>ø‡<òHÜsÏ=ñÐCÅôôtéYDD§Ó‰… ÆòåËcþüù¥çÀP ÉgœW\qELMMŶmÛb÷îݱgÏžb¤ªªY§Ôqý²£ß;–Û÷û}ë§÷U[Žó÷¯ÌŸ©”Rt»Ý˜7o^LNN¾ðåVÇz`vdÖívcÅŠ¿òöƒø÷@è¸Á?®Ÿ·Íå¸~Û3ˆÇõó¶a<ÈÃk@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l`6z¥Ð„ºì.=hÔÞÒhB]´›Çzj!@¨‹JÐb)¥]¥7Єºl-=hN¯×óXO-µH)m(½hŽÇzê"@¨Ëƒ¥ÍI)m.½v Ô¢ÓéÜWzМ^¯÷ÃÒhB-Î>ûì'"b}é@#î¿á†ž(=‚v ÔéîÒ€FÜ]zí!@¨MJéKoêç1ž: j322ò•ðó@ mvíß¿ÿ+¥GЄڜuÖYϦ”>WzP«Ï­[·nªôÚC€P·O”Ô§×ë}²ôÚE€P«+VüSDü ô ÷}èCú§Ò#hB­RJ‘Rú@é@-<¦S;BíV¬Xñ÷~Z* ¶ªª6Ο?ÿ ¥wÐ>„Ú¥”z½^ï=¥wG¯Óé¼gÍš5½Ò;hB#Î=÷Ü/TUå[öÀ`úŸ×]wÝ¥GÐN„ÆŒŽŽ^¾m –g;ÎÛK ½yéK_ú`UU¾ HUUÿíÚk¯}°ôÚK€Ð¨sÏ=÷#UUýCéÀ‹«ªêŽë¯¿þ£¥wÐn„F¥”¢ªª?‰ˆŸ”ÞÑ####Rzí'@hÜyç·£×ë½!"v•ÞÒ“###¿síµ×z¬¦q„,Î;ï¼ûSJ¿SUÕ3¥·¿ä™^¯÷ûk×®ÝXzÃA€ÍÊ•+¿ÿI„@ßx&"Þ|à 7|·ô†‡!«U«V}eddäòˆØQz ¹Nçß]wÝuÿ«ô†‹!»sÎ9ç;333¯‹ˆ‡Ko€!õp§ÓyÝÚµk=óAv„".¸à‚õóæÍûˆøBé-0d¾pàÀßX»víúÒCN£¥0¼Î:ë¬]UU½yÓ¦Mÿ5"ÖFÄxéMÐbÏTUõß®»îº•Âpó E¥”bÕªUI)~`!4㎑‘‘óÄýÀ3 ô…U«V=°aÆÿˆˆ‹Ê.€VøAJé}k×®ýŸ¥‡Àó}å¼óÎû‡ªªþaÓ¦Moìõz‹Ko€ASUÕw:Î5ƒ~$@è;)¥ˆˆ;"âŽõë׿<"þ”ÒUU\vô¯”Òã½^ï3Nço×®]ûƒÒ{àpRé0_ÿú×G—.]úÚªª.¯ªê²ˆxuüB@WUõKÇüëA8®Ÿ·9®ÞãúyÛ\Žë·=ƒx\?osÜ@ü˜ŠˆïFÄ×:Î×7mÚôO·Ýv[ï'€>"@H?þñÇŸ~úé•)¥•)¥U½^ïô”Ò¢^¯7Ïÿ÷+Žõ­ƒõz¿üqþX¬Žt«îáÎ?×ó ÓýhÃ}(yA|µá>ê:îÇìÎ?Ësí}þ¿^¯·+"¶¥”6OOOožššÚüáøÙY]ø¹ÿ‘iEtÄ\oIEND®B`‚zuluCrypt-6.2.0/plugins/generic_header/000077500000000000000000000000001425361753700201625ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/generic_header/CMakeLists.txt000066400000000000000000000013121425361753700227170ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.6) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -std=c++11 -I${PROJECT_BINARY_DIR}/plugins/luks -I${PROJECT_BINARY_DIR} ) if( QT5 ) QT5_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( generic_header ${ICON} main.cpp ) else() QT4_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( generic_header ${ICON} main.cpp ) endif() set_target_properties( generic_header PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( generic_header PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) TARGET_LINK_LIBRARIES( generic_header plugin ) install( TARGETS generic_header RUNTIME DESTINATION "${PLUGINPATH}" ) zuluCrypt-6.2.0/plugins/generic_header/main.cpp000066400000000000000000000022121425361753700216070ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "../mainwindow.h" #include "../plugins.h" int main( int argc,char * argv[] ) { QApplication a( argc,argv ) ; MainWindow w( plugins::luks ) ; w.setToken( argv ) ; w.setApplicationName( "luks" ) ; w.setkeyLabel( QObject::tr( "Enter LUKS Key Below" ) ) ; w.setkeyFileLabel( QObject::tr( "Enter A Path To A LUKS Header Below" ) ) ; w.Show() ; return a.exec() ; } zuluCrypt-6.2.0/plugins/gpg/000077500000000000000000000000001425361753700160135ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/gpg/CMakeLists.txt000066400000000000000000000012111425361753700205460ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -std=c++11 -I${PROJECT_BINARY_DIR}/plugins/gpg -I${PROJECT_BINARY_DIR} ) if( QT5 ) QT5_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( gpg ${ICON} main.cpp ) else() QT4_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( gpg ${ICON} main.cpp ) endif() set_target_properties( gpg PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( gpg PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) TARGET_LINK_LIBRARIES( gpg plugin ) install( TARGETS gpg RUNTIME DESTINATION "${PLUGINPATH}" ) zuluCrypt-6.2.0/plugins/gpg/main.cpp000066400000000000000000000022421425361753700174430ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "../mainwindow.h" #include "../plugins.h" int main( int argc,char * argv[] ) { QApplication a( argc,argv ) ; MainWindow w( plugins::gpg ) ; w.setToken( argv ) ; w.setApplicationName( "gpg" ) ; w.setkeyLabel( QObject::tr( "Enter GPG Key Below" ) ) ; w.setkeyFileLabel( QObject::tr( "Enter A Path To A GPG Keyfile Below" ) ) ; w.setExe( { "gpg" } ) ; w.Show() ; return a.exec() ; } zuluCrypt-6.2.0/plugins/hmac/000077500000000000000000000000001425361753700161465ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/hmac/CMakeLists.txt000066400000000000000000000011641425361753700207100ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -std=c++11 -I${PROJECT_BINARY_DIR} ) if( QT5 ) QT5_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( hmac ${ICON} main.cpp ) else() QT4_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( hmac ${ICON} main.cpp ) endif() set_target_properties( hmac PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( hmac PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) TARGET_LINK_LIBRARIES( hmac plugin -lgcrypt ) install( TARGETS hmac RUNTIME DESTINATION "${PLUGINPATH}" ) zuluCrypt-6.2.0/plugins/hmac/README000066400000000000000000000002461425361753700170300ustar00rootroot00000000000000 This plugin takes a path to a keyfile and a password and then generates a key by calculating hmac-sha256 of the contents of the keyfile using the provided password. zuluCrypt-6.2.0/plugins/hmac/hmac.pro000066400000000000000000000007031425361753700176000ustar00rootroot00000000000000#------------------------------------------------- # # Project created by QtCreator 2012-08-26T19:48:55 # #------------------------------------------------- QT += core gui TARGET = hmac TEMPLATE = app SOURCES += main.cpp\ ../mainwindow.cpp \ ../../zuluCrypt-gui/dialogmsg.cpp HEADERS += ../mainwindow.h \ ../../zuluCrypt-gui/dialogmsg.h FORMS += ../mainwindow.ui ../../zuluCrypt-gui/dialogmsg.ui QMAKE_CXXFLAGS += -std=c++11 zuluCrypt-6.2.0/plugins/hmac/main.cpp000066400000000000000000000022121425361753700175730ustar00rootroot00000000000000/* * * Copyright (c) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "../mainwindow.h" #include "../plugins.h" #include int main( int argc,char * argv[] ) { QApplication a( argc,argv ) ; MainWindow w( plugins::hmac_key_1 ) ; w.setToken( argv ) ; w.setApplicationName( "hmac" ) ; w.setkeyLabel( QObject::tr( "Enter A Password Below" ) ) ; w.setkeyFileLabel( QObject::tr( "Enter A Path To A Keyfile Below" ) ) ; w.Show() ; return a.exec() ; } zuluCrypt-6.2.0/plugins/icon.qrc000066400000000000000000000002341425361753700166740ustar00rootroot00000000000000 default.png keyfile.png file.png zuluCrypt-6.2.0/plugins/keydialog-qt/000077500000000000000000000000001425361753700176305ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/keydialog-qt/CMakeLists.txt000066400000000000000000000024571425361753700224000ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -std=c++11 -I${PROJECT_BINARY_DIR}/plugins/keydialog-qt -I${PROJECT_BINARY_DIR} ) if( QT5 ) QT5_WRAP_UI( UI mainwindow.ui ) QT5_WRAP_CPP( MOC mainwindow.h ) QT5_ADD_RESOURCES( ICON icon.qrc ) add_executable( keydialog-qt ${ICON} ${MOC} ${UI} main.cpp mainwindow.cpp ) TARGET_LINK_LIBRARIES( keydialog-qt sharedObject ${Qt5Widgets_LIBRARIES} ${QtCore_LIBRARIES} zuluCryptPluginManager ${blkid} ) set_target_properties( keydialog-qt PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( keydialog-qt PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) else() INCLUDE( ${QT_USE_FILE} ) QT4_WRAP_UI( UI mainwindow.ui ) QT4_WRAP_CPP( MOC mainwindow.h ) QT4_ADD_RESOURCES( ICON icon.qrc ) add_executable( keydialog-qt ${ICON} ${MOC} ${UI} main.cpp mainwindow.cpp ) TARGET_LINK_LIBRARIES( keydialog-qt sharedObject ${QT_LIBRARIES} zuluCryptPluginManager ${blkid} ) set_target_properties( keydialog-qt PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( keydialog-qt PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) endif() install( TARGETS keydialog-qt RUNTIME DESTINATION "${PLUGINPATH}" ) zuluCrypt-6.2.0/plugins/keydialog-qt/icon.qrc000066400000000000000000000001461425361753700212700ustar00rootroot00000000000000 key.png zuluCrypt-6.2.0/plugins/keydialog-qt/key.png000066400000000000000000000036141425361753700211320ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎébKGDÿÿÿ ½§“ pHYs¯¯^‘tIMEÚ ÷Ææë IDATXí—]h\ÇÇsï{W»+YÚ]}X’%Û)vâš’8µ yP ”Ò<…×ÐBí§búJk§¥PBÉCiñKÓCêÚPhÒ`h)¡-Ôýql7õ‡lË–¥H+íJ»{¿ïÜéÃ]m%[–T·.sïÌΞÿœùŸÿ™´­R©÷ÿ›‰5ïú±°¿¿²Z­¶6šxDÿ?¬õ÷M‡Ï­uj­yÏÔ––BdË!²B€ÖYŸad3Ò4kÛß©ÈS½tš°aqåÊú™››Ã–ÇqXY^&_(Ë僀J¥B£årò]ºr’]£9¼ FõîL „!=ÝÝHÛÞ„À‚‰‰‰NDÆÇÆ:¡†Ñ!cÆÃ”]†ÉØpžßŸ{Ô¨&N÷³”Ëe†0¥$]%ìv" $޳ ÕÞ?Ñfþjf¬šR Ë$_´ðš‹È‚C"ºpr†eÖë¹³tûe{¿ ÓDJÙé“Rv2Ų,,ËBë'ßE¡§ we)%‰Îxbš&†iþ'u·Š€‚‹~ˆ%%;wî¤^«‘jeY„aˆ”’ÞÞ^¤”ÌÌÌÐ××G,Þû+õ˜Ùk0þ³°$˜žÞEWW޳µÀNh­u†%€?;ý–>ø™Ãн}ƒúßü–¾zõšv]WÇq¬ƒ XUÂÏo×u¹yó&®ë244D³Ù¤Õj‘Ëå0 ß÷Éçó,..£££LMM‘&!½=Ù*‹Ise™¹¹YŠÅ½½½!6ŒÂ†B´ÿ~,ËZG²UulµZ …uDŸ~å+¼XýOê¡1Å݇9ÿ›IªŒíehçN=<< ødaaáÑJx§îéc^Ò7]íµš:I­”ÒI’h×uuÇ:ˆc=ñ¢þçoèé»wõ…¿þm3‘L§ï܉Û~©¿¿ßÜ’ãÁ£Ù×kÆ)I:£1†å©¥bDw7±ÖÔoÜ êûÙ‘7 ÑZgÄ Z­–n4¼ôòË_.‹¿«V«jË,@´Ïš«5ߟ…k?G'bþT? M­Û·8vŒê{ïáºnG’$! C|ß×Q‰¯?~¬V«½S«Õ’m¥a†¡-8i ùQÐ)´Á0ð£1î¾ùcºöì!cr{÷²|þ<´ÏQxžŽ¢H|õèÑã—/_>[¯×“GUÀ‡ODZ£E LC ÒˆpøKØ÷þ€.ì"72ÀîW_%p]Âf“î矧”¥Qáyž6LSœüΉï^ü裟zž§6+ÁEàvC±à§üñ^È‹1o^÷(”öBí*Tž%B”ç¡ãÒåûˆ¶`y­–6-Süòì[¯¿ýëw¿¿•ó #0V08ý\w¦Á©à¹AI£_@« ³×«Oš¦äóy-m[œxíÄ÷Μ9û:nç÷€HiâtµAîý ý©W@%뜫4%N†‡‡u³±,N~ûµ“gΜý Ø¦mÌ@ ‘«ã/¶§z¡”"IR¥ô'Ÿ{žxâëµÚÒOþçòÅâ?+n89UŠ(Šê£cc'ÇùEÅÉc_¥Ëår÷ÒÒÒS[\Ïõsp¿¯¯ï^½^Oy û7ÉK1¯õƒ IEND®B`‚zuluCrypt-6.2.0/plugins/keydialog-qt/keydialog-qt.pro000066400000000000000000000010331425361753700227410ustar00rootroot00000000000000#------------------------------------------------- # # Project created by QtCreator 2012-08-26T19:48:55 # #------------------------------------------------- QT += core gui TARGET = keykeyfile TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp \ ../../zuluCrypt-gui/socketsendkey.cpp \ ../../zuluCrypt-gui/dialogmsg.cpp HEADERS += mainwindow.h \ ../../zuluCrypt-gui/socketsendkey.h \ ../../zuluCrypt-gui/dialogmsg.h FORMS += mainwindow.ui ../../zuluCrypt-gui/dialogmsg.ui LIBS += -lzuluCryptPluginManager zuluCrypt-6.2.0/plugins/keydialog-qt/main.cpp000066400000000000000000000016621425361753700212650ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "mainwindow.h" int main( int argc,char * argv[] ) { QApplication a( argc,argv ) ; MainWindow w ; w.setToken( argv ) ; w.show() ; return a.exec() ; } zuluCrypt-6.2.0/plugins/keydialog-qt/mainwindow.cpp000066400000000000000000000050271425361753700225140ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "mainwindow.h" #include "ui_mainwindow.h" #include "../../zuluCrypt-cli/pluginManager/libzuluCryptPluginManager.h" MainWindow::MainWindow( QWidget * parent ) : QWidget( parent ),m_ui( new Ui::MainWindow ) { m_ui->setupUi( this ) ; this->setFixedSize( this->size() ) ; m_ui->lineEditKey->setEchoMode( QLineEdit::Password ) ; this->setWindowIcon( QIcon( ":/key.png" ) ) ; QAction * ac = new QAction( this ) ; QList keys ; keys.append( Qt::Key_Enter ) ; keys.append( Qt::Key_Return ) ; ac->setShortcuts( keys ) ; connect( ac,SIGNAL( triggered() ),this,SLOT( defaultButton() ) ) ; this->addAction( ac ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->pbOpen,SIGNAL( clicked() ),this,SLOT( pbOpen() ) ) ; this->SetFocus() ; } void MainWindow::defaultButton() { if( m_ui->pbCancel->hasFocus() ){ this->pbCancel() ; }else{ this->pbOpen() ; } } void MainWindow::setToken( char * const * e ) { m_token = *( e + 3 ) ; m_handle = zuluCryptPluginManagerOpenConnection( m_token.toLatin1().constData() ) ; } void MainWindow::SetFocus() { if( m_ui->lineEditKey->text().isEmpty() ){ m_ui->lineEditKey->setFocus() ; }else{ m_ui->pbOpen->setFocus() ; } } void MainWindow::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbCancel() ; } void MainWindow::pbCancel() { m_handle = zuluCryptPluginManagerOpenConnection( m_token.toLatin1().constData() ) ; QCoreApplication::exit( 1 ) ; } void MainWindow::done() { this->hide() ; QCoreApplication::exit() ; } void MainWindow::pbOpen() { QByteArray key = m_ui->lineEditKey->text().toLatin1() ; zuluCryptPluginManagerSendKey( m_handle,key.constData(),key.size() ) ; this->done() ; } MainWindow::~MainWindow() { zuluCryptPluginManagerCloseConnection( m_handle ) ; delete m_ui ; } zuluCrypt-6.2.0/plugins/keydialog-qt/mainwindow.h000066400000000000000000000026541425361753700221640ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include #include #include #include "../../zuluCrypt-gui/dialogmsg.h" namespace Ui { class MainWindow; } class MainWindow : public QWidget { Q_OBJECT public: MainWindow( QWidget * parent = 0 ) ; void setToken( char * const * ) ; ~MainWindow(); private slots: void defaultButton( void ) ; void pbOpen( void ) ; void pbCancel( void ) ; void done( void ) ; private: void closeEvent( QCloseEvent * ) ; void SetFocus( void ); Ui::MainWindow * m_ui; QString m_token ; void * m_handle ; }; #endif // MAINWINDOW_H zuluCrypt-6.2.0/plugins/keydialog-qt/mainwindow.ui000066400000000000000000000042011425361753700223400ustar00rootroot00000000000000 MainWindow 0 0 542 82 Send A Key To Unlock A Volume 0 0 541 81 180 50 91 31 &Send 270 50 91 31 &Cancel 0 20 81 31 Key Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 90 20 361 31 0 0 0 6 lineEditKey pbOpen pbCancel zuluCrypt-6.2.0/plugins/keyfile.png000066400000000000000000000036141425361753700174000ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎébKGDÿÿÿ ½§“ pHYs¯¯^‘tIMEÚ ÷Ææë IDATXí—]h\ÇÇsï{W»+YÚ]}X’%Û)vâš’8µ yP ”Ò<…×ÐBí§búJk§¥PBÉCiñKÓCêÚPhÒ`h)¡-Ôýql7õ‡lË–¥H+íJ»{¿ïÜéÃ]m%[–T·.sïÌΞÿœùŸÿ™´­R©÷ÿ›‰5ïú±°¿¿²Z­¶6šxDÿ?¬õ÷M‡Ï­uj­yÏÔ––BdË!²B€ÖYŸad3Ò4kÛß©ÈS½tš°aqåÊú™››Ã–ÇqXY^&_(Ë僀J¥B£årò]ºr’]£9¼ FõîL „!=ÝÝHÛÞ„À‚‰‰‰NDÆÇÆ:¡†Ñ!cÆÃ”]†ÉØpžßŸ{Ô¨&N÷³”Ëe†0¥$]%ìv" $޳ ÕÞ?Ñfþjf¬šR Ë$_´ðš‹È‚C"ºpr†eÖë¹³tûe{¿ ÓDJÙé“Rv2Ų,,ËBë'ßE¡§ we)%‰Îxbš&†iþ'u·Š€‚‹~ˆ%%;wî¤^«‘jeY„aˆ”’ÞÞ^¤”ÌÌÌÐ××G,Þû+õ˜Ùk0þ³°$˜žÞEWW޳µÀNh­u†%€?;ý–>ø™Ãн}ƒúßü–¾zõšv]WÇq¬ƒ XUÂÏo×u¹yó&®ë244D³Ù¤Õj‘Ëå0 ß÷Éçó,..£££LMM‘&!½=Ù*‹Ise™¹¹YŠÅ½½½!6ŒÂ†B´ÿ~,ËZG²UulµZ …uDŸ~å+¼XýOê¡1Å݇9ÿ›IªŒíehçN=<< ødaaáÑJx§îéc^Ò7]íµš:I­”ÒI’h×uuÇ:ˆc=ñ¢þçoèé»wõ…¿þm3‘L§ï܉Û~©¿¿ßÜ’ãÁ£Ù×kÆ)I:£1†å©¥bDw7±ÖÔoÜ êûÙ‘7 ÑZgÄ Z­–n4¼ôòË_.‹¿«V«jË,@´Ïš«5ߟ…k?G'bþT? M­Û·8vŒê{ïáºnG’$! C|ß×Q‰¯?~¬V«½S«Õ’m¥a†¡-8i ùQÐ)´Á0ð£1î¾ùcºöì!cr{÷²|þ<´ÏQxžŽ¢H|õèÑã—/_>[¯×“GUÀ‡ODZ£E LC ÒˆpøKØ÷þ€.ì"72ÀîW_%p]Âf“î矧”¥Qáyž6LSœüΉï^ü裟zž§6+ÁEàvC±à§üñ^È‹1o^÷(”öBí*Tž%B”ç¡ãÒåûˆ¶`y­–6-Süòì[¯¿ýëw¿¿•ó #0V08ý\w¦Á©à¹AI£_@« ³×«Oš¦äóy-m[œxíÄ÷Μ9û:nç÷€HiâtµAîý ý©W@%뜫4%N†‡‡u³±,N~ûµ“gΜý Ø¦mÌ@ ‘«ã/¶§z¡”"IR¥ô'Ÿ{žxâëµÚÒOþçòÅâ?+n89UŠ(Šê£cc'ÇùEÅÉc_¥Ëår÷ÒÒÒS[\Ïõsp¿¯¯ï^½^Oy û7ÉK1¯õƒ IEND®B`‚zuluCrypt-6.2.0/plugins/keykeyfile/000077500000000000000000000000001425361753700173775ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/keykeyfile/CMakeLists.txt000066400000000000000000000012721425361753700221410ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -std=c++11 -I${PROJECT_BINARY_DIR}/plugins/keykeyfile -I${PROJECT_BINARY_DIR} ) if( QT5 ) QT5_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( keykeyfile ${ICON} main.cpp ) else() QT4_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( keykeyfile ${ICON} main.cpp ) endif() set_target_properties( keykeyfile PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( keykeyfile PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) TARGET_LINK_LIBRARIES( keykeyfile plugin ) install( TARGETS keykeyfile RUNTIME DESTINATION "${PLUGINPATH}" ) zuluCrypt-6.2.0/plugins/keykeyfile/main.cpp000066400000000000000000000022051425361753700210260ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "../mainwindow.h" #include "../plugins.h" int main( int argc,char * argv[] ) { QApplication a( argc,argv ) ; MainWindow w( plugins::keyKeyFile ) ; w.setToken( argv ) ; w.setkeyLabel( QObject::tr( "Enter Key Below" ) ) ; w.setkeyFileLabel( QObject::tr( "Enter A Path To A Keyfile Below" ) ) ; w.setButtonIcon( "Keyfile" ) ; w.Show() ; return a.exec() ; } zuluCrypt-6.2.0/plugins/keyring/000077500000000000000000000000001425361753700167065ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/keyring/README000066400000000000000000000001161425361753700175640ustar00rootroot00000000000000 This source file is handled by "CMakeLists.txt" file in ../../zuluCrypt-cli zuluCrypt-6.2.0/plugins/keyring/keyring.c000066400000000000000000000063521425361753700205300ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ /* * http://developer.gnome.org/gnome-keyring/stable/gnome-keyring-Simple-Password-Storage.html#gnome-keyring-find-password-sync */ #include "../../zuluCrypt-cli/pluginManager/libzuluCryptPluginManager.h" #include #include #include #include static int getKey( const char * path,const char * uuid,gchar ** key ) { gchar * c ; SecretSchema lps ; char UUID[ 64 ] ; memset( &lps,'\0',sizeof( SecretSchema ) ) ; lps.name = "lxqt.Wallet.zuluCrypt.zuluCrypt" ; lps.flags = SECRET_SCHEMA_NONE ; lps.attributes[0].name = "string" ; lps.attributes[0].type = SECRET_SCHEMA_ATTRIBUTE_STRING ; lps.attributes[1].name = "NULL" ; lps.attributes[1].type = 0 ; if( strcmp( uuid,"Nil" ) == 0 ){ c = secret_password_lookup_sync( &lps,NULL,NULL,"string",path,NULL ) ; if( c != NULL ){ *key = c ; return 1 ; }else{ return 0 ; } } snprintf( UUID,64,"UUID=\"%s\"",uuid ) ; c = secret_password_lookup_sync( &lps,NULL,NULL,"string",UUID,NULL ) ; if( c != NULL ){ *key = c ; return 1 ; }else{ snprintf( UUID,64,"UUID=%s",uuid ) ; c = secret_password_lookup_sync( &lps,NULL,NULL,"string",UUID,NULL ) ; if( c != NULL ){ *key = c ; return 1 ; }else{ c = secret_password_lookup_sync( &lps,NULL,NULL,"string",uuid,NULL ) ; if( c != NULL ){ *key = c ; return 1 ; }else{ return 0 ; } } } return 0 ; } int main( int argc,char * argv[] ) { /* * const char * exe = argv[ 0 ] ; name of this executable * const char * device = argv[ 1 ] ; path to the encrypted volume * int size = atoi( argv[ 4 ] ) ; key maximum length * * argv[ 5 ] is argument list given to zuluCrypt-cli * const char * arg_v = argv[ 5 ] ; command line arguments passed to zuluCrypt-cli/zuluMount-cli * */ const char * path = argv[ 1 ] ; const char * uuid = argv[ 2 ] ; const char * addr = argv[ 3 ] ; int st = 1 ; void * handle ; gchar * key ; const char * e ; if( argc <= 3 ){ return 1 ; } /* * this function is to be called as soon as possible. * It will fail if called 10 seconds after the plugin is started. */ handle = zuluCryptPluginManagerOpenConnection( addr ) ; if( handle ){ if( getKey( path,uuid,&key ) ){ e = ( const char * ) key ; zuluCryptPluginManagerSendKey( handle,e,strlen( e ) ) ; secret_password_free( key ) ; st = 0 ; }else{ st = 1 ; } zuluCryptPluginManagerCloseConnection( handle ) ; }else{ st = 1 ; } return st ; } zuluCrypt-6.2.0/plugins/kwallet/000077500000000000000000000000001425361753700167015ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/kwallet/CMakeLists.txt000066400000000000000000000027351425361753700214500ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.6) if( QT5 ) #QT5_WRAP_CPP( MOC wallet.h ) else() find_package(KDE4 QUIET) if(KDE4_FOUND) find_library( LIBKWALLETBACKEND_ libkwalletbackend.so ) find_library( LIBQTCORE_ libQtCore.so ) find_library( LIBQTGUI_ libQtGui.so ) find_library( LIBKDEUI_ libkdeui.so ) find_library( LIBKDECORE_ libkdecore.so ) if( NOT LIBKWALLETBACKEND_ ) find_library( LIBKWALLETBACKEND_ libkwalletbackend.so.4 ) endif() if( LIBKWALLETBACKEND_ ) if( LIBQTCORE_ ) if( LIBQTGUI_ ) if( LIBKDEUI_ ) if( LIBKDECORE_ ) include(KDE4Defaults) include_directories(${KDE4_INCLUDES}) add_definitions(-I${KDE4_INCLUDE_DIR}) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -std=c++11 -I${PROJECT_BINARY_DIR}/plugins/kwallet/ -I${PROJECT_BINARY_DIR} -I${KDEINCLUDE} ) INCLUDE( ${QT_USE_FILE} ) QT4_WRAP_CPP( MOC wallet.h ) add_executable( kwallet ${MOC} main.cpp wallet.cpp ) TARGET_LINK_LIBRARIES( kwallet ${LIBQTCORE_} ${LIBQTGUI_} ${LIBKDECORE_} ${LIBKDEUI_} sharedObject ${LIBKWALLETBACKEND_} zuluCryptPluginManager ) set_target_properties( kwallet PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( kwallet PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) install( TARGETS kwallet RUNTIME DESTINATION "${PLUGINPATH}" ) endif() endif() endif() endif() endif() endif() endif() zuluCrypt-6.2.0/plugins/kwallet/kwallet.pro000066400000000000000000000012551425361753700210710ustar00rootroot00000000000000#------------------------------------------------- # # Project created by QtCreator 2012-08-10T23:43:26 # #------------------------------------------------- QT += core QT -= gui TARGET = kwallet CONFIG += console CONFIG -= app_bundle TEMPLATE = app SOURCES += main.cpp \ wallet.cpp \ ../../zuluCrypt-gui/socketsendkey.cpp \ ../../zuluCrypt-gui/zuluoptions.cpp QMAKE_CXXFLAGS += -I/home/local/KDE4/include -Wall LIBS += -lkwalletbackend -L/home/local/KDE4/lib -lzuluCryptPluginManager INCLUDEPATH +=/home/ink/build /home/local/KDE4/include HEADERS += \ wallet.h \ ../../zuluCrypt-gui/socketsendkey.h \ ../../zuluCrypt-gui/zuluoptions.h zuluCrypt-6.2.0/plugins/kwallet/main.cpp000066400000000000000000000021001425361753700203220ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "wallet.h" int main( int argc,char * argv[] ) { QCoreApplication a( argc,argv ) ; wallet w( argv[ 1 ],argv[ 2 ],argv[ 3 ] ) ; QCoreApplication::setApplicationName( "zuluCrypt kwallet plugin" ) ; QMetaObject::invokeMethod( &w,"openWallet",Qt::QueuedConnection ) ; return a.exec() ; } zuluCrypt-6.2.0/plugins/kwallet/wallet.cpp000066400000000000000000000036061425361753700207020ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "wallet.h" #include #include "../../zuluCrypt-gui/utility.h" #include "../../zuluCrypt-cli/pluginManager/libzuluCryptPluginManager.h" wallet::wallet( const QString& path,const QString& uuid,const QString& sockAddr ) { if( uuid == "Nil" ){ m_keyID = path ; }else{ m_keyID = QString( "UUID=\"%1\"" ).arg( uuid ) ; } m_sockAddr = sockAddr ; m_handle = ::zuluCryptPluginManagerOpenConnection( m_sockAddr.toLatin1().constData() ) ; } void wallet::openWallet() { m_wallet = Wallet::openWallet( KWallet::Wallet::LocalWallet(),0,KWallet::Wallet::Synchronous ) ; if( m_wallet ){ m_wallet->setFolder( utility::applicationName() ) ; QString key ; m_wallet->readPassword( m_keyID,key ) ; if( key.isEmpty() && m_keyID.startsWith( "UUID=" ) ){ m_wallet->readPassword( m_keyID.replace( "\"","" ),key ) ; } if( key.isEmpty() ){ QCoreApplication::exit( 1 ) ; }else{ ::zuluCryptPluginManagerSendKey( m_handle,key.toLatin1().constData(),key.size() ) ; QCoreApplication::exit( 0 ) ; } }else{ QCoreApplication::exit( 1 ) ; } } wallet::~wallet() { ::zuluCryptPluginManagerCloseConnection( m_handle ) ; delete m_wallet ; } zuluCrypt-6.2.0/plugins/kwallet/wallet.h000066400000000000000000000024571425361753700203520ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef WALLET_H #define WALLET_H #include #include #include #include #include #include #include #include #include "wallet.h" using namespace KWallet ; class wallet : public QObject { Q_OBJECT public: wallet( const QString& path,const QString& uuid,const QString& sockAddr ) ; ~wallet() ; private slots: void openWallet( void ) ; private: Wallet * m_wallet ; QString m_keyID ; QString m_sockAddr ; void * m_handle ; }; #endif // WALLET_H zuluCrypt-6.2.0/plugins/luks/000077500000000000000000000000001425361753700162145ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/luks/CMakeLists.txt000066400000000000000000000012161425361753700207540ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.6) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -std=c++11 -I${PROJECT_BINARY_DIR}/plugins/luks -I${PROJECT_BINARY_DIR} ) if( QT5 ) QT5_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( luks ${ICON} main.cpp ) else() QT4_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( luks ${ICON} main.cpp ) endif() set_target_properties( luks PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( luks PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) TARGET_LINK_LIBRARIES( luks plugin ) install( TARGETS luks RUNTIME DESTINATION "${PLUGINPATH}" ) zuluCrypt-6.2.0/plugins/luks/main.cpp000066400000000000000000000022121425361753700176410ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "../mainwindow.h" #include "../plugins.h" int main( int argc,char * argv[] ) { QApplication a( argc,argv ) ; MainWindow w( plugins::luks ) ; w.setToken( argv ) ; w.setApplicationName( "luks" ) ; w.setkeyLabel( QObject::tr( "Enter LUKS Key Below" ) ) ; w.setkeyFileLabel( QObject::tr( "Enter A Path To A LUKS Header Below" ) ) ; w.Show() ; return a.exec() ; } zuluCrypt-6.2.0/plugins/mainwindow.cpp000066400000000000000000000171701425361753700201240ustar00rootroot00000000000000/* * * Copyright (c) 2012 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include "../zuluCrypt-gui/utility.h" #include "../zuluCrypt-cli/pluginManager/libzuluCryptPluginManager.h" #include "task.hpp" #include MainWindow::MainWindow( MainWindow::function_t f,QWidget * parent ) : QWidget( parent ), m_ui( new Ui::MainWindow ), m_printToStdOut( !qgetenv( "zuluCryptPrintToStdOut" ).isEmpty() ), m_handle( nullptr ), m_function( std::move( f ) ) { m_ui->setupUi( this ) ; this->setFixedSize( this->size() ) ; m_ui->lineEditKey->setEchoMode( QLineEdit::Password ) ; this->setWindowIcon( QIcon( ":/default.png" ) ) ; m_ui->pbKeyFile->setIcon( QIcon( ":/file.png" ) ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->pbOpen,SIGNAL( clicked() ),this,SLOT( pbOpen() ) ) ; connect( m_ui->pbKeyFile,SIGNAL( clicked() ),this,SLOT( pbKeyFile() ) ) ; m_ui->lineEditKey->setFocus() ; m_working = false ; m_requireKey = false ; m_requireKeyFile = true ; auto ac = new QAction( this ) ; QList keys ; keys.append( Qt::Key_Enter ) ; keys.append( Qt::Key_Return ) ; ac->setShortcuts( keys ) ; connect( ac,SIGNAL( triggered() ),this,SLOT( defaultButton() ) ) ; this->addAction( ac ) ; m_findExecutable = []( QVector& updated,const QVector& original ){ if( original.isEmpty() ){ return QString() ; } QString e ; for( const auto& it : original ){ auto _not_found = [&]( const char * path ){ e = path + it ; bool r = QFile::exists( e ) ; if( r ){ updated.append( e ) ; }else{ updated.append( it ) ; } return r == false ; } ; if( _not_found( "/usr/local/bin/" ) ){ if( _not_found( "/usr/bin/" ) ){ if( _not_found( "/usr/sbin/" ) ){ return it ; } } } } return QString() ; } ; } void MainWindow::Show() { if( m_appName.endsWith( " Key" ) ){ this->setWindowTitle( tr( "%1 Module" ).arg( m_appName ) ) ; }else{ this->setWindowTitle( tr( "%1 Key Module" ).arg( m_appName ) ) ; } this->show() ; } void MainWindow::setButtonIcon( const QString& icon ) { QString x( ":/" + icon ) ; this->setWindowIcon( QIcon( x ) ) ; m_ui->pbKeyFile->setIcon( QIcon( x ) ) ; } void MainWindow::setRequireKey( bool k ) { m_requireKey = k ; } void MainWindow::setRequireKeyFile( bool k ) { m_requireKeyFile = k ; } void MainWindow::defaultButton() { if( m_ui->pbCancel->hasFocus() ){ this->pbCancel() ; }else{ this->pbOpen() ; } } void MainWindow::setToken( char * const * e ) { if( !m_printToStdOut ){ m_handle = zuluCryptPluginManagerOpenConnection( *( e + 3 ) ) ; } } void MainWindow::setApplicationName( const QString& appName ) { m_appName = appName ; } void MainWindow::setkeyLabel( const QString& keyLabel ) { m_ui->label_2->setText( keyLabel ) ; } void MainWindow::setheaderPath(const QString& s ) { m_ui->lineEditKeyFile->setText( s ) ; } void MainWindow::setkeyFileLabel( const QString& keyFileLabel ) { m_ui->label->setText( keyFileLabel ) ; } void MainWindow::SetFocus() { if( m_ui->lineEditKey->text().isEmpty() ){ m_ui->lineEditKey->setFocus() ; }else if( m_ui->lineEditKeyFile->text().isEmpty() ){ m_ui->lineEditKeyFile->setFocus() ; }else{ m_ui->pbOpen->setFocus() ; } } void MainWindow::pbCancel() { if( m_working ){ DialogMsg msg( this ) ; auto st = msg.ShowUIYesNoDefaultNo( tr( "WARNING"), tr( "Are you sure you want to terminate this operation prematurely?" ) ) ; if( st == QMessageBox::Yes ){ this->enableAlll() ; m_working = false ; this->cancelled() ; } }else{ this->cancelled() ; } } void MainWindow::cancelled() { this->Exit( 1 ) ; } void MainWindow::Exit( int st ) { QCoreApplication::exit( st ) ; } void MainWindow::setfindExeFunction( std::function&,const QVector& )> f ) { m_findExecutable = f ; } void MainWindow::setExe( const QVector& exe ) { m_exe = exe ; } void MainWindow::setKeyFileAsKey( void ) { m_keyfileAsKey = true ; m_ui->lineEditKeyFile->setEchoMode( QLineEdit::Password ) ; m_ui->pbKeyFile->setVisible( false ) ; } void MainWindow::pbOpen() { DialogMsg msg( this ) ; QString key = m_ui->lineEditKey->text().toLatin1() ; if( m_requireKey ){ if( key.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR" ),tr( "Key field is empty" ) ) ; } } QString keyFile = m_ui->lineEditKeyFile->text() ; keyFile.replace( "file://","" ) ; if( m_requireKeyFile ){ if( !m_keyfileAsKey ){ if( keyFile.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR" ),tr( "Path to %1 keyfile is empty" ).arg( m_appName ) ) ; } if( !QFile::exists( keyFile ) ){ return msg.ShowUIOK( tr( "ERROR" ),tr( "Invalid path to %1 keyfile" ).arg( m_appName ) ) ; } } } QVector exe ; auto e = m_findExecutable( exe,m_exe ) ; if( !e.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR" ), tr( "Could not find \"%1\" executable in \"/usr/local/bin\",\"/usr/bin\" and \"/usr/sbin\"" ).arg( e ) ) ; } this->disableAll() ; m_working = true ; Task::run( [ &,exe,keyFile,key ](){ auto s = m_function( exe,keyFile,key ) ; if( s.isEmpty() ){ return false ; }else{ if( m_printToStdOut ){ std::cout << s.constData() << std::flush ; return true ; }else{ if( m_handle ){ zuluCryptPluginManagerSendKey( m_handle,s.constData(),size_t( s.size() ) ) ; return true ; }else{ return false ; } } } } ).then( [ this ]( bool passed ){ if( passed ){ this->Exit( 0 ) ; }else{ DialogMsg msg( this ) ; m_working = false ; if( m_appName.endsWith( " key" ) ){ msg.ShowUIOK( tr( "ERROR" ),tr("Could not decrypt the %1,wrong key?" ).arg( m_appName ) ) ; }else{ msg.ShowUIOK( tr( "ERROR" ),tr("Could not decrypt the %1 key,wrong key?" ).arg( m_appName ) ) ; } this->enableAlll() ; m_ui->lineEditKey->setFocus() ; } } ) ; } void MainWindow::pbKeyFile() { auto Z = QFileDialog::getOpenFileName( this,tr( "Select A Keyfile" ),utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->lineEditKeyFile->setText( Z ) ; } this->SetFocus() ; } void MainWindow::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbCancel() ; } void MainWindow::disableAll() { m_ui->label->setEnabled( false ) ; m_ui->label_2->setEnabled( false ) ; m_ui->lineEditKey->setEnabled( false ) ; m_ui->lineEditKeyFile->setEnabled( false ) ; m_ui->pbKeyFile->setEnabled( false ) ; m_ui->pbOpen->setEnabled( false ) ; m_ui->pbCancel->setEnabled( false ) ; } void MainWindow::enableAlll() { m_ui->label->setEnabled( true ) ; m_ui->label_2->setEnabled( true ) ; m_ui->lineEditKey->setEnabled( true ) ; m_ui->lineEditKeyFile->setEnabled( true ) ; m_ui->pbKeyFile->setEnabled( true ) ; m_ui->pbOpen->setEnabled( true ) ; m_ui->pbCancel->setEnabled( true ) ; } MainWindow::~MainWindow() { zuluCryptPluginManagerCloseConnection( m_handle ) ; delete m_ui ; } zuluCrypt-6.2.0/plugins/mainwindow.h000066400000000000000000000050151425361753700175640ustar00rootroot00000000000000/* * * Copyright (c) 2012 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include #include #include #include #include #include #include #include "../zuluCrypt-gui/dialogmsg.h" #include #include namespace Ui { class MainWindow ; } class MainWindow : public QWidget { Q_OBJECT public: using function_t = std::function&,const QString& keyFile,const QString& password )> ; MainWindow( MainWindow::function_t,QWidget * parent = 0 ) ; void setToken( char * const * ) ; void setApplicationName( const QString& ) ; void setkeyLabel( const QString& ) ; void setheaderPath( const QString& ) ; void setkeyFileLabel( const QString& ) ; void setButtonIcon( const QString& ) ; void setRequireKey( bool = true ) ; void setRequireKeyFile( bool = true ) ; void setKeyFileAsKey( void ) ; void Show( void ) ; void setExe( const QVector& exe ) ; void setfindExeFunction( std::function&,const QVector& )> ) ; ~MainWindow() ; private slots: void defaultButton( void ) ; void pbOpen( void ) ; void pbCancel( void ) ; void pbKeyFile( void ) ; private: void closeEvent( QCloseEvent * ) ; void disableAll( void ) ; void enableAlll( void ) ; void SetFocus( void ) ; void Exit( int ) ; void cancelled( void ) ; Ui::MainWindow * m_ui ; QString m_appName ; bool m_printToStdOut ; bool m_working ; bool m_requireKey ; bool m_requireKeyFile ; bool m_keyfileAsKey = false ; QVector m_exe ; void * m_handle ; MainWindow::function_t m_function ; std::function&,const QVector& )> m_findExecutable ; }; #endif // MAINWINDOW_H zuluCrypt-6.2.0/plugins/mainwindow.ui000066400000000000000000000070021425361753700177500ustar00rootroot00000000000000 MainWindow Qt::ApplicationModal 0 0 450 152 Key Module 0 10 451 141 130 110 91 31 &Open true true 220 110 91 31 &Cancel true 400 80 31 31 50 50 351 31 keyfile Qt::AutoText false Qt::AlignCenter false 50 -10 351 31 Key Qt::AlignCenter 50 20 351 31 50 80 351 31 0 0 0 6 lineEditKey lineEditKeyFile pbKeyFile pbOpen pbCancel zuluCrypt-6.2.0/plugins/network_key/000077500000000000000000000000001425361753700175775ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/network_key/CMakeLists.txt000066400000000000000000000013331425361753700223370ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.6) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -std=c++11 -I${PROJECT_BINARY_DIR}/plugins/luks -I${PROJECT_BINARY_DIR} ) if( QT5 ) QT5_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( network_key ${ICON} main.cpp ) else() QT4_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( network_key ${ICON} main.cpp ) endif() set_target_properties( network_key PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( network_key PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) TARGET_LINK_LIBRARIES( network_key crypt_buffer plugin ) #currently not used install( TARGETS network_key RUNTIME DESTINATION "${PLUGINPATH}" ) zuluCrypt-6.2.0/plugins/network_key/README000066400000000000000000000000721425361753700204560ustar00rootroot00000000000000 server.c is build by ../../zuluCrypt-cli/CMakeLists.txt zuluCrypt-6.2.0/plugins/network_key/crypt_buffer.c000066400000000000000000000271601425361753700224430ustar00rootroot00000000000000 /* * copyright: 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "crypt_buffer.h" #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include #pragma GCC diagnostic warning "-Wdeprecated-declarations" #define KEY_LENGTH 32 #define SALT_SIZE 16 #define IV_SIZE 16 #define LOAD_INFO_SIZE 32 #define HMAC_SIZE 24 #define MAGIC_STRING "TRUE" #define MAGIC_STRING_LENGTH 4 #define PBKDF2_ITERATIONS 5000 /* * This library takes a block of data and returns an encrypted version of the data. * This library also has the ability to reverse the above action. * * A user gives a password of specified size and the library coverts it to a 32 byte key using * pbkdf2 with iteration count of 5000 and a hash function of sha2. * * Data is encrypted using 256 bit AES in CBC mode. * * The format of the encrypted data: * 16 bytes from offset 0 stores pbkdf2 salt. * 16 bytes from offset 16 stores AES initialization vector. * 4 bytes from offset 32 stores the size of the load given by the user. * 4 bytes from offset 36 stores a string "TRUE" that is used to verify encryption key during decryption. * 24 bytes from offset 40 are used to store hmac hash value of the clear text. * The load the user gave to be stored encrypted starts from offset 64.The load will be padded up to a multiple of 32. * * Encrypted data starts at offset 32. * * The size of ciphertext will be ( 64 + 32n ) bytes where n is a number starting from 0. */ struct crypt_buffer_ctx_1 { char * buffer ; char * key ; size_t buffer_size ; size_t key_size ; int fd ; gcry_cipher_hd_t h ; gcry_md_hd_t m ; } ; static int _debug( crypt_buffer_ctx ctx,const char * e ) { #if 0 if( 0 && ctx ){;} puts( e ) ; #else if( 0 && ctx && e ){;} #endif return 0 ; } static int _failed( gcry_error_t r ) { return r != GPG_ERR_NO_ERROR ; } static int _passed( gcry_error_t r ) { return r == GPG_ERR_NO_ERROR ; } static int _failed_init( int fd,char * key,crypt_buffer_ctx c,gcry_cipher_hd_t h,gcry_md_hd_t m ) { close( fd ) ; free( key ) ; free( c ) ; if( h != 0 ){ gcry_cipher_close( h ) ; } if( m != 0 ){ gcry_md_close( m ) ; } return 0 ; } int crypt_buffer_init( crypt_buffer_ctx * ctx,const void * k,size_t key_size ) { gcry_error_t r ; gcry_cipher_hd_t h = 0 ; gcry_md_hd_t m = 0 ; crypt_buffer_ctx c ; void * key = NULL ; int fd = open( "/dev/urandom",O_RDONLY ) ; if( fd == -1 ){ return 0 ; } if( gcry_control( GCRYCTL_INITIALIZATION_FINISHED_P ) == 0 ){ gcry_check_version( NULL ) ; gcry_control( GCRYCTL_INITIALIZATION_FINISHED,0 ) ; } c = malloc( sizeof( struct crypt_buffer_ctx_1 ) ) ; if( c == NULL ){ return _failed_init( fd,key,c,h,m ) ; } key = malloc( key_size ) ; if( key == NULL ){ return _failed_init( fd,key,c,h,m ) ; } r = gcry_cipher_open( &h,GCRY_CIPHER_AES256,GCRY_CIPHER_MODE_CBC,0 ) ; if( _failed( r ) ){ return _failed_init( fd,key,c,h,m ) ; } r = gcry_md_open( &m,GCRY_MD_SHA256,GCRY_MD_FLAG_HMAC ) ; if( _failed( r ) ){ return _failed_init( fd,key,c,h,m ) ; } r = gcry_md_setkey( m,k,key_size ) ; if( _failed( r ) ){ return _failed_init( fd,key,c,h,m ) ; }else{ memcpy( key,k,key_size ) ; c->buffer = NULL ; c->buffer_size = 0 ; c->h = h ; c->m = m ; c->key = key ; c->key_size = key_size ; c->fd = fd ; *ctx = c ; return 1 ; } } void crypt_buffer_uninit( crypt_buffer_ctx * ctx ) { crypt_buffer_ctx t ; if( ctx != NULL && *ctx != NULL ){ t = *ctx ; *ctx = NULL ; gcry_cipher_close( t->h ) ; gcry_md_close( t->m ) ; close( t->fd ) ; free( t->key ) ; free( t->buffer ) ; free( t ) ; } } static int _get_random_data( crypt_buffer_ctx ctx,char * buffer,size_t buffer_size ) { ssize_t e = buffer_size ; ssize_t z = read( ctx->fd,buffer,buffer_size ) ; return z != e ; } static gcry_error_t _create_key( const char * salt,size_t salt_size,const char * input_key, size_t input_key_length,char * output_key,size_t output_key_size ) { return gcry_kdf_derive( input_key,input_key_length,GCRY_KDF_PBKDF2,GCRY_MD_SHA256, salt,salt_size,PBKDF2_ITERATIONS,output_key_size,output_key ) ; } static int _set_gcrypt_handle( crypt_buffer_ctx ctx,const char * salt,size_t salt_size,const char * iv,size_t iv_size ) { char key[ KEY_LENGTH ] ; gcry_error_t r ; gcry_cipher_hd_t handle = ctx->h ; r = gcry_cipher_reset( handle ) ; if( _passed( r ) ){ r = _create_key( salt,salt_size,ctx->key,ctx->key_size,key,KEY_LENGTH ) ; if( _passed( r ) ){ r = gcry_cipher_setkey( handle,key,KEY_LENGTH ) ; if( _passed( r ) ){ r = gcry_cipher_setiv( handle,iv,iv_size ) ; if( _passed( r ) ){ return 1 ; }else{ return _debug( ctx,"failed to set iv" ) ; } }else{ return _debug( ctx,"failed to set key" ) ; } }else{ return _debug( ctx,"failed to create key" ) ; } }else{ return _debug( ctx,"failed to reset handle" ) ; } } static char * _expand_buffer( crypt_buffer_ctx h,size_t z ) { char * e = NULL ; if( h == NULL ){ return 0 ; } if( h->buffer_size < z ){ e = realloc( h->buffer,z ) ; if( e != NULL ){ h->buffer = e ; h->buffer_size = z ; return e ; }else{ return NULL ; } }else{ return h->buffer ; } } static unsigned char * _create_hmac( crypt_buffer_ctx ctx,const void * buffer,u_int32_t buffer_size ) { gcry_md_reset( ctx->m ) ; gcry_md_write( ctx->m,buffer,buffer_size ) ; return gcry_md_read( ctx->m,0 ) ; } int crypt_buffer_encrypt( crypt_buffer_ctx ctx,const void * buffer,u_int32_t buffer_size,crypt_buffer_result * r ) { char buff[ SALT_SIZE + IV_SIZE ] ; gcry_error_t z ; size_t len ; size_t k = buffer_size ; char * e ; unsigned char * f ; const char * salt = buff ; const char * iv = buff + SALT_SIZE ; if( _get_random_data( ctx,buff,SALT_SIZE + IV_SIZE ) ){ return _debug( ctx,"failed to get random data" ) ; } /* * make sure the block buffer we are going to encrypt is a multiple of 32 */ while( k % 32 != 0 ){ k += 1 ; } e = _expand_buffer( ctx,k + SALT_SIZE + IV_SIZE + LOAD_INFO_SIZE ) ; if( e == NULL ){ return _debug( ctx,"faile to expand memory buffer" ) ; } f = _create_hmac( ctx,buffer,buffer_size ) ; if( f == NULL ){ return _debug( ctx,"failed to create hmac hash" ) ; } if( _set_gcrypt_handle( ctx,salt,SALT_SIZE,iv,IV_SIZE ) ){ len = SALT_SIZE + IV_SIZE ; /* * 16 bytes from offset 0 contains pbkdf2 salt. * 16 bytes from offset 16 contains AES initialization vector. * The sum of the above makes the first 32 byte block. * This block is stored in clear text. */ memcpy( e,buff,len ) ; /* * 4 bytes from offset 32 stores the size of the clear text we are going to encrypt */ memcpy( e + len,&buffer_size,sizeof( u_int32_t ) ) ; /* * 4 bytes at offset 36 stores "TRUE" bytes to be used to verify decryption key */ memcpy( e + len + sizeof( u_int32_t ),MAGIC_STRING,MAGIC_STRING_LENGTH ) ; /* * 24 bytes from offset 40 contains hmac digest of the cleartext * * These 24 bytes plus the 4 above and the 4 above it makes the second 32 byte block. * Ciphertext starts with this block. */ memcpy( e + len + sizeof( u_int32_t ) + sizeof( u_int32_t ) ,f,HMAC_SIZE ) ; /* * User data to encrypt starts at the 64th bytes. * The 64th bytes marks the end of the header and the beginning of the load. */ memcpy( e + len + LOAD_INFO_SIZE,buffer,buffer_size ) ; /* * Encryption starts at offset 32 */ z = gcry_cipher_encrypt( ctx->h,e + len,LOAD_INFO_SIZE + k,NULL,0 ) ; if( _passed( z ) ){ r->buffer = ctx->buffer ; /* * SALT_SIZE + IV_SIZE + LOAD_INFO_SIZE will equal 64. * k will equal the size of the data we were asked to encrypt rounded up to a multiple of 32 */ r->length = k + SALT_SIZE + IV_SIZE + LOAD_INFO_SIZE ; return 1 ; }else{ return _debug( ctx,"failed to encrypt data" ) ; } }else{ return _debug( ctx,"failed to create encryption handle" ) ; } } /* * The password is assumed to be correct if the 4 bytes from offset 36 equal "TRUE" */ static int _password_is_correct( const char * buffer ) { return memcmp( buffer + sizeof( u_int32_t ),MAGIC_STRING,MAGIC_STRING_LENGTH ) == 0 ; } static u_int32_t _get_data_length( const char * buffer ) { u_int32_t l ; memcpy( &l,buffer,sizeof( u_int32_t ) ) ; return l ; } static int _hmac_passed( crypt_buffer_ctx ctx,const char * e,u_int32_t buffer_size ) { /* * calculate the hmac hash of the decrypted data. */ unsigned char * f = _create_hmac( ctx,e + LOAD_INFO_SIZE,buffer_size ) ; /* * compare the hmac of the decrypted data against the stored hmac at offset 8 of the decrypted data. * This offset 8 is actually offset 40 since the decryption skipped the first 32 bytes of the salt and IV. */ return memcmp( f,e + sizeof( u_int32_t ) + sizeof( u_int32_t ),HMAC_SIZE ) == 0 ; } int crypt_buffer_decrypt( crypt_buffer_ctx ctx,const void * buffer,u_int32_t buffer_size,crypt_buffer_result * r ) { gcry_error_t z ; char * e ; const char * buff = buffer ; const char * salt = buff ; const char * iv = buff + SALT_SIZE ; size_t len = buffer_size - ( SALT_SIZE + IV_SIZE ) ; ssize_t l = buffer_size - ( SALT_SIZE + IV_SIZE + LOAD_INFO_SIZE ) ; if( l < 0 ){ return _debug( ctx,"inconsistent data size detected" ) ; } e = _expand_buffer( ctx,buffer_size ) ; if( e == NULL ){ return _debug( ctx,"failed to expand internal buffer" ) ; } if( _set_gcrypt_handle( ctx,salt,SALT_SIZE,iv,IV_SIZE ) ){ /* * Skip to offset 32 and start decryption from there.Thats because the first 32 bytes * holds salt and IV and are stored unencrypted. */ z = gcry_cipher_decrypt( ctx->h,e,len,buff + SALT_SIZE + IV_SIZE,len ) ; if( _passed( z ) ){ if( _password_is_correct( e ) ){ len = _get_data_length( e ) ; if( len <= buffer_size - ( SALT_SIZE + IV_SIZE + LOAD_INFO_SIZE ) ){ if( _hmac_passed( ctx,e,len ) ){ r->buffer = e + LOAD_INFO_SIZE ; r->length = len ; return 1 ; }else{ return _debug( ctx,"hmac check failed" ) ; } }else{ return _debug( ctx,"inconsistency detected on stored data size" ) ; } }else{ return _debug( ctx,"password check failed" ) ; } }else{ return _debug( ctx,"decryption routine failed 1" ) ; } }else{ return _debug( ctx,"decryption routine failed 2" ) ; } } zuluCrypt-6.2.0/plugins/network_key/crypt_buffer.h000066400000000000000000000125241425361753700224460ustar00rootroot00000000000000/* * copyright: 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef __cplusplus extern "C" { #endif #include /* * This data structure hold result of the operation. */ typedef struct{ void * buffer ; size_t length ; }crypt_buffer_result ; typedef struct crypt_buffer_ctx_1 * crypt_buffer_ctx ; /* * create crypt buffer_context object. * The same context object can be used for both encryption and decryption. * 1 is returned on success. * 0 is returned on error. */ int crypt_buffer_init( crypt_buffer_ctx * ctx,const void * password,size_t passphrase_size ) ; /* * destroy crypt_buffer context object when done with it. */ void crypt_buffer_uninit( crypt_buffer_ctx * ctx ) ; /* * This routine takes a block of data and encrypts it * The first argument is for internal use of the library and it is to be reused between encryption/decryption operations. * 1 is returned on success. * 0 is returned on error. */ int crypt_buffer_encrypt( crypt_buffer_ctx ctx,const void * buffer,u_int32_t buffer_size,crypt_buffer_result * r ) ; /* * This routine takes a block of data encrypted by crypt_buffer_encrypt() decrypt it. * The first argument is for internal use of the library and it is to be reused between encryption/decryption operations. * * 1 is returned on success. * 0 is returned on error. */ int crypt_buffer_decrypt( crypt_buffer_ctx ctx,const void * buffer,u_int32_t buffer_size,crypt_buffer_result * r ) ; /* * example use case using a complete workable program is below. */ #if 0 #include "crypt_buffer.h" #include #include #include static void * _buffer ; static size_t _buffer_size ; static void sendData( const void * buffer,size_t buffer_size ) { _buffer = malloc( buffer_size ) ; _buffer = memcpy( _buffer,buffer,buffer_size ) ; _buffer_size = buffer_size ; } static void receiveEncryptedDataFromSomeWhere( void ** buffer,size_t * buffer_size ) { *buffer = _buffer ; *buffer_size = _buffer_size ; } static void consumeDecryptedReceivedData( const void * buffer,size_t buffer_size ) { const char * x = buffer ; size_t i ; char e ; for( i = 0 ; i < buffer_size ; i++ ){ e = *( x + i ) ; printf( "%c",e ) ; } printf( "\n" ) ; } static void encryptAndSendData( crypt_buffer_ctx ctx,const void * data,size_t data_size ) { crypt_buffer_result r ; if( crypt_buffer_encrypt( ctx,data,data_size,&r ) ){ /* * encryption succeeded,simulate sending encrypted data somewhere */ sendData( r.buffer,r.length ) ; } } void decryptReceivedDataAndConsumeIt( crypt_buffer_ctx ctx,const void * cipher_text_data,size_t cipher_text_data_size ) { crypt_buffer_result r ; if( crypt_buffer_decrypt( ctx,cipher_text_data,cipher_text_data_size,&r ) ){ /* * decryption succeeded, */ /* * This function simulates using of now decrypted data */ consumeDecryptedReceivedData( r.buffer,r.length ) ; } } int main( int argc,char * argv[] ) { /* * data to be encrypted before sending it somewhere. */ const char * data = "works as expected" ; size_t data_size = strlen( data ) ; /* * key to be used for encryption and decryption */ const char * key = "xyz" ; size_t key_size = strlen( key ) ; void * cipher_buffer ; size_t cipher_buffer_size ; crypt_buffer_ctx ctx ; /* * we dont need these two arguments */ if( argc && argv ){;} _buffer = NULL ; if( crypt_buffer_init( &ctx,key,key_size ) ){ /* * This function simulates encrypting data and sending it somewhere */ encryptAndSendData( ctx,data,data_size ) ; /* * This function simulates receiving encrypted data. */ receiveEncryptedDataFromSomeWhere( &cipher_buffer,&cipher_buffer_size ) ; /* * This function simulates data decryption received from somewhere. * Notice the same context is used for encryption and decryption */ decryptReceivedDataAndConsumeIt( ctx,cipher_buffer,cipher_buffer_size ) ; crypt_buffer_uninit( &ctx ) ; /* * clean up after simulation ; */ free( _buffer ) ; return 0 ; }else{ return 1 ; } } #endif #ifdef __cplusplus } #endif zuluCrypt-6.2.0/plugins/network_key/main.cpp000066400000000000000000000120471425361753700212330ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "../mainwindow.h" #include #include #include #include #include #include #include "network_key.h" #define DEBUG 0 static void _debug( const char * msg ) { #if DEBUG puts( msg ) ; #endif } #define _cast( x ) ( const char * ) x static result_t _network_key_get_key( const arguments_t * e ) { zuluKey_t key ; zuluValue_t * value ; socket_t s ; result_t result ; crypt_buffer_ctx ctx ; crypt_buffer_result r ; const char * encryption_key = e->encryption_key ; size_t encryption_key_key_length = strlen( encryption_key ) ; const char * wallet_name = "zuluCrypt" ; const char * wallet_key = e->wallet_key ; size_t n ; int k = 0 ; char * buffer ; memset( &result,'\0',sizeof( result ) ) ; memset( &key,'\0',sizeof( zuluKey_t ) ) ; key.key_0_length = strlen( e->path ) + 1 ; if( key.key_0_length > sizeof( key.key_0 ) ){ _debug( "error: key length buffer overflow" ) ; return result ; }else{ memcpy( key.key_0,e->path,key.key_0_length ) ; } key.key_1_length = strlen( e->uuid ) + 1 ; if( key.key_1_length > sizeof( key.key_1 ) ){ _debug( "error: key length buffer overflow" ) ; return result ; }else{ memcpy( key.key_1,e->uuid,key.key_1_length ) ; } key.wallet_key_length = strlen( wallet_key ) ; if( key.wallet_key_length > sizeof( key.wallet_key ) ){ _debug( "error: wallet key length buffer overflow" ) ; return result ; }else{ memcpy( key.wallet_key,wallet_key,key.wallet_key_length ) ; } n = strlen( wallet_name ) ; if( n > sizeof( key.wallet_name ) ){ _debug( "error: buffer overflow" ) ; return result ; }else{ memcpy( key.wallet_name,wallet_name,n + 1 ) ; memcpy( key.application_name,wallet_name,n + 1 ) ; } while( 1 ){ _debug( "client connecting ..." ) ; s = SocketNet( e->network_address,e->port_number ) ; if( SocketConnect( &s ) ){ _debug( "client connected" ) ; break ; }else{ if( k == 10 ){ _debug( "failed to connect to server" ) ; return result ; }else{ sleep( 1 ) ; k++ ; } } } if( crypt_buffer_init( &ctx,encryption_key,encryption_key_key_length ) ){ if( crypt_buffer_encrypt( ctx,_cast( &key ),sizeof( zuluKey_t ),&r ) ){ SocketSendData( s,_cast( r.buffer ),r.length ) ; buffer = nullptr ; n = SocketGetData( s,&buffer ) ; if( buffer ){ if( crypt_buffer_decrypt( ctx,buffer,n,&r ) ){ if( r.length == sizeof( zuluValue_t ) ){ value = ( zuluValue_t * )r.buffer ; if( value->key_found ){ if( value->value_length <= sizeof( result.key ) ){ result.key_len = value->value_length ; memcpy( result.key,value->value,value->value_length ) ; result.got_key = 1 ; } }else{ _debug( "key not found" ) ; } } } free( buffer ) ; } } crypt_buffer_uninit( &ctx ) ; } SocketClose( &s ) ; return result ; } int main( int argc,char * argv[] ) { QApplication a( argc,argv ) ; MainWindow w ; w.setToken( *( argv + 3 ) ) ; w.setApplicationName( "network key" ) ; w.setkeyLabel( QObject::tr( "Enter zuluCrypt Wallet Key Below" ) ) ; w.setkeyFileLabel( QObject::tr( "Enter Network Key Below" ) ) ; w.setKeyFileAsKey() ; auto e = [ = ]( const QVector& exe,const QString& network_key,const QString& password ){ Q_UNUSED( exe ) ; arguments_t e ; QByteArray k = password.toLatin1() ; QByteArray n = network_key.toLatin1() ; QByteArray z = QString( "UUID=\"%1\"" ).arg( QString( *( argv + 2 ) ) ).toLatin1() ; e.path = *( argv + 1 ) ; e.uuid = z.constData() ; e.wallet_key = k.constData() ; e.encryption_key = n.constData() ; e.network_address = NETWORK_ADDRESS ; e.port_number = PORT_NUMBER ; QFile file( QDir::homePath() + "/.zuluCrypt/network_key" ) ; QByteArray networkAddress ; if( file.open( QIODevice::ReadOnly ) ){ QStringList l = QString( file.readAll() ).split( "\n" ) ; if( l.size() >= 2 ){ networkAddress = l.first().toLatin1() ; e.network_address = networkAddress.constData() ; e.port_number = l.at( 1 ).toInt() ; } } auto r = _network_key_get_key( &e ) ; if( r.got_key ){ return QByteArray( r.key,r.key_len ) ; }else{ return QByteArray() ; } } ; w.setKeyFunction( e ) ; w.Show() ; return a.exec() ; } zuluCrypt-6.2.0/plugins/network_key/network_key.h000066400000000000000000000047521425361753700223210ustar00rootroot00000000000000/* * copyright: 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "crypt_buffer.h" #include "../../zuluCrypt-cli/pluginManager/libzuluCryptPluginManager.h" #include "../../zuluCrypt-cli/utility/socket/socket.h" #include "lxqtwallet.h" #define BUFFER_SIZE 1024 struct zuluKey{ u_int32_t wallet_key_length ; u_int32_t key_0_length ; u_int32_t key_1_length ; char key_0[ BUFFER_SIZE ] ; char key_1[ BUFFER_SIZE ] ; char wallet_key[ BUFFER_SIZE ] ; char wallet_name[ BUFFER_SIZE ] ; char application_name[ BUFFER_SIZE ] ; }__attribute__((__packed__)) ; typedef struct zuluKey zuluKey_t ; struct zuluValue{ int key_found ; size_t value_length ; char value[ BUFFER_SIZE ] ; }__attribute__((__packed__)) ; typedef struct zuluValue zuluValue_t ; typedef struct{ const char * path ; const char * uuid ; const char * wallet_key ; const char * encryption_key ; const char * network_address ; int port_number ; }arguments_t ; typedef struct{ int got_key ; char key[ 1024 ] ; size_t key_len ; }result_t ; const char * NETWORK_ADDRESS = "127.0.0.1" ; int PORT_NUMBER = 40000 ; zuluCrypt-6.2.0/plugins/network_key/server.c000066400000000000000000000135541425361753700212610ustar00rootroot00000000000000/* * copyright: 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "network_key.h" #include #define DEBUG 1 static void _debug( const char * msg ) { #if DEBUG puts( msg ) ; #endif } #define _cast( x ) ( const char * ) x static zuluValue_t _get_key_from_wallet( const zuluKey_t * key ) { zuluValue_t value ; lxqt_wallet_t w ; lxqt_wallet_key_values_t key_value ; lxqt_wallet_error r ; /* * make sure these are NULL terminated */ char wallet_name[ sizeof( key->wallet_name ) ] ; char application_name[ sizeof( key->wallet_name ) ] ; memcpy( wallet_name,key->wallet_name,sizeof( key->wallet_name ) ) ; memcpy( application_name,key->application_name,sizeof( key->application_name ) ) ; *( wallet_name + sizeof( key->wallet_name ) - 1 ) = '\0' ; *( application_name + sizeof( key->application_name ) - 1 ) = '\0' ; memset( &value,'\0',sizeof( zuluValue_t ) ) ; if( key->wallet_key_length > sizeof( key->wallet_key ) || key->key_0_length > sizeof( key->key_0 ) || key->key_1_length > sizeof( key->key_1 ) ){ return value ; }else{ r = lxqt_wallet_open( &w,key->wallet_key,key->wallet_key_length,wallet_name,application_name ) ; if( r == lxqt_wallet_no_error ){ if( lxqt_wallet_read_key_value( w,key->key_0,key->key_0_length,&key_value ) ){ if( key_value.key_value_size <= sizeof( value.value ) ){ value.key_found = 1 ; value.value_length = key_value.key_value_size ; memcpy( value.value,key_value.key_value,key_value.key_value_size ) ; } }else if( lxqt_wallet_read_key_value( w,key->key_1,key->key_1_length,&key_value ) ){ if( key_value.key_value_size <= sizeof( value.value ) ){ value.key_found = 1 ; value.value_length = key_value.key_value_size ; memcpy( value.value,key_value.key_value,key_value.key_value_size ) ; } } lxqt_wallet_close( &w ) ; } return value ; } } static void _process_request( socket_t s,crypt_buffer_ctx ctx,const crypt_buffer_result * r ) { zuluValue_t value ; crypt_buffer_result e ; if( r->length != sizeof( zuluKey_t ) ){ value.key_found = 0 ; }else{ value = _get_key_from_wallet( r->buffer ) ; if( crypt_buffer_encrypt( ctx,_cast( &value ),sizeof( zuluValue_t ),&e ) ){ SocketSendData( s,e.buffer,e.length ) ; } } } typedef struct{ crypt_buffer_ctx ctx ; socket_t s ; char * buffer ; size_t buffer_length ; }exit_struct ; static exit_struct _clean_on_exit ; static int _exitServer( const char * msg ) { _debug( msg ) ; crypt_buffer_uninit( &_clean_on_exit.ctx ) ; SocketClose( &_clean_on_exit.s ) ; memset( _clean_on_exit.buffer,'\0',_clean_on_exit.buffer_length ) ; free( _clean_on_exit.buffer ) ; return 1 ; } static void _closeServer( int sig ) { _exitServer( "got TERM signal,terminating" ) ; exit( 1 ) ; } int main( int argc,char * argv[] ) { crypt_buffer_ctx ctx ; crypt_buffer_result r ; ssize_t n ; char * encryption_key ; size_t encryption_key_length ; int network_port = PORT_NUMBER ; const char * network_address = NETWORK_ADDRESS ; socket_t c ; char * e ; #define buffer_size sizeof( zuluKey_t ) * 2 char buffer[ buffer_size ] ; socket_t s ; struct sigaction sa ; if( argc < 2 ){ puts( "error: invalid number of arguments" ) ; return 1 ; }else if( argc >= 4 ){ network_address = *( argv + 2 ) ; network_port = atoi( *( argv + 3 ) ) ; } memset( &sa,'\0',sizeof( struct sigaction ) ) ; sa.sa_handler = _closeServer ; sigaction( SIGTERM,&sa,NULL ) ; e = *( argv + 1 ) ; encryption_key_length = strlen( e ) ; encryption_key = malloc( sizeof( char ) * encryption_key_length ) ; memcpy( encryption_key,e,encryption_key_length ) ; memset( e,'\0',encryption_key_length ) ; s = SocketNet( network_address,network_port ) ; _clean_on_exit.s = s ; _clean_on_exit.buffer = encryption_key ; _clean_on_exit.buffer_length = encryption_key_length ; _debug( "server started" ) ; if( !SocketBind( s ) ){ return _exitServer( "socket bind failed" ) ; } if( !SocketListen( s ) ){ return _exitServer( "socket listen failed" ) ; } if( crypt_buffer_init( &ctx,encryption_key,encryption_key_length ) ){ _clean_on_exit.ctx = ctx ; while( 1 ){ c = SocketAccept( s ) ; n = SocketGetData_3( c,buffer,buffer_size,4 ) ; if( n != -1 ){ if( crypt_buffer_decrypt( ctx,buffer,n,&r ) ){ _process_request( c,ctx,&r ) ; }else{ _debug( "failed to decrypt data" ) ; } }else{ _debug( "network timed out" ) ; } SocketClose( &c ) ; } }else{ _debug( "failed to initialize encryption routine" ) ; } return 0 ; } zuluCrypt-6.2.0/plugins/network_key/zuluCryptKeyServer.desktop000077500000000000000000000007621425361753700250630ustar00rootroot00000000000000#!/usr/bin/env xdg-open [Desktop Entry] Comment[en_US]= Comment= Exec=/usr/bin/zuluCryptKeyServer ink 127.0.0.1 40000 GenericName[en_US]=Encrypted volumes key manager GenericName=Encrypted volumes manager Icon=zuluCrypt MimeType= Name[en_US]=ZuluCrypt Key Server Name=ZuluCrypt NoDisplay=false Path= StartupNotify=true Terminal=false Type=Application X-DBUS-ServiceName= X-DBUS-StartupType= X-KDE-SubstituteUID=false X-KDE-Username= Categories=Security;Utility;Qt;X-MandrivaLinux-System-FileTools; zuluCrypt-6.2.0/plugins/plugins.h000066400000000000000000000111301425361753700170640ustar00rootroot00000000000000/* * * Copyright (c) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef PLUGINS_H #define PLUGINS_H #include #include #include #include #include #include #include #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include #pragma GCC diagnostic warning "-Wdeprecated-declarations" namespace plugins { enum class plugin{ gpg,hmac_key,hmac_key_1,keyKeyFile,luks,steghide } ; static inline QByteArray gpg( const QVector& exe,const QString& keyFile,const QString& password ) { QProcess p ; if( password.isEmpty() ){ p.start( exe.first(),{ "--no-tty","--yes","--no-mdc-warning","--no-verbose","-d",keyFile } ) ; }else{ p.start( exe.first(),{ "--no-tty","--yes","--no-mdc-warning","--no-verbose","--passphrase-fd","0","-d",keyFile } ) ; } p.waitForStarted() ; p.write( password.toLatin1() ) ; p.closeWriteChannel() ; p.waitForFinished() ; return p.readAllStandardOutput() ; } static inline QByteArray hmac_key( const QString& keyFile,const QString& password ) { auto _getKey = []( gcry_md_hd_t handle,const QString& keyFile ){ QFile f( keyFile ) ; if( f.open( QIODevice::ReadOnly ) ){ const int size = 1024 ; char buffer[ size ] ; while( true ){ auto e = f.read( buffer,size ) ; if( e <= 0 ){ break ; }else{ gcry_md_write( handle,buffer,e ) ; } } auto key = reinterpret_cast< const char * >( gcry_md_read( handle,0 ) ) ; auto len = static_cast< int >( gcry_md_get_algo_dlen( GCRY_MD_SHA256 ) ) ; QByteArray r( key,len ) ; return r.toHex() ; }else{ return QByteArray() ; } } ; if( gcry_control( GCRYCTL_INITIALIZATION_FINISHED_P ) == 0 ){ gcry_check_version( nullptr ) ; gcry_control( GCRYCTL_INITIALIZATION_FINISHED,0 ) ; } QByteArray key ; gcry_md_hd_t handle ; auto r = gcry_md_open( &handle,GCRY_MD_SHA256,GCRY_MD_FLAG_HMAC ) ; if( r == GPG_ERR_NO_ERROR ){ auto e = password.toLatin1() ; r = gcry_md_setkey( handle,e.constData(),e.size() ) ; if( r == GPG_ERR_NO_ERROR ){ key = _getKey( handle,keyFile ) ; } gcry_md_close( handle ) ; } return key ; } static inline QByteArray hmac_key_1( const QVector& exe,const QString& keyFile,const QString& password ) { Q_UNUSED( exe ) return hmac_key( keyFile,password ) ; } static inline QByteArray keyKeyFile( const QVector& exe,const QString& keyFile,const QString& password ) { Q_UNUSED( exe ) QFile f( keyFile ) ; f.open( QIODevice::ReadOnly ) ; return password.toLatin1() + f.readAll() ; } static inline QByteArray luks( const QVector& exe,const QString& keyFile,const QString& password ) { Q_UNUSED( exe ) /* * we are sending a 4 component structure. * first component at offset 0 is a u_int32_t structure holding the size of the passphrase * Second component at offset 4 is a u_int32_t structure holding the size of the contents of luks header * third component at offset 8 is the passphrase to unlock the LUKS volume. * last component is at offset that marks the end of the third component.Where this offset will be depends on the length of the passphrase */ auto intToByteArray = []( quint32 s ){ const char * e = reinterpret_cast< const char * >( &s ) ; return QByteArray( e,sizeof( quint32 ) ) ; } ; QFile keyfile( keyFile ) ; QByteArray keyFileSize = intToByteArray( keyfile.size() ) ; QByteArray passWordSize = intToByteArray( password.size() ) ; keyfile.open( QIODevice::ReadOnly ) ; return passWordSize + keyFileSize + password.toLatin1() + keyfile.readAll() ; } static inline QByteArray steghide( const QVector& exe,const QString& keyFile,const QString& password ){ /* * TODO: look into passing the passphrase more securely */ QProcess p ; p.start( exe.first(),{ "--extract","-sf",keyFile,"-xf","-","-p",password } ) ; p.waitForFinished( -1 ) ; return p.readAllStandardOutput() ; } } //namespace plugins #endif // PLUGINS_H zuluCrypt-6.2.0/plugins/plugins.pro000066400000000000000000000005561425361753700174470ustar00rootroot00000000000000#------------------------------------------------- # # Project created by QtCreator 2011-09-09T10:15:19 # #------------------------------------------------- QT += core gui TARGET = zuluCrypt TEMPLATE = app SOURCES += mainwindow.cpp HEADERS += mainwindow.h FORMS += mainwindow.ui TRANSLATIONS = ../translations/plugins/messages.ts RESOURCES = icon.qrc zuluCrypt-6.2.0/plugins/steghide/000077500000000000000000000000001425361753700170325ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/steghide/CMakeLists.txt000066400000000000000000000012541425361753700215740ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -std=c++11 -I${PROJECT_BINARY_DIR}/plugins/steghide -I${PROJECT_BINARY_DIR} ) if( QT5 ) QT5_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( steghide ${ICON} main.cpp ) else() QT4_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( steghide ${ICON} main.cpp ) endif() set_target_properties( steghide PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( steghide PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) TARGET_LINK_LIBRARIES( steghide plugin ) install( TARGETS steghide RUNTIME DESTINATION "${PLUGINPATH}" ) zuluCrypt-6.2.0/plugins/steghide/main.cpp000066400000000000000000000022731425361753700204660ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "../mainwindow.h" #include "../plugins.h" int main( int argc,char * argv[] ) { QApplication a( argc,argv ) ; MainWindow w( plugins::steghide ) ; w.setToken( argv ) ; w.setApplicationName( "steghide" ) ; w.setkeyLabel( QObject::tr( "Enter steghide Key Below" ) ) ; w.setkeyFileLabel( QObject::tr( "Enter A Path To A Steghide Keyfile Below" ) ) ; w.setExe( { "steghide" } ) ; w.Show() ; return a.exec() ; } zuluCrypt-6.2.0/plugins/test/000077500000000000000000000000001425361753700162155ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/test/README000066400000000000000000000001131425361753700170700ustar00rootroot00000000000000 ../../zuluCrypt-cli/CMakeLists.txt controls building of this source file zuluCrypt-6.2.0/plugins/test/zuluCrypt-testKey.c000066400000000000000000000027201425361753700220310ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "../../zuluCrypt-cli/pluginManager/libzuluCryptPluginManager.h" #include int main( int argc,char * argv[] ) { /* * const char * exe = argv[ 0 ] ; * const char * device = argv[ 1 ] ; * const char * uuid = argv[ 2 ] ; * int size = atoi( argv[ 4 ] ) ; * * argv[ 5 ] is argument list given to zuluCrypt-cli * const char * argv = argv[ 5 ] ; * const char * msg ; */ const char * key = "xyz" ; void * handle ; if( argc < 3 ){ return 1 ; } handle = zuluCryptPluginManagerOpenConnection( argv[ 3 ] ) ; if( handle ){ zuluCryptPluginManagerSendKey( handle,key,strlen( key ) ) ; zuluCryptPluginManagerCloseConnection( handle ) ; return 0 ; }else{ return 1 ; } } zuluCrypt-6.2.0/plugins/tomb/000077500000000000000000000000001425361753700161775ustar00rootroot00000000000000zuluCrypt-6.2.0/plugins/tomb/CMakeLists.txt000066400000000000000000000012201425361753700207320ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) add_definitions( -D_FILE_OFFSET_BITS=64 -Wall -pedantic -std=c++11 -I${PROJECT_BINARY_DIR}/plugins/tomb -I${PROJECT_BINARY_DIR} ) if( QT5 ) QT5_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( tomb ${ICON} main.cpp ) else() QT4_ADD_RESOURCES( ICON ../icon.qrc ) add_executable( tomb ${ICON} main.cpp ) endif() set_target_properties( tomb PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( tomb PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) TARGET_LINK_LIBRARIES( tomb plugin ) install( TARGETS tomb RUNTIME DESTINATION "${PLUGINPATH}" ) zuluCrypt-6.2.0/plugins/tomb/main.cpp000066400000000000000000000054431425361753700176350ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "../mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include "../plugins.h" int main( int argc,char * argv[] ) { QApplication a( argc,argv ) ; MainWindow w( []( const QVector& exe,const QString& keyFile,const QString& password ){ /* * TODO: look into passing the passphrase more securely */ QProcess p ; p.start( exe.first(),{ "--extract","-sf",keyFile,"-xf","-","-p",password } ) ; p.waitForFinished( -1 ) ; QByteArray key = p.readAllStandardOutput() ; p.close() ; if( key.isEmpty() ){ return key ; }else{ key = "\n-----BEGIN PGP MESSAGE-----\n\n" + key + "-----END PGP MESSAGE-----\n" ; QString temp_path = QString( "%1/%2/" ).arg( QDir::homePath(),"/.zuluCrypt/" ) ; QDir d ; d.mkpath( temp_path ) ; temp_path += QString( ".tomb-%1" ).arg( QString::number( getpid() ) ) ; /* * temp_path will have something like "/home/ink/.zuluCrypt/.tomb-3452" * this will be a path to a temporary file we will pass to gpg since gpg expects a keyfile path * TODO: look into skipping creating a temporary file and do everything in memory */ QFile temp_file( temp_path ) ; temp_file.open( QIODevice::WriteOnly ) ; temp_file.write( key ) ; temp_file.close() ; key = plugins::gpg( QVector{ exe.at( 1 ) },temp_path,password ) ; temp_file.setFileName( temp_path ) ; temp_file.open( QIODevice::WriteOnly ) ; uchar * m = temp_file.map( 0,temp_file.size() ) ; if( m ){ memset( m,'\0',temp_file.size() ) ; temp_file.unmap( m ) ; } temp_file.close() ; temp_file.remove() ; return key ; } } ) ; w.setToken( argv ) ; w.setApplicationName( "tomb" ) ; w.setkeyLabel( QObject::tr( "Enter tomb/steghide Key Below" ) ) ; w.setkeyFileLabel( QObject::tr( "Enter A Path To A tomb/steghide Keyfile Below" ) ) ; w.setExe( { "steghide","gpg" } ) ; w.Show() ; return a.exec() ; } zuluCrypt-6.2.0/rpm/000077500000000000000000000000001425361753700143535ustar00rootroot00000000000000zuluCrypt-6.2.0/rpm/BUILD_INSTRUCTIONS000066400000000000000000000046271425361753700171720ustar00rootroot00000000000000 ps: copy and paste all given commands to make sure you dont mistype them. ps: at step 5,replace "5.7.1" to zuluCrypt version you are building. ps: these instructions assumes rpm build directory is at "~/rpmbuild". Modify the paths in step 5 if they are different in your distribution. 1. make sure the following packages are installed in your system. Their precise names maybe different in your distribution: a. libpwquality-devel( optional dependency used to check the quality of passwords when creating volumes ) b. libblkid-devel c. libqt4-devel( required if building GUI components ) d. gcc e. gcc-c++ f. cryptsetup-devel g. cmake h. i. libgcrypt-devel j. libsecret-devel( optional dependency to store keys in gnome's libsecret ) k. kde-devel( optional dependency to store keys in kde's kwallet ) l. pkg-config m. libdevmapper-devel aka device-mapper-devel. n. uuid-devel o. rpmdevtools( this package contains programs necessary to build rpm packages ) 2. make sure "tar" and "xz" commands are installed in your computer as they are needed in step 5. 3. decompress the zuluCrypt archive you downloaded(you should be able to do this from context menu when you right the archive on your file manager). 4. open the terminal and change directory to zuluCrypt's source folder. 5. while on zuluCrypt source folder,run the following commands to create rpm building environment **************************************************************************************************************** rpmdev-setuptree tar -cf ~/rpmbuild/SOURCES/zuluCrypt-5.7.1.tar ../zuluCrypt-5.7.1 xz -z ~/rpmbuild/SOURCES/zuluCrypt-5.7.1.tar **************************************************************************************************************** 5. while on zuluCrypt source folder,run the following commad to create a zuluCrypt rpm package. **************************************************************************************************************** QA_RPATHS=$[ 0x0001|0x0010 ] rpmbuild -bb rpm/zuluCrypt.spec **************************************************************************************************************** 6. wait for the build to finish and look for the rpm packages in a folder located in "~/rpmbuild/RPMS/". 7. consult your distribution's documentation on how to install .rpm packages and install the ones you will find in step 6 above. zuluCrypt-6.2.0/rpm/zuluCrypt.spec000066400000000000000000000117041425361753700172530ustar00rootroot00000000000000# # Spec file for package zuluCrypt # # Copyright © 2011-2015 Francis Banyikwa # # 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, see . Name: zuluCrypt Version: 5.7.1 Release: 0 Summary: Qt GUI front end to cryptsetup License: GPL-2.0+ Group: Productivity/Security Source: %{name}-%{version}.tar.xz Source100: zuluCrypt-rpmlint URL: https://github.com/mhogomchungu/zuluCrypt %define libversion 3_2_0 %define srcname zuluCrypt %define libname lib%srcname%libversion %define libnamedev %{srcname}%{libversion}-devel #You may want to add dependencies for kwallet,gnome-keyring and pwquality below #if you want to include optional functionality they provide. BuildRequires: cmake BuildRequires: device-mapper-devel BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: glibc-devel BuildRequires: libblkid-devel BuildRequires: libgcrypt-devel BuildRequires: libsecret-devel BuildRequires: libpwquality-devel BuildRequires: pkgconfig(QtCore) BuildRequires: pkgconfig(QtGui) BuildRequires: pkgconfig(QtNetwork) %if 0%{?fedora} BuildRequires: cryptsetup-luks-devel %endif %if 0%{?suse_version} BuildRequires: libcryptsetup-devel %endif %description zuluCrypt is a front end to cryptsetup. It makes it easier to use cryptsetup by providing a Qt-based GUI and a simpler to use CLI front end to cryptsetup. It does the same thing truecrypt does but without licensing problems or requiring a user to setup sudo for it or presenting root's password. This package contains the applications. %package -n %{libnamedev} Requires: %{libname} = %{version} Summary: Development library package Group: Development/Libraries/C and C++ %description -n %{libnamedev} This package contains development files and libraries necessary to build programs around zulucrypt %package -n %{libname} Summary: Library for %{name} Group: Productivity/Security %description -n %{libname} This package contains libraries that provide higher level access to cryptsetup API and provide mounting/unmounting API to easy opening and closing of volumes %prep %setup -q %build mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/usr -DREUSEMOUNTPOINT=false -DUDEVSUPPORT=true -DNOGUI=false -DQT5=true -DHOMEMOUNTPREFIX=false -DNOGNOME=false -DNOKDE=false -DCMAKE_BUILD_TYPE=RELEASE .. %install cd build make DESTDIR=$RPM_BUILD_ROOT install %post chmod 4755 %{_bindir}/zuluCrypt-cli chmod 4755 %{_bindir}/zuluMount-cli %post -n %{libnamedev} sbin/ldconfig %postun -n %{libnamedev} sbin/ldconfig %post -n %{libname} sbin/ldconfig %postun -n %{libname} sbin/ldconfig %clean rm -rf %{buildroot} rm -rf $RPM_BUILD_DIR/zuluCrypt %files %defattr(0755,root,root) %{_bindir}/zuluMount-gui %{_bindir}/zuluMount-cli %{_bindir}/zuluPolkit %{_bindir}/zuluCrypt-gui %{_bindir}/zuluCrypt-cli %{_bindir}/zuluSafe-cli %dir %{_libdir}/zuluCrypt %dir %{_datadir}/zuluCrypt %dir %{_datadir}/doc/zuluCrypt %{_libdir}/zuluCrypt/keyring %{_libdir}/zuluCrypt/zuluCrypt-testKey %{_libdir}/zuluCrypt/keykeyfile %{_libdir}/zuluCrypt/keydialog-qt %{_libdir}/zuluCrypt/steghide %{_libdir}/zuluCrypt/tomb %{_libdir}/zuluCrypt/gpg %{_libdir}/zuluCrypt/hmac %{_datadir}/applications/zuluCrypt.desktop %{_datadir}/applications/zuluMount.desktop %defattr(0644,root,root) %{_datadir}/icons/* %{_datadir}/doc/zuluCrypt/* %{_datadir}/zuluCrypt/* %{_datadir}/pixmaps/* %{_datadir}/mime/packages/zuluCrypt.xml %{_datadir}/polkit-1/actions/org.zulucrypt.zulupolkit.policy %{_mandir}/man1/* %defattr(0644,root,root) %files -n %{libname} %defattr(0644,root,root) %{_libdir}/libzuluCrypt.so.* %{_libdir}/libzuluCrypt-exe.so.* %{_libdir}/libzuluCryptPluginManager.so.* %files -n %{libnamedev} %defattr(0644,root,root) %dir %{_includedir}/zuluCrypt %{_includedir}/zuluCrypt/libzuluCrypt.h %{_includedir}/zuluCrypt/libzuluCrypt-exe.h %{_includedir}/zuluCrypt/libzuluCryptPluginManager.h %{_libdir}/libzuluCryptPluginManager.so #%%{_libdir}/libzuluCryptPluginManager-static.a %{_libdir}/libzuluCrypt.so %{_libdir}/libzuluCrypt-exe.so #%%{_libdir}/libzuluCrypt-static.a #%%{_libdir}/libzuluCrypt-exe-static.a %{_libdir}/pkgconfig/libzuluCrypt.pc %changelog # openSUSE is strict about the date format used. # To do: Fix date format. #* Thu May 1 2014 mhogomchungu@gmail.com #* Fri Mar 15 2013 mhogomchungu@gmail.com #- upate to version 4.6.2 #* Mon Jan 14 2012 mhogomchungu@gmail.com #- update to version 4.6.0 zuluCrypt-6.2.0/translations/000077500000000000000000000000001425361753700162765ustar00rootroot00000000000000zuluCrypt-6.2.0/translations/INSTRUCTIONS000066400000000000000000000036361425361753700201750ustar00rootroot00000000000000 /* * commands to run to build .mo files for the backends */ xgettext -d zuluCrypt-cli -s -o zuluCrypt-cli.pot ../../zuluCrypt-cli/bin/add_key.c ../../zuluCrypt-cli/bin/close_volume.c ../../zuluCrypt-cli/bin/create_volumes.c ../../zuluCrypt-cli/bin/crypt_file.c ../../zuluCrypt-cli/bin/main.c ../../zuluCrypt-cli/bin/open_volume.c ../../zuluCrypt-cli/bin/remove_key.c ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c ../../zuluCrypt-cli/bin/volume_info.c ../../zuluCrypt-cli/bin/write_device_with_junk.c msginit -l en_US -o zuluCrypt-cli.po -i zuluCrypt-cli.pot msgfmt -c -v -o zuluCrypt-cli.mo zuluCrypt-cli.po xgettext -d zuluMount-cli -s -o zuluMount-cli.pot ../../zuluMount-cli/main.c ../../zuluMount-cli/mount.c ../../zuluMount-cli/umount.c msginit -l en_US -o zuluMount-cli.po -i zuluMount-cli.pot msgfmt -c -v -o zuluMount-cli.mo zuluMount-cli.po zuluCrypt-gui localization files are Qt translation files ending in ".qm" and they must be placed at $PREFIX/share/zuluCrypt/translations/zuluCrypt-gui/ zuluCrypt-cli localization files are gettext translation files ending in ".mo" and they must be placed at $PREFIX/zuluCrypt/translations/LANGUAGE/LC_MESSAGES zuluMount-gui localization files are Qt translation files ending in ".qm" and they must be placed at $PREFIX/share/zuluCrypt/translations/zuluMount-gui/ zuluMount-cli localization files are gettext translation files ending in ".mo" and they must be placed at $PREFIX/zuluCrypt/translations/LANGUAGE/LC_MESSAGES let PATH = "$PREFIX/zuluCrypt/translations/" localization files may be something like below $PATH/en_US/zuluMount.mo $PATH/en_GB/zuluMount.mo $PATH/en_US/zuluCrypt.mo $PATH/en_GB/zuluCrypt.mo NOTE: the "LANGUAGE" path components allows for the same translation filename to be used with different translations.I do not know if it is intended to be used this way but it worked on my first attempt and i am sticking with it until i know of a better way zuluCrypt-6.2.0/translations/plugins/000077500000000000000000000000001425361753700177575ustar00rootroot00000000000000zuluCrypt-6.2.0/translations/plugins/messages.ts000066400000000000000000000075461425361753700221520ustar00rootroot00000000000000 MainWindow key module &open &cancel keyfile key %1 module %1 key module warning are you sure you want to terminate this operation prematurely? ERROR key field is empty path to %1 keyfile is empty invalid path to %1 keyfile could not find "%1" executable in "/usr/local","/usr/bin" and "/usr/sbin" could not decrypt the %1,wrong key? could not decrypt the %1 key,wrong key? select a key file zuluCrypt-6.2.0/translations/zuluCrypt/000077500000000000000000000000001425361753700203175ustar00rootroot00000000000000zuluCrypt-6.2.0/translations/zuluCrypt/README000066400000000000000000000001601425361753700211740ustar00rootroot00000000000000 messages.ts has zuluCrypt-gui strings to be translated messages.pot has zuluCrypt-cli strings to be translated zuluCrypt-6.2.0/translations/zuluCrypt/ar_SA.qm000066400000000000000000002366361425361753700216630ustar00rootroot00000000000000<¸dÊÍ!¿`¡½Ý§ar_SAB@²3×ò4ø5+[u¦Ó +Oe+Oü+OyE+[Š+[yi+[õ-ã \QÉMQÉm¯TÝV„TÝšûTÝÂOW';àW'[lfîg觤‹Ú¹Ä‰¹Äö÷¿Ã±¿Ã *¿Ãyâ¯4 â¯ÍR⯰N…˜ÔNŒøÀe"Ö6`  E¥ õ¡§¡Ó¬ôÏÀe;ÀeÓ@É´ÄËôÓiÞjõ¨51öeu*¶E¯[*ì0ËÈ*ì0A+f¾í+f¾Ëø+f¾öÏ+f¾F+Œq2®ÁÍ3uP#E’(ŽFØó]xH7 J Ã@Jgz ‚JwBÂJwB&aJwBG²JwBÍ(JwBÜúJwBó7JwB÷ÒJwBìJ  üqN+ºÆQ aO Q bO—T}ÕëæZz  ^Ü„_ú%É&bƒÉð[d¤t d¤tV®jyeJ@jye“¾jye¥pjyeáFrx¼Ò½sf: ÊtZŠ|Šc|fEY,3²µ„žÎΤŒéñ¦ó ®°Ub>º…ŽÎ ½ …ÀA¿ë”̓Å1õøÅÃ…[ùÅÃ…îßψlßM'êÍÈ}äúëcÛû‰¤Æ<¦s <Z´ålÞ=7ÕÝ™FwVùXîåDþXîåÜ^]”Ñ«sO¨n[sO¨˜€{˜M™u˜ÿš2Nëœ%tœ%MGœ%mÛœ%—Xœd%©žÖ’^A¯ Žƒg¶4:‡ÍΕpÍÐuÄÍÐuM‘ÍÐun#ÍÐu—¤ÍÐu©ØÍÐu¾ÂÍÐuôMÝÒeðóþ¼=€wÿPõšg¼•£5mKñÓdü"Oµ$:4eô:4e­Æ=8R 8K6Õ¢ÿKìêY´e5âçœu 51~u%¨1¸uî1ô‰ÔQXŒÃå}7ŒÃåÛ¤XUB¼§–Ä`º¨”zuÅ<0QÙÆ£·èìtG3ƒcÏ&W -(â"! ( h ( hv( h­ƒ( hÆÐ(ã¥P(ã¥^(㥶(ã¥Ç)Å]Á:XÃNIN‚ÅéP„3)P„8ÇPP…{­_ꎺjeôDxjeôŽæjeô¢tm©DrýõC耢 Áš!´(í›Ñõjü±·.í©¶ÿô!}½("kÐDSü×c•°ÝP=؈  2Ö+ hñ+ ’€+ ÝWEìÑ’i%ÄÂN²- ‡Ö/K ’¾/K ¤Á1'"((Dê5Fg½5J¬>ZŽU€Ôz[h¥ïõ[¥Eši™Õ#³“±…e‡–Ê›˜I¼°Ÿ˜I¼×E˜I¼ îšÒ–C¢aû¤F¼§tAGÞ§tA‘ý§tA¤“§tA¸/§tAÝ(§tA§Ð©9’«Žñ «Žò<«Žól«Žôœ«ŽõÌ«Žöü«Ž÷,«Žø\«ŽùŒ«Žú¼«Žû쫎ü«ŽýL«Žþ|«Žÿ¬«Ü« «<«l«œ«Ì«ü«,«\« Œ« ¼¯ƒWÙ¯ƒWy¶²4ÊŒ¾ïˆæ×ÕĘÛÅÞ_ ãUeqôð$?¨ò¤EA}ò¤EŽJò¤E¡Õô,uÊÌ Ç•¨e÷ódq(ëÔ¦6°e¨×:_yú>vÔq/?ÅÂÙ@Z$S˜BGÔ™ÀF›£J%Oz¥\ÆDµ\ÙÄçebõmgòæšk•¨sùs½þWtÌÅ~Q‡­Õ@ëˆ!$«‹°t‚¹™ÔŽÙ„š”DšÈú ”œôÄ ¦È•rnª-¬<ŽŸ¦µ®•÷Àn< Ëí2Ä8Íœ tÎvÔp³Õf)@Õf)7Õf) ®Õf)µ Õf)ÖÑظå.|ظå8Hظå@»ظåcQظ巀á³c&›á³c$÷ú£uÍý¨ÍHmgÚâ“ ÜI±ž,Ö%Ý,Ö%¾]DIT4;EX,§EXbðLü…¯Ï`Zcïˆ`Zcú`}°fÊw6fÊw•¡fÊw§¼fÊwäÂiµÔ~Àrç!_ýrç!‡¤rç!Ç`rç!%Þ€]tS>™ZƒùA n É£¶U"Ÿ¥ýSî+©Už’¬Ï• "¿…ˆHíÂ݉ "ÈìnÐCÌÖ£ÆÑô^ÞŠ¥íìñ”fýð‚´`ÈòÌ¿Ñô‰5!øöi5é¬5®^®T«®n­®«o$ý5+õDÑ6sr6ÿ6sr<œ6srsBX/nϳX§~†\ÙÄFi•¨MËiµ¨:9iµ¨—àiµ¨æKi»5:ñkµ¨˜+kµ¨ªxÇ…«ø€Tß<Š ^‹þ ì ¥H –ÇŠRœMÄĦQ‰ ©ƒ±6°3”³š#Œ…» `…\ÅÉ´Œɶ%òɶŠ{Ëòú ½ÏÆòŠÚâê0âïÎ=çåšoêÄÁôÖ#}½Î ßÓÂ'¼&ßSö&ßšN&ߪ¿&ßê]) ‡´X5´M@92œG¥X™MQüÃáÓX•wÉéZÜ´ÎZÜ´<\aòF”¯ 2—zÓÄšïî&Ÿ,•·¸³gâ.ª³gâBµ›Z [¶CÞ+¶_=X»ô?-ËÆ?®‰.Ê´5³"àT¢|4á­tR¨æ1•ó¶éªåWbéªå›#êÚeŠð:eŒ/ Ø ™ a„C/ P±%ë Zùh‡ ] ùf dõ¥†ü n$%8y u¬ÑZ w­Ñ[– {„¾&ó ƒ"bŽ ƒŒõf Šö%? ”:£°Ó ¥lNi/ ¥lNÞD ®Ì$ °ÚÞÒé Å“ƒÀ‡ ÆSyñ ËK“j Í¥4G ÒÝÛÞ³ Úì5±ý æ j¥ êÿb¶L êÿb ˆ ïÖ©"9 ï×V"l ì: õ nh 7*ý] C< ±åœ5 )"» jD÷] !X5 #xàS 0L í 5ÞÕ$‡ 6 äú~ ?ä]2 BéÈXt Pò9pY a&Ðà a@7lA cöÚUö d Ã6e jà5ôÏ k)ÊU lUq¥ nUì‚ nUù‰ qõ– { 2. €´Ù_p ‡¢à²ª ‹&„E iÕ¯Œ ˜Iœ½ ˜Iœ&% ˜Iœ,Ü ˜Iœ8 ˜Iœ?í ˜Iœc% ˜IœzH ˜IœŒ ˜Iœ N ˜Iœ²î ˜IœËœ ˜IœñY ˜Iœö§ ¥S„Ó  ¨¸…{ ¬,… } ¶/Tô Ìùê N Ò¥ì* Ø_Ÿ ÚÉE’ âá×t ñ¸¸b ò¹2¿c A%¸è >>r “bÔE lÇcö f¨7À þ•FÆ !ª$Rñ &—N­ 9ÿ‰û _DÕ÷ø `ÂEKj `ÂE¥ü aJu“i dþµ5^ dþµ‚9 g.w6Ï g.w_Ë g.w‡s g.w®+ g.w²q g.wör jP®¯ j½Ô¤ m@c!· |d¿&ž ƒÝ©p Œöò|Ø šÛä ¥LN’þ ¥LN¥ ¶¥’û Á¬2¼ ÊÊcut Õìc&å â²Ã\ã ·»Û OåYm Oåƒ% ¯åXé ºEžV U/ÿ 8y„I… ;I4€ Oc/Ï Tl"þ VL| _Èe a¤^ é e‘´rŸ m>µô pQc} q6e‘Ÿ w²¶Å ‰žÐš ‘TBD •~¬ ¢Ù²ù ¨o>õ/ ®itþ ¯yµKô ¯yµlè ¯yµåä µ‰”» µÚ”Úô ·¨ ( ¹^'3 »~, ômõÔð ü© ü¡- ª.ñ¸ š d 4ú„à @D)¹ BåJÓ D¦™¬\ IŽ5`0 OE³j ZG3H± ZYsQÊ cÁs * k¦Cµ pBq/E y…µÚa Ž›W¼ Ž››} œMI9 °ì7É ¸Û¤ Ø}•Ç™ Úz { çþ¾L_ ïéÅ^ ñY%z(¢¹o*ˆÔ5áFrOÇGrO;P5%½ÕWœUiš’5F’5ë•Ï”G•ýuÈ›n¥X›n¥›Ö¥HeÃ.§é´ D­ãŠƯ¤ªa· rí+¾«…PÃýD;=ÄÄDãÈÆù„JÍ®Yó]Þ²³\˜Þ²³ùÐàcûò Š˜%¢%>KEÂ\7eëªpß¾žÝˆø’(ˆøYŠ.¸à’"|Œ’"|[Ç’"|yã’"|Šg’"|œÔ’"|Æžã娭É#-¯©®ª¶|ß³]Ó‰ÙtDé;ämýk£ý(â¿i)&2E,D/'* 'DF8'E GJ 'D*J J-//G' JH /JA EF .D'D *91JAG AJ EDA "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list %0' DE *1:( AJ '9*('1 'DE,D/ CE,D/ F8'EJ 4:D 'D*7(JB CE3*./E E/J1 +E '0G( %DI B'&E) 'D.J'1'* H'.*1 %/'1) 'D#,2'! :J1 'DF8'EJ). #6A 'DE,D/ 6EF 'DB'&E) HEF *DC 'DD-8) DF J9*(1 0'C 'DE,D/ CE,D/ F8'EJ. C(/JD 9F 0DC *3*7J9 %6'A) FA3C *-* E,EH9) 2HDHC1(* H2HDHE'HF* H3HA *2HD G0G 'DBJH/. "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. DialogMsgD'&No DialogMsgF9E&Ok DialogMsgF9E&Yes DialogMsgF'A0) 13'D)Dialog DialogMsg8D' *8G1 G0G 'D13'D) E1) #.1IDo not show this dialog again DialogMsg E9DHE) INFORMATION DialogMsgî5D'-J) :J1 C'AJ) DD/.HD 9DI ,G'2 'DF8'E DDC*'(). AB7 'DE3*./E 'DE/J1 #H 96H 6EF E,EH9) 2HDHC1(*-'DC*'() J3*7J9 9ED 0DC.ƒInsufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that DialogMsgÎ5D'-J) :J1 C'AJ) DD/.HD 9DI ,G'2 'DF8'E. AB7 'DE3*./E 'DE/J1 #H 96H 6EF E,EH9) 2HDHC1(* J3*7J9 9ED 0DC.jInsufficient privilege to access a system device, only root user or members of group zulucrypt can do that DialogMsg'D1BE 'D*91JAJUUID: DialogMsgÈD' J8G1 #F D/JC 5D'-J'* C'AJ) DD/.HD 9DI 'DEDA 'DE4A1 AJ 7H1 1%. *#C/ EF 'D5D'-J'* +E -'HD E1) #.1I.wYou do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again DialogMsg'D.'F'* 'DF47) active slots DialogMsg'D.'F'* 'DF47) active slots: DialogMsg4A1)cipher DialogMsg4A1)cipher: DialogMsg,G'2device DialogMsg,G'2device: DialogMsgF8'E 'DEDA'* file system: DialogMsg'DE3'-) 'DE*'-) free space: DialogMsgfsfs DialogMsg-,E 'DEA*'-key size DialogMsg-,E 'DEA*'-keysize: DialogMsg/H1)loop DialogMsg/H1)loop: DialogMsg7H1mode DialogMsg7H1mode: DialogMsg %2'-)offset DialogMsg'D%2'-)offset: DialogMsg-,Esize DialogMsgF5text DialogMsg'DE3'-) 'DCDJ) total space: DialogMsgFH9type DialogMsgFH9type: DialogMsg:J1 E3*./Eunused DialogMsg E3*./Eused DialogMsgF3() 'DE3*./Eused % DialogMsg"'DE3'-) 'DE3*./E) used space: DialogMsgF3() 'D'3*./'E%used%: DialogMsg#D:&CancelPasswordDialog'A*-&OpenPasswordDialog"4'1C FB7) 'D*-EJD&Share Mount PointPasswordDialog"EA*'-+EDA 'DEA*'- Key+KeyFilePasswordDialogEDA D(EA*'-KeyFilePasswordDialog.-END AJ 7H1 'DB1'!) AB7Mount In &Read Only ModePasswordDialog'3E 'D*-EJD Mount NamePasswordDialog$'A*- 'DC,D/ 'DE4A1Open Encrypted VolumePasswordDialogdm-crypt 9'/JPLAIN dm-cryptPasswordDialog %6'A'*PluginPasswordDialog'DF5 'DED5B TextLabelPasswordDialogAJ1' C1(* VeraCryptPasswordDialogE3'1 'DE,D/ Volume PathPasswordDialogFH9 'DE,D/ Volume TypePasswordDialog 'A*- EDA 'DEA*'- open key filePasswordDialog '.*1 E3'1 'DE,D/open volume pathPasswordDialog,'.*1 E3'1 FB7) 'D*-EJDselect mount point pathPasswordDialog8.J'1'* d .. 'DE3'1 %DI 'DE,D/ DJ*E A*-G/*-EJDG *DB'&J' m.. #/') A*- E/J1 'DEDA'* 'D'A*1'6J ('D'A*1'6J GH xdg-open) e.. 4:D 'D*7(JB EF /HF 'DH',G) 'D13HEJ) Í options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI QObjectœDE JECF *-/J/ EDA pgp 'D*FAJ0J AJ "/usr/local/bin","/usr/bin" and "/usr/sbin"NCould not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin"QObject.7#ERRORQObjectDA4D AJ *-/J/ 'DEDA 'D*FAJ0J pkexec"Failed to locate pkexec executableQObject%0' *E *A9JD 'D.J'1 3HA J*E *GJ&) FB7) *-EJD .'5) 1&J3J) AJ "1%" H #.1I A19J) 'D/.HD %DJG' 9'E H5H1) EF FB7) 'D*-EJD *GJ& AJ "2%"ŸIf the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2"QObject$'D*-CE AJ 'DEA6D'*Manage FavoritesQObject-ED 'D,EJ9 Mount AllQObject-HD 2HDH C1(*about zuluCryptQObjectŠ%6'A) pgp G0G 'D%6'A) *3*1,9 'DEA*'- 'DE:DB AJ EDA pgp (EA*'- E*E'+DQgpg plugin. This plugin retrives a key locked in a gpg file with a symmetric keyQObjectÀ%6'A) hmc G0G 'D%6'A) *HD/ EA*'-' 7(B' DDE9'/D): 'DEA*'-= hmac(sha256,CDE) 'D31,EA*'- 'DE-*HI)ohmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents)QObjectì'D%6'A) 'DEA*'--EDA 'DEA*'- G0G 'D%6'A) *HD/ EA*'-' ('3*./'E 'D5J:) 'D*'DJ): 'DEA*'- = CDE) 'D31 + E-*HI EDA 'DEA*'-jkeykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contentsQObjectFB7) *-EJD 9'E)public mount point: QObjectD'&NocreateVolumeDialogF9E&YescreateVolumeDialogÎJF5- (%F4'! -'HJ'* E4A1) 9DI (J'F'* 94H'&J) EF9' D*31( 'DE9DHE'*. GD *1:( AJ C*'() (J'F'* 94H'&J) 9DI "1%" #HD' B(D %F4'! 'D-'HJ) (G' JECFC %JB'A 9EDJ) C*'() 'D(J'F'* 'D94H'&J) AJ #J HB* %0' '3*:1B* E/) 7HJD) HD' JECFC 'D'F*8'1.-It is advised to create encrypted containers over random data to prevent information leakage. Do you want to write random data to "%1" first before creating an encrypted container in it? You can stop the random data writing process anytime you want if it takes too long and you can no longer wait. createVolumeDialog”G0G 'D9EDJ) 3HA *$/J %DI */EJ1 C'ED DD(J'F'* 'DEH,H/) AJ1%. GD #F* E*#C/sThis operation will lead to permanent destrunction of all present data in "%1". Are you sure you want to continue?createVolumeDialog¢G0G 'D9EDJ) 3HA *$/J %DI */EJ1 C'ED DD(J'F'* 'DEH,H/) AJ /dev/sdc1. GD #F* E*#C/wThis operation will lead to permanent destrunction of all present data in /dev/sdc1. Are you sure you want to continue?createVolumeDialog *-0J1 Warning!!createVolumeDialog#D:&CancelcreateVolumeInExistingFIle.7#ERRORcreateVolumeInExistingFIle.5'&5 'DE,D/Volume PropertiescreateVolumeInExistingFIleì'DH69 'D'A*1'6J #F 2HDH C1(* JF4& 'D-'HJ) 'DE4A1) 9DI (J'F'* 94H'&J) D%.A'! FE7 'D'3*./'E DG'. G0G 'D9EDJ)*3*:1B HB*' 7HJD' .5H5' %0' C'F -,E 'D-'HJ) C(J1'. GF'C .J'1 D*,'H2 G0G 'D9EDJ) DDE3*./E 'D9,D. DCF 61J() 0DC 9'DJ) HJECF #F *C4A DD.5E -JF JA-5 'D-'HJ) EF 'D.'1,. %0' CF* *9J E' *A9DG '3*E1 (CD 'D#-H'D H%0' CF* AJ 4C AJF5- (*-ED 7HD 'D9EDJ) D*CHF AJ E#EF E3*B(D'.© By default,zuluCrypt creates a volume in a container file over randomly generated data to hide usage patterns of the container. This process takes time and it may take a very,very long time if the volume about to be created is large enough and this option exists to skip the process for the impatient among us but but it comes at a cost and the cost may be too high when it finally reveal itself while infront of an adversary when they look at the encrypted container and manage to derive meaning based on how the container looks from outside. If you know what you are doing,then continue by all means,if in doubt,my advise is to endure the process and be safer in the long run. createfile %EC*ED % Complete createfile#D:&Cancel createfile`GD #F* E*#C/ #FC D' *1J/ %F4'! -'HJ) #C+1 #E'F'DAre you really sure you do not want to create a more secured volume? createfile^GD #F* E*#C/ EF 1:(*C AJ %JB'A 9EDJ) %F4'! EDA4Are you sure you want to stop file creation process? createfile#F4&C&reate createfileVEDA 'D-'HJ) J,( #F JCHF #C(1 EF 3 EJ,' ('J*&Container file must be bigger than 3MB createfile^DE JECF A*- .DAJ) 'D*4AJ1 D*HDJ/ (J'F'* 94H'&J)=Could not open cryptographic back end to generate random data createfile#F4& EDA -'HJ)Create A Container File createfilehD' *C*( (J'F'* 94H'&J) 9DI 'D-'HJ) (D' JF5- (G (4/));Do Not Write Random Data To Container(STRONGLY discouraged) createfile0A4D AJ %F4'! EDA 'D-'HJ)Failed to create volume file createfile'3E 'DEDA File Name createfileE3'1 'DEDA File Path createfile-,E 'DEDA File Size createfile-BD 'D'3E A'1:File name field is empty createfile-BD 'DE3'1 A'1:File path field is empty createfile-BD 'D-,E A'1:File size field is empty createfileLJH,/ '3E (FA3 'D'3E AJ 'DE,D/ 'DE3*G/ACFile with the same name and at the destination folder already exist createfile,J,' ('J*GB createfileE9DHE'*INFO createfile^%/.'D :J1 EB(HD AJ -BD 'D-,E. *B(D 'D#1B'E AB7.@Illegal character in the file size field.Only digits are allowed createfileCJDH ('J*KB createfileEJ,' ('J*MB createfile@*E %D:'! 'D9EDJ) EF B(D 'DE3*./E$Operation terminated per user choice createfile8'.*1 E3'1' DDEDA 'D0J 3*F4&G-Select Path to where the file will be created createfile*%FG'! 9EDJ) %F4'! EDA!Terminating file creation process createfile *-0J1WARNING createfiledD' J(/H #F D/JC 5D'-J) 'DC*'() 9DI 'DE,D/ 'DE3*G/A>You dont seem to have writing access to the destination folder createfile"'A*- F'A0) 'DE,D/open a folder dialog box createfile#D:&Cancel createkeyfile#F4&C&reate createkeyfile#F4& EDA EA*'-Create A KeyFile createkeyfilefJH,/ EDA (FA3 'D'3E AJ 'DE,D/ 'D0J J-HJ EDA 'DEA*'-CFile with the same name and at the destination folder already exist createkeyfileP'DE3'1 DDE,D/ 'D0J J-HJ EDA 'DEA*'- A'1:5Folder path to where the key will be created is empty createkeyfile E3'1 EDA 'DEA*'- KeyFile Path createkeyfile,EDA 'DEA*'- #F4& (F,'-KeyFile successfully created createkeyfile'3E EDA 'DEA*'- Keyfile Name createkeyfileV'D9EDJ) *E B79G'. 'DEA*'- DE JHD/ (4CD C'ED+Process interrupted,key not fully generated createkeyfileRNGRNG createkeyfileH'.*1 'DE,D/ 'D0J JF4& (G EDA 'DEA*'-'Select A Folder To Create A Key File In createkeyfile\D'J(/H #F D/JC 5D'-J) /.HD 9DI 'DE,D/ 'DE3*G/A>You dont seem to have writing access to the destination folder createkeyfileB'A*- 'DE,D/ 'D0J J-HJ EDA 'DEA*'-+open a folder a key file will be created in createkeyfileF'DE3'1 DDE,D/ 'D0J J-HJ EDA 'DEA*'-#path to a folder to create a key in createkeyfile JF5- (4/) 9ED F3.) '-*J'7J) D*1HJ3) 'DE,D/ "1%". J1,I B1'!) 'D/DJD 9F #GEJ) 0DC.u Creating a backup of the "%1" volume header is strongly advised. Please read documentation on why this is important. createvolume%1 :J1 EH,H/ %1 not found createvolume#D:&Cancel createvolume.-BD H'-/ A'1: 9DI 'D#BD#Atleast one required field is empty createvolume('J*Bytes createvolume#F4&C&reate createvolumeFDE JECF %F4'! E,D/ 9DI 'DB15 'DE-ED+Can not create a volume on a mounted device createvolumeTDE JECF 'D9+H1 9DI 'DEA*'- AJ 'D7H1 'D5'E*%Can not get passphrase in silent mode createvolume^'D-'HJ) J,( #F JCHF -,EG' 3 EJ,' ('J* 9DI 'D#BD&Container file must be bigger than 3MB createvolume.DE JECF %F4'! E,D/ E4A1$Could not create an encrypted volume createvolumedDE J9+1 9DI #J B3E J-ED G0' 'D1BE 'D*91JAJ 'DE91H64Could not find any partition with the presented UUID createvolumeLDE JECF '3*1,'9 'DEA*'- EF EDA 'DEA*'-#Could not get a key from a key file createvolumeDDE JECF 'D-5HD 9DI EA*'- EF 'DEFA0!Could not get a key from a socket createvolumeTDE JECF 'D9+H1 9DI CDE) 'D31 ('D7H1 'D5'E*'Could not get passphrase in silent mode createvolume4DE JECF A*- 'DE,D/ DBB1'!)!Could not open volume for writing createvolumefDE JECF 'D-5HD 9DI 0'C1) C'AJ) D'3*J9'( EDA 'DEA*'-/Couldnt get enought memory to hold the key file createvolume #F4& E,D/' ,/J/'Create A New Volume createvolumeJ'D.J'1 'D'A*1'6J GH 'D#HD 6EF 'DB'&E)-Default option is the first entry on the list createvolume.7#ERROR createvolume.7#ERROR! createvolume(A4D AJ %F4'! 'DEA*'-Failed to create a volume createvolumeF8'E 'DEDA'* File System createvolume,J,' ('J* GigaBytes createvolumeXCDE*' 'D31 'DE/.D) DDE,D/ 'DE.AJ D' **7'(B'FHidden passphrases do not match createvolume`1E2 :J1 EB(HD *E %/.'DG AJ -BD -,E 'DE,D/ 'DE.AJ:Illegal character detected in the hidden volume size field createvolumeLD' *H,/ 0'C1) C'AJ) D'3*J9'( CDE) 'D31&Insufficient memory to hold passphrase createvolumeLD' *H,/ 0'C1) C'AJ) D'3*J9'( CDE) 'D31*Insufficient memory to hold the passphrase createvolume@D' *H,/ 0'C1) C'AJ) D'3*J9'( 1/C)Insufficient memory to hold your response createvolume2E3'1 EDA 'DEA*'- :J1 5-J-Invalid path to key file createvolumeZJA6D %F4'! 'DE,D/ 'DE.AJ (F8'E EDA'* vfat/fat?It is best to create a hidden volume with vfat/fat file system. createvolume EA*'-Key createvolumeEA*'-+EDA EA*'- Key+KeyFile createvolumeEDA EA*'-KeyFile createvolume E3'1 EDA 'DEA*'- Keyfile Path createvolume EA'*J-Keys createvolumeCJDH ('J* KiloBytes createvolumeLUKSLUKS createvolume$LUKS+*1HJ3) .'1,J)LUKS+External Header createvolume LUKS1LUKS1 createvolume&LUKS1+*1HJ3) .'1,J)LUKS1+External Header createvolume LUKS2LUKS2 createvolume&LUKS2+*1HJ3) .'1,J)LUKS2+External Header createvolume¦*E %F4'! E,D/ DHC3 (F,'- HF,'- %F4'! *1HJ3) .'1,J). DCF A4D E3- 'D*1HJ3) 9DI 'DB15nLuks volume created successfully,external header created successfully but failed to erase header on the device createvolume0*E %F4'! E,D/ DHC3 (F,'-!Luks volume created successfully. createvolumeEJ,' ('J* MegaBytes createvolumeL.H'12EJ'* 9/) EA5HD) 9F (96G' (1E2 ":"5Multiple algorithms are separated by ":" character.  createvolume*1HC1(* 9'/JNormal TrueCrypt createvolumeAJ1' C1(* 9'/JNormal VeraCrypt createvolume"*1HC1(* 9'/J+E.AJNormal+Hidden TrueCrypt createvolume&AJ1' C1(* 9'/J+E.AJNormal+Hidden VeraCrypt createvolumeVE97I #H #C+1 EF 'DE97J'* 'DE7DH() :J1 EH,H/>One or more required argument(s) for this operation is missing createvolume*#D:I 'DE3*./E 'D9EDJ)%Operation terminated per user request createvolumep'D.J'1'* (GJ&) ".H'12EJ'* *4AJ1 -,E 'DEA*'- ('D(* DDG'4"JOptions are in a format of "algorithm.cipher mode.key size in bits.hash"  createvolumeB'D.J'1'* EA5HD) 9F (96G' (1E2 "."+Options are separated by a "." character.  createvolumePIMPIM createvolumePLAIN dm-cryptPLAIN dm-crypt createvolume.PLAIN dm-crypt E9 %2'-)PLAIN dm-crypt with offset createvolume",H/) CDE) 'D31:1%Passphrase Quality: %1% createvolume",H/) CDE) 'D31:0%Passphrase Quality: 0% createvolume&,H/) CDE) 'D31:100%Passphrase Quality: 100% createvolume<CDE*' 'D31 'DE/.D) D' **7'(B'FPassphrases do not match createvolumeE3'1 'DB15Path To Device createvolumeE3'1 'DEDA Path To File createvolume'DE3'1 DDB15Path to Device createvolumelJ1,I 'D*1J+ D#F %F4'! E,D/ AJ1' C1(* J3*:1B HB*' 7HJD'MPlease be patient as creating a VeraCrypt volume may take a very long time.  createvolumep'DEDA 'DE91H6 :J1 E/9HE. #F81 'D/DJD DE2J/ EF 'DE9DHE'*.MPresented file system is not supported,see documentation for more information createvolumeRNGRNG createvolumeF,'-SUCCESS! createvolume'DF5 TextLabel createvolumeBJ(/H #F 'DE.77 'DE9JF DDB15 EA*H-You dont seem to have writing access to the destination folder cryptfiles E3'1 EDA 'DEA*'- keyfile path cryptfilesf2HDH C1(* 4A1 'DEDA'* s ( *.zc ) ;; All Files ( * )5zuluCrypt encrypted files ( *.zc ) ;; All Files ( * ) cryptfiles8D' *8G1 G0G 'D13'D) E1) #.1IDo not show this message again. cryptoinfo *-J'* Greetings cryptoinfoF9EOk cryptoinfo*J1,I 'D1,H9 DB'&E) 'DE3'9/) +E 'A*- EDA zuluCrypt.pd DE91A) E(/&J) 9F 2HDH C1(* DE3*./EJ Unity 'DB'&E) AJ 'D#9DI J3'1 'DF'A0) -JFE' JCHF 2HDH C1(* EA*H-' HEA9D' EHB9 'DE41H9: https://mhogomchungu.github.io/zuluCrypt JF5- (B1'!) 5A-) 'D#3&D) H'D#,H() EF EHB9 'DE41H9 'D1&J3/Please consult "menu->help->open zuluCrypt.pdf" to get an introduction on zuluCrypt. Unity users,the menu is on the upper left corner of the screen when zuluCrypt has focus. Project's homepage is at: https://mhogomchungu.github.io/zuluCrypt Recommending reading FAQ page from the project's main page. cryptoinfoD'&NodialogokF9E&OkdialogokF9E&Yesdialogok F'A0)Dialogdialogok'DF5 TextLabeldialogok %EC*ED % Completed erasedevice#D:&Cancel erasedevice (/'J)&Start erasedevice„GD A9D' *1J/ C*'() (J'F'* 94H'&J) 9DI "1%". 9EDJ' 3HA */E1 E-*H'GdAre you really sure you want to write random data to "%1" effectively destroying all contents in it? erasedevice>DE JECF A*- 'DE.77 DDB15 'DE-ED)Can not open a mapper on a mounted device erasedeviceXDE JECF 'DC*'() 9DI 'DB15 (JFE' 'DE.77 EA*H-,Can not write on a device with opened mapper erasedevice(DE JECF %F4'! 'DE.77Could not create mapper erasedevice\DE JECF *-/J/ 0'C1) C'AJ) D'3*J9'( EDA 'DEA*'-1Could not get enought memory to hold the key file erasedevice0DE JECF E91A) E3'1 'DB15Could not resolve device path erasedevice2DE JECF 'DC*'() 9DI 'DB15Could not write to the device erasedevice>*E E3- 'D(J'F'* 9DI 'DB15 (F,'-&Data on the device successfully erased erasedevice&-BD E3'1 'DB15 A'1:Device path field is empty erasedevice&E3'1 'DB15 :J1 5-J-Device path is invalid erasedevice6#/.D E3'1 'DB15 'DE1'/ E3-G!Enter Path To Volume To Be Erased erasedevicef'E3- 'D(J'F'* 9DI 'DB15 (C*'() (J'F'* 94H'&J) 9DJG'9Erase Data On The Device By Writing Random Data Over Them erasedeviceT5D'-J'* :J1 C'AJ) DA*- EDA 'DEA*'- DBB1'!)3Insufficient privilege to open key file for reading erasedevice&E3'1 'DB15 :J1 5-J-Invalid path to device erasedevice<'DE3*./E #FGI 'D9EDJ) ('.*J'1G$Operation terminated per user choice erasedevice.EDA CDE) 'D31 :J1 EH,H/Passphrase file does not exist erasedeviceE3'1 'DB15Path to Device erasedevice~3J'3) 'D'3*./'E *EF9 :J1 'DE3*./E 'DE/J1 EF A*- E.77 B3E 'DF8'E@Policy prevents non root user opening mapper on system partition erasedevice<*E* C*'() (J'F'* 94H'&J) (F,'- Random data successfully written erasedeviceH'.*1 B3E' :J1 B3E 'DF8'E DE3- E-*H'G3Select A Non System Partition To Erase Its Contents erasedeviceð'DF'A0) 'D*'DJ) 3HA *C*( (J'F'* 94H'&J) 9DI 'DB15 EE' J$/J DAB/'F E-*HI 'DB15 ('DC'ED. GD #F* E*#C/ H*1:( AJ 'D'3*E1'1The next dialog will write random data to a device leading to permanent loss of all contents on the device. Are you sure you want to continue?  erasedevice0'DB15 J(/H E4:HD' EF B(D'This device appear to already be in use erasedevice *-0J1WARNING erasedevice *-0J1WARNING! erasedeviceR'C*( (J'F'* 94H'&J) 9DI 'D(J'F'* 'DEH,H/)$Write Random Data Over Existing Data erasedeviceRC*() (J'F'* 94H'&J) 9DI 'D(J'F'* 'DEH,H/)&Writing Random Data Over Existing Data erasedevice9JF&Set fileManagerx#/.D ('D#3AD '3E 'D*7(JB 'D0J *H/ '3*./'EG DA*- FA7) 'D*-EJDQEnter Below The Name Of The Application You Want To Be Used To Open Mount Points. fileManager 9JF E/J1 'DEDA'*Set File Manager fileManager'DF5 TextLabel fileManagerÆA4D AJ A*- EDA ZuluCrypt.pdf *#C/ #F 'DF8'E J3*7J9 A*- EDA PDF ('3*./'E #/') "1%" +E -'HD E1) #.1IcFailed to open zuluCrypt.pdf,make sure your system can open pdf files using "%1" tool and try againhelp#6A&Add luksaddkey#D:&Cancel luksaddkey"#6A EA*'-' DDE,D/Add A Key To A Volume luksaddkey^CD EF'A0 'DEA'*J- E4:HD). D' JECF %6'A) EA'*J-.5All key slots are occupied, can not add any more keys luksaddkey0-BD H'-/ E7DH( 9DI 'D#BD#Atleast one required field is empty luksaddkeyPDE JECF 'D9+H1 9DI B3E (FA3 'D1BE 'DE97I2Can not find a partition that match presented UUID luksaddkeyXD' JECF 'D-5HD 9DI CDE) 'D31 AJ 'D7H1 'D5'E*%Can not get passphrase in silent mode luksaddkeyDDE JECF 'D-5HD 9DI EA*'- EF 'DEFA0!Could not get a key from a socket luksaddkeyPDE JECF *1BJ) 'D5D'-J). *#C/ EF 'D#0HF'*9Could not get elevated privilege,check binary permissions luksaddkey*DE JECF A*- E,D/ DHC3Could not open luks volume luksaddkey4D' JECF A*- 'DE,D/ DDC*'()#Could not open volume in write mode luksaddkeyfDE JECF 'D-5HD 9DI 0'C1) C'AJ) D'3*J9'( EDA 'DEA*'-/Couldnt get enought memory to hold the key file luksaddkey$'DB15 DJ3 B15 DHC3Device is not a luks device luksaddkey.7#ERROR! luksaddkey$E3'1 'DE,D/ 'DE4A1Encrypted Volume Path luksaddkey#/.D EA*'- Enter A Key luksaddkey#/.D EA*'-' Enter a key luksaddkey*#/.D E3'1 EDA 'DEA*'-"Enter a path to a keyfile location luksaddkey&EDA 'DEA*'- 'DEH,H/Existing KeyFile luksaddkeyD0'C1) :J1 C'AJ) D'3*J9'( CDE) 'D31&Insufficient memory to hold passphrase luksaddkeyÈ5D'-J'* :J1 C'AJ) D%6'A) EA*'- DB15 'DF8'E. 'DE3*./E 'DE/J1 H#96'! E,EH9) 2HDHC1(* AB7 J3*7J9HF 0DC.sInsufficient privilege to add a key to a system device, only root user or members of group "zulucrypt" can do that  luksaddkeyP0'C1) :J1 C'AJ) DA*- EDA 'DEA*'- DDB1'!)3Insufficient privilege to open key file for reading luksaddkey$'DEA*'- #6JA (F,'-Key added successfully. luksaddkeyh'DEA*'- #6JA (F,'-. 'DEF'A0 1% 2% 'D"F BJ/ 'D'3*./'E4Key added successfully. %1 / %2 slots are now in use luksaddkey"EA*'-+EDA 'DEA*'- Key+KeyFile luksaddkeyEDA 'DEA*'-KeyFile luksaddkey E3'1 EDA 'DEA*'- KeyFile Path luksaddkey*#/.D E3'1 EDA 'DEA*'- KeyFile path luksaddkey$'DEA'*J- D' **7'(BKeys do not match luksaddkeyDHC3LUKS luksaddkey$EDA 'DEA*'- 'D,/J/ New KeyFile luksaddkey8CDE'* 'D31 'D,/J/) D' **7'(BNew passphrases do not match luksaddkeyJEDA EA*'- #H CD' EDAJ EA*'- :J1 EH,H/%One or both keyfile(s) does not exist luksaddkeyPE97I #H #C+1E7DH( :J1 E*HA1 DG0G 'D9EDJ)>One or more required argument(s) for this operation is missing luksaddkeyPIMPIM luksaddkey$,H/) CDE) 'D31: 1%Passphrase Quality: %1% luksaddkey$,H/) CDE) 'D31: 0%Passphrase Quality: 0% luksaddkey(,H/) CDE) 'D31: 100%Passphrase Quality: 100% luksaddkeyN'DEA*'- 'DE.D D' J*7'(B E9 EA*'- 'DE,D/2Presented key does not match any key in the volume luksaddkey'DF5 TextLabel luksaddkey*1H C1(* TrueCrypt luksaddkeyAJ1' C1(* VeraCrypt luksaddkeyE3'1 'DE,D/ Volume Path luksaddkeyFH9 'DE,D/ Volume Type luksaddkey('DE,D/ DJ3 E,D/ DHC3Volume is not a luks volume luksaddkey'A*- 'DEDA open file luksaddkey 'A*- EDA 'DEA*'- open keyfile luksaddkey'A*- 'DB3Eopen partition luksaddkey<GD E*#C/ #FC *1J/ E3- 'DEA*'-* Are you sure you want to delete this key? luksdeletekeyH(E3-G J3*-JD A*- 'DE,D/ H3JAB/ DD#(/> Deleting it will make the volume unopenable and lost forever. luksdeletekey#D:&Cancel luksdeletekey'E3-&Delete luksdeletekey:-BD H'-/ E7DH( 9DI 'D#BD A'1:#Atleast one required field is empty luksdeletekeyTDE JECF 'D9+H1 9DI B3E (FA3 'D1BE 'D*91JAJ2Can not find a partition that match presented UUID luksdeletekeyXDE JECF 'D-5HD 9DI CDE) 'D31 AJ 'D7H1 'D5'E*%Can not get passphrase in silent mode luksdeletekeyHDE JECF 'D-5HD 9DI 'DEA*'- EF 'DEFA0!Could not get a key from a socket luksdeletekeyfDE JECF 'D-5HD 9DI 0'C1) C'AJ) D'3*J9'( EDA 'DEA*'-0Could not get enough memory to open the key file luksdeletekey$DE JECF A*- 'DE,D/Could not open the volume luksdeletekey4DE JECF A*- 'DE,D/ DDB1'!)'Could not open the volume in write mode luksdeletekey.7#ERROR! luksdeletekey#/.D EA*'- Enter a key luksdeletekey*#/.D E3'1 EDA 'DEA*'-"Enter a path to a keyfile location luksdeletekeyD0'C1) :J1 C'AJ) D'3*J9'( CDE) 'D31&Insufficient memory to hold passphrase luksdeletekey80'C1) :J1 C'AJ) D'3*J9'( 1/C)Insufficient memory to hold your response luksdeletekey´5D'-J'* :J1 C'AJ) DA*- B15 'DF8'E. AB7 'DE3*./E 'DE/J1 H#96'! E,EH9) 2HDHC1(* (%EC'FGE 0DCgInsufficient privilege to open a system device,only root user or members of group zulucrypt can do that luksdeletekeyT5D'-J'* :J1 C'AJ) DA*- EDA 'DEA*'- DDB1'!)3Insufficient privilege to open key file for reading luksdeletekey,E3- EDA EA*'- (CDE) 31$Key File With A Passphrase To Delete luksdeletekey^'DEA*'- *E E3-G (F,'- 'DEF'A0 1% 2% 'D"F E4:HD)6Key removed successfully. %1 / %2 slots are now in use luksdeletekeyEA*'-+EDA EA*'- Key+KeyFIle luksdeletekeyEDA EA*'-KeyFile luksdeletekey E3'1 EDA 'DEA*'- KeyFile path luksdeletekey&EDA EA*'- :J1 EH,H/Keyfile does not exist luksdeletekeyPE97I E7DH( #H #C+1 DE J*HA1 DG0G 'D9EDJ)>One or more required argument(s) for this operation is missing luksdeletekeyB'D9EDJ) *E %D:$G' EF 71A 'DE3*./E%Operation terminated per user request luksdeletekey('-0A EA*'- EF 'DE,D/Remove A Key From A Volume luksdeletekeyJ'DEA*'- D' J7'(B #J' EF EA'*J- 'DE,D/:There is no key in the volume that match the presented key luksdeletekey6JH,/ EA*'- #.J1 AB7 ('DE,D/)There is only one last key in the volume. luksdeletekeyE3'1 'DE,D/ Volume Path luksdeletekey('DE,D/ DJ3 E,D/ DHC3Volume is not a luks volume luksdeletekey *-0J1WARNING luksdeletekey'A*- EDA EA*'-open a keyfile luksdeletekey'A*- EDA' E4A1'open an encrypted file luksdeletekey'A*- B3E' E4A1'open an encrypted partition luksdeletekey*E&DonemanageSystemVolumes#6A B15' Add Dev&icemanageSystemVolumes#6A EDA Add Fi&lemanageSystemVolumes4GD *1J/ -A "1%" EF 'DB'&E)5Are you sure you want to remove "%1" from the list?manageSystemVolumes#D:CancelmanageSystemVolumes&*-CE AJ E,D/ 'DF8'EManage System VolumesmanageSystemVolumes*'DE3'1 DE,D/'* 'DF8'EPath To System VolumesmanageSystemVolumes"'-A 'D(F/ 'DE.*'1Remove Selected EntrymanageSystemVolumes0'.*1 E3'1D DE,D/ 'DF8'ESelect Path To System VolumemanageSystemVolumes *-0J1WARNINGmanageSystemVolumesF3. '-*J'7J&Backupmanagevolumeheader#D:&Cancelmanagevolumeheader '3*1,9&Restoremanagevolumeheader€GD *1J/ '3*(/'D 'D*1HJ3) 9DI 'DB15 "1%" (*1HJ3) '-*J'7J) AJ "2%"TAre you sure you want to replace a header on device "%1" with a backup copy at "%2"?managevolumeheaderVE97I E7DH( DE3'1 F3. *1HJ3) 'DEDA :J1 E*HA15Argument for path to a backup header file is missingmanagevolumeheader0-BD E7DH( 9DI 'D#BD A'1:#Atleast one required field is emptymanagevolumeheader4F3. '-*J'7J D*1HJ3) 'DE,D/Back up volume headermanagevolumeheader&'3E 'DF3. 'D'-*J'7J Backup Namemanagevolumeheader>BE (F3. '-*J'7J D*1HJ3) 'DED,D/Backup Volume Headermanagevolumeheaderb'D*1HJ3) 'D'-*J'7J) D' *(/H #FG' *-HJ *1HJ3) DHC32Backup file does not appear to contain luks headermanagevolumeheader %F4'!C&reatemanagevolumeheader0DE JECF E91A) E3'1 'DB15 Could not resolve path to devicemanagevolumeheader.7#ERROR!managevolumeheader:A4D AJ *FAJ0 'D9EDJ) 'DE7DH()%Failed to perform requested operationmanagevolumeheaderVA4D AJ *FAJ0 'D9EDJ) 'DE7DH() 9DI E,D/ DHC38Failed to perform requested operation on the LUKS volumemanagevolumeheader2*E '3*9'/) 'D*1HJ3) (F,'-Header restored successfullymanagevolumeheaderT'D*1HJ3) -A8 (F,'-. %0' 'ECF .2FG' (#E'F.9Header saved successfully. If possible,store it securely.managevolumeheaderE9DHE'*INFO!managevolumeheaderl5D'-J'* :J1 C'AJ) DF3. *1HJ3) 'DEDA AJ 'DE,D/ 'DE3*G/AHInsufficient privilege to create a backup header in a destination foldermanagevolumeheaderV5D'-J'* :J1 C'AJ) DA*- *1HJ3) 'DEDA DDB1'!)=Insufficient privilege to open backup header file for readingmanagevolumeheaderH5D'-J'* :J1 C'AJ) DA*- 'DB15 DDB1'!)1Insufficient privilege to open device for readingmanagevolumeheaderH5D'-J'* :J1 C'AJ) DA*- 'DB15 DDC*'()1Insufficient privilege to open device for writingmanagevolumeheader>E3'1 :J1 5-J- DF3. EDA 'D*1HJ3)#Invalid path to back up header filemanagevolumeheader(E3'1 :J1 5-J- DDE,D/Invalid path to devicemanagevolumeheaderEDA EA*'-KeyFilemanagevolumeheader&*-CE AJ *1HJ3) DHC3Manage A LUKS Headermanagevolumeheader.*-CE AJ *1HJ3) *1H C1(*Manage A TrueCrypt Headermanagevolumeheader0*-CE AJ *1HJ3) AJ1' C1(*Manage A VeraCrypt HeadermanagevolumeheaderE,D/ 9'/J Normal VolumemanagevolumeheaderÂAB7 'DE3*./E 'DE/J1 H#96'! E,EH9) 2HDH C1(* JECFGE '3*1,'9 HF3. '-*J'7J D*1HJ3) DHC3 9DI B15 F8'E]Only root user and "zulucrypt" members can restore and back up luks headers on system devicesmanagevolumeheader6'DE3*./E B'E (%D:'! 'D9EDJ)%Operation terminater per user requestmanagevolumeheaderPIMPIMmanagevolumeheaderT'DE3'1 'DEA*16 '3*.'EG DF3. 'DEDA :J1 4':14Path to be used to create a back up file is occupiedmanagevolumeheader$'DB15 DJ3 B15 DHC3%Presented device is not a LUKS devicemanagevolumeheader('3*1,9 *1HJ3) 'DE,D/Restore volume headermanagevolumeheaderF,'-SUCCESSmanagevolumeheader>'.*1 EDA' '-*J'7J' D*1HJ3) DHC3'Select A File With A LUKS Backup HeadermanagevolumeheaderP'.*1 E,D/' D-A8 *1HJ3) 'DE,D/ 'D'-*J'7J)#Select A Folder To Store The HeadermanagevolumeheaderL'.*1 -'HJ) DHC3 'D*J *1J/ F3. *1HJ3*G'3Select luks container you want to backup its headermanagevolumeheader'DF5 TextLabelmanagevolumeheader8.7# :J1 E91HA. 1BE 'D-'D) 1%5Unrecognized ERROR! with status number %1 encounteredmanagevolumeheaderE3'1 'DE,D/ Volume PathmanagevolumeheaderFH9 'DED,D/ Volume Typemanagevolumeheader *-0J1WARNING!managevolumeheader$'DB15 E4A1 ('DC'EDWhole Drive Encrypted Volumemanagevolumeheader*E3'1 E,D/ F8'E HJF/H2Window System Volumemanagevolumeheader`CDE) 31 :J1 5-J-) #H #F 'DE,D/ DJ3 E,D/ *1H C1(*:Wrong password entered or volume is not a truecrypt volumemanagevolumeheaderbCDE) 31 :J1 5-J-) #H #F 'DE,D/ DJ3 E,D/ AJ1' C1(*:Wrong password entered or volume is not a veracrypt volumemanagevolumeheaderz'D(1F'E, *E *4:JDG EF B(D H*97D. -'HD 'D*F8JA +E %(/# EF ,/J/IPrevious instance seem to have crashed,trying to clean up before starting oneinstancevJ(/H GF'C F3.) #.1I EF 'D(1F'E, *9ED "FJ'. #.1, EF 'D(1F'E,:There seem to be another instance running,exiting this one oneinstance#D:&Cancel openvolume E3'9/)&Help openvolume'A*-&Open openvolumeŠB'&E) (CD 'D#B3'E 9DI 'DF8'E *916 GF'. 'FB1 E6'9A' 9DI H'-/ D'3*./'EG[A list of all partitions on this system are displayed here. Double click an entry to use it openvolume.7#ERROR openvolumeE9DHE'*INFO openvolumeBJECF '.*J'1 E,D/'* C1(*H DHC3 AB7(Only crypto_LUKS volumes can be selected openvolumeð#9/ *4:JD 'D(1F'E, (5D'-J) E/J1 #H (9/ #F *6JA FA3C DE,EH9) 2HDH C1(* %0' C'F 'DE,D/ 'D0J *1J/ '3*./'EG DJ3 9DI 'DB'&E).˜Restart the tool from root's account or after you have created and added yourself to group "zulucrypt" if the volume you want to use is not on the list. openvolume>'.*1 B3E' D%F4'! E,D/ E4A1 9DJG3Select A Partition To Create An Encrypted Volume In openvolume'.*1 B3E' DA*-GSelect A Partition To Open openvolume*'.*1 B3E' E4A1' DA*-G%Select An Encrypted Partition To Open openvolume*'3*./E 'D1BE 'D*91JAJ Use &UUID openvolume*'3*./E 'D1BE 'D*91JAJUse UUID openvolumež#F* E3*./E E/J1 CD 'D#B3'E 9DI 'DF8'E *916 GF'. 'FB1 E6'9A' 9DI H'-/ D'3*./'EGUYou are a root user and all partitions are displayed. Double click an entry to use it openvolumeED5Blabel openvolumeB3E partition openvolume-,Esize openvolumeFH9type openvolume1BE *91JAJuuid openvolumeR'D1E2 "/" :J1 E3EH- (G AJ -BD '3E 'D*-EJD0"/" character is not allowed in mount name fieldpasswordDialog^.J'1' O- H m- D' JECF '3*./'EGE' E9' AJ "F H'-/*-O and -m options can not be used togetherpasswordDialogB15 :J1 E/9HE #H B15 :J1 EH,H/ #H #0HF'* :J1 E*HA1) #3('( E-*ED) DG0' 'D.7#: 1- E3'1 'DB15 :J1 5-J- 2- 'DB15 DG *HBJ9 LVM #H MDRAID¸A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signaturepasswordDialog.-BD H'-/ A'1: 9DI 'D#BD#Atleast one required field is emptypasswordDialog#D:CancelpasswordDialogFA9D G0' 'D.J'1 D,9D CDE) 'D31 8'G1)'Check This Box To Make Password VisiblepasswordDialog<'.*1 EDA EA*'- EF F8'E 'DEDA'*%Choose A KeyFile From The File SystempasswordDialog2'.*1 H-/) EF F8'E 'DEDA'*$Choose A Module From The File SystempasswordDialog<DE JECF %F4'! BAD AJ /etc/mtab$Could not create a lock on /etc/mtabpasswordDialogzDE JECF %F4'! FB7) 'D*-EJD. E3'1 .'7& #H 'DE3'1 B/ 3(B *9JJFG@Could not create mount point, invalid path or path already takenpasswordDialogFDE JECF '3*1,'9 CDE) 'D31 EF 'DH-/)*Could not get a passphrase from the modulepasswordDialog\DE JECF 'D-5HD 9DI CDE) 'D31 EF .D'D EFA0 E-DJ1Could not get a passphrase through a local socketpasswordDialogfDE JECF 'D-5HD 9DI 0'C1) C'AJ) D'3J*9'( EDA 'DEA*'-1Could not get enought memory to hold the key filepasswordDialogRDE JECF '3*1,'9 CDE) 'D31 A J'D7H1 'D5'E*'Could not get passphrase in silent modepasswordDialog.7#ERRORpasswordDialog.7#ERROR!passwordDialog'.*1 EA*'- Enter A KeypasswordDialog\#/.D '3E 'DH-/) 'DE3*G/A) DD-5HD 9DI CDE) 'D31,Enter A Module Name To Use To Get PassphrasepasswordDialog*#/.D E3'1 EDA 'DEA*'-"Enter A Path To A Keyfile LocationpasswordDialogBA4D AJ 'D-5HD 9DI EA*'- EF 'D4(C)$Failed to get a key from the networkpasswordDialogA4D AJ *-EJD F8'E 'DEDA'*: FB7) *-EJD :J1 E/9HE) #H F8'E EDA'* :J1 E/9HEdFailed to mount a filesystem:invalid/unsupported mount option or unsupported file system encounteredpasswordDialogxA4D AJ *-EJD F8'E EDA'* ntfs/exfat ('3*./'E ntfs-3g 'DE+(*)XFailed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed?passwordDialogD0'C1) :J1 C'AJ) D'3*J9'( CDE) 'D31&Insufficient memory to hold passphrasepasswordDialog`5D'-J'* :J1 C'AJ) D*-EJD 'DB15 ('D.J'1'* 'DE-//)=Insufficient privilege to mount the device with given optionspasswordDialog®5D'-J'* :J1 C'AJ) DA*- E,D/ 'DF8'E. 1',9 B'&E) 'DE3'9/) +E 'D#0HF'* DE2J/ EF 'DE9DHE'*dInsufficient privilege to open a system volume. Consult menu->help->permission for more informaion passwordDialog†5D'-J'* :J1 C'AJ) DA*- 'DB15 DDB1'!) H'DC*'() #H #F 'DB15 :J1 EH,H/QInsufficient privilege to open device in read write mode or device does not existpasswordDialogT5D'-J'* :J1 C'AJ) DA*- EDA 'DEA*'- DDB1'!)3Insufficient privilege to open key file for readingpasswordDialog4'D.2'F) 'D/'.DJ) :J1 EGJ#)!Internal wallet is not configuredpasswordDialog,E3'1 .'7& DEDA 'DEA*'-Invalid path to key filepasswordDialog E3'1 EDA 'DEA*'- KeyFile PathpasswordDialog-ED "1%" Mount "%1"passwordDialogFD' JH,/ EDA #H B15 AJ 'DE3'1 'DE97I%No file or device exist on given pathpasswordDialog'D%2'-)OffsetpasswordDialog²3HA *8G1 'D%2'-) ('D3C*H1 %0' C*(* 'DBJE) ('D#1B'E AB7 H ('D('J* %0' C'F* FG'J) 'D%/.'D "b" H ('DCJDH ('J* %0' C'F* FG'J) 'D%/.'D "k" H ('DEJ,' ('J* %0' C'F* FG'J) 'D%/.'D "m" H ('D*J1' ('J* %0' C'F* FG'J) 'D%/.'D "t"ìOffset Will Be In Sectors If The Entry Is Made Up Of Only Digits And In Bytes If The Entry Ends With "b" And In Kilobytes If The Entry Ends With "k" And In Megabytes If The Entry Ends With "m" And In Terabytes If The Entry Ends With "t"passwordDialogRE97I E7DH( #H #C+1 DG0G 'D9EDJ) :J1 E*HA1>One or more required argument(s) for this operation is missingpasswordDialogNAB7 E3*./E E/J1 JECFG *FAJ0 G0G 'D9EDJ))Only root user can perform this operationpasswordDialogBJE) PIM PIM ValuepasswordDialog'3E 'D%6'A) Plugin NamepasswordDialog"'.*1 EA*'- 'DH-/)Select A Key ModulepasswordDialog'.*1 EDA EA*'-Select A KeyFilepasswordDialog '.*1 E,D/' E4A1'Select Encrypted volumepasswordDialog:'.*1 E'31' DFB7) *-EJD 'DE,D/!Select Path To Mount Point FolderpasswordDialog:FB7) *-EJD E4*1C) 3(B *9JJFG'%Shared mount point path already takenpasswordDialogTJ(/H #F E,D/' EB*1F' ('D9FH'F 'DE97I EA*H-=There seem to be an open volume accociated with given addresspasswordDialogJJ(/H H,H/ E.77 EA*H- EB*1F (G0' 'DB15Resetting font size to %1 because larger font sizes do not fit zuluCrypt*'3*9'/) *1HJ3) 'DE,D/Restore Volume Header zuluCrypt'.*1 .7' Select &Font zuluCrypt'.*1 #JBHF) Select &Icons zuluCrypt'.*1 'DD:)Select Language zuluCryptShift+IShift+I zuluCryptShift+VShift+V zuluCrypt'8G1/#.A Show/Hide zuluCryptFH9Type zuluCrypt *F2JDUnmount zuluCrypt4.7# :J1 E91HA (1BE -'D) 1%4Unrecognized error with status number %1 encountered zuluCrypt,-'HJ) AJ1' C1(* AJ EDAVeraCrypt Container In A File zuluCrypt,-'HJ) AJ1' C1(* AJ B15#VeraCrypt Container In A Hard Drive zuluCrypt4'DE,D/'* 'DE3*6'A) 9DI B15Volume &Hosted In A Hard Drive zuluCrypt.5'&5 'DE,D/Volume Properties zuluCryptN'DE,D/ :J1 EA*H- #H EA*H- EF E3*./E ".14Volume is not open or was opened by a different user zuluCrypt *-0J1!WARNING! zuluCrypt#:DB 'D*7(JBclose application zuluCryptGJ& 'D.2'F'*configure wallets zuluCryptE9DHE'* 'D*4AJ1 crypto info zuluCrypt 'DE,D/'* 'DEA6D)favorite volumes zuluCrypt *-CE AJ 'DEA6D'*manage favorites zuluCrypt'D5D'-J'* permissions zuluCrypt0'.*1 EHD/ 'D1BE 'D94H'&Jselect random number generator zuluCrypt4F3. '*J'7J D*1HJ3) *1HC1(*tcrypt backup header zuluCrypt,'3*9'/) *1HJ3) *1HC1(*tcrypt restore header zuluCrypt2HDH C1(* zuluCrypt zuluCryptˆÿÿÿ$ ÿ* zuluCrypt-6.2.0/translations/zuluCrypt/ar_SA.ts000066400000000000000000010544451425361753700216710ustar00rootroot00000000000000 DialogMsg Dialog Ù†Ø§ÙØ°Ø© رسالة &Ok نعم &Yes نعم &No لا text نص type نوع cipher Ø´ÙØ±Ø© key size حجم Ø§Ù„Ù…ÙØªØ§Ø­ device جهاز loop دورة offset إزاحة size حجم mode طور fs fs used مستخدم unused غير مستخدم used % نسبة المستخدم active slots الخانات النشطة "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. مجلدات النظام هي التي يحددها يو دي٠من خلال تعريÙÙ‡ ÙÙŠ مل٠"/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list إذا لم ترغب ÙÙŠ اعتبار المجلد كمجلد نظامي، شغل التطبيق كمستخدم مدير ثم اذهب إلى قائمة الخيارات واختر إدارة الأجزاء غير النظامية. أض٠المجلد ضمن القائمة ومن تلك اللحظة لن يعتبر ذاك المجلد كمجلد نظامي. كبديل عن ذلك تستطيع Ø¥Ø¶Ø§ÙØ© Ù†ÙØ³Ùƒ تحت مجموعة زولوكربت وزولوماونت وسو٠تزول هذه القيود. INFORMATION معلومة Insufficient privilege to access a system device, only root user or members of group zulucrypt can do that صلاحية غير كاÙية للدخول على جهاز النظام. Ùقط المستخدم المدير أو عضو ضمن مجموعة زولوكربت يستطيع عمل ذلك. Insufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that صلاحية غير كاÙية للدخول على جهاز النظام للكتابة. Ùقط المستخدم المدير أو عضو ضمن مجموعة زولوكربت-الكتابة يستطيع عمل ذلك. You do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again لا يظهر أن لديك صلاحيات كاÙية للدخول على Ø§Ù„Ù…Ù„Ù Ø§Ù„Ù…Ø´ÙØ± ÙÙŠ طور 1%. تأكد من الصلاحيات ثم حاول مرة أخرى. type: نوع cipher: Ø´ÙØ±Ø© keysize: حجم Ø§Ù„Ù…ÙØªØ§Ø­ offset: الإزاحة device: جهاز loop: دورة mode: طور active slots: الخانات النشطة file system: نظام Ø§Ù„Ù…Ù„ÙØ§Øª total space: المساحة الكلية used space: المساحة المستخدمة free space: المساحة المتاحة used%: نسبة الاستخدام% UUID: الرقم التعريÙÙŠ Do not show this dialog again لا تظهر هذه الرسالة مرة أخرى PasswordDialog Open Encrypted Volume Ø§ÙØªØ­ الكجلد Ø§Ù„Ù…Ø´ÙØ± &Open Ø§ÙØªØ­ &Cancel ألغ Mount In &Read Only Mode حمَل ÙÙŠ طور القراءة Ùقط select mount point path اختر مسار نقطة التحميل open volume path اختر مسار المجلد open key file Ø§ÙØªØ­ Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Password LUKS/TrueCrypt/BitLocker &OK Mount Name اسم التحميل &Options Volume Path مسار المجلد KeyFile Ù…Ù„Ù Ù„Ø¨Ù…ÙØªØ§Ø­ Key+KeyFile Ù…ÙØªØ§Ø­+Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Plugin Ø¥Ø¶Ø§ÙØ§Øª &Share Mount Point شارك نقطة التحميل VeraCrypt Ùيرا كربت VeraCrypt System PLAIN dm-crypt dm-crypt عادي Volume Type نوع المجلد TextLabel النص الملصق Enter Comma Separated Volume's File System Options Below Set Cancel QObject zuluCrypt: Failed To Establish Connection With zuluPolkit options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI خيارات d .. المسار إلى المجلد ليتم ÙØªØ­Ù‡/تحميله تلقائيا m.. أداة ÙØªØ­ مدير Ø§Ù„Ù…Ù„ÙØ§Øª Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠ (Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠ Ù‡Ùˆ xdg-open) e.. شغل التطبيق من دون الواجهة الرسومية If the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2" إذا تم ØªÙØ¹ÙŠÙ„ الخيار، سو٠يتم تهيئة نقطة تحميل خاصة رئيسية ÙÙŠ "1%" Ùˆ أخرى ÙØ±Ø¹ÙŠØ© الدخول إليها عام، وصورة من نقطة التحميل تهيئ ÙÙŠ "2%" public mount point: نقطة تحميل عامة Manage Favorites التحكم ÙÙŠ Ø§Ù„Ù…ÙØ¶Ù„ات Mount All حمل الجميع about zuluCrypt حول زولو كربت hmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents) Ø¥Ø¶Ø§ÙØ© hmc هذه Ø§Ù„Ø¥Ø¶Ø§ÙØ© تولد Ù…ÙØªØ§Ø­Ø§ طبقا للمعادلة: Ø§Ù„Ù…ÙØªØ§Ø­= hmac(sha256,كلمة السر,Ù…ÙØªØ§Ø­ المحتوى) keykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contents Ø§Ù„Ø¥Ø¶Ø§ÙØ© Ø§Ù„Ù…ÙØªØ§Ø­-Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ هذه Ø§Ù„Ø¥Ø¶Ø§ÙØ© تولد Ù…ÙØªØ§Ø­Ø§ باستخدام الصيغة التالية: Ø§Ù„Ù…ÙØªØ§Ø­ = كلمة السر + محتوى Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ gpg plugin. This plugin retrives a key locked in a gpg file with a symmetric key Ø¥Ø¶Ø§ÙØ© pgp هذه Ø§Ù„Ø¥Ø¶Ø§ÙØ© تسترجع Ø§Ù„Ù…ÙØªØ§Ø­ المغلق ÙÙŠ مل٠pgp Ø¨Ù…ÙØªØ§Ø­ متماثل Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit. ERROR خطأ Failed to locate pkexec executable ÙØ´Ù„ ÙÙŠ تحديد المل٠التنÙيذي pkexec "%1" and "%2" Folders Must Be Writable. Could not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin" لم يمكن تحديد مل٠pgp التنÙيذي ÙÙŠ "/usr/local/bin","/usr/bin" and "/usr/sbin" createVolumeDialog Warning!! تحذير &Yes نعم &No لا This operation will lead to permanent destrunction of all present data in /dev/sdc1. Are you sure you want to continue? هذه العملية سو٠تؤدي إلى تدمير كامل للبيانات الموجودة ÙÙŠ /dev/sdc1. هل أنت متأكد؟ This operation will lead to permanent destrunction of all present data in "%1". Are you sure you want to continue? هذه العملية سو٠تؤدي إلى تدمير كامل للبيانات الموجودة ÙÙŠ1%. هل أنت متأكد؟ It is advised to create encrypted containers over random data to prevent information leakage. Do you want to write random data to "%1" first before creating an encrypted container in it? You can stop the random data writing process anytime you want if it takes too long and you can no longer wait. ينصح بإنشاء حاويات Ù…Ø´ÙØ±Ø© على بيانات عشوائية منعا لتسرب المعلومات. هل ترغب ÙÙŠ كتابة بيانات عشوائية على "1%" أولا قبل إنشاء الحاوية بها؟ يمكنك إيقا٠عملية كتابة البيانات العشوائية ÙÙŠ أي وقت إذا استغرقت مدة طويلة ولا يمكنك الانتظار. createVolumeInExistingFIle Create Volume In Existing File Select Cover File (Video files like mp4 and mkv) Container Size (MB) Volume Properties خصائص المجلد &Cancel ألغ C&reate Volume OffSet (Auto calculated) Create A Plain dm-crypt Container Hidden Inside Cover File (Steganography) Password TextLabel Extending A Host File Size. Enter Path To Existing File Average Speed: ETA: Percentage Completed: %1% ERROR خطأ AtLeast One Required Field Is Empty Illegal Character Found In The Container Size Field Failed To Open File In Write Mode Failed To Open "/dev/urandom" Device In Read Mode Creating A Plain DM-Crypt Volume Volume Created Successfully Failed To Create A Volume createfile Create A Container File أنشئ مل٠حاوية File Name اسم المل٠File Path مسار المل٠File Size حجم المل٠open a folder dialog box Ø§ÙØªØ­ Ù†Ø§ÙØ°Ø© المجلد &Cancel ألغ % Complete %مكتمل C&reate أنشئ KB كيلو بايت MB ميجا بايت GB جيجا بايت Do Not Write Random Data To Container(STRONGLY discouraged) لا تكتب بيانات عشوائية على الحاوية (لا ينصح به بشدة) TextLabel &OK By default,zuluCrypt creates a volume in a container file over randomly generated data to hide usage patterns of the container. This process takes time and it may take a very,very long time if the volume about to be created is large enough and this option exists to skip the process for the impatient among us but but it comes at a cost and the cost may be too high when it finally reveal itself while infront of an adversary when they look at the encrypted container and manage to derive meaning based on how the container looks from outside. If you know what you are doing,then continue by all means,if in doubt,my advise is to endure the process and be safer in the long run. الوضع Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠ Ø£Ù† زولو كربت ينشئ الحاوية Ø§Ù„Ù…Ø´ÙØ±Ø© على بيانات عشوائية Ù„Ø¥Ø®ÙØ§Ø¡ نمط الاستخدام لها. هذه العمليةتستغرق وقتا طويلا خصوصا إذا كان حجم الحاوية كبيرا. هناك خيار لتجاوز هذه العملية للمستخدم العجل. لكن ضريبة ذلك عالية ويمكن أن تكش٠للخصم حين ÙŠÙØ­Øµ الحاوية من الخارج. إذا كنت تعي ما ØªÙØ¹Ù„ه، استمر بكل الأحوال، وإذا كنت ÙÙŠ شك Ùينصح بتحمل طول العملية لتكون ÙÙŠ مأمن مستقبلا. INFO معلومات File name field is empty حقل الاسم ÙØ§Ø±Øº File path field is empty حقل المسار ÙØ§Ø±Øº File size field is empty حقل الحجم ÙØ§Ø±Øº WARNING تحذير Are you really sure you do not want to create a more secured volume? هل أنت متأكد أنك لا تريد إنشاء حاوية أكثر أمانا؟ Illegal character in the file size field.Only digits are allowed إدخال غير مقبول ÙÙŠ حقل الحجم. تقبل الأرقام Ùقط. File with the same name and at the destination folder already exist يوجد اسم Ø¨Ù†ÙØ³ الاسم ÙÙŠ المجلد المستهد٠You dont seem to have writing access to the destination folder لا يبدو أن لديك صلاحية الكتابة على المجلد المستهد٠Container file must be bigger than 3MB مل٠الحاوية يجب أن يكون أكبر من 3 ميجا بايت Failed to create volume file ÙØ´Ù„ ÙÙŠ إنشاء مل٠الحاوية Failed to enable polkit support Operation terminated per user choice تم إلغاء العملية من قبل المستخدم Could not open cryptographic back end to generate random data لم يمكن ÙØªØ­ خلÙية التشÙير لتوليد بيانات عشوائية Terminating file creation process إنهاء عملية إنشاء مل٠Are you sure you want to stop file creation process? هل أنت متأكد من رغبتك ÙÙŠ إيقا٠عملية إنشاء Ù…Ù„ÙØŸ Average Speed: ETA: Select Path to where the file will be created اختر مسارا للمل٠الذي ستنشئه createkeyfile Create A KeyFile أنشئ Ù…Ù„Ù Ù…ÙØªØ§Ø­ Keyfile Name اسم Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ path to a folder to create a key in المسار للمجلد الذي يحوي Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ open a folder a key file will be created in Ø§ÙØªØ­ المجلد الذي يحوي Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ C&reate أنشئ &Cancel ألغ KeyFile Path مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ RNG RNG TextLabel &OK The key name field is empty Folder path to where the key will be created is empty المسار للمجلد الذي يحوي Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ ÙØ§Ø±Øº File with the same name and at the destination folder already exist يوجد Ù…Ù„Ù Ø¨Ù†ÙØ³ الاسم ÙÙŠ المجلد الذي يحوي Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ You dont seem to have writing access to the destination folder لايبدو أن لديك صلاحية دخول على المجلد المستهد٠Process interrupted,key not fully generated العملية تم قطعها. Ø§Ù„Ù…ÙØªØ§Ø­ لم يولد بشكل كامل KeyFile successfully created Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ أنشئ بنجاح Select A Folder To Create A Key File In اختر المجلد الذي ينشئ به Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ createvolume Create A New Volume أنشئ مجلدا جديدا Path to Device المسار للقرص C&reate أنشئ &Cancel ألغ open a key file Ø§ÙØªØ­ Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Key Ù…ÙØªØ§Ø­ Password Repeat Password Advanced LUKS2 Options Volume Type نوع المجلد Volume Size حجم المجلد Bytes بايت KiloBytes كيلو بايت MegaBytes ميجا بايت GigaBytes جيجا بايت Iteration Time (milliseconds) Volume Options خيارات المجلد File System نظام Ø§Ù„Ù…Ù„ÙØ§Øª random number generator مولد الأرقام العشوائي RNG RNG PIM PIM TextLabel النص Advanced Luks2 Options Set Label Sub System Pbkdf Type argon2id argon2i pbkdf2 Max Memory (KB) Parallel Threads Unlocking Time Cost(Milliseconds) Allow Discard(TRIM) Forced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) Cancel Options are separated by a "." character. الخيارات Ù…ÙØµÙˆÙ„Ø© عن بعضها برمز "." Multiple algorithms are separated by ":" character. خوارزميات عدة Ù…ÙØµÙˆÙ„Ø© عن بعضها برمز ":" Options are in a format of "algorithm.cipher mode.key size in bits.hash" الخيارات بهيئة "خوارزميات تشÙير حجم Ø§Ù„Ù…ÙØªØ§Ø­ بالبت للهاش" Default option is the first entry on the list الخيار Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠ Ù‡Ùˆ الأول ضمن القائمة KeyFile Ù…Ù„Ù Ù…ÙØªØ§Ø­ Key+KeyFile Ù…ÙØªØ§Ø­+Ù…Ù„Ù Ù…ÙØªØ§Ø­ YubiKey Challenge/Response PLAIN dm-crypt PLAIN dm-crypt PLAIN dm-crypt with offset PLAIN dm-crypt مع إزاحة LUKS1 LUKS1 LUKS1+External Header LUKS1+ترويسة خارجية LUKS2 LUKS2 LUKS2+External Header LUKS2+ترويسة خارجية LUKS LUKS LUKS+External Header LUKS+ترويسة خارجية Normal TrueCrypt تروكربت عادي Normal+Hidden TrueCrypt تروكربت عادي+مخÙÙŠ Normal VeraCrypt Ùيرا كربت عادي Normal+Hidden VeraCrypt Ùيرا كربت عادي+مخÙÙŠ Passphrase Quality: 0% جودة كلمة السر:0% Passphrase Quality: %1% جودة كلمة السر:1% TrueCrypt Keys Ù…ÙØ§ØªÙŠØ­ تروكربت VeraCrypt Keys Ù…ÙØ§ØªÙŠØ­ Ùيرا كربت Volume Offset إزاحة المجلد Path To Device مسار القرص Path To File مسار المل٠Keyfile Path مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Passphrase Quality: 100% جودة كلمة السر:100% Keys Ù…ÙØ§ØªÙŠØ­ ERROR! خطأ Failed to enable polkit support Volume path field is empty مسار المجلد ÙØ§Ø±Øº Atleast one required field is empty حقل واحد ÙØ§Ø±Øº على الأقل Illegal character detected in the hidden volume size field رمز غير مقبول تم إدخاله ÙÙŠ حقل حجم المجلد المخÙÙŠ Hidden passphrases do not match كلمتا السر المدخلة للمجلد المخÙÙŠ لا تتطابقان WARNING تحذير It is best to create a hidden volume with vfat/fat file system. ÙŠÙØ¶Ù„ إنشاء المجلد المخÙÙŠ بنظام Ù…Ù„ÙØ§Øª vfat/fat Passphrases do not match كلمتا السر المدخلة لا تتطابقان ERROR خطأ Failed To Locate Or Run Yubikey's "ykchalresp" Program. Please be patient as creating a VeraCrypt volume may take a very long time. يرجى التريث لأن إنشاء مجلد Ùيرا كربت يستغرق وقتا طويلا WARNING! تحذير Volume created successfully but failed to create an external header أنشئ المجلد بنجاح لكن ÙØ´Ù„ت عملية إنشاء ترويسة خارجية SUCCESS! نجاح Luks volume created successfully. تم إنشاء مجلد لوكس بنجاح Luks volume created successfully,external header created successfully but failed to erase header on the device تم إنشاء مجلد لوكس بنجاح، ونجاح إنشاء ترويسة خارجية. لكن ÙØ´Ù„ مسح الترويسة على القرص Volume created successfully. تم إنشاء مجلد بنجاح Creating a backup of the "%1" volume header is strongly advised. Please read documentation on why this is important. ينصح بشدة عمل نسخة احتياطية لترويسة المجلد "1%". يرجى قراءة الدليل عن أهمية ذلك. Presented file system is not supported,see documentation for more information المل٠المعروض غير مدعوم. أنظر الدليل لمزيد من المعلومات. insufficient privilege to open a system device in read/write mode, only root user or members of group zulucrypt can do that صلاحيات غير كاÙية Ù„ÙØªØ­ مجلد النظام للقراءة والكتابة. Ùقط المستخدم المدير أو أعضاء مجموعة زولوكربت يمكنهم ذلك. Could not create an encrypted volume لم يمكن إنشاء مجلد Ù…Ø´ÙØ± Could not open volume for writing لم يمكن ÙØªØ­ المجلد لققراءة There seem to be an opened mapper associated with the device يبدو أن المخطط المعين للقرص Ù…ÙØªÙˆØ­ Can not create a volume on a mounted device لم يمكن إنشاء مجلد على القرص المحمل Container file must be bigger than 3MB الحاوية يجب أن يكون حجمها 3 ميجا بايت على الأقل %1 not found %1 غير موجود Insufficient memory to hold your response لا توجد ذاكرة كاÙية لاستيعاب ردك Operation terminated per user request ألغى المستخدم العملية Could not get passphrase in silent mode لم يمكن العثور على كلمة السر بالطور الصامت Insufficient memory to hold the passphrase لا توجد ذاكرة كاÙية لاستيعاب كلمة السر Invalid path to key file مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ غير صحيح Could not get a key from a key file لم يمكن استرجاع Ø§Ù„Ù…ÙØªØ§Ø­ من Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Couldnt get enought memory to hold the key file لم يمكن الحصول على ذاكرة كاÙية لاستيعاب Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Could not get a key from a socket لم يمكن الحصول على Ù…ÙØªØ§Ø­ من Ø§Ù„Ù…Ù†ÙØ° One or more required argument(s) for this operation is missing معطى أو أكثر من المعطيات المطلوبة غير موجود Can not get passphrase in silent mode لم يمكن العثور على Ø§Ù„Ù…ÙØªØ§Ø­ ÙÙŠ الطور الصامت Insufficient memory to hold passphrase لا توجد ذاكرة كاÙية لاستيعاب كلمة السر Failed to create a volume ÙØ´Ù„ ÙÙŠ إنشاء Ø§Ù„Ù…ÙØªØ§Ø­ Wrong argument detected for tcrypt volume معطى غير صحيح تم اكتشاÙÙ‡ لمجلد ترو كربت Could not find any partition with the presented UUID لم يعثر على أي قسم يحمل هذا الرقم التعريÙÙŠ المعروض Error Code: %1 -- StdOut: %2 -- StdError: %3 cryptfiles Destination الوجهة C&reate أنشئ Source المصدر Password Repeat Password TextLabel &OK Key Ù…ÙØªØ§Ø­ KeyFile Ù…Ù„Ù Ù…ÙØªØ§Ø­ Key+KeyFile Ù…ÙØªØ§Ø­+Ù…Ù„Ù Ù…ÙØªØ§Ø­ Repeat Key كرر Ø§Ù„Ù…ÙØªØ§Ø­ &Cancel ألغ % Complete %مكتمل Create An Encrypted Version Of A File أنشئ نسخة Ù…Ø´ÙØ±Ø© من المل٠Create A Decrypted Version Of An encrypted File أنشئ مل٠عن طريق ÙÙƒ تشÙير Ù…Ù„Ù Ù…Ø´ÙØ± Path to source field is empty مسار المل٠الأصل ÙØ§Ø±Øº Invalid path to source file مسار خطأ للمل٠المصدر Destination path already taken مسار الوجهة سبق تعيينه You dont seem to have writing access to the destination folder لا يبدو لديك صلاحية الكتابة على المجلد الوجهة Invalid path to key file مسار خاطئ Ù„Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ First key field is empty الحقل الأول ÙØ§Ø±Øº Second key field is empty الحقل الثاني ÙØ§Ø±Øº Keys do not match Ø§Ù„Ù…ÙØªØ§Ø­ لا يتطابق These very old encrypted files are no longer supported هذه Ø§Ù„Ù…Ù„ÙØ§Øª Ø§Ù„Ù…Ø´ÙØ±Ø© قديما لم تعد مدعومة Select Path to put destination file اختر مسارا لوضع المل٠الوجهة Enter A Key أدخل Ù…ÙØªØ§Ø­ Enter A Path To A Keyfile Location أدخل مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ keyfile path مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Generate a key made up of a passphrase and a keyfile ولد Ù…ÙØªØ§Ø­Ø§ مكونا من كلمة السر ÙˆÙ…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Select A File You Want To Encrypt اختر المل٠الذي تريد تشÙيره zuluCrypt encrypted files ( *.zc ) ;; All Files ( * ) زولو كربت Ø´ÙØ± Ø§Ù„Ù…Ù„ÙØ§Øª s ( *.zc ) ;; All Files ( * ) Select A File You Want To Decrypt اختر المل٠الذي تريد ÙÙƒ تشÙيره Select A Keyfile اختر Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Encrypted file created successfully تم تشÙير المل٠بنجاح Decrypted file created successfully تم ÙÙƒ تشÙير المل٠بنجاح Could not open keyfile for reading لم يمكن ÙØªØ­ Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ بنجاح Could not open encryption routines لم يمكن ÙØªØ­ برمجيات التشÙير File or folder already exist at destination address المل٠موجود من قبل ÙÙŠ هذه الوجهة Insufficient privilege to create destination file صلاحيات غير كاÙية لإنشاء المل٠المستهد٠Presented key did not match the encryption key Ø§Ù„Ù…ÙØªØ§Ø­ المعروض لا يطابق Ù…ÙØªØ§Ø­ التشÙير Operation terminated per user request ألغى المستخدم العملية Insufficient privilege to open source file for reading صلاحيات غير كاÙية لقراءةء المل٠من المصدر Decrypted file created successfully but md5 checksum failed,file maybe corrupted تم ÙÙƒ تشÙير المل٠بنجاح لكن الهاش md5 ÙØ´Ù„. يمكن أن المل٠معطوب Could not open reading encryption routines لم يمكن ÙØªØ­ برمجيات تشÙير القراءة Could not open writing encryption routines لم يمكن ÙØªØ­ برمجيات تشÙير الكتابة Failed to close encryption routine لم يمكن غلق برمجيات التشÙير cryptoinfo Greetings تحيات Ok نعم Please consult "menu->help->open zuluCrypt.pdf" to get an introduction on zuluCrypt. Unity users,the menu is on the upper left corner of the screen when zuluCrypt has focus. Project's homepage is at: https://mhogomchungu.github.io/zuluCrypt Recommending reading FAQ page from the project's main page. يرجى الرجوع لقائمة المساعدة ثم Ø§ÙØªØ­ مل٠zuluCrypt.pd Ù„Ù…Ø¹Ø±ÙØ© مبدئية عن زولو كربت لمستخدمي UnityØŒ القائمة ÙÙŠ الأعلى يسار Ø§Ù„Ù†Ø§ÙØ°Ø© حينما يكون زولو كربت Ù…ÙØªÙˆØ­Ø§ ÙˆÙ…ÙØ¹Ù„ا موقع المشروع: https://mhogomchungu.github.io/zuluCrypt ينصح بقراءة ØµÙØ­Ø© الأسئلة والأجوبة من موقع المشروع الرئيس Do not show this message again. لا تظهر هذه الرسالة مرة أخرى debugWindow zuluCrypt Debug Window C&lear &Close dialogok Dialog Ù†Ø§ÙØ°Ø© &Ok نعم TextLabel النص &Yes نعم &No لا erasedevice Erase Data On The Device By Writing Random Data Over Them امسح البيانات على القرص بكتابة بيانات عشوائية عليها Path to Device مسار القرص % Completed %مكتمل &Start بداية &Cancel ألغ Average Speed ETA N/A TextLabel &OK Write Random Data Over Existing Data اكتب بيانات عشوائية على البيانات الموجودة The next dialog will write random data to a device leading to permanent loss of all contents on the device. Are you sure you want to continue? Ø§Ù„Ù†Ø§ÙØ°Ø© التالية سو٠تكتب بيانات عشوائية على القرص مما يؤدي Ù„Ùقدان محتوى القرص بالكامل. هل أنت متأكد وترغب ÙÙŠ الاستمرار؟ WARNING تحذير Average Speed: Total Time: Data on the device successfully erased تم مسح البيانات على القرص بنجاح Could not create mapper لم يمكن إنشاء المخطط Could not resolve device path لم يمكن Ù…Ø¹Ø±ÙØ© مسار القرص Random data successfully written تمت كتابة بيانات عشوائية بنجاح Operation terminated per user choice المستخدم أنهى العملية باختياره Can not write on a device with opened mapper لم يمكن الكتابة على القرص بينما المخطط Ù…ÙØªÙˆØ­ Policy prevents non root user opening mapper on system partition سياسة الاستخدام تمنع غير المستخدم المدير من ÙØªØ­ مخطط قسم النظام Device path is invalid مسار القرص غير صحيح Passphrase file does not exist مل٠كلمة السر غير موجود Could not get enought memory to hold the key file لم يمكن تحديد ذاكرة كاÙية لاستيعاب Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Insufficient privilege to open key file for reading صلاحيات غير كاÙية Ù„ÙØªØ­ Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ لققراءة This device appear to already be in use القرص يبدو مشغولا من قبل Can not open a mapper on a mounted device لم يمكن ÙØªØ­ المخطط للقرص المحمل Could not write to the device لم يمكن الكتابة على القرص Device path field is empty حقل مسار القرص ÙØ§Ø±Øº Invalid path to device مسار القرص غير صحيح Are you really sure you want to write random data to "%1" effectively destroying all contents in it? هل ÙØ¹Ù„ا تريد كتابة بيانات عشوائية على "1%". عمليا سو٠تدمر محتواه؟ WARNING! تحذير Failed to enable polkit support Writing Random Data Over Existing Data كتبة بيانات عشوائية على البيانات الموجودة Enter Path To Volume To Be Erased أدخل مسار القرص المراد مسحه Select A Non System Partition To Erase Its Contents اختر قسما غير قسم النظام لمسح محتواه favorites2 Favorites Favorite List Volume ID Mount Point Add Add A volume Mount Path &Close Mount Options Manage Keys In Wallets Set Default Wallet Internal Wallet Libsecret KWallet None Volume Path Enter Volume Path Below Enter Password Below Change Internal Wallet Password TextLabel Ok fileManager Set File Manager عين مدير Ø§Ù„Ù…Ù„ÙØ§Øª TextLabel النص &Set عين Enter Below The Name Of The Application You Want To Be Used To Open Mount Points. أدخل بالأسÙÙ„ اسم التطبيق الذي تود استخدامه Ù„ÙØªØ­ Ù†ÙØ·Ø© التحميل help Help &Close <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt;">ZuluCrypt is a simple, feature rich and powerful solution for hard drives encryption for linux.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt supports LUKS, TrueCrypt, VeraCrypt and PLAIN dm-crypt encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These supported encrypted volumes may resides in image files, hard drives and usb sticks, LVM</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volumes as well as in mdraid devices.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of encrypted volumes. Those that use what is commonly know as “a header†and</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">those that do not. TrueCrypt, VeraCry and LUKS volumes use a header. PLAIN dm-crypt volumes do</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">not use a header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a &quot;volume header&quot;.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">The damage to the header is usually caused by accidental formatting of the device or use of</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">some buggy partitioning tools or wrongly reassembled logical volumes.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack'; color:#008000;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of header using encrypted volumes. Those that use an encrypted header and those</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">that do not. TrueCrypt and VeraCrypt use an encrypted header whereas LUKS does not. The use of non</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted header in LUKS makes it obvious to everybody that the volume is an encrypted LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may be problematic to some people. How big the problem may be depends on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">person and their use case for hard drive encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The use of encrypted header as in TrueCrypt or VeraCrypt volumes or no header at all as in PLAIN dm-</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">crypt volumes make these volumes indistinguishable from random noise and this may seem useful at a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">glance but its usefulness may not hold up against scrutiny as the likelihood of being believed that a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">100GB file made up of cryptographically sound random data is just a 100GB file made up of random</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data and not a container file for an encrypted volume is not very high.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With LUKS, TrueCrypt and VeraCrypt volumes, it is very important to have a volume header backup</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">since a valid header is required to unlock the volume. A corrupted or missing header will make the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume unusable causing the loss of all encrypted data.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">LUKS stands for “Linux Unified Key Setupâ€. It is a specification of how to store information necessary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to open a LUKS formatted encryption volume. LUKS encryption format is the standard format in linux</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and a recommended one if the encrypted volume is to be used among linux systems. TrueCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt volumes are better alternative if the encrypted volume is to be shared between linux,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">windows and OSX computers.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can create and open 5 types of encrypted volumes, LUKS, TrueCrypt, VeraCrypt,PLAIN</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dm-crypt and PLAIN dm-crypt volume at a none zero offset. PLAIN dmcrypt volume is a header less</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume and all necessary encryption information is provided by zuluCrypt when it creates or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open these volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; text-decoration: underline;">Pros and cons of the five volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt; text-decoration: underline;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It does not use a volume header and hence its not possible to “brick†the entire volume simply by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over writing a small part of it.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It does not use a header and hence its impossible to know if the volume is made up of only</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">cryptographically sound random data or if its an encrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It does not use a header and hence any tool that opens these volumes must provide the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options that were used when the volume was created. Different tools may use different encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options making these encrypted volumes not very portable between applications or even between</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">different versions of the same application.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt at a none zero offset.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This volume has the same pros and cons as those of a PLAIN dm-crypt volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional pro for this volume is that it can be places anywhere on the device making it possible</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to have this volume on top of any one of the other supported encrypted volume or on top of an</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">unencrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For example, its possible to have an X MB drive that has unencrypted file system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">at the beginning of the device and a “PLAIN dm-crypt volume with an offset†somewhere towards the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">end of the device making it possible to use the drive as unencrypted volume and as encrypted volume</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">simultaneously depending on sensitivity of the data to be stored on the device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this volume type is to be used, preceding part of the drive should be formatted in “FAT†family of file systems.This volume types gives a “hidden volume†type functionality offered by TrueCrypt and VeraCrypt. When creating or unlocking this volume type, the starting offset of the volume will be asked and NOT the volume size as TrueCrypt and VeraCrypt does with the hidden volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above means, if you have a 100 MB drive and you want to create a 30MB “PLAIN dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume at a none zero offsetâ€, you will enter the starting offset of the volume as 70MB. In VeraCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt, you will enter the hidden volume size of 30MB. The starting offset and the size of the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hidden volume are related by a simple formula: starting offset(70MB) = device size(100MB) – hidden</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume size(30MB).</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TrueCrypt</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and hence its not possible to know if the volume is TrueCrypt formatted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume or if the volume is just made up of cryptographically sound random data.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Hidden volume. A TrueCrypt volume can have up to two different encrypted volumes. The first</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume is commonly know as “outer volume†and the second optional one is commonly known as</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“hidden volumeâ€.When a TrueCrypt volume is about to be opened, the user has an option to select</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">which one of the two to open by giving appropriate key.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and it is not possible to open the volume without a valid header. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">use a TrueCrypt volume, make sure you have at least one backup of the volume header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VeraCrypt</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt is an extension of TrueCrypt and it shares the same TrueCrypt’s pros and cons.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Pro for VeraCrypt over TrueCrypt.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It requires stronger effort to unlock VeraCrypt volume and this makes them more secure over</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt volumes.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Cons for VeraCrypt over TrueCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It requires stronger effort to unlock a VeraCrypt volume and this increases the time it takes to unlock</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a VeraCrypt volume. How long it will take depends on the strength of the computer and it may vary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from a few seconds to several minutes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS volume can be opened with up to 8 different keys.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS header is stored unencrypted making it obvious the volume is LUKS formatted encrypted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may not be desirable under certain circumstances. It is possible to create a LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume with a detached header and zuluCrypt can open these volumes using “luks†plugin.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It uses a header. As it is not possible to open a header using encrypted volume without its header, a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">corrupted LUKS header makes it impossible to open the volume. If you use a LUKS volume, make</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sure you have at least one backup of the volume header.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can do two types of encryption. It can do single file encryption/decryption or block device</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">File encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can encrypt and decrypt individual files. This feature is useful when a user just wants to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt a single file and taking the route of creating an encrypted container file to host the file is seen</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as an unnecessary hassle. This functionality is akin to file encryption using gpg with a symmetric key.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">File encryption is done using libgcrypt as a cryptographic backend. Files are encrypted using 256 bit</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">AES in CBC mode. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The encryption key is derived from user pass phrase using pbkdf2 with 10,000</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">rounds of iterations and sha2 as a cryptographic hash function. The resulting encrypted file will have a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file size that equals (64 + 1024 * n) bytes where n is a number starting from zero.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted file:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;encrypt a file†to open a file encryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to store encrypted, enter the password to be used to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt the file and then click “create†and the encrypted version of the file will be created at the path</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by “destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">To decrypt the file created with above steps:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;decrypt a file†to open a file decryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to decrypt, enter the password to be used to decrypt the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file and then click “create†and the decrypted version of the file will be created at the path given by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Block device encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A hard drive or a usb stick are two examples of block devices. A regular file can simulate a block</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">device through a use of devices known as “loop devicesâ€. These devices have a device path that starts</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">with “/dev/loopâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The infrastructure in the linux kernel that deal with block device encryption is called “dm-crypt†and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does its work through a process commonly known as OTF(on the file encryption). Dm-crypt devices</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">are represented by device addresses that starts with “/dev/dm-†and these paths are usually accessed</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">through their soft links that reside in “/dev/mapperâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Below is an example of steps taken in creating a 100MB encrypted container in a file and adding a file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">in it to be stored securely.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Create a 100MB file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Attach a loop device to the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Create an OTF encryption mapper against the loop device.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Put a file system on the encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Mount the file system on the mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Copy The file to be stored securely to the file system through the mount point.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Unmount the file system.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Destroy the OTF encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Detach the loop device from the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">10. Maintain the encrypted volume as a secure holder of files within it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All zuluCrypt does is provide a GUI to make it easy to do above specified tasks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With the above steps:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 1 deal with a path that look like “/home/ink/secret.imgâ€, this is a path to a regular file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 2 converts “/home/ink/secret.img†file to something like “/dev/loop0†loop device path.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 3 converts “/dev/loop0†loop device path to something like “/dev/mapper/secrets.imgâ€. Data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">written to “/dev/mapper/secrets.img†will get encrypted and then passed forward to “/dev/loop0†on its</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">way to “/home/ink/secret.imgâ€. When data is read from “/dev/mapper/secrets.imgâ€, the data will be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">read from “/dev/loop0†who in turn will read it from “/home/ink/secret.imgâ€, decrypted by dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then given to the reader. This process is called “on the fly encryption†because the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mapper does not store or hold on to data, it gets data and then encrypts or decrypts it depending on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">direction of data flow and then passes it along.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in an image file.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a file†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Enter the name of the file to be used to hold the container in the “file name†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the size of the container in the “file size†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Click “createâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Wait for the container file to be created and for the volume creation dialog to show up.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Enter the password to be used to create the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Select the type of volume you want to create from the “volume type†list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Click create to create the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in a partition.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a hard drive†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Click/double click on the hard drive you want to create a volume in and then advance to instruction</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">number 7 in the instruction list above. If the partition you want to put an encrypted container does not</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">show up on the list, then restart zuluCrypt from root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a file using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a file†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click the button to the right of “volume path†field and then browse to where</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the volume is and click it to open it. Alternatively, you can just drag the volume file on zuluCrypt to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">generate a password dialog prompt with the file path already filled in.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a partition using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a partition†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click/double click on the partition with an encrypted volume you want to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With both two steps above, the volume will be opened and mounted at a path whose last component is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by the entry in the field “mount nameâ€. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When the volume is successfully opened, zuluCrypt will</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">automatically open the mount point path. To close the volume, click its entry on the zuluCrypt window</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then click “close†on the pop up window.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can open an encrypted volume using keys derived from different sources. These sources</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">include, a pass phrase, a key file, a key retrieved from kwallet, a key retrieved from Gnome's libsecret,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a key retrieved from an internal secure storage system, a key from gpg encrypted key file among other</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sources.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a pass phrase volume key, make sure the key source option read “key†and then enter the pass</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phrase on the entry field at the bottom.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a keyfile as the source of volume key, click the option bar and then select “keyfile†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring a dialog box that will allow you to browse to where the key</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file is.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a plugin as the source of volume key, click the option bar and then select “plugin†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring up a list of available plugins and then select the one you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want from the list.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Volume keys stored in kwallet, Gnome keyring or internal secure storage system plugins can be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">managed by going to “menu-&gt;options-&gt;manage volumes in internal/kde/gnome walletâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Storage of keys in a gnome wallet/keyring seem most appropriate in a gnome session but this has some security repercussions, the keys are stored in the user keyring and this keyring gets unlocked when the user logs in. This means that once a user is logged in and the keyring is open, any application that runs in that user session can read those keys using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In a kde system, a kwallet secure storage system seem most appropriate but it suffers from the same</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">security problem the gnome secure storage system has, once the wallet is open, any application running in the user session can access it using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The behaviors of the above secure storage systems is by design but this design may not be ideal for</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">some users under certain use cases. The internal secure storage system is powered by libgcrypt and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does not have the behavior of the above two systems. An unlocked internal secured storage system is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">accessible only to the instance of zuluCrypt that unlocked it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Favorites.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For convenience, most used volumes can be easily opened by adding them to the favorite list. Entries</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">on the list are added in the dialog window opened by clicking “menu-&gt;options-&gt;manage favoritesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Favorite entries are added by clicking the “favorite†entry on the menu.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Erase data in a device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It is very important to create encrypted volume over cryptographically strong random data to make it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">impossible to know what part of the encrypted volume has been used and what part has not. If the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume is created over predictable data patterns like on a device with only zeros in it,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">forensic analysis may reveal how much and what part of the encrypted volume are in use.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When creating an encrypted container in a device, zuluCrypt offers an option to first write random data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over the device. This feature can be performed on other devices by activating it through “menu-&gt;erase</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data in a deviceâ€. Random data are written to disk by opening a plain dm-crypt encryption mapper on</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the device with a 64 byte random key and then blasting zeros on the device through the mapper. This</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">technique has proven to be faster compared to alternatives like writing random data on the device read</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from “/dev/urandomâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">System and non system volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To enforce access controls on what user can access what block device and what they can do with the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">access they have, zuluCrypt employes a concept of “system volumes†and “non system volumesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A system volume is defined as a volume that has an active entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/fstabâ€,â€/etc/crypptabâ€,“/etc/zuluCrypt/system_volumes.list†or if udev identify it as such if udev</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">is enabled. Ideally, all volumes inside the computer are to be considers system volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A non system volume is a volume that failed in the above considerations or if it has an entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/zuluCrypt/non_system_volumes.listâ€. Ideally, these volumes are plug gable usb based hard drives</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">or usb sticks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Partitions can be added or removed from the list of system or non system volumes simply by starting</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zuluCrypt from root's account and then going to “menu-&gt;options-&gt;manage system volumes/manage</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">non system volumes†and then adding the volume in the appropriate list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Permissions.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt limits what a user can do on block devices through unix's group based permission system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">using two groups, “zulucrypt†and “zulumountâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, only a root user or a user who is a member of group</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“zulucrypt†can create an encrypted volume in the device or taking/restoring volume headers. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want to create a volume in a device and the device does not show up on the list, restart zuluCrypt from</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, zuluMount will mount it only if the user is root, is a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">member of group “zulumount†or the device has an entry in “/etc/fstab†with either “user†or “usersâ€</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mount options set.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ZuluMount.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount is a general purpose mounting tool that can open zuluCrypt supported encrypted volumes</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as well as non encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also auto detect plugged in devices and auto mount them.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also unlock encfs volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2015-2017 Francis Banyikwa, mhogomchungu@gmail.com</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Open &PDF WARNING! Failed to open zuluCrypt.pdf,make sure your system can open pdf files using "%1" tool and try again ÙØ´Ù„ ÙÙŠ ÙØªØ­ مل٠ZuluCrypt.pdfØŒ تأكد أن النظام يستطيع ÙØªØ­ مل٠PDF باستخدام أداة "1%" ثم حاول مرة أخرى luksaddkey Add A Key To A Volume Ø£Ø¶Ù Ù…ÙØªØ§Ø­Ø§ للمجلد Volume Path مسار المجلد open file Ø§ÙØªØ­ المل٠open partition Ø§ÙØªØ­ القسم Advanced LUKS2 Options LUKS لوكس TrueCrypt ترو كربت VeraCrypt Ùيرا كربت Volume Type نوع المجلد PIM PIM TextLabel النص Advanced Luks2 Options Set Pbkdf Type argon2id argon2i pbkdf2 Max Memory (KB) Parallel Threads Unlocking Time Cost(Milliseconds) Forced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) Cancel open keyfile Ø§ÙØªØ­ Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Password Already In The Encrypted Volume Password To Be Added To The Encrypted Volume Reenter Password Password KeyFile Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Key+KeyFile Ù…ÙØªØ§Ø­+Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ YubiKey Challenge/Response &OK &Add أض٠&Cancel ألغ Passphrase Quality: 0% جودة كلمة السر: 0% Passphrase Quality: %1% جودة كلمة السر: 1% Key Slot Number To Add Key In Enter A Key أدخل Ù…ÙØªØ§Ø­ Enter a path to a keyfile location أدخل مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ KeyFile Path مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Enter a key أدخل Ù…ÙØªØ§Ø­Ø§ KeyFile path أدخل مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Passphrase Quality: 100% جودة كلمة السر: 100% Existing KeyFile Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ الموجود New KeyFile Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ الجديد Encrypted Volume Path مسار المجلد Ø§Ù„Ù…Ø´ÙØ± ERROR! خطأ Atleast one required field is empty حقل واحد مطلوب على الأقل Failed to enable polkit support Keys do not match Ø§Ù„Ù…ÙØ§ØªÙŠØ­ لا تتطابق Failed To Locate Or Run Yubikey's "ykchalresp" Program. Key added successfully. Ø§Ù„Ù…ÙØªØ§Ø­ أضي٠بنجاح Key added successfully. %1 / %2 slots are now in use Ø§Ù„Ù…ÙØªØ§Ø­ أضي٠بنجاح. Ø§Ù„Ù…Ù†Ø§ÙØ° 1% 2% الآن قيد الاستخدام Presented key does not match any key in the volume Ø§Ù„Ù…ÙØªØ§Ø­ المخل لا يتطابق مع Ù…ÙØªØ§Ø­ المجلد Could not open luks volume لم يمكن ÙØªØ­ مجلد لوكس Volume is not a luks volume المجلد ليس مجلد لوكس Insufficient privilege to add a key to a system device, only root user or members of group "zulucrypt" can do that صلاحيات غير كاÙية Ù„Ø¥Ø¶Ø§ÙØ© Ù…ÙØªØ§Ø­ لقرص النظام. المستخدم المدير وأعضاء مجموعة زولوكربت Ùقط يستطيعون ذلك. Could not open volume in write mode لا يمكن ÙØªØ­ المجلد للكتابة All key slots are occupied, can not add any more keys كل Ù…Ù†Ø§ÙØ° Ø§Ù„Ù…ÙØ§ØªÙŠØ­ مشغولة. لا يمكن Ø¥Ø¶Ø§ÙØ© Ù…ÙØ§ØªÙŠØ­. Can not get passphrase in silent mode لا يمكن الحصول على كلمة السر ÙÙŠ الطور الصامت Insufficient memory to hold passphrase ذاكرة غير كاÙية لاستيعاب كلمة السر New passphrases do not match كلمات السر الجديدة لا تتطابق One or more required argument(s) for this operation is missing معطى أو أكثرمطلوب غير Ù…ØªÙˆÙØ± لهذه العملية One or both keyfile(s) does not exist Ù…Ù„Ù Ù…ÙØªØ§Ø­ أو كلا ملÙÙŠ Ù…ÙØªØ§Ø­ غير موجود Insufficient privilege to open key file for reading ذاكرة غير كاÙية Ù„ÙØªØ­ Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ للقراءة Couldnt get enought memory to hold the key file لم يمكن الحصول على ذاكرة كاÙية لاستيعاب Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Could not get a key from a socket لم يمكن الحصول على Ù…ÙØªØ§Ø­ من Ø§Ù„Ù…Ù†ÙØ° Could not get elevated privilege,check binary permissions لم يمكن ترقية الصلاحية. تأكد من الأذونات Key slot already occupied Failed to find empty key slot or key slot out of range Can not find a partition that match presented UUID لم يمكن العثور على قسم Ø¨Ù†ÙØ³ الرقم المعطى Device is not a luks device القرص ليس قرص لوكس Error Code: %1 -- StdOut: %2 -- StdError: %3 luksdeletekey Remove A Key From A Volume Ø§Ø­Ø°Ù Ù…ÙØªØ§Ø­ من المجلد LUKS Slot Number Password open a keyfile Ø§ÙØªØ­ Ù…Ù„Ù Ù…ÙØªØ§Ø­ &Delete امسح &Cancel ألغ Volume Path مسار المجلد open an encrypted file Ø§ÙØªØ­ Ù…Ù„ÙØ§ Ù…Ø´ÙØ±Ø§ open an encrypted partition Ø§ÙØªØ­ قسما Ù…Ø´ÙØ±Ø§ TextLabel &OK KeyFile Ù…Ù„Ù Ù…ÙØªØ§Ø­ Key+KeyFIle Ù…ÙØªØ§Ø­+Ù…Ù„Ù Ù…ÙØªØ§Ø­ Enter a key أدخل Ù…ÙØªØ§Ø­ Enter a path to a keyfile location أدخل مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ KeyFile path مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Key File With A Passphrase To Delete مسح Ù…Ù„Ù Ù…ÙØªØ§Ø­ بكلمة سر ERROR! خطأ Atleast one required field is empty حقل واحد مطلوب على الأقل ÙØ§Ø±Øº Failed to enable polkit support Volume is not a luks volume المجلد ليس مجلد لوكس There is only one last key in the volume. يوجد Ù…ÙØªØ§Ø­ أخير Ùقط بالمجلد Deleting it will make the volume unopenable and lost forever. بمسحه يستحيل ÙØªØ­ المجلد وسيÙقد للأبد Are you sure you want to delete this key? هل متأكد أنك تريد مسح Ø§Ù„Ù…ÙØªØ§Ø­ØŸ WARNING تحذير Key removed successfully. %1 / %2 slots are now in use Ø§Ù„Ù…ÙØªØ§Ø­ تم مسحه بنجاح Ø§Ù„Ù…Ù†Ø§ÙØ° 1% 2% الآن مشغولة YubiKey Challenge/Response zuluCrypt will have the same behavious as luksKillSlot if a key slot is given zuluCrypt will have the same behavious as luksRemoveKey if a key slot is NOT given Failed To Locate Or Run Yubikey's "ykchalresp" Program. There is no key in the volume that match the presented key Ø§Ù„Ù…ÙØªØ§Ø­ لا يطابق أيا من Ù…ÙØ§ØªÙŠØ­ المجلد Could not open the volume لم يمكن ÙØªØ­ المجلد Insufficient privilege to open a system device,only root user or members of group zulucrypt can do that صلاحيات غير كاÙية Ù„ÙØªØ­ قرص النظام. Ùقط المستخدم المدير وأعضاء مجموعة زولوكربت بإمكانهم ذلك Could not open the volume in write mode لم يمكن ÙØªØ­ المجلد للقراءة Insufficient memory to hold your response ذاكرة غير كاÙية لاستيعاب ردك Operation terminated per user request العملية تم إلغؤها من طر٠المستخدم Can not get passphrase in silent mode لم يمكن الحصول على كلمة السر ÙÙŠ الطور الصامت Insufficient memory to hold passphrase ذاكرة غير كاÙية لاستيعاب كلمة السر One or more required argument(s) for this operation is missing معطى مطلوب أو أكثر لم ÙŠØªÙˆÙØ± لهذه العملية Keyfile does not exist Ù…Ù„Ù Ù…ÙØªØ§Ø­ غير موجود Could not get enough memory to open the key file لم يمكن الحصول على ذاكرة كاÙية لاستيعاب Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Insufficient privilege to open key file for reading صلاحيات غير كاÙية Ù„ÙØªØ­ Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ للقراءة Could not get a key from a socket لم يمكن الحصول على Ø§Ù„Ù…ÙØªØ§Ø­ من Ø§Ù„Ù…Ù†ÙØ° Can not find a partition that match presented UUID لم يمكن العثور على قسم Ø¨Ù†ÙØ³ الرقم التعريÙÙŠ Error Code: %1 -- StdOut: %2 -- StdError: %3 manageSystemVolumes Manage System Volumes تحكم ÙÙŠ مجلد النظام &Done تم Add Fi&le أض٠مل٠Add Dev&ice أض٠قرصا Path To System Volumes المسار لمجلدات النظام Remove Selected Entry اح٠البند المختار Cancel ألغ Are you sure you want to remove "%1" from the list? هل تريد Ø­Ù "1%" من القائمة WARNING تحذير Select Path To System Volume اختر مسارل لمجلد النظام managevolumeheader Backup Volume Header قم بنسخ احتياطي لترويسة الملجلد Backup Name اسم النسخ الاحتياطي C&reate إنشاء &Cancel ألغ Volume Path مسار المجلد Window System Volume مسار مجلد نظام ويندوز Volume Type نوع الملجلد Manage A VeraCrypt Header تحكم ÙÙŠ ترويسة Ùيرا كربت PIM PIM Password Password Source Outer Volume Password ONLY KeyFile Ù…Ù„Ù Ù…ÙØªØ§Ø­ TextLabel النص Normal Volume مجلد عادي Whole Drive Encrypted Volume القرص Ù…Ø´ÙØ± بالكامل Manage A LUKS Header تحكم ÙÙŠ ترويسة لوكس Manage A TrueCrypt Header تحكم ÙÙŠ ترويسة ترو كربت Restore volume header استرجع ترويسة المجلد &Restore استرجع Back up volume header نسخ احتياطي لترويسة المجلد &Backup نسخ احتياطي Select A File With A LUKS Backup Header اختر Ù…Ù„ÙØ§ احتياطيا لترويسة لوكس Select A Folder To Store The Header اختر مجلدا Ù„Ø­ÙØ¸ ترويسة المجلد الاحتياطية ERROR! خطأ Atleast one required field is empty حقل مطلوب على الأقل ÙØ§Ø±Øº Failed to enable polkit support Are you sure you want to replace a header on device "%1" with a backup copy at "%2"? هل تريد استبدال الترويسة على القرص "1%" بترويسة احتياطية ÙÙŠ "2%" WARNING! تحذير Select luks container you want to backup its header اختر حاوية لوكس التي تريد نسخ ترويستها SUCCESS نجاح Header saved successfully. If possible,store it securely. الترويسة Ø­ÙØ¸ بنجاح. إذا امكن، خزنها بأمان. Header restored successfully تم استعادة الترويسة بنجاح Presented device is not a LUKS device القرص ليس قرص لوكس Failed to perform requested operation ÙØ´Ù„ ÙÙŠ تنÙيذ العملية المطلوبة INFO! معلومات Operation terminater per user request المستخدم قام بإلغاء العملية Path to be used to create a back up file is occupied المسار Ø§Ù„Ù…ÙØªØ±Ø¶ استخامه لنسخ المل٠غير شاغر Insufficient privilege to open backup header file for reading صلاحيات غير كاÙية Ù„ÙØªØ­ ترويسة المل٠للقراءة Invalid path to back up header file مسار غير صحيح لنسخ مل٠الترويسة Insufficient privilege to create a backup header in a destination folder صلاحيات غير كاÙية لنسخ ترويسة المل٠ÙÙŠ المجلد المستهد٠Invalid path to device مسار غير صحيح للمجلد Argument for path to a backup header file is missing معطى مطلوب لمسار نسخ ترويسة المل٠غير Ù…ØªÙˆÙØ± Only root user and "zulucrypt" members can restore and back up luks headers on system devices Ùقط المستخدم المدير وأعضاء مجموعة زولو كربت يمكنهم استرجاع ونسخ احتياطي لترويسة لوكس على قرص نظام Insufficient privilege to open device for writing صلاحيات غير كاÙية Ù„ÙØªØ­ القرص للكتابة Could not resolve path to device لم يمكن Ù…Ø¹Ø±ÙØ© مسار القرص Backup file does not appear to contain luks header الترويسة الاحتياطية لا تبدو أنها تحوي ترويسة لوكس Insufficient privilege to open device for reading صلاحيات غير كاÙية Ù„ÙØªØ­ القرص للقراءة Wrong password entered or volume is not a truecrypt volume كلمة سر غير صحيحة أو أن المجلد ليس مجلد ترو كربت Failed to perform requested operation on the LUKS volume ÙØ´Ù„ ÙÙŠ تنÙيذ العملية المطلوبة على مجلد لوكس Wrong password entered or volume is not a veracrypt volume كلمة سر غير صحيحة أو أن المجلد ليس مجلد Ùيرا كربت Unrecognized ERROR! with status number %1 encountered خطأ غير معروÙ. رقم الحالة 1% oneinstance Previous instance seem to have crashed,trying to clean up before starting البرنامج تم تشغيله من قبل وتعطل. حاول التنظي٠ثم إبدأ من جديد There seem to be another instance running,exiting this one يبدو هناك نسخة أخرى من البرنامج تعمل آنيا. أخرج من البرنامج openvolume Select A Partition To Open اختر قسما Ù„ÙØªØ­Ù‡ Use UUID استخدم الرقم التعريÙÙŠ &Help مساعدة Use &UUID استخدم الرقم التعريÙÙŠ &Cancel ألغ partition قسم size حجم label ملصق type نوع uuid رقم تعريÙÙŠ &Open Ø§ÙØªØ­ A list of all partitions on this system are displayed here. Double click an entry to use it قائمة بكل الأقسام على النظام تعرض هنا. انقر Ù…Ø¶Ø§Ø¹ÙØ§ على واحد لاستخدامه Restart the tool from root's account or after you have created and added yourself to group "zulucrypt" if the volume you want to use is not on the list. أعد تشغيل البرنامج بصلاحية مدير أو بعد أن ØªØ¶ÙŠÙ Ù†ÙØ³Ùƒ لمجموعة زولو كربت إذا كان المجلد الذي تريد استخدامه ليس على القائمة. You are a root user and all partitions are displayed. Double click an entry to use it أنت مستخدم مدير، كل الأقسام على النظام تعرض هنا. انقر Ù…Ø¶Ø§Ø¹ÙØ§ على واحد لاستخدامه INFO معلومات Select A Partition To Create An Encrypted Volume In اختر قسما لإنشاء مجلد Ù…Ø´ÙØ± عليه Select An Encrypted Partition To Open اختر قسما Ù…Ø´ÙØ±Ø§ Ù„ÙØªØ­Ù‡ ERROR خطأ Only crypto_LUKS volumes can be selected يمكن اختيار مجلدات كربتو لوكس Ùقط passwordDialog TrueCrypt/VeraCrypt Keys Ù…ÙØ§ØªÙŠØ­ Ùيرا كربت/ترو كربت YubiKey Challenge/Response Check This Box To Make Password Visible ÙØ¹Ù„ هذا الخيار لجعل كلمة السر ظاهرة Unlock Encrypted Volume ÙÙƒ تشÙير المجلد Ø§Ù„Ù…Ø´ÙØ± PIM Value قيمة PIM Offset الإزاحة Offset Will Be In Sectors If The Entry Is Made Up Of Only Digits And In Bytes If The Entry Ends With "b" And In Kilobytes If The Entry Ends With "k" And In Megabytes If The Entry Ends With "m" And In Terabytes If The Entry Ends With "t" سو٠تظهر الإزاحة بالسكتور إذا كتبت القيمة بالأرقام Ùقط Ùˆ بالبايت إذا كانت نهاية الإدخال "b" Ùˆ بالكيلو بايت إذا كانت نهاية الإدخال "k" Ùˆ بالميجا بايت إذا كانت نهاية الإدخال "m" Ùˆ بالتيرا بايت إذا كانت نهاية الإدخال "t" Cancel ألغ Mount "%1" حمل "1%" Choose A Module From The File System اختر وحدة من نظام Ø§Ù„Ù…Ù„ÙØ§Øª Enter A Module Name To Use To Get Passphrase أدخل اسم الوحدة Ø§Ù„Ù…Ø³ØªÙ‡Ø¯ÙØ© للحصول على كلمة السر Plugin Name اسم Ø§Ù„Ø¥Ø¶Ø§ÙØ© Password Select A Key Module اختر Ù…ÙØªØ§Ø­ الوحدة Enter A Key اختر Ù…ÙØªØ§Ø­ Select External LUKS Header File LUKS External Header Path Choose A KeyFile From The File System اختر Ù…Ù„Ù Ù…ÙØªØ§Ø­ من نظام Ø§Ù„Ù…Ù„ÙØ§Øª Enter A Path To A Keyfile Location أدخل مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ KeyFile Path مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Select A KeyFile اختر Ù…Ù„Ù Ù…ÙØªØ§Ø­ Select Path To Mount Point Folder اختر ماسرا لنقطة تحميل المجلد Select Encrypted volume اختر مجلدا Ù…Ø´ÙØ±Ø§ ERROR! خطأ Internal wallet is not configured الخزانة الداخلية غير مهيأة ERROR خطأ Failed To Locate Or Run Yubikey's "ykchalresp" Program. Atleast one required field is empty حقل واحد ÙØ§Ø±Øº على الأقل "/" character is not allowed in mount name field الرمز "/" غير مسموح به ÙÙŠ حقل اسم التحميل Volume is not a LUKS volume المجلد ليس مجلد لوكس Failed to get a key from the network ÙØ´Ù„ ÙÙŠ الحصول على Ù…ÙØªØ§Ø­ من الشبكة Failed to get a key from a plugin Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? ÙØ´Ù„ ÙÙŠ تحميل نظام Ù…Ù„ÙØ§Øª ntfs/exfat باستخدام ntfs-3g المثبتة؟ There seem to be an open volume accociated with given address يبدو أن مجلدا مقترنا بالعنوان المعطى Ù…ÙØªÙˆØ­ No file or device exist on given path لا يوجد مل٠أو قرص ÙÙŠ المسار المعطى Volume could not be opened with the presented key لم يمكن ÙØªØ­ المجلد Ø¨Ø§Ù„Ù…ÙØªØ§Ø­ المعطى Insufficient privilege to mount the device with given options صلاحيات غير كاÙية لتحميل القرص بالخيارات المحددة Insufficient privilege to open device in read write mode or device does not exist صلاحيات غير كاÙية Ù„ÙØªØ­ القرص للقراءة والكتابة أو أن القرص غير موجود Only root user can perform this operation Ùقط مستخدم مدير يمكنه تنÙيذ هذه العملية -O and -m options can not be used together خيارا O- Ùˆ m- لا يمكن استخدامهما معا ÙÙŠ آن واحد Could not create mount point, invalid path or path already taken لم يمكن إنشاء نقطة التحميل. مسار خاطئ أو المسار قد سبق تعيينه Shared mount point path already taken نقطة تحميل مشتركة سبق تعيينها There seem to be an opened mapper associated with the device يبدو وجود مخطط Ù…ÙØªÙˆØ­ مقترن بهذا القرص Could not get a passphrase from the module لم يمكن استرجاع كلمة السر من الوحدة Could not get passphrase in silent mode لم يمكن استرجاع كلمة السر ٠يالطور الصامت Insufficient memory to hold passphrase ذاكرة غير كاÙية لاستيعاب كلمة السر One or more required argument(s) for this operation is missing معطى مطلوب أو أكثر لهذه العملية غير Ù…ØªÙˆÙØ± Invalid path to key file مسار خاطئ Ù„Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Could not get enought memory to hold the key file لم يمكن الحصول على ذاكرة كاÙية لاسيتعاب Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Insufficient privilege to open key file for reading صلاحيات غير كاÙية Ù„ÙØªØ­ Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ للقراءة Could not get a passphrase through a local socket لم يمكن الحصول على كلمة السر من خلال Ù…Ù†ÙØ° محلي Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered ÙØ´Ù„ ÙÙŠ تحميل نظام Ø§Ù„Ù…Ù„ÙØ§Øª: نقطة تحميل غير مدعومة أو نظام Ù…Ù„ÙØ§Øª غير مدعوم Could not create a lock on /etc/mtab لم يمكن إنشاء Ù‚ÙÙ„ ÙÙŠ /etc/mtab Insufficient privilege to open a system volume. Consult menu->help->permission for more informaion صلاحيات غير كاÙية Ù„ÙØªØ­ مجلد النظام. راجع قائمة المساعدة ثم الأذونات لمزيد من المعلومات A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature قرص غير مدعوم أو قرص غير موجود أو أذونات غير Ù…ØªÙˆÙØ±Ø© أسباب محتملة لهذا الخطأ: 1- مسار القرص غير صحيح 2- القرص له توقيع LVM أو MDRAID Error Code: %1 -- StdOut: %2 -- StdError: %3 plugin Key Generator Using A Passphrase And A KeyFile مولد Ø§Ù„Ù…ÙØªØ§Ø­ يستخدم كلمة سر Ùˆ Ù…Ù„Ù Ù…ÙØªØ§Ø­ &Set Key حدد Ù…ÙØªØ§Ø­Ø§ &Cancel ألغ Create an encryption key that is made up of a passphrase and a keyfile. A volume created with a key generated here should be opened with "hmac" plugin. أنشئ Ù…ÙØªØ§Ø­ تشÙير مكون من Ù…ÙØªØ§Ø­ ÙˆÙ…Ù„Ù Ù…ÙØªØ§Ø­ مجلد أنشئ Ø¨Ù…ÙØªØ§Ø­ ولد هنا لابد أن ÙŠÙØªØ­ بأداة "hmac" الإضاÙية Passphrase كلمة سر KeyFile Ù…Ù„Ù Ù…ÙØªØ§Ø­ ERROR خطأ KeyFile Not Set Ù…Ù„Ù Ù…ÙØªØ§Ø­ غير محدد Failed To Generate Key ÙØ´Ù„ ÙÙŠ توليد Ø§Ù„Ù…ÙØªØ§Ø­ readOnlyWarning WARNING تحذير Do Not Show This Message Again. لا تظهر هذا مرة أخرى Setting this option will cause the volume to open in read only mode. تهيئة هذا الخيار سو٠يؤدي Ù„ÙØªØ­ المجلد ÙÙŠ طور القراءة Ùقط &Ok نعم tcrypt TrueCrypt Keys Ù…ÙØ§ØªÙŠØ­ ترو كربت &Open Ø§ÙØªØ­ &Cancel ألغ Add &Keyfile Ø£Ø¶Ù Ù…Ù„Ù Ù…ÙØªØ§Ø­ drag and drop key files to add them to the list اسحب وأÙلت Ù…Ù„ÙØ§Øª Ø§Ù„Ù…ÙØªØ§Ø­ Ù„Ø¥Ø¶Ø§ÙØªÙ‡Ù… بالقائمة Keyfile Paths مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Enter key files below to be used to open the volume أدخل Ù…Ù„ÙØ§Øª Ø§Ù„Ù…ÙØªØ§Ø­ بالأسÙÙ„ لاستخدامهم ÙÙŠ ÙØªØ­ المجلد Enter A Passphrase Below To Be Used To Open The Volume أدخل كلمة السر بالأسÙÙ„ Ù„ÙØªØ­ المجلد &Set حدد TrueCrypt/VeraCrypt Keys Ù…ÙØ§ØªÙŠØ­ Ùيرا كربت/ ترو كربت ERROR خطأ At least one keyfile is required عل الأقل Ù…Ù„Ù Ù…ÙØªØ§Ø­ واحد مطلوب Select A KeyFile اختر Ù…Ù„Ù Ù…ÙØªØ§Ø­ utility::veraCryptWarning Elapsed time: 0 seconds الوقت المنقضي: 0 ثوان Elapsed time: %0 minutes الوقت المنقضي: 0% دقائق Elapsed time: %0 seconds الوقت المنقضي: 0% ثوان Please be patient as unlocking a VeraCrypt volume may take a very long time. يرجى الانتظار ÙÙÙƒ تشÙير مجلد Ùيرا كربت يستغرق وقتا طويلا warnWhenExtendingContainerFile WARNING!! OK Dont Show This Warning Again. Your cover file will be irreversibly changed and we suggest continuing with a backup file and not the original. To unlock the volume about to be created, you will need to enter the password you will choose and the volume offset automatically generated by zuluCrypt. Instructions to unlock the volume are as follows: 1. From the menu, choose Open -> Volume Hosted In A File. 2. Select file, then choose "Volume Type" = PLAIN dm-crypt. 3. Enter the generated offset value along with your password. IMPORTANT!!! zuluCrypt zuluCrypt زولو كربت Encrypted Volume Path مسار المجلد Ø§Ù„Ù…Ø´ÙØ± Encrypted Volume Mount Point Path مسار نقطة تحميل المجلد Ø§Ù„Ù…Ø´ÙØ± Type نوع &Open Ø§ÙØªØ­ &Create أنشئ &Help مساعدة &Volumes مجلدات Optio&ns خيلرلت &Volume Hosted In A File المجلدات Ø§Ù„Ù…Ø³ØªØ¶Ø§ÙØ© ÙÙŠ مل٠Volume &Hosted In A Hard Drive المجلدات Ø§Ù„Ù…Ø³ØªØ¶Ø§ÙØ© على قرص Encrypted &Container In A Hard Drive حاوية Ù…Ø´ÙØ±Ø© ÙÙŠ قرص &About حول &Add A Key To A Volume Ø£Ø¶Ù Ù…ÙØªØ§Ø­Ø§ للمجلد &Delete A Key From A Volume امسح Ù…ÙØªØ§Ø­Ø§ من المجلد &KeyFile Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ &Tray Icon أيقونة الشريط Select &Font اختر خطا &Update Volume List حدث قائمة المجلدات &Minimize To Tray صغر إلى الشريط &Quit اخرج &Close All Opened Volumes اغلق جميع المجلدات Ø§Ù„Ù…ÙØªÙˆØ­Ø© &Manage Favorites تحكم ÙÙŠ Ø§Ù„Ù…ÙØ¶Ù„ات &Erase Data In A Device امسح البيانات على الجهاز &Backup Header نسخ احتياطي للترويسة &Restore Header استعادة الترويسة Encrypt A &File Ø´ÙØ± مل٠&Decrypt A File ÙÙƒ تشÙير مل٠&Header Backup نسخ احتياطي للترويسة Manag&e System Volumes تحكم ÙÙŠ مجلدات النظام Manage &Volumes In Internal Wallet تحكم ÙÙŠ المجلدات بداخل الخزانة Manage &Non System Volumes تحكم ÙÙŠ المجلدات غير النظامية Manage Volumes In &KDE Wallet تحكم ÙÙŠ المجلدات ÙÙŠ خزانة KDE Manage Volumes In &GNOME keyring تحكم ÙÙŠ المجلدات ÙÙŠ Ù…ÙØ§ØªÙŠØ­ GNOME &Change Internal Wallet Password غير كلمة سر الخزانة الداخلية H&elp F1 Show LUKS Key Slots Set Fi&le Manager Do Not Minimize To Tray This Option Will Close The App Instead Of Minimizing It To Tray Encrypted Container Hidden In Video/Cover File (Steganography) Show Debug Window Ctrl+Shift+D Encrypted Container In An Existing File Clear Dead Mount Points Contact &Info معلومات التواصل &Select Language اختر اللغة &Auto Open Mount Point ÙØªØ­ تلقائي لنقطة التحميل Select &Icons اختر أيقونة &Favorites Ø§Ù„Ù…ÙØ¶Ù„ات &zC زولو كربت Ctrl+Z Ctrl+Z Ctrl+X Ctrl+X &Encrypted Container In A New File Ctrl+A Ctrl+A Ctrl+S Ctrl+S Ctrl+R Ctrl+R Ctrl+U Ctrl+U Ctrl+W Ctrl+W crypto info معلومات التشÙير Ctrl+E Ctrl+E Ctrl+D Ctrl+D Ctrl+K Ctrl+K Ctrl+L Ctrl+L favorite volumes المجلدات Ø§Ù„Ù…ÙØ¶Ù„Ø© manage favorites تحكم ÙÙŠ Ø§Ù„Ù…ÙØ¶Ù„ات select random number generator اختر مولد الرقم العشوائي Ctrl+P Ctrl+P close application أغلق التطبيق Ctrl+C Ctrl+C Ctrl+T Ctrl+T Ctrl+Y Ctrl+Y Quit خروج Ctrl+Q Ctrl+Q Ctrl+G Ctrl+G Ctrl+F Ctrl+F Ctrl+N Ctrl+N Ctrl+B Ctrl+B permissions الصلاحيات Ctrl+I Ctrl+I Ctrl+H Ctrl+H Ctrl+J Ctrl+J Ctrl+V Ctrl+V configure wallets هيئ الخزانات Ctrl+M Ctrl+M Shift+V Shift+V Alt+V Alt+V Ctrl+O Ctrl+O tcrypt backup header نسخ اتياطي لترويسة تروكربت tcrypt restore header استعادة ترويسة تروكربت VeraCrypt Container In A File حاوية Ùيرا كربت ÙÙŠ مل٠VeraCrypt Container In A Hard Drive حاوية Ùيرا كربت ÙÙŠ قرص Shift+I Shift+I Select Language اختر اللغة Restore Volume Header استعادة ترويسة المجلد Backup Volume Header نسخ احتياطي لترويسة المجلد INFO معلومات Resetting font size to %1 because larger font sizes do not fit إعادة ضبط الخطوط لحجم 1% لأن الخطوط الكبيرة لا تضبط LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a "volume header". A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data. The damage to the header is usually caused by accidental formatting of the device or use of some buggy partitioning tools or wrongly reassembled logical volumes. Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted. المجلدات Ø§Ù„Ù…Ø´ÙØ±Ø© بلوكس Ùˆ ترو كربت Ùˆ Ùيرا كربت لها ترويسة. ترويسة المجلد مهمته Ø­ÙØ¸ المعلومات الضرورية Ù„ÙØªØ­ المجلد Ø§Ù„Ù…Ø´ÙØ± وأي عطب به سو٠يتسبب ÙÙŠ عدم ÙØªØ­ المجلد وبالتالي Ùقد البيانات للأبد. لذلك ÙØ¥Ù†Ù‡ ينصح بشدة بنسخ احتياطي للترويسة والتي ستمكنك من ÙØªØ­ المجلد ÙÙŠ حالة عطب ترويسة المجلد الأصل. Important Information On Volume Header Backup معلومات مهمة عن ترويسة المجلد الاحتياطية. ERROR! خطأ Volume is not open or was opened by a different user المجلد غير Ù…ÙØªÙˆØ­ أو Ù…ÙØªÙˆØ­ من مستخدم آخر Volume Properties خصائص المجلد WARNING! تحذير! Could not open mount point because "%1" tool does not appear to be working correctly لا يمكن ÙØªØ­ نقطة التحميل لأن أداة "1%" لايبدو أنها تعمل بشكل سليم Properties خصائص Open Folder Ø§ÙØªØ­ المجلد ERROR خطأ zuluCrypt Failed To Connect To zuluPolkit. Please Report This Serious Bug. Cryptsetup library could not be found and zuluCrypt will most likely not work as expected. Please recompile zuluCrypt to force it to re-discover the new library Path To A File Show/Hide اظهر/أخ٠Open Private Folder Ø§ÙØªØ­ مجلد خاص Open Shared Folder Ø§ÙØªØ­ مجلد مشترك Add Key Ø£Ø¶Ù Ù…ÙØªØ§Ø­ Remove Key امسح Ù…ÙØªØ§Ø­ Show Key Slots Information Backup LUKS Header تنسخ ترويسة لوكس Add To Favorite Ø£Ø¶Ù Ù„Ù„Ù…ÙØ¶Ù„ات Unmount تنزيل Cancel إلغاء Close failed, volume is not open or was opened by a different user ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. المجلد غير Ù…ÙØªÙˆØ­ أو Ù…ÙØªÙˆØ­ من مستخدم آخر Close failed, one or more files in the volume are in use. ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. مل٠أو أكثر قيد الاستخدام Close failed, volume does not have an entry in /etc/mtab ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. المجلد ليس له سجل ÙÙŠ /etc/mtab Close failed, could not get a lock on /etc/mtab~ ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. المجلد ليس له سجل ÙÙŠ /etc/mtab~ Close failed, volume is unmounted but could not close mapper,advice to close it manually ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. المجلد تم تنزيله لكن لم يمكن إغلاق الاقتران. قم بالاغلاق اليدوي Close failed, could not resolve full path of device ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. لم يمكن Ù…Ø¹Ø±ÙØ© المسار الكامل للجهاز Close failed, shared mount point appear to be busy ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. نقطة التحميل المشتركة تبدو مشغولة Close failed, shared mount point appear to belong to a different user or multiple mount points detected ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. نقطة التحميل المشتركة تتبع مستخدما آخر أو Ø§ÙƒØªØ´ÙØª نقاط متعددة Close failed, shared mount point appear to be in an ambiguous state,advice to unmount manually ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. نقطة التحميل المشتركة غير واضحة. قم Ø¨Ø§Ù„Ø§Ù‚ÙØ§Ù„ اليدوي Close failed, multiple mount points for the volume detected ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. Ø§ÙƒØªØ´ÙØª نقاط متعددة للمجلد Close failed, could not find any partition with the presented UUID ÙØ´Ù„ Ø§Ù„Ø§Ù‚ÙØ§Ù„. لا يوجد أي قسم يحمل الرقم التعريÙÙŠ المستخدم Unrecognized error with status number %1 encountered خطأ غير معرو٠برقم حالة 1% zuluCrypt-6.2.0/translations/zuluCrypt/de_DE.qm000066400000000000000000003276621425361753700216360ustar00rootroot00000000000000<¸dÊÍ!¿`¡½Ý§de_DEB0‘…c²F-òGlG‘;R¤[œÓ¢+O1+O*‹+O õ+[\+[¡+[G2-ãkQÉgËQÉ‘TÝstTÝϤTÝÂW'OÔW'y©f§¤º‰¹ÄµN¹ÄI‰¿Ãƒ¿Ã*¿¿Ã¡?â¯FRâ¯ð⯅¶ì0¹+isÍiŒŠðÀeA6`LE¥³¡q¡·¬ôÀeÀeäÉ´–Ëô ÞjǨ5BöeÀË*¶Eìå*ì0ö*ì0h+f¾±+f¾&+f¾I[+f¾i)+ŒiZ2®«3uk4fôB¦4fôa4fô«4fôÆ 4fôÞü4fô÷xE’—SFØó|ŸH7lPJ ÃVõJgz JwBVJwB2†JwB_ÅJwBÀJwB'JwBDÕJwBJ´JwB\J  PƒJÌ0…‡N+û8Q ajQ bj•T}Õ:®Zz è^Ü„ç_ú% ðbƒÉ@—d¤tÔd¤tsžjyedjyeÆ·jyeß©jye-çrx¼Csf:~tZŠß|Š7|fEv•3²ôˆžÎÎÛ¤Œé%ç¦ó )J°U‚=º…ŽÖ½ …Ó¿ë”)Å1õKÛÅÃ…zÎÅÃ…>ÁÏ´¨ßM–0êÍȦÖúëc‡û‰¤ V”ɀͦs ÞZ´2ÿè.(gŽ”=7Õ'ïFwséXîå\oXîå&h]”×sO¨‘æsO¨Ì¡{˜v^™uÍBš2N9œ%œ%hœ%‘Fœ%ËOœd%äîžÖ’}p¯ Ž®l¶4N!ÍΕh/ÍÐuãÍÐuhaÍÐu‘¤ÍÐuË­ÍÐuåOÍÐu$ÍÐuFUÝÒeAwþ¼=ª-ÿPGêgý£5œñÓ…Ã"Oµ‘í:4eÔ^:4eêÔ=8Rl}K6ÕÚÕKìêw)e5â5§u 5CPu%¨CŠuîCĉÔl¾ŒÃå¥õŒÃå%„XUYµ§–Äbת6• #ª6•·dº¨”¢MÅ<A?ÙÆÛ«èìtˆŸ3ƒƒ°Ï”Ä -(ÿ"Œp( h!( hÓà( hê‘( h .(ã¥e(ã¥}0(ã¥Ô (㥠v)Å|ì:XÃi7N‚Å »P„EIP„LPP…£é_êŽú>jeô[×jeô¾œjeôÚ<m©¨šrýõ[%€¢ xpš!´—ΛÑõ­¯Ã~Q¹±·.<ý¶ÿôŒå½("!kÊC`,ÊCÄÙÊCÞ*ÊC)‘ÐDSP×c•bÝP=!Ä  DÚ+ ŠÖ+ Ãr+ '‡E;Ý’izY%ÄÂi - ´/K ÃÖ/K Ý!1'"–ëDêtºFgþCJ¬>xMU€Ô¡×[h¥@[¥]!]+‚ ]i™Õ‘nwú™5“±…†ˆ–ÊÆ˜I¼F˜I¼XݘI¼¾e˜I¼î§˜I¼ÿ˜I¼m;šÒÉò¢aO¤F‰§tA_÷§tAÂͧtAÜë§tA÷=§tA'P§tA‹§Ð©M«Žñ{¥«Žò{Õ«Žó|«Žô|5«Žõ|e«Žö|•«Ž÷|ū޸|õ«Žù}%«Žú}U«Žû}…«Žü}µ«Žý}嫎þ~«Žÿ~E«~u«~¥«~Õ««}«­«Ý«€ «€=« €m« €¯ƒW«¯ƒW¡f²4Êr#¾ïˆ4¼ÕÄdIÛÅÞ~~ãUe—bð$UØò¤EX-ò¤E½·ò¤EÙ‹ô,uú Ç•ãh÷ó…(ëÔá6°eä:_y$b>vÔ–Y?ÅÂ"c@Z$o†BGÔÎ#F›£dÑJ%O¢\ÆD$\ÙÄ5rbõgò4sk•¨šs½þ\tÌŧi‡­ÕWaˆ!0Ê‹°t­œ™ÔŽ#š”DƒšÈúoQœôÄmq¦È•—äª=.¬<ŽÖvµ®•I¼ÀnP%Ëí2 Íœ >ÎvÔ•ÃÕf)VcÕf)¼jÕf)Ø8Õf)óðÕf)cظå?ظåKlظåW%ظåƒvظåödá³c3aá³c’òú£œ%ý¨Íb-gÚ/– ÜIï¾,Ö%¬Œ,Ö%ÿµ4iÑ5DITF‹EX<»EXƒLü…íu`Zc?¢`ZcMé`}íÈfÊw«¹fÊwÉ(fÊwâ›fÊw21iµÔ§îrç!žrç!³Îrç!¹Šrç! ¼rç!”9€]tnö’#é:™ZƒLá nÂW£¶UŽí¥ýS=¯©Uլϕ¾¿…ˆb«Â݉‹$ÈìnÌ֣ЮÑô^ÞŠ¥eäìñ”ˆHð‚´€…òÌSô‰5vöi5iô¬5놮q ®’\®çF$ý5À:+õDN.rQRÝ6srIã6srQÔ6sr™:X/nX§~\\ÙÄi•¨h¥iµ¨MÅiµ¨Ëïiµ¨4i»5N¥kµ¨ÌHkµ¨å”xÇ…è+€T++Š‹n‹þny ¥`ý–ÇŠm~œMj¦Q‰k¨©ƒïT°3Š$³š#»l» `± ÅÉ´bɶ%ÄɶŠ?Ëòú_ÏÆò¶ÃÚâêøâïÎSqåš“«êïþíD")ôÖ/\½Î Ó–u&ßp&ßÎÍ&ßæl&ß8Â) ‡ó5´‡‡@92i‘G¥XÍ’QüÃ.¢X•wÝZÜ´ãZÜ´Ó¦\aò‰Â”¯ Dm—zÓfšïî”oŸ,•ö¦ªãä!ªãä2ƪãävªã䓪ãäÐþªãäçñªãäòªãä:s³gâ?@³gâYµ›Z*ð¶CÞjF¶_R¶»ô?>+Æ?®µ†Ê´5ñp×˧ “àT¢¤ á­tnLæ1•EréªåtVéªåÏÌêÚecð:eºü ! ™” a„Zd P±2D ZùŠB ] ù‡È dõ¥²ô n$%K© u¬” w­ÑzQ {„¾3É ƒ"‚Ÿ ƒŒõ‡$ Šö%½ ”:£îç ¥lN‹: ¥lN(î ®X °ÚÞ} ¸¬ufc Å“ƒ% ÆSyB! ËK“¿2 Í¥4_ ÒÝÛ*d Úì5ð1 ÜÅéQG æ 6 êÿbõ& êÿblÙ ïÖ©Ž" ï×VŽ[ ì:‰ n‰Õ 7*Y¨ C'œ ±åÑì )"û| jDJ !XV #x,ª 0L g¬ 5ÞÕ’~ 6 äNV ?ä|W BéÈuŽ Pò9•I a&Ð…î a@7V cöÚrÆ d ÃHë jà5Fù k)Êq· lU–ï nU;n nUM1 qõÊl { D €´Ù~ó ‡¢àðò ‹&¯v iÕí ˜Iœs ˜Iœ<ô ˜IœK/ ˜IœV' ˜Iœƒ< ˜Iœ¢ ˜IœºÂ ˜Iœ× ˜Iœñ. ˜Iœ¼ ˜IœAë ˜IœI% ¥S„8 ¦wþƒ ¨¸…eL ¬,…×ÿ ¶/TF“ Ìùêì Ò¥:ü Ø_Õ² ÚÉE§ âá : ñ¸ø* ò¹2Ù A%øÊ >T& “b lÇ„e f¨J¼ þ•^­ !ª$n¡ &—Néà 9ÿ‰hÌ _DÕJà `ÂEeŽ `ÂEàc aJuŨ dþµG¶ dþµ¬ô g.wI¯ g.wh g.w³™ g.wëO g.wðµ g.wHì jP®ì` j½Ô© m@c' |d¿•' ƒÝ©”˜ Œöò¥t šÛäÓl ¥LNÄ: ¥LN݈ ¶¥’‰] Á¬2 ÊÊc›Î Õìc•† â²Ã| ·ü“ âæ¹R OåvÞ Oå®" ¯åvJ ºEÔÖ tÄ)² U@Ï 8y„cM ;I4©v Oc/z Tli VL#Ú W½…¹» _  a¤^q. e‘´˜Y g䂾 m>ôô pQc†« q6eÂY w²õ‘ ‰žœ ‘TBcù •~hu ž°UŠ\ ¢Ù²w> ¨o>G_ ®i›H ¯yµfH ¯yµ! ¯yµ3— µ‰”› µÚ”$À ·¨Æ ¹^•Ü »~#ˆ Á7ARQ ômõØ ü¼ú üØË ($ÒÉ ª.Bl š 4ú„cƒ @D)ù­ BådÑ DYô5 D¦™èö IŽ5× N³•ƒ¬ OE³Œ” ZG3bo ZYsmB cÁskK k¦Cgp pBq?Ý y…µ$ Ž›t¾ Ž›Ð2 œMIs °ì7ˆ ¸ÛÜ4 Ø}• û Úz çþ¾fÅ ïé " ñY%‚û$yùû$”ó(¢¹“;*ˆÔH]Frj»Grj1P5%ÿ WœU‹Ù’5]Í’5Á{•ÏÇn•ýu ž›n¥u#›n¥Ð•œT S+¥HeH§é´p9­ãÅkõ¯¤åð· r Optionen -> Nicht-System-Partitionen verwalten" und fügen Sie das Volume der Liste hinzu, und das Volume wird nicht mehr als "System" betrachtet. Alternativ können Sie sich in die Gruppe "zulucrypt" und "zulumount" eintragen und alle Einschränkungen werden aufgehoben. "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. DialogMsg &Nein&No DialogMsg&OK&Ok DialogMsg&Ja&Yes DialogMsg DialogDialog DialogMsgFDiesen Dialog nicht erneut anzeigenDo not show this dialog again DialogMsgINFORMATION INFORMATION DialogMsg(Unzureichende Rechte für den Zugriff auf ein Systemgerät im Lese-/Schreibmodus, nur der Benutzer root und Mitglieder der Gruppe zulucrypt dürfen dasƒInsufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that DialogMsgüUnzureichende Rechte für den Zugriff auf ein Systemgerät, nur der Benutzer root und Mitglieder der Gruppe zulucrypt dürfen dasjInsufficient privilege to access a system device, only root user or members of group zulucrypt can do that DialogMsg UUID:UUID: DialogMsg4Sie scheinen nicht genügend Rechte für den Zugriff auf die verschlüsselte Datei im %1 zu haben. Überprüfen Sie die Dateirechte und probieren Sie es erneutwYou do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again DialogMsgAktive Slots active slots DialogMsg Slots: active slots: DialogMsgChiffrecipher DialogMsgChiffre:cipher: DialogMsg Gerätdevice DialogMsg Gerät:device: DialogMsgDateisystem: file system: DialogMsgFreier Platz: free space: DialogMsgfsfs DialogMsgSchlüssellängekey size DialogMsgSchlüssellänge:keysize: DialogMsgSchleifeloop DialogMsgSchleife:loop: DialogMsg Modusmode DialogMsg Modus:mode: DialogMsg Offsetoffset DialogMsgOffset:offset: DialogMsg Größesize DialogMsgTexttext DialogMsgGesamter Platz: total space: DialogMsgTyptype DialogMsgTyp:type: DialogMsgUnbelegtunused DialogMsg Belegtused DialogMsgBelegt %used % DialogMsgBelegter Platz: used space: DialogMsgBelegt%:used%: DialogMsg&Abbrechen&CancelPasswordDialog&Öffnen&OpenPasswordDialog*Einhängepunkt &teilen&Share Mount PointPasswordDialogAbbrechenCancelPasswordDialog4Schlüssel + Schlüsseldatei Key+KeyFilePasswordDialogSchlüsseldateiKeyFilePasswordDialog0LUKS/TrueCrypt/BitLockerLUKS/TrueCrypt/BitLockerPasswordDialog8Im Nu&r-Lese-Modus einhängenMount In &Read Only ModePasswordDialog.Name des Einhängepunkts Mount NamePasswordDialog:Verschlüsseltes Volume öffnenOpen Encrypted VolumePasswordDialogPLAIN DM-CryptPLAIN dm-cryptPasswordDialogPasswortPasswordPasswordDialogErweiterungPluginPasswordDialogTextmarkierung TextLabelPasswordDialogVeraCrypt VeraCryptPasswordDialogVolume-Pfad Volume PathPasswordDialogVolume-Typ Volume TypePasswordDialog(Öffne Schlüsseldatei open key filePasswordDialog$Volume-Pfad öffnenopen volume pathPasswordDialog6Einhängepunktpfad auswählenselect mount point pathPasswordDialogÆ Optionen: d Pfad zu einem Volume, das automatisch aufgeschlossen/eingehängt werden soll m Werkzeug zum Öffnen eines Standard-Dateimanagers (Standard-Werkzeug ist xdg-open) e Starten der Anwendung ohne Anzeige der GUI Í options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI QObjectdDie Ordner "%1" und "%2" müssen beschreibbar sein.'"%1" and "%2" Folders Must Be Writable.QObjectÐDie ausführbare Datei "gpg" konnte nicht in "/usr/local/bin", "/usr/bin" und "/usr/sbin" gefunden werdenNCould not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin"QObject FEHLERERRORQObjecthFailed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit.´Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit.QObjectrDie ausführbare Datei pkexec konnte nicht gefunden werden"Failed to locate pkexec executableQObjectbWenn die Option aktiviert ist, wird in "%1" ein primärer privater Einhängepunkt erstellt und ein sekundärer öffentlich zugänglicher "Spiegel"-Einhängepunkt wird in "%2" erstelltŸIf the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2"QObject&Favoriten verwaltenManage FavoritesQObjectAlle einhängen Mount AllQObjectÜber zuluCryptabout zuluCryptQObjectgpg-Erweiterung. Diese Erweiterung stellt einen Schlüssel wieder her, der in einer gpg-Datei mit einem symmetrischen Schlüssel gesperrt istQgpg plugin. This plugin retrives a key locked in a gpg file with a symmetric keyQObject*hmac-Erweiterung. Diese Erweiterung erzeugt einen Schlüssel mit Hilfe des folgenden Formulars: key = hmac(sha256, Passphrase, Schlüsseldateiinhalt)ohmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents)QObject(keykeyfile-Erweiterung. Diese Erweiterung erzeugt einen Schlüssel mit Hilfe des folgenden Formulars: Schlüssel = Passphrase + Schlüsseldateiinhaltjkeykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contentsQObject8öffentlicher Einhängepunkt: public mount point: QObject„zuluCrypt: Der Verbindungsaufbau mit zuluPolkit ist fehlgeschlagen9zuluCrypt: Failed To Establish Connection With zuluPolkitQObject &Nein&NocreateVolumeDialog&Ja&YescreateVolumeDialogEs wird empfohlen, verschlüsselte Container auf einer zuvor mit Zufallsdaten beschriebenen Partition zu erstellen, um eine Wiederherstellung alter Daten zu verhindern. Möchten Sie Zufallsdaten nach "%1" schreiben, bevor der verschlüsselte Container darin erstellt wird? Sie können den zufälligen Datenschreibprozess jederzeit stoppen, wenn es zu lange dauert und Sie nicht mehr warten können. -It is advised to create encrypted containers over random data to prevent information leakage. Do you want to write random data to "%1" first before creating an encrypted container in it? You can stop the random data writing process anytime you want if it takes too long and you can no longer wait. createVolumeDialogÔDiese Operation wird zum vollständigen Verlust der Daten in "%1" führen. Möchten Sie wirklich fortfahren?sThis operation will lead to permanent destrunction of all present data in "%1". Are you sure you want to continue?createVolumeDialogÜDiese Operation wird zum vollständigen Verlust der Daten in /dev/sdc1 führen. Möchten Sie wirklich fortfahren?wThis operation will lead to permanent destrunction of all present data in /dev/sdc1. Are you sure you want to continue?createVolumeDialogWarnung!! Warning!!createVolumeDialog FEHLERERRORcreateVolumeInExistingFIlePasswortPasswordcreateVolumeInExistingFIleTextmarkierung TextLabelcreateVolumeInExistingFIle(Volume-EigenschaftenVolume PropertiescreateVolumeInExistingFIle* Standardmäßig erzeugt zuluCrypt ein Volume in einem Container, in den vorher Zufallszahlen geschrieben wurden, um Muster der Anwendung des Containers zu verstecken. Dieser Prozess braucht Zeit und kann unter Umständen sehr lange dauern, wenn das zu erstellende Volume sehr groß ist. Es gibt zwar für die Ungeduldigen unter uns die Möglichkeit, den Prozess abzubrechen, aber das hat seinen Preis. Dieser Preis könnte sich als zu hoch erweisen, wenn der verschlüsselte Container bei einer Untersuchung oder für einen Angreifer durch sein Aussehen Rückschlüsse auf den Inhalt zulässt. Da Sie jetzt wissen, was Sie tun, brechen Sie den Vorgang ab, wenn es sein muss. Im Zweifelsfall sollte aber abgewartet werden, bis der Vorgang zu Ende ist. Dadurch sind Sie auf lange Sicht abgesicherter.© By default,zuluCrypt creates a volume in a container file over randomly generated data to hide usage patterns of the container. This process takes time and it may take a very,very long time if the volume about to be created is large enough and this option exists to skip the process for the impatient among us but but it comes at a cost and the cost may be too high when it finally reveal itself while infront of an adversary when they look at the encrypted container and manage to derive meaning based on how the container looks from outside. If you know what you are doing,then continue by all means,if in doubt,my advise is to endure the process and be safer in the long run. createfile% Fertig % Complete createfile&Abbrechen&Cancel createfilešSind Sie wirklich sicher, dass Sie kein gesichertes Volume erstellen möchten?DAre you really sure you do not want to create a more secured volume? createfileˆSind sie sicher, dass Sie das Erstellen der Datei abbrechen möchten?4Are you sure you want to stop file creation process? createfile&ErstellenC&reate createfileXDie Containerdatei muss größer als 3 MB sein&Container file must be bigger than 3MB createfile–Konnte das kryptografische Backend nicht öffnen um Zufallsdaten zu erzeugen=Could not open cryptographic back end to generate random data createfile:Erstelle eine Container-DateiCreate A Container File createfilezSchreibe keine Zufallsdaten in den Container (NICHT empfohlen;Do Not Write Random Data To Container(STRONGLY discouraged) createfileXEs konnte keine Volume-Datei erstellt werdenFailed to create volume file createfilelDie polkit-Unterstützung konnte nicht aktiviert werdenFailed to enable polkit support createfileDateiname File Name createfileDateipfad File Path createfileDateigröße File Size createfile6Das Feld Dateiname ist leerFile name field is empty createfile6Das Feld Dateipfad ist leerFile path field is empty createfile8Das Feld Dateigröße ist leerFile size field is empty createfile‚Es existiert bereits eine Datei mit dem gleichen Namen am ZielortCFile with the same name and at the destination folder already exist createfileGBGB createfileINFORMATIONINFO createfile‚Ungültiges Zeichen im Dateigrößenfeld. Es sind nur Zahlen erlaubt@Illegal character in the file size field.Only digits are allowed createfileKBKB createfileMBMB createfiledDie Operation wurde durch den Benutzer abgebrochen$Operation terminated per user choice createfileBPfad zum Erstellungsort der Datei-Select Path to where the file will be created createfile@Erstellung der Datei abgebrochen!Terminating file creation process createfileTextmarkierung TextLabel createfileWARNUNGWARNING createfile|Sie scheinen keinen Schreibzugriff auf den Zielordner zu haben>You dont seem to have writing access to the destination folder createfile<Einen Verzeichnisdialog öffnenopen a folder dialog box createfileAbbre&chen&Cancel createkeyfileE&rstellenC&reate createkeyfile8Eine Schlüsseldatei erzeugenCreate A KeyFile createkeyfile¤Es existiert bereits eine Datei mit dem gewählten Namen im angegebenen VerzeichnisCFile with the same name and at the destination folder already exist createkeyfileRDas Feld für den Verzeichnispfad ist leer5Folder path to where the key will be created is empty createkeyfile.Pfad zur Schlüsseldatei KeyFile Path createkeyfileFSchlüsseldatei erfolgreich erstelltKeyFile successfully created createkeyfile.Name der Schlüsseldatei Keyfile Name createkeyfile†Prozess unterbrochen, der Schlüssel wurde nicht vollständig erzeugt+Process interrupted,key not fully generated createkeyfile,ZufallszahlengeneratorRNG createkeyfile’Wählen Sie ein Verzeichnis in dem die Schlüsseldatei erstellt werden soll'Select A Folder To Create A Key File In createkeyfileTextmarkierung TextLabel createkeyfilePDas Feld für den Schlüsselnamen ist leerThe key name field is empty createkeyfile‚Sie scheinen keine Schreibrechte für das Zielverzeichnis zu haben>You dont seem to have writing access to the destination folder createkeyfilenOrdner öffnen, in dem eine Schlüsseldatei erstellt wird+open a folder a key file will be created in createkeyfilepPfad zu einem Ordner, in dem ein Schlüssel erstellt wird#path to a folder to create a key in createkeyfile Es wird dringend empfohlen, eine Sicherung der Volume-Kopfdaten "%1" zu erstellen. Bitte lesen Sie die Dokumentation, warum dies wichtig ist.u Creating a backup of the "%1" volume header is strongly advised. Please read documentation on why this is important. createvolume"%1 nicht gefunden %1 not found createvolume&Abbrechen&Cancel createvolumeNMindestens ein benötigtes Feld ist leer#Atleast one required field is empty createvolume BytesBytes createvolume&ErstellenC&reate createvolume€Es kann kein Volume auf einem eingehängten Gerät erstellt werden+Can not create a volume on a mounted device createvolumejKonnte die Passphrase nicht im stillen Modus bekommen%Can not get passphrase in silent mode createvolumeAbbrechenCancel createvolumeXDie Containerdatei muss größer als 3 MB sein&Container file must be bigger than 3MB createvolumejEs konnte kein verschlüsseltes Volume erstellt werden$Could not create an encrypted volume createvolumelKonnte keine Partition mit der angegebenen UUID finden4Could not find any partition with the presented UUID createvolumenKonnte keinen Schlüssel aus der Schlüsseldatei bekommen#Could not get a key from a key file createvolumeVKonnte keinen Schlüssel vom Socket erhalten!Could not get a key from a socket createvolumejKonnte die Passphrase nicht im stillen Modus bekommen'Could not get passphrase in silent mode createvolumejDas Volume konnte nicht zum Schreiben geöffnet werden!Could not open volume for writing createvolumeKonnte nicht genügend Speicher zum Speichern der Schlüsseldatei bekommen/Couldnt get enought memory to hold the key file createvolume,Neues Volume erstellenCreate A New Volume createvolumejDie Standardoption ist der erste Eintrag in der Liste-Default option is the first entry on the list createvolume FEHLERERROR createvolumeFEHLER!ERROR! createvolume„Fehlercode: %1 -- Standardausgabe: %2 -- Standardfehlerausgabe: %3,Error Code: %1 -- StdOut: %2 -- StdError: %3 createvolumeJEs konnte kein Volume erstellt werdenFailed to create a volume createvolumelDie polkit-Unterstützung konnte nicht aktiviert werdenFailed to enable polkit support createvolumeDateisystem File System createvolumeGigaBytes GigaBytes createvolumebDie versteckten Passphrasen stimmen nicht übereinHidden passphrases do not match createvolumepUngültiges Zeichen im Feld Größe des versteckten Volumes:Illegal character detected in the hidden volume size field createvolumerNicht genügend Speicherplatz zum Speichern der Passphrase&Insufficient memory to hold passphrase createvolumerNicht genügend Speicherplatz zum Speichern der Passphrase*Insufficient memory to hold the passphrase createvolumepNicht genügend Speicherplatz zum Speichern Ihrer Antwort)Insufficient memory to hold your response createvolumeDUngültiger Pfad zur SchlüsseldateiInvalid path to key file createvolume¦Es ist am besten, ein verstecktes Volume mit dem Dateisystem vfat/fat zu erstellen.?It is best to create a hidden volume with vfat/fat file system. createvolumeSchlüsselKey createvolume4Schlüssel + Schlüsseldatei Key+KeyFile createvolumeSchlüsseldateiKeyFile createvolume.Pfad zur Schlüsseldatei Keyfile Path createvolumeSchlüsselKeys createvolumeKiloBytes KiloBytes createvolumeLUKSLUKS createvolume,LUKS + Externer HeaderLUKS+External Header createvolume LUKS1LUKS1 createvolume.LUKS1+Externe KopfdatenLUKS1+External Header createvolumeÿÿÿÿLUKS2 createvolume.LUKS1 + Externer HeaderLUKS2+External Header createvolumeLUKS-Volume erfolgreich erstellt, externe Kopfdaten erfolgreich erstellt, aber die Kopfdaten auf dem Gerät konnten nicht gelöscht werdennLuks volume created successfully,external header created successfully but failed to erase header on the device createvolumeBLUKS-Volume erfolgreich erstellt.!Luks volume created successfully. createvolumeMegaBytes MegaBytes createvolumexMehrere Algorithmen werden durch das Zeichen ":" getrennt. 5Multiple algorithms are separated by ":" character.  createvolume$Normales TrueCryptNormal TrueCrypt createvolume$Standard VeraCryptNormal VeraCrypt createvolumeXStandard (+ versteckter Container) TrueCryptNormal+Hidden TrueCrypt createvolumeXStandard (+ versteckter Container) VeraCryptNormal+Hidden VeraCrypt createvolume˜Ein oder mehrere für diese Operation erforderlichen Argument(e) fehlt/fehlen>One or more required argument(s) for this operation is missing createvolumedDie Operation wurde durch den Benutzer abgebrochen%Operation terminated per user request createvolume¤Optionen haben das Format "Algorithmus.Chiffremodus.Schlüssellänge in Bits.Hash" JOptions are in a format of "algorithm.cipher mode.key size in bits.hash"  createvolumebOptionen werden durch das Zeichen "." getrennt. +Options are separated by a "." character.  createvolumePIMPIM createvolumePLAIN DM-CryptPLAIN dm-crypt createvolume2PLAIN DM-Crypt mit OffsetPLAIN dm-crypt with offset createvolume0Passphrasenqualität: %1%Passphrase Quality: %1% createvolume.Passphrasenqualität: 0%Passphrase Quality: 0% createvolume2Passphrasenqualität: 100%Passphrase Quality: 100% createvolumeJDie Passphrasen stimmen nicht übereinPassphrases do not match createvolumePasswortPassword createvolumePfad zum GerätPath To Device createvolumePfad zur Datei Path To File createvolumePfad zum GerätPath to Device createvolume¶Bitte haben Sie Geduld, da die Erstellung eines VeraCrypt-Volumes sehr lange dauern kann. MPlease be patient as creating a VeraCrypt volume may take a very long time.  createvolumeîDas präsentierte Dateisystem wird nicht unterstützt, bitte konsultieren Sie die Dokumentation für weitere InformationenMPresented file system is not supported,see documentation for more information createvolume,ZufallszahlengeneratorRNG createvolume(Passwort wiederholenRepeat Password createvolumeERFOLG!SUCCESS! createvolumeTextmarkierung TextLabel createvolume‚Es scheint ein geöffneter Mapper mit dem Gerät assoziiert zu seinDatei erfolgreich entschlüsselt#Decrypted file created successfully cryptfilesôDie verschlüsselte Datei wurde erfolgreich erstellt, aber die md5 Prüfsumme stimmt nicht. Die Datei könnte beschädigt seinPDecrypted file created successfully but md5 checksum failed,file maybe corrupted cryptfilesÿÿÿÿ Destination cryptfiles0Zielpfad bereits gewähltDestination path already taken cryptfilesRVerschlüsselte Datei erfolgreich erstellt#Encrypted file created successfully cryptfiles:Geben Sie einen Schlüssel ein Enter A Key cryptfiles^Geben Sie einen Pfad zu einer Schlüsseldatei an"Enter A Path To A Keyfile Location cryptfileszDas Schließen der Verschlüsselungsroutinen ist fehlgeschlagen"Failed to close encryption routine cryptfilesPDatei oder Verzeichnis existiert bereits3File or folder already exist at destination address cryptfiles@Das erste Schlüsselfeld ist leerFirst key field is empty cryptfiles¦Einen Schlüssel erzeugen, der aus einer Passphrase und einer Schlüsseldatei besteht4Generate a key made up of a passphrase and a keyfile cryptfiles`Unzureichende Rechte zum Erstellen der Zieldatei1Insufficient privilege to create destination file cryptfilesvUnzureichende Rechte, um die Quelldatei zum Lesen zu öffnen6Insufficient privilege to open source file for reading cryptfilesDUngültiger Pfad zur SchlüsseldateiInvalid path to key file cryptfiles<Ungültiger Pfad zur QuelldateiInvalid path to source file cryptfilesSchlüsselKey cryptfiles4Schlüssel + Schlüsseldatei Key+KeyFile cryptfilesSchlüsseldateiKeyFile cryptfilesFDie Schlüssel stimmen nicht übereinKeys do not match cryptfilesdDie Operation wurde durch den Benutzer abgebrochen%Operation terminated per user request cryptfilesPasswortPassword cryptfiles4Das Quellpfadfeld ist leerPath to source field is empty cryptfiles Der eingegebene Schlüssel stimmt nicht mit dem Verschlüsselungsschlüssel überein.Presented key did not match the encryption key cryptfiles2Schlüssel erneut eingeben Repeat Key cryptfiles(Passwort wiederholenRepeat Password cryptfilesBDas zweite Schlüsselfeld ist leerSecond key field is empty cryptfilesVWählen Sie eine Datei zum Entschlüsseln aus!Select A File You Want To Decrypt cryptfilesVWählen Sie eine Datei zum Verschlüsseln aus!Select A File You Want To Encrypt cryptfilesDWählen Sie eine Schlüsseldatei ausSelect A Keyfile cryptfiles@Wähle Sie den Pfad zur Zieldatei#Select Path to put destination file cryptfiles QuelleSource cryptfilesTextmarkierung TextLabel cryptfilesŒDiese sehr alten verschlüsselten Dateien werden nicht mehr unterstützt6These very old encrypted files are no longer supported cryptfiles‚Sie scheinen keine Schreibrechte für das Zielverzeichnis zu haben>You dont seem to have writing access to the destination folder cryptfiles.Pfad zur Schlüsseldatei keyfile path cryptfiles‚mit zuluCrypt verschlüsselte Dateien (*.zc) ;; Alle Dateien ( * )5zuluCrypt encrypted files ( *.zc ) ;; All Files ( * ) cryptfilesHDiese Meldung nicht erneut anzeigen.Do not show this message again. cryptoinfo Grüße Greetings cryptoinfoOkOk cryptoinfo°Konsultieren Sie für eine Einführung in zuluCrypt bitte "menu->help->open zuluCrypt.pdf" FürAnwender von Unity: das Menü ist in der oberen linken Ecke, wenn zuluCrypt den Fokus hat Die Projekt's Webseite ist: https://mhogomchungu.github.io/zuluCrypt Es empfiehlt sich, vorab die FAQ auf der Webseite zu lesen./Please consult "menu->help->open zuluCrypt.pdf" to get an introduction on zuluCrypt. Unity users,the menu is on the upper left corner of the screen when zuluCrypt has focus. Project's homepage is at: https://mhogomchungu.github.io/zuluCrypt Recommending reading FAQ page from the project's main page. cryptoinfoS&chließen&Close debugWindow&LöschenC&lear debugWindow,zuluCrypt DebugfensterzuluCrypt Debug Window debugWindow &Nein&Nodialogokÿÿÿÿ&Okdialogok&Ja&Yesdialogok DialogDialogdialogokTextmarkierung TextLabeldialogok% fertig % Completed erasedevice&Abbrechen&Cancel erasedevice &Start&Start erasedeviceæSind Sie wirklich sicher, dass Sie Zufallsdaten nach "%1" schreiben möchten, um alle Inhalte effektiv zu zerstören?dAre you really sure you want to write random data to "%1" effectively destroying all contents in it? erasedevicenKonnte keinen Mapper auf dem eingehangenen Gerät öffnen)Can not open a mapper on a mounted device erasedeviceˆEs kann nicht auf ein Gerät mit geöffnetem Mapper geschrieben werden,Can not write on a device with opened mapper erasedeviceJEs konnte kein Mapper erstellt werdenCould not create mapper erasedeviceKonnte nicht genügend Speicher zum Speichern der Schlüsseldatei bekommen1Could not get enought memory to hold the key file erasedeviceVDer Gerätpfad konnte nicht aufgelöst werdenCould not resolve device path erasedeviceHKonnte nicht auf das Gerät schreibenCould not write to the device erasedevicefDie Daten auf dem Gerät wurden erfolgreich gelöscht&Data on the device successfully erased erasedevice6Das Gerätepfadfeld ist leerDevice path field is empty erasedevice6Der Gerätepfad ist ungültigDevice path is invalid erasedevicevGeben Sie den Pfad zum Volume ein, das gelöscht werden soll!Enter Path To Volume To Be Erased erasedeviceˆDaten auf dem Gerät durch das Überschreiben mit Zufallsdaten löschen9Erase Data On The Device By Writing Random Data Over Them erasedevicelDie polkit-Unterstützung konnte nicht aktiviert werdenFailed to enable polkit support erasedevice€Unzureichende Rechte zum Öffnen der Schlüsseldatei für das Lesen3Insufficient privilege to open key file for reading erasedevice2Ungültiger Pfad zum GerätInvalid path to device erasedevicedDie Operation wurde durch den Benutzer abgebrochen$Operation terminated per user choice erasedeviceHDie Passphrasendatei existiert nichtPassphrase file does not exist erasedevicePfad zum GerätPath to Device erasedeviceªDie Richtlinien verhindern, dass normale Benutzer Mapper auf Systempartitionen öffnen@Policy prevents non root user opening mapper on system partition erasedeviceHZufallsdaten erfolgreich geschrieben Random data successfully written erasedeviceŠWählen Sie eine Nicht-Systempartition aus, um deren Inhalt zu löschen3Select A Non System Partition To Erase Its Contents erasedeviceTextmarkierung TextLabel erasedevice$Der nächte Dialog schreibt Zufallsdaten auf das Gerät, wodurch der Inhalt permanent gelöscht wird. Sind Sie sicher, dass Sie fortfahren möchten? The next dialog will write random data to a device leading to permanent loss of all contents on the device. Are you sure you want to continue?  erasedevice^Dieses Gerät scheint bereits im Einsatz zu sein'This device appear to already be in use erasedeviceWARNUNGWARNING erasedeviceWARUNG!WARNING! erasedevice`Überschreibe existierende Daten mit Zufallsdaten$Write Random Data Over Existing Data erasedevice`Überschreibe existierende Daten mit Zufallsdaten&Writing Random Data Over Existing Data erasedeviceFe&stlegen&Set fileManagerÌGeben Sie unten den Namen der Anwendung ein, die Sie zum Öffnen von Einhängepunkten verwenden möchten.QEnter Below The Name Of The Application You Want To Be Used To Open Mount Points. fileManager,Dateimanager festlegenSet File Manager fileManagerTextmarkierung TextLabel fileManagerS&chließen&ClosehelpzuluCrypt.pdf konnte nicht geöffnet werden. Stellen Sie sicher, dass Ihr System PDF-Dateien mit "%1" öffnen kann und versuchen Sie es erneutcFailed to open zuluCrypt.pdf,make sure your system can open pdf files using "%1" tool and try againhelp HilfeHelphelp&PDF öffnen Open &PDFhelpWARNUNG!WARNING!help‚ Passwort, das dem verschlüsselten Volume hinzugefügt werden soll- Password To Be Added To The Encrypted Volume luksaddkey&Hinzufügen&Add luksaddkey&Abbrechen&Cancel luksaddkey<Schlüssel zu Volume hinzufügenAdd A Key To A Volume luksaddkeyªAlle Schlüsselslots sind belegt, es konnte kein weiterer Schlüssel hinzugefügt werden5All key slots are occupied, can not add any more keys luksaddkeyNMindestens ein benötigtes Feld ist leer#Atleast one required field is empty luksaddkeylKonnte keine Partition mit der angegebenen UUID finden2Can not find a partition that match presented UUID luksaddkeyjKonnte die Passphrase nicht im stillen Modus bekommen%Can not get passphrase in silent mode luksaddkeyAbbrechenCancel luksaddkeyVKonnte keinen Schlüssel vom Socket bekommen!Could not get a key from a socket luksaddkey°Konnte keine erhöhten Berechtigungen bekommen, überprüfen Sie die binären Berechtigungen9Could not get elevated privilege,check binary permissions luksaddkeyXDas LUKS-Volume konnte nicht geöffnet werdenCould not open luks volume luksaddkeynDas Volume konnte nicht im Schreibmodus geöffnet werden#Could not open volume in write mode luksaddkeyKonnte nicht genügend Speicher zum Speichern der Schlüsseldatei bekommen/Couldnt get enought memory to hold the key file luksaddkey:Das Gerät ist kein LUKS-GerätDevice is not a luks device luksaddkeyFEHLER!ERROR! luksaddkey>Pfad zum verschlüsselten VolumeEncrypted Volume Path luksaddkey:Geben Sie einen Schlüssel ein Enter A Key luksaddkey:Geben Sie einen Schlüssel ein Enter a key luksaddkey^Geben Sie einen Pfad zu einer Schlüsseldatei an"Enter a path to a keyfile location luksaddkey„Fehlercode: %1 -- Standardausgabe: %2 -- Standardfehlerausgabe: %3,Error Code: %1 -- StdOut: %2 -- StdError: %3 luksaddkey6Existierende SchlüsseldateiExisting KeyFile luksaddkeylDie polkit-Unterstützung konnte nicht aktiviert werdenFailed to enable polkit support luksaddkeyrNicht genügend Speicherplatz zum Speichern der Passphrase&Insufficient memory to hold passphrase luksaddkey(Unzureichende Rechte, um einen Schlüssel zu einem Systemgerät hinzuzufügen, nur der Benutzer root oder Mitglieder der Gruppe "zulucrypt" dürfen das sInsufficient privilege to add a key to a system device, only root user or members of group "zulucrypt" can do that  luksaddkeyxUnzureichende Rechte zum Öffnen der Schlüsseldatei zum Lesen3Insufficient privilege to open key file for reading luksaddkeyDSchlüssel erfolgreich hinzugefügt.Key added successfully. luksaddkeySchlüssel erfolgreich hinzugefügt. %1 / %2 Slots sind jetzt in Benutzung4Key added successfully. %1 / %2 slots are now in use luksaddkey4Schlüssel + Schlüsseldatei Key+KeyFile luksaddkeySchlüsseldateiKeyFile luksaddkey.Pfad zur Schlüsseldatei KeyFile Path luksaddkey.Pfad zur Schlüsseldatei KeyFile path luksaddkeyFDie Schlüssel stimmen nicht übereinKeys do not match luksaddkeyLUKSLUKS luksaddkey&Neue Schlüsseldatei New KeyFile luksaddkeyVDie neuen Passphrasen stimmen nicht übereinNew passphrases do not match luksaddkeyfEine oder beide Schlüsseldatei(en) existieren nicht%One or both keyfile(s) does not exist luksaddkeyzEin oder mehrere Argument(e) für diese Operation fehlt/fehlen>One or more required argument(s) for this operation is missing luksaddkeyPIMPIM luksaddkey0Passphrasenqualität: %1%Passphrase Quality: %1% luksaddkey.Passphrasenqualität: 0%Passphrase Quality: 0% luksaddkey2Passphrasenqualität: 100%Passphrase Quality: 100% luksaddkeyPasswortPassword luksaddkeypPasswort ist bereits im verschlüsselten Volume vorhanden(Password Already In The Encrypted Volume luksaddkeyŒDer vorgelegte Schlüssel stimmt mit keinem Schlüssel im Volume überein2Presented key does not match any key in the volume luksaddkey0Passwort erneut eingebenReenter Password luksaddkeyTextmarkierung TextLabel luksaddkeyTrueCrypt TrueCrypt luksaddkeyVeraCrypt VeraCrypt luksaddkeyVolume-Pfad Volume Path luksaddkeyVolume-Typ Volume Type luksaddkey>Das Volume ist kein LUKS-VolumeVolume is not a luks volume luksaddkeyÖffne Datei open file luksaddkey(Öffne Schlüsseldatei open keyfile luksaddkeyÖffne Partitionopen partition luksaddkeyx Sind Sie sicher, dass Sie diesen Schlüssel löschen möchten?* Are you sure you want to delete this key? luksdeletekeyì Das Löschen dieses Schlüssels führt dazu, dass das Volume nicht mehr geöffnet werden kann und für immer verloren ist.> Deleting it will make the volume unopenable and lost forever. luksdeletekey&Abbrechen&Cancel luksdeletekey&Löschen&Delete luksdeletekeyNMindestens ein benötigtes Feld ist leer#Atleast one required field is empty luksdeletekeylKonnte keine Partition mit der angegebenen UUID finden2Can not find a partition that match presented UUID luksdeletekeyjKonnte die Passphrase nicht im stillen Modus bekommen%Can not get passphrase in silent mode luksdeletekeyVKonnte keinen Schlüssel vom Socket bekommen!Could not get a key from a socket luksdeletekey„Konnte nicht genug Speicher zum Halten der Schlüsseldatei bekommen0Could not get enough memory to open the key file luksdeletekeyNDas Volume konnte nicht geöffnet werdenCould not open the volume luksdeletekeynDas Volume konnte nicht im Schreibmodus geöffnet werden'Could not open the volume in write mode luksdeletekeyFEHLER!ERROR! luksdeletekey:Geben Sie einen Schlüssel ein Enter a key luksdeletekey^Geben Sie einen Pfad zu einer Schlüsseldatei an"Enter a path to a keyfile location luksdeletekey„Fehlercode: %1 -- Standardausgabe: %2 -- Standardfehlerausgabe: %3,Error Code: %1 -- StdOut: %2 -- StdError: %3 luksdeletekeylDie polkit-Unterstützung konnte nicht aktiviert werdenFailed to enable polkit support luksdeletekeyrNicht genügend Speicherplatz zum Speichern der Passphrase&Insufficient memory to hold passphrase luksdeletekeypNicht genügend Speicherplatz zum Speichern Ihrer Antwort)Insufficient memory to hold your response luksdeletekeyôUnzureichende Rechte zum Zugriff auf ein Systemgerät, nur der Benutzer root und Mitglieder der Gruppe zulucrypt dürfen dasgInsufficient privilege to open a system device,only root user or members of group zulucrypt can do that luksdeletekeyxUnzureichende Rechte zum Öffnen der Schlüsseldatei zum Lesen3Insufficient privilege to open key file for reading luksdeletekeybSchlüsseldatei mit einer zu löschenden Passphrase$Key File With A Passphrase To Delete luksdeletekey†Schlüssel erfolgreich gelöscht. %1 / %2 Slots sind nun in Benutzung6Key removed successfully. %1 / %2 slots are now in use luksdeletekey4Schlüssel + Schlüsseldatei Key+KeyFIle luksdeletekeySchlüsseldateiKeyFile luksdeletekey.Pfad zur Schlüsseldatei KeyFile path luksdeletekeyDDie Schlüsseldatei existiert nichtKeyfile does not exist luksdeletekeyzEin oder mehrere Argument(e) für diese Operation fehlt/fehlen>One or more required argument(s) for this operation is missing luksdeletekeydDie Operation wurde durch den Benutzer abgebrochen%Operation terminated per user request luksdeletekeyPasswortPassword luksdeletekeyHSchlüssel aus einem Volume entfernenRemove A Key From A Volume luksdeletekeyTextmarkierung TextLabel luksdeletekeyŽDer eingegebene Schlüssel stimmt mit keinem Schlüssel im Volume überein:There is no key in the volume that match the presented key luksdeletekeyfEs gibt nur noch einen letzten Schlüssel im Volume.)There is only one last key in the volume. luksdeletekeyVolume-Pfad Volume Path luksdeletekey>Das Volume ist kein LUKS-VolumeVolume is not a luks volume luksdeletekeyWARNUNGWARNING luksdeletekey2Öffne eine Schlüsseldateiopen a keyfile luksdeletekey@Eine verschlüsselte Datei öffnenopen an encrypted file luksdeletekeyHEine verschlüsselte Partition öffnenopen an encrypted partition luksdeletekey&Fertig&DonemanageSystemVolumes"Gerät &hinzufügen Add Dev&icemanageSystemVolumes"Datei &hinzufügen Add Fi&lemanageSystemVolumes‚Sind Sie sicher, dass Sie "%1" aus der Liste entfernen möchten?5Are you sure you want to remove "%1" from the list?manageSystemVolumesAbbrechenCancelmanageSystemVolumes0System-Volumes verwaltenManage System VolumesmanageSystemVolumes,Pfad zu System-VolumesPath To System VolumesmanageSystemVolumes6Entferne markierten EintragRemove Selected EntrymanageSystemVolumes@Pfad zum System-Volume auswählenSelect Path To System VolumemanageSystemVolumesWARNUNGWARNINGmanageSystemVolumes&Backup&BackupmanagevolumeheaderAbbre&chen&Cancelmanagevolumeheader"&Wiederherstellen&RestoremanagevolumeheaderÞSind Sie sicher, dass Sie die Kopfdaten auf dem Gerät "%1" mit einer Sicherungskopie von "%2" ersetzen möchten?TAre you sure you want to replace a header on device "%1" with a backup copy at "%2"?managevolumeheaderzArgument für den Pfad zur Sicherung der Kopfdaten-Datei fehlt5Argument for path to a backup header file is missingmanagevolumeheaderNMindestens ein benötigtes Feld ist leer#Atleast one required field is emptymanagevolumeheader0Volume-Kopfdaten sichernBack up volume headermanagevolumeheaderÿÿÿÿ Backup Namemanagevolumeheader0Volume-Kopfdaten sichernBackup Volume HeadermanagevolumeheaderzDie Sicherungsdatei scheint keine LUKS-Kopfdaten zu enthalten2Backup file does not appear to contain luks headermanagevolumeheader&ErstellenC&reatemanagevolumeheaderPKonnte den Pfad zum Gerät nicht auflösen Could not resolve path to devicemanagevolumeheaderFEHLER!ERROR!managevolumeheaderlDie polkit-Unterstützung konnte nicht aktiviert werdenFailed to enable polkit supportmanagevolumeheaderTKonnte die gewählte Aktion nicht ausführen%Failed to perform requested operationmanagevolumeheader„Konnte die angeforderte Aktion auf dem LUKS-Volume nicht ausführen8Failed to perform requested operation on the LUKS volumemanagevolumeheaderNKopfdaten erfolgreich wiederhergestelltHeader restored successfullymanagevolumeheaderšKopfdaten erfolgreich gespeichert. Wenn möglich, bewahren Sie sie sicher auf.9Header saved successfully. If possible,store it securely.managevolumeheaderINFORMATION!INFO!managevolumeheader¨Unzureichende Rechte zum Erstellen einer Sicherung der Kopfdaten in einem ZielordnerHInsufficient privilege to create a backup header in a destination foldermanagevolumeheaderŠUnzureichende Rechte zum Öffnen der Sicherung der Kopfdaten zum Lesen=Insufficient privilege to open backup header file for readingmanagevolumeheaderjUnzureichende Rechte um das Gerät zum Lesen zu öffnen1Insufficient privilege to open device for readingmanagevolumeheaderrUnzureichende Rechte um das Gerät zum Schreiben zu öffnen1Insufficient privilege to open device for writingmanagevolumeheader^Ungültiger Pfad zum Sichern der Kopfdaten-Datei#Invalid path to back up header filemanagevolumeheader2Ungültiger Pfad zum GerätInvalid path to devicemanagevolumeheaderSchlüsseldateiKeyFilemanagevolumeheader0LUKS-Kopfdaten verwaltenManage A LUKS Headermanagevolumeheader:TrueCrypt-Kopfdaten verwaltenManage A TrueCrypt Headermanagevolumeheader@Einen VeraCrypt Header verwaltenManage A VeraCrypt HeadermanagevolumeheaderNormales Volume Normal VolumemanagevolumeheaderNur der Benutzer root und Miglieder der Gruppe "zulucrypt" können LUKS-Kopfdaten auf Systemgeräten erstellen und wiederherstellen]Only root user and "zulucrypt" members can restore and back up luks headers on system devicesmanagevolumeheader>Aktion vom Anwender abgebrochen%Operation terminater per user requestmanagevolumeheaderLNUR das Passwort für das äußere VolumeOuter Volume Password ONLYmanagevolumeheaderPIMPIMmanagevolumeheaderPasswortPasswordmanagevolumeheaderPasswortquellePassword SourcemanagevolumeheaderjDer zu verwendende Pfad für eine Sicherung ist belegt4Path to be used to create a back up file is occupiedmanagevolumeheaderTDas präsentierte Gerät ist kein LUKS-Gerät%Presented device is not a LUKS devicemanagevolumeheaderBVolume-Kopfdaten wiederherstellenRestore volume headermanagevolumeheader ERFOLGSUCCESSmanagevolumeheader|Wählen Sie eine Datei mit der Sicherung der LUKS-Kopfdaten aus'Select A File With A LUKS Backup HeadermanagevolumeheadernWählen Sie einen Ordner zur Sicherung der Kopfdaten aus#Select A Folder To Store The HeadermanagevolumeheaderŽWählen Sie den LUKS-Container aus, dessen Kopfdaten Sie sichern möchten3Select luks container you want to backup its headermanagevolumeheaderTextmarkierung TextLabelmanagevolumeheader|Ein Unbekannter FEHLER mit der Statusnummer %1 ist aufgetreten5Unrecognized ERROR! with status number %1 encounteredmanagevolumeheaderVolume-Pfad Volume PathmanagevolumeheaderVolume-Typ Volume TypemanagevolumeheaderWarnung!WARNING!managevolumeheader`Verschlüsseltes Volume über das gesamte LaufwerkWhole Drive Encrypted Volumemanagevolumeheader*Windows System-VolumeWindow System VolumemanagevolumeheaderŒFalsches Passwort eingegeben oder das Volume ist kein TrueCrypt-Volume:Wrong password entered or volume is not a truecrypt volumemanagevolumeheaderŒFalsches Passwort eingegeben oder das Volume ist kein VeraCrypt-Volume:Wrong password entered or volume is not a veracrypt volumemanagevolumeheader´Die vorherige Instanz scheint abgestürzt zu sein, versuche sie vor dem Start zu bereinigenIPrevious instance seem to have crashed,trying to clean up before starting oneinstancehEs scheint bereits eine Instanz zu laufen, breche ab:There seem to be another instance running,exiting this one oneinstance&Abbrechen&Cancel openvolume &Hilfe&Help openvolume&Öffnen&Open openvolumeîEine Liste aller Patitionen des Systems wird hier angezeigt. Klicken Sie doppelt auf einen Eintrag, um ihn zu verwenden[A list of all partitions on this system are displayed here. Double click an entry to use it openvolume FEHLERERROR openvolumeINFORMATIONINFO openvolumefEs können nur crypto_LUKS-Volumes ausgewählt werden(Only crypto_LUKS volumes can be selected openvolumeˆStarten Sie die Anwendung von einem root-Konto aus neu oder nachdem Sie sich der Gruppe "zulucrypt" hinzugefügt haben, wenn das Volume, das Sie verwenden möchten, nicht in der Liste enthalten ist.˜Restart the tool from root's account or after you have created and added yourself to group "zulucrypt" if the volume you want to use is not on the list. openvolume¬Wählen Sie eine Partition aus, in der Sie ein verschlüsseltes Volume erstellen möchten3Select A Partition To Create An Encrypted Volume In openvolumePWählen Sie eine Partition zum Öffnen ausSelect A Partition To Open openvolumenWählen Sie eine verschlüsselte Partition zum Öffnen aus%Select An Encrypted Partition To Open openvolume&UUID verwenden Use &UUID openvolumeUUID verwendenUse UUID openvolumeøSie sind der Benutzer root und alle Partitionen werden angezeigt. Klicken Sie doppelt auf einen Eintrag, um ihn zu verwendenUYou are a root user and all partitions are displayed. Double click an entry to use it openvolumeBezeichnunglabel openvolumePartition partition openvolume Größesize openvolumeTyptype openvolumeUUIDuuid openvolume†Das "/" Zeichen ist im Namensfeld des Einhängepunktes nicht erlaubt0"/" character is not allowed in mount name fieldpasswordDialogzDie Optionen -O und -m können nicht zusammen verwendet werden*-O and -m options can not be used togetherpasswordDialog°Ein nicht unterstütztes Gerät wurde gefunden, das Gerät fehlt oder Sie haben keine Berechtigung. Mögliche Gründe für diesen Fehler sind: 1. Der Gerätepfad ist ungültig. 2. Das Gerät hat eine LVM oder MD-RAID Signatur¸A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signaturepasswordDialogVMindestens ein erforderliches Feld ist leer#Atleast one required field is emptypasswordDialogAbbrechenCancelpasswordDialog”Aktivieren Sie dieses Kontrollkästchen, um das Passwort sichtbar zu machen'Check This Box To Make Password VisiblepasswordDialogdWählen sie eine Schlüsseldatei aus dem Dateisystem%Choose A KeyFile From The File SystempasswordDialogXWählen Sie ein Modul aus dem Dateisystem aus$Choose A Module From The File SystempasswordDialogVKonnte keine Sperre für /etc/mtab erstellen$Could not create a lock on /etc/mtabpasswordDialog´Es konnte kein Einhängepunkt erstellt werden, ungültiger Pfad oder bereits vergebener Pfad@Could not create mount point, invalid path or path already takenpasswordDialog\Konnte keine Passphrase von dem Modul erhalten*Could not get a passphrase from the modulepasswordDialogpKonnte keine Passphrase über den lokalen Socket erhalten1Could not get a passphrase through a local socketpasswordDialogKonnte nicht genügend Speicher zum Speichern der Schlüsseldatei bekommen1Could not get enought memory to hold the key filepasswordDialogjKonnte die Passphrase nicht im stillen Modus erhalten'Could not get passphrase in silent modepasswordDialog FEHLERERRORpasswordDialogFEHLER!ERROR!passwordDialog:Geben Sie einen Schlüssel ein Enter A KeypasswordDialog°Geben Sie einen Modulnamen ein, der verwendet werden soll, um die Passphrase zu bekommen,Enter A Module Name To Use To Get PassphrasepasswordDialog^Geben Sie einen Pfad zu einer Schlüsseldatei an"Enter A Path To A Keyfile LocationpasswordDialog„Fehlercode: %1 -- Standardausgabe: %2 -- Standardfehlerausgabe: %3,Error Code: %1 -- StdOut: %2 -- StdError: %3passwordDialog€Das Abrufen eines Schlüssels aus dem Netzwerk ist fehlgeschlagen$Failed to get a key from the networkpasswordDialogøKonnte kein Dateisystem einhängen: ungültige/nicht unterstützte Einhängeoption oder nicht unterstütztes Dateisystem entdecktdFailed to mount a filesystem:invalid/unsupported mount option or unsupported file system encounteredpasswordDialogÂKonnte das NTFS/EXFAT-Dateisystem mit ntfs-3g nicht einhängen, ist das ntfs-3g-Paket installiert?XFailed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed?passwordDialogrNicht genügend Speicherplatz zum Speichern der Passphrase&Insufficient memory to hold passphrasepasswordDialog”Unzureichende Rechte zum Einhängen des Geräts mit den angegebenen Optionen=Insufficient privilege to mount the device with given optionspasswordDialogâUnzureichende Rechte zum Öffnen eines System-Volumes. Siehe Menü->Hilfe->Berechtigung für weitere Informationen dInsufficient privilege to open a system volume. Consult menu->help->permission for more informaion passwordDialog¾Unzureichende Rechte zum Öffnen des Geräts im Schreib-/Lesemodus oder das Gerät existiert nichtQInsufficient privilege to open device in read write mode or device does not existpasswordDialogxUnzureichende Rechte zum Öffnen der Schlüsseldatei zum Lesen3Insufficient privilege to open key file for readingpasswordDialogTInterne Brieftasche ist nicht konfiguriert!Internal wallet is not configuredpasswordDialogDUngültiger Pfad zur SchlüsseldateiInvalid path to key filepasswordDialog.Pfad zur Schlüsseldatei KeyFile PathpasswordDialog"%1" einhängen Mount "%1"passwordDialognEs existiert keine Datei oder Gerät am angegebenen Pfad%No file or device exist on given pathpasswordDialog OffsetOffsetpasswordDialog Offset wird in Sektoren sein, wenn die Eingabe nur aus Ziffern besteht oder in Byte, wenn der Eintrag mit "b" endet oder in Kilobyte, wenn der Eintrag mit "k" endet oder in Megabyte, wenn der Eintrag mit "m" endet oder in Terabyte, wenn der Eintrag mit "t" endetìOffset Will Be In Sectors If The Entry Is Made Up Of Only Digits And In Bytes If The Entry Ends With "b" And In Kilobytes If The Entry Ends With "k" And In Megabytes If The Entry Ends With "m" And In Terabytes If The Entry Ends With "t"passwordDialogzEin oder mehrere Argument(e) für diese Operation fehlt/fehlen>One or more required argument(s) for this operation is missingpasswordDialogNNur root kann diese Operation ausführen)Only root user can perform this operationpasswordDialogPIM-Wert PIM ValuepasswordDialogPasswortPasswordpasswordDialog Erweiterungsname Plugin NamepasswordDialog<Wählen Sie ein Schlüssel-ModulSelect A Key ModulepasswordDialog<Wählen Sie eine schlüsseldateiSelect A KeyFilepasswordDialog@Verschlüsseltes Volume auswählenSelect Encrypted volumepasswordDialogbWählen sie den Pfad zum Einhängepunkt des Ordners!Select Path To Mount Point FolderpasswordDialogjDer gemeinsame Einhängepunktpfad ist bereits vergeben%Shared mount point path already takenpasswordDialog²Es scheint ein geöffnetes Volumen zu geben, das mit der angegebenen Adresse verknüpft ist=There seem to be an open volume accociated with given addresspasswordDialog‚Es scheint ein geöffneter Mapper mit dem Gerät assoziiert zu seinWählen Sie eine Schlüssel-DateiSelect A KeyFiletcrypt&TrueCeypt-SchlüsselTrueCrypt Keystcrypt:TrueCrypt/VeraCrypt-SchlüsselTrueCrypt/VeraCrypt KeystcryptpSchlüssel-Dateien per Drag-and-Drop der Liste hinzufügen/drag and drop key files to add them to the listtcrypt6Vergangene Zeit: %0 MinutenElapsed time: %0 minutesutility::veraCryptWarning6Vergangene Zeit: %0SekundenElapsed time: %0 secondsutility::veraCryptWarning6Vergangene Zeit: 0 SekundenElapsed time: 0 secondsutility::veraCryptWarningºBitte haben Sie Geduld, da das Aufschließen eines VeraCrypt-Volumes sehr lange dauern kann. NPlease be patient as unlocking a VeraCrypt volume may take a very long time. utility::veraCryptWarningHDiese Warnung nicht erneut anzeigen.Dont Show This Warning Again.warnWhenExtendingContainerFileWICHTIG!!! IMPORTANT!!!warnWhenExtendingContainerFileOKOKwarnWhenExtendingContainerFileWARNUNG!! WARNING!!warnWhenExtendingContainerFileXIhre Cover-Datei wird unwiderruflich geändert und wir empfehlen, mit einer Sicherungsdatei fortzufahren und nicht mit dem Original. Um das zu erstellende Volume freizuschalten, müssen Sie das von Ihnen gewählte Passwort und den von zuluCrypt automatisch generierten Volume-Offset eingeben. Anweisungen zum Entsperren des Volumes lauten wie folgt: 1. Wählen Sie im Menü Öffnen -> Volume in einer Datei 2. Wählen Sie die Datei aus und wählen Sie dann "Volume-Typ" = PLAIN dm-crypt. 3. Geben Sie den generierten Offset-Wert zusammen mit Ihrem Passwort ein. òYour cover file will be irreversibly changed and we suggest continuing with a backup file and not the original. To unlock the volume about to be created, you will need to enter the password you will choose and the volume offset automatically generated by zuluCrypt. Instructions to unlock the volume are as follows: 1. From the menu, choose Open -> Volume Hosted In A File. 2. Select file, then choose "Volume Type" = PLAIN dm-crypt. 3. Enter the generated offset value along with your password. warnWhenExtendingContainerFiler LUKS, TrueCrypt und VeraCrypt-basierte verschlüsselte Volumes haben sogenannte "Volume-Kopfdaten". Volume-Kopfdaten sind verantwortlich für die Speicherung von Informationen, die zum Öffnen der Kopfdaten mit verschlüsseltem Volume erforderlich sind, und jede Beschädigung macht es unmöglich, das Volume zu öffnen, was zum dauerhaften Verlust verschlüsselter Daten führt. Die Beschädigung der Kopfdaten wird in der Regel durch versehentliche Formatierung des Geräts oder durch die Verwendung einiger fehlerhafter Partitionierungswerkzeuge oder falscher Zusammenstellungen von logischen Volumes verursacht. Eine Sicherung der Volume-Kopfdaten wird dringend empfohlen, da nur so die verschlüsselten Daten nach der Wiederherstellung der Kopfdaten wieder zugänglich sind, wenn die Kopfdaten auf dem Volume beschädigt werden. Ÿ LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a "volume header". A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data. The damage to the header is usually caused by accidental formatting of the device or use of some buggy partitioning tools or wrongly reassembled logical volumes. Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted.  zuluCrypt &Über&About zuluCryptJ&Schlüssel zu einem Volume hinzufügen&Add A Key To A Volume zuluCryptB&Einhängepunkt automatisch öffnen&Auto Open Mount Point zuluCrypt$Kopfdaten &sichern&Backup Header zuluCryptJ&Internes Brieftaschenpasswort ändern &Change Internal Wallet Password zuluCryptDAlle geöffneten Volumes s&chließen&Close All Opened Volumes zuluCrypt&Erstellen&Create zuluCrypt2&Eine Datei entschlüsseln&Decrypt A File zuluCryptF&Schlüssel aus einem Volume löschen&Delete A Key From A Volume zuluCrypt^&Verschlüsselter Container in einer neuen Datei"&Encrypted Container In A New File zuluCrypt:&Daten in einem Gerät löschen&Erase Data In A Device zuluCrypt&Favoriten &Favorites zuluCrypt(&Kopfdaten-Sicherung&Header Backup zuluCrypt &Hilfe&Help zuluCrypt &Schlüssel-Datei&KeyFile zuluCrypt(&Favoriten verwalten&Manage Favorites zuluCrypt.&Ins Systray minimieren&Minimize To Tray zuluCrypt&Öffnen&Open zuluCrypt&Schließen&Quit zuluCrypt6Kopfdaten wiede&rherstellen&Restore Header zuluCrypt$&Sprache auswählen&Select Language zuluCrypt&Systray-Symbol &Tray Icon zuluCrypt,Volume-Liste &erneuern&Update Volume List zuluCrypt,&Volume in einer Datei&Volume Hosted In A File zuluCrypt&Volumes&Volumes zuluCrypt&zC&zC zuluCrypt(Schlüssel hinzufügenAdd Key zuluCrypt.Zu Favoriten hinzufügenAdd To Favorite zuluCrypt Alt+VAlt+V zuluCrypt,LUKS-Kopfdaten sichernBackup LUKS Header zuluCrypt0Volume-Kopfdaten sichernBackup Volume Header zuluCryptAbbrechenCancel zuluCrypt¨Schließen fehlgeschlagen, es wurde keine Partition mit der angegebenen UUID gefundenBClose failed, could not find any partition with the presented UUID zuluCryptŠSchließen fehlgeschlagen, konnte keine Sperre auf /etc/mtab~ erhalten0Close failed, could not get a lock on /etc/mtab~ zuluCrypt–Schließen fehlgeschlagen, der Pfad zum Gerät konnte nicht aufgelöst werden 4Close failed, could not resolve full path of device  zuluCryptœSchließen fehlgeschlagen, für das Volume wurden mehrere Einhängepunkte erkannt;Close failed, multiple mount points for the volume detected zuluCryptžSchließen fehlgeschlagen, eine oder mehrere Dateien im Volume werden verwendet.9Close failed, one or more files in the volume are in use. zuluCrypt¦Schließen fehlgeschlagen, der gemeinsame Einhängepunkt scheint ausgelastet zu sein 3Close failed, shared mount point appear to be busy  zuluCrypt$Schließen fehlgeschlagen, der gemeinsame Einhängepunkt scheint in einem ungewöhnlichen Zustand zu sein. Es wird empfohlen, ihn manuell auszuhängen^Close failed, shared mount point appear to be in an ambiguous state,advice to unmount manually zuluCryptSchließen fehlgeschlagen, der gemeinsame Einhängepunkt scheint einem anderen Benutzer zu gehören oder es wurden mehrere Einhängepunkte erkannt hClose failed, shared mount point appear to belong to a different user or multiple mount points detected  zuluCryptŠSchließen fehlgeschlagen, das Volume hat keinen Eintrag in /etc/mstab8Close failed, volume does not have an entry in /etc/mtab zuluCryptÒSchließen fehlgeschlagen, das Volume ist nicht geöffnet oder es wurde von einem anderen Benutzer geöffnetBClose failed, volume is not open or was opened by a different user zuluCrypt.Schließen fehlgeschlagen, das Volume ist nicht eingehängt, aber der Mapper konnte nicht geschlossen werden. Es wird empfohlen, ihn manuell zu schließenXClose failed, volume is unmounted but could not close mapper,advice to close it manually zuluCrypt&Kontakt-Info Contact &Info zuluCryptÚDer Einhängepunkt konnte nicht geöffnet werden, weil das Werkzeug "%1" nicht richtig zu funktionieren scheintTCould not open mount point because "%1" tool does not appear to be working correctly zuluCrypt Strg+ACtrl+A zuluCrypt Strg+BCtrl+B zuluCrypt Strg+CCtrl+C zuluCrypt Strg+DCtrl+D zuluCrypt Strg+ECtrl+E zuluCrypt Strg+FCtrl+F zuluCrypt Strg+GCtrl+G zuluCrypt Strg+HCtrl+H zuluCrypt Strg+ICtrl+I zuluCrypt Strg+JCtrl+J zuluCrypt Strg+KCtrl+K zuluCrypt Strg+LCtrl+L zuluCrypt Strg+MCtrl+M zuluCrypt Strg+NCtrl+N zuluCrypt Strg+OCtrl+O zuluCrypt Strg+PCtrl+P zuluCrypt Strg+QCtrl+Q zuluCrypt Strg+RCtrl+R zuluCrypt Strg+SCtrl+S zuluCryptStrg+Umschalt+D Ctrl+Shift+D zuluCrypt Strg+TCtrl+T zuluCrypt Strg+UCtrl+U zuluCrypt Strg+VCtrl+V zuluCrypt Strg+WCtrl+W zuluCrypt Strg+XCtrl+X zuluCrypt Strg+YCtrl+Y zuluCrypt Strg+ZCtrl+Z zuluCryptZNicht in das Benachrichtigungsfeld minimierenDo Not Minimize To Tray zuluCrypt FEHLERERROR zuluCryptFEHLER!ERROR! zuluCrypt2&Eine Datei verschlüsselnEncrypt A &File zuluCrypt`&Verschlüsselter container auf einer Ferstplatte$Encrypted &Container In A Hard Drive zuluCrypt’Verschlüsselter Container versteckt in Video/Cover-Datei (Steganographie)>Encrypted Container Hidden In Video/Cover File (Steganography) zuluCrypthVerschlüsselter Container in einer vorhandenen Datei'Encrypted Container In An Existing File zuluCryptZEinhängepunktpfad des verschlüsselten Volumes!Encrypted Volume Mount Point Path zuluCrypt>Pfad zum verschlüsselten VolumeEncrypted Volume Path zuluCryptF1F1 zuluCrypt H&ilfeH&elp zuluCryptINFORMATIONINFO zuluCryptrWichtige Informationen zur Sicherung der Volume-Kopfdaten-Important Information On Volume Header Backup zuluCrypt2System-Volumes v&erwaltenManag&e System Volumes zuluCrypt>&Nicht-System-Volumes verwaltenManage &Non System Volumes zuluCryptT&Volumes in interner Brieftasche verwalten"Manage &Volumes In Internal Wallet zuluCryptFVolumes in &GNOME Keyring verwalten Manage Volumes In &GNOME keyring zuluCrypt@Volumes in &KDE Wallet verwaltenManage Volumes In &KDE Wallet zuluCryptOrdner öffnen Open Folder zuluCrypt4Öffne privates VerzeichnisOpen Private Folder zuluCrypt2Gemeinsamen Ordner öffnenOpen Shared Folder zuluCrypt&OptionenOptio&ns zuluCrypt&Pfad zu einer DateiPath To A File zuluCryptEigenschaften Properties zuluCryptSchließenQuit zuluCrypt"Schlüssel löschen Remove Key zuluCrypt¦Die Schriftgröße wird auf %1 zurückgesetzt, weil größere Schriftgrößen nicht passen>Resetting font size to %1 because larger font sizes do not fit zuluCryptBVolume-Kopfdaten wiederherstellenRestore Volume Header zuluCrypt&Font wählen Select &Font zuluCrypt$Symbole aus&wählen Select &Icons zuluCrypt"Sprache auswählenSelect Language zuluCrypt.Dateimanager fest&legenSet Fi&le Manager zuluCryptUmschalt+IShift+I zuluCryptUmschalt+VShift+V zuluCrypt*Debugfenster anzeigenShow Debug Window zuluCrypt&Anzeigen/Ausblenden Show/Hide zuluCryptªDiese Option schließt die App, anstatt sie in das Benachrichtigungsfeld zu minimieren?This Option Will Close The App Instead Of Minimizing It To Tray zuluCryptTypType zuluCryptAushängenUnmount zuluCrypt|Ein unbekannter Fehler mit der Statusnummer %1 ist aufgetreten4Unrecognized error with status number %1 encountered zuluCryptDVeraCrypt-Container in einer DateiVeraCrypt Container In A File zuluCryptPVeraCrypt-Container auf einer Festplatte#VeraCrypt Container In A Hard Drive zuluCrypt8Volume &auf einer FestplatteVolume &Hosted In A Hard Drive zuluCrypt(Volume-EigenschaftenVolume Properties zuluCryptžDas Volume ist nicht geöffnet oder es wurde von einem anderen Benutzer geöffnet4Volume is not open or was opened by a different user zuluCryptWARNUNG!WARNING! zuluCrypt&Anwendung schließenclose application zuluCrypt4Brieftaschen konfigurierenconfigure wallets zuluCrypt6Verschlüsselungsinformation crypto info zuluCrypt(Favorisierte Volumesfavorite volumes zuluCrypt&Favoriten verwaltenmanage favorites zuluCryptBerechtigungen permissions zuluCrypt:Zufallszahlengenerator wählenselect random number generator zuluCrypt6TrueCrypt-Kopfdaten sicherntcrypt backup header zuluCryptHTrueCrypt-Kopfdaten wiederherstellentcrypt restore header zuluCryptzuluCrypt zuluCrypt zuluCryptèDie Verbindung zwischen zuluCrypt und zuluPolkit ist fehlgeschlagen. Bitte melden Sie diesen schwerwiegenden Fehler.JzuluCrypt Failed To Connect To zuluPolkit. Please Report This Serious Bug. zuluCryptˆzuluCrypt-6.2.0/translations/zuluCrypt/de_DE.ts000066400000000000000000010526101425361753700216340ustar00rootroot00000000000000 DialogMsg Dialog Dialog &Ok &OK &Yes &Ja &No &Nein text Text type Typ cipher Chiffre key size Schlüssellänge device Gerät loop Schleife offset Offset size Größe mode Modus fs fs used Belegt unused Unbelegt used % Belegt % active slots Aktive Slots "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. "System-Volumes" sind Volumes, die entweder von udev als solche identifiziert werden, wenn udev aktiviert ist oder einen Eintrag in "/etc/fstab", "/etc/c/crypttab" oder "/etc/zuluCrypt/system_volumes.list" haben. Wenn Sie es vorziehen, dass ein Volume nicht als System-Volume betrachtet wird, starten Sie das Werkzeug vom root-Konto aus und gehen Sie dann zu "Menü -> Optionen -> Nicht-System-Partitionen verwalten" und fügen Sie das Volume der Liste hinzu, und das Volume wird nicht mehr als "System" betrachtet. Alternativ können Sie sich in die Gruppe "zulucrypt" und "zulumount" eintragen und alle Einschränkungen werden aufgehoben. INFORMATION INFORMATION Insufficient privilege to access a system device, only root user or members of group zulucrypt can do that Unzureichende Rechte für den Zugriff auf ein Systemgerät, nur der Benutzer root und Mitglieder der Gruppe zulucrypt dürfen das Insufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that Unzureichende Rechte für den Zugriff auf ein Systemgerät im Lese-/Schreibmodus, nur der Benutzer root und Mitglieder der Gruppe zulucrypt dürfen das You do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again Sie scheinen nicht genügend Rechte für den Zugriff auf die verschlüsselte Datei im %1 zu haben. Überprüfen Sie die Dateirechte und probieren Sie es erneut type: Typ: cipher: Chiffre: keysize: Schlüssellänge: offset: Offset: device: Gerät: loop: Schleife: mode: Modus: active slots: Slots: file system: Dateisystem: total space: Gesamter Platz: used space: Belegter Platz: free space: Freier Platz: used%: Belegt%: UUID: UUID: Do not show this dialog again Diesen Dialog nicht erneut anzeigen PasswordDialog Open Encrypted Volume Verschlüsseltes Volume öffnen &Open &Öffnen &Cancel &Abbrechen Mount In &Read Only Mode Im Nu&r-Lese-Modus einhängen select mount point path Einhängepunktpfad auswählen open volume path Volume-Pfad öffnen Password Passwort LUKS/TrueCrypt/BitLocker LUKS/TrueCrypt/BitLocker &OK Mount Name Name des Einhängepunkts &Options Volume Path Volume-Pfad KeyFile Schlüsseldatei Key+KeyFile Schlüssel + Schlüsseldatei Plugin Erweiterung &Share Mount Point Einhängepunkt &teilen VeraCrypt VeraCrypt VeraCrypt System PLAIN dm-crypt PLAIN DM-Crypt Volume Type Volume-Typ TextLabel Textmarkierung Enter Comma Separated Volume's File System Options Below Set Cancel Abbrechen open key file Öffne Schlüsseldatei QObject zuluCrypt: Failed To Establish Connection With zuluPolkit zuluCrypt: Der Verbindungsaufbau mit zuluPolkit ist fehlgeschlagen options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI Optionen: d Pfad zu einem Volume, das automatisch aufgeschlossen/eingehängt werden soll m Werkzeug zum Öffnen eines Standard-Dateimanagers (Standard-Werkzeug ist xdg-open) e Starten der Anwendung ohne Anzeige der GUI If the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2" Wenn die Option aktiviert ist, wird in "%1" ein primärer privater Einhängepunkt erstellt und ein sekundärer öffentlich zugänglicher "Spiegel"-Einhängepunkt wird in "%2" erstellt public mount point: öffentlicher Einhängepunkt: Manage Favorites Favoriten verwalten Mount All Alle einhängen about zuluCrypt Über zuluCrypt hmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents) hmac-Erweiterung. Diese Erweiterung erzeugt einen Schlüssel mit Hilfe des folgenden Formulars: key = hmac(sha256, Passphrase, Schlüsseldateiinhalt) keykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contents keykeyfile-Erweiterung. Diese Erweiterung erzeugt einen Schlüssel mit Hilfe des folgenden Formulars: Schlüssel = Passphrase + Schlüsseldateiinhalt gpg plugin. This plugin retrives a key locked in a gpg file with a symmetric key gpg-Erweiterung. Diese Erweiterung stellt einen Schlüssel wieder her, der in einer gpg-Datei mit einem symmetrischen Schlüssel gesperrt ist Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit. Die Hilfsanwendung konnte nicht gestartet werden. "org.zulucrypt.zulupolkit.policy" polkit-Datei ist falsch konfiguriert, ausführbare Datei zuluPolkit konnte nicht gefunden werden oder pkexec konnte zuluPolkit nicht starten. Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit. ERROR FEHLER Failed to locate pkexec executable Die ausführbare Datei pkexec konnte nicht gefunden werden "%1" and "%2" Folders Must Be Writable. Die Ordner "%1" und "%2" müssen beschreibbar sein. Could not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin" Die ausführbare Datei "gpg" konnte nicht in "/usr/local/bin", "/usr/bin" und "/usr/sbin" gefunden werden createVolumeDialog Warning!! Warnung!! &Yes &Ja &No &Nein This operation will lead to permanent destrunction of all present data in /dev/sdc1. Are you sure you want to continue? Diese Operation wird zum vollständigen Verlust der Daten in /dev/sdc1 führen. Möchten Sie wirklich fortfahren? This operation will lead to permanent destrunction of all present data in "%1". Are you sure you want to continue? Diese Operation wird zum vollständigen Verlust der Daten in "%1" führen. Möchten Sie wirklich fortfahren? It is advised to create encrypted containers over random data to prevent information leakage. Do you want to write random data to "%1" first before creating an encrypted container in it? You can stop the random data writing process anytime you want if it takes too long and you can no longer wait. Es wird empfohlen, verschlüsselte Container auf einer zuvor mit Zufallsdaten beschriebenen Partition zu erstellen, um eine Wiederherstellung alter Daten zu verhindern. Möchten Sie Zufallsdaten nach "%1" schreiben, bevor der verschlüsselte Container darin erstellt wird? Sie können den zufälligen Datenschreibprozess jederzeit stoppen, wenn es zu lange dauert und Sie nicht mehr warten können. createVolumeInExistingFIle Create Volume In Existing File Select Cover File (Video files like mp4 and mkv) Container Size (MB) Volume Properties Volume-Eigenschaften &Cancel C&reate Volume OffSet (Auto calculated) Create A Plain dm-crypt Container Hidden Inside Cover File (Steganography) Password Passwort TextLabel Textmarkierung Extending A Host File Size. Enter Path To Existing File Average Speed: ETA: Percentage Completed: %1% ERROR FEHLER AtLeast One Required Field Is Empty Illegal Character Found In The Container Size Field Failed To Open File In Write Mode Failed To Open "/dev/urandom" Device In Read Mode Creating A Plain DM-Crypt Volume Volume Created Successfully Failed To Create A Volume createfile open a folder dialog box Einen Verzeichnisdialog öffnen File Name Dateiname File Path Dateipfad File Size Dateigröße &Cancel &Abbrechen % Complete % Fertig C&reate &Erstellen KB KB MB MB GB GB Do Not Write Random Data To Container(STRONGLY discouraged) Schreibe keine Zufallsdaten in den Container (NICHT empfohlen TextLabel Textmarkierung &OK Illegal character in the file size field.Only digits are allowed Ungültiges Zeichen im Dateigrößenfeld. Es sind nur Zahlen erlaubt Create A Container File Erstelle eine Container-Datei By default,zuluCrypt creates a volume in a container file over randomly generated data to hide usage patterns of the container. This process takes time and it may take a very,very long time if the volume about to be created is large enough and this option exists to skip the process for the impatient among us but but it comes at a cost and the cost may be too high when it finally reveal itself while infront of an adversary when they look at the encrypted container and manage to derive meaning based on how the container looks from outside. If you know what you are doing,then continue by all means,if in doubt,my advise is to endure the process and be safer in the long run. Standardmäßig erzeugt zuluCrypt ein Volume in einem Container, in den vorher Zufallszahlen geschrieben wurden, um Muster der Anwendung des Containers zu verstecken. Dieser Prozess braucht Zeit und kann unter Umständen sehr lange dauern, wenn das zu erstellende Volume sehr groß ist. Es gibt zwar für die Ungeduldigen unter uns die Möglichkeit, den Prozess abzubrechen, aber das hat seinen Preis. Dieser Preis könnte sich als zu hoch erweisen, wenn der verschlüsselte Container bei einer Untersuchung oder für einen Angreifer durch sein Aussehen Rückschlüsse auf den Inhalt zulässt. Da Sie jetzt wissen, was Sie tun, brechen Sie den Vorgang ab, wenn es sein muss. Im Zweifelsfall sollte aber abgewartet werden, bis der Vorgang zu Ende ist. Dadurch sind Sie auf lange Sicht abgesicherter. INFO INFORMATION File name field is empty Das Feld Dateiname ist leer File path field is empty Das Feld Dateipfad ist leer File size field is empty Das Feld Dateigröße ist leer WARNING WARNUNG Are you really sure you do not want to create a more secured volume? Sind Sie wirklich sicher, dass Sie kein gesichertes Volume erstellen möchten? File with the same name and at the destination folder already exist Es existiert bereits eine Datei mit dem gleichen Namen am Zielort You dont seem to have writing access to the destination folder Sie scheinen keinen Schreibzugriff auf den Zielordner zu haben Container file must be bigger than 3MB Die Containerdatei muss größer als 3 MB sein Failed to create volume file Es konnte keine Volume-Datei erstellt werden Failed to enable polkit support Die polkit-Unterstützung konnte nicht aktiviert werden Operation terminated per user choice Die Operation wurde durch den Benutzer abgebrochen Could not open cryptographic back end to generate random data Konnte das kryptografische Backend nicht öffnen um Zufallsdaten zu erzeugen Terminating file creation process Erstellung der Datei abgebrochen Are you sure you want to stop file creation process? Sind sie sicher, dass Sie das Erstellen der Datei abbrechen möchten? Average Speed: ETA: Select Path to where the file will be created Pfad zum Erstellungsort der Datei createkeyfile Create A KeyFile Eine Schlüsseldatei erzeugen Keyfile Name Name der Schlüsseldatei path to a folder to create a key in Pfad zu einem Ordner, in dem ein Schlüssel erstellt wird open a folder a key file will be created in Ordner öffnen, in dem eine Schlüsseldatei erstellt wird C&reate E&rstellen &Cancel Abbre&chen KeyFile Path Pfad zur Schlüsseldatei RNG Zufallszahlengenerator TextLabel Textmarkierung &OK The key name field is empty Das Feld für den Schlüsselnamen ist leer Folder path to where the key will be created is empty Das Feld für den Verzeichnispfad ist leer File with the same name and at the destination folder already exist Es existiert bereits eine Datei mit dem gewählten Namen im angegebenen Verzeichnis You dont seem to have writing access to the destination folder Sie scheinen keine Schreibrechte für das Zielverzeichnis zu haben Process interrupted,key not fully generated Prozess unterbrochen, der Schlüssel wurde nicht vollständig erzeugt KeyFile successfully created Schlüsseldatei erfolgreich erstellt Select A Folder To Create A Key File In Wählen Sie ein Verzeichnis in dem die Schlüsseldatei erstellt werden soll createvolume open a key file Öffne eine Schlüsseldatei Path to Device Pfad zum Gerät C&reate &Erstellen &Cancel &Abbrechen Key Schlüssel Volume Type Volume-Typ Volume Size Volume-Größe Volume Options Volume-Optionen File System Dateisystem RNG Zufallszahlengenerator random number generator Zufallszahlengenerator Password Passwort Repeat Password Passwort wiederholen Advanced LUKS2 Options Bytes Bytes KiloBytes KiloBytes MegaBytes MegaBytes GigaBytes GigaBytes Iteration Time (milliseconds) PIM PIM TextLabel Textmarkierung Advanced Luks2 Options Set Label Sub System Pbkdf Type argon2id argon2i pbkdf2 Max Memory (KB) Parallel Threads Unlocking Time Cost(Milliseconds) Allow Discard(TRIM) Forced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) Cancel Abbrechen Options are separated by a "." character. Optionen werden durch das Zeichen "." getrennt. Multiple algorithms are separated by ":" character. Mehrere Algorithmen werden durch das Zeichen ":" getrennt. Options are in a format of "algorithm.cipher mode.key size in bits.hash" Optionen haben das Format "Algorithmus.Chiffremodus.Schlüssellänge in Bits.Hash" Default option is the first entry on the list Die Standardoption ist der erste Eintrag in der Liste Key+KeyFile Schlüssel + Schlüsseldatei Normal+Hidden TrueCrypt Standard (+ versteckter Container) TrueCrypt Normal VeraCrypt Standard VeraCrypt Normal+Hidden VeraCrypt Standard (+ versteckter Container) VeraCrypt Passphrase Quality: 0% Passphrasenqualität: 0% Passphrase Quality: %1% Passphrasenqualität: %1% Create A New Volume Neues Volume erstellen KeyFile Schlüsseldatei YubiKey Challenge/Response PLAIN dm-crypt PLAIN DM-Crypt PLAIN dm-crypt with offset PLAIN DM-Crypt mit Offset LUKS1 LUKS1 LUKS1+External Header LUKS1+Externe Kopfdaten LUKS2 LUKS2+External Header LUKS1 + Externer Header LUKS LUKS LUKS+External Header LUKS + Externer Header Normal TrueCrypt Normales TrueCrypt TrueCrypt Keys TrueCrypt-Schlüssel VeraCrypt Keys VeraCrypt-Schlüssel Volume Offset Volume-Offset Path To Device Pfad zum Gerät Path To File Pfad zur Datei Keyfile Path Pfad zur Schlüsseldatei Passphrase Quality: 100% Passphrasenqualität: 100% Keys Schlüssel ERROR! FEHLER! Failed to enable polkit support Die polkit-Unterstützung konnte nicht aktiviert werden Volume path field is empty Das Feld Volume-Pfad ist leer Atleast one required field is empty Mindestens ein benötigtes Feld ist leer Illegal character detected in the hidden volume size field Ungültiges Zeichen im Feld Größe des versteckten Volumes Hidden passphrases do not match Die versteckten Passphrasen stimmen nicht überein Passphrases do not match Die Passphrasen stimmen nicht überein ERROR FEHLER Failed To Locate Or Run Yubikey's "ykchalresp" Program. Please be patient as creating a VeraCrypt volume may take a very long time. Bitte haben Sie Geduld, da die Erstellung eines VeraCrypt-Volumes sehr lange dauern kann. WARNING! WARNUNG! Volume created successfully but failed to create an external header Volume erfolgreich erstellt, aber es konnten keine externen Kopfdaten erstellt werden Luks volume created successfully. LUKS-Volume erfolgreich erstellt. Luks volume created successfully,external header created successfully but failed to erase header on the device LUKS-Volume erfolgreich erstellt, externe Kopfdaten erfolgreich erstellt, aber die Kopfdaten auf dem Gerät konnten nicht gelöscht werden Volume created successfully. Volume erfolgreich erstellt. Creating a backup of the "%1" volume header is strongly advised. Please read documentation on why this is important. Es wird dringend empfohlen, eine Sicherung der Volume-Kopfdaten "%1" zu erstellen. Bitte lesen Sie die Dokumentation, warum dies wichtig ist. Presented file system is not supported,see documentation for more information Das präsentierte Dateisystem wird nicht unterstützt, bitte konsultieren Sie die Dokumentation für weitere Informationen Could not create an encrypted volume Es konnte kein verschlüsseltes Volume erstellt werden Could not open volume for writing Das Volume konnte nicht zum Schreiben geöffnet werden There seem to be an opened mapper associated with the device Es scheint ein geöffneter Mapper mit dem Gerät assoziiert zu sein Can not create a volume on a mounted device Es kann kein Volume auf einem eingehängten Gerät erstellt werden Container file must be bigger than 3MB Die Containerdatei muss größer als 3 MB sein Insufficient memory to hold your response Nicht genügend Speicherplatz zum Speichern Ihrer Antwort Operation terminated per user request Die Operation wurde durch den Benutzer abgebrochen Could not get passphrase in silent mode Konnte die Passphrase nicht im stillen Modus bekommen Insufficient memory to hold the passphrase Nicht genügend Speicherplatz zum Speichern der Passphrase Invalid path to key file Ungültiger Pfad zur Schlüsseldatei Could not get a key from a key file Konnte keinen Schlüssel aus der Schlüsseldatei bekommen Couldnt get enought memory to hold the key file Konnte nicht genügend Speicher zum Speichern der Schlüsseldatei bekommen Could not get a key from a socket Konnte keinen Schlüssel vom Socket erhalten One or more required argument(s) for this operation is missing Ein oder mehrere für diese Operation erforderlichen Argument(e) fehlt/fehlen Can not get passphrase in silent mode Konnte die Passphrase nicht im stillen Modus bekommen Insufficient memory to hold passphrase Nicht genügend Speicherplatz zum Speichern der Passphrase Failed to create a volume Es konnte kein Volume erstellt werden Wrong argument detected for tcrypt volume Falsches Argument für ein Truecrypt-Volume erkannt Could not find any partition with the presented UUID Konnte keine Partition mit der angegebenen UUID finden Error Code: %1 -- StdOut: %2 -- StdError: %3 Fehlercode: %1 -- Standardausgabe: %2 -- Standardfehlerausgabe: %3 It is best to create a hidden volume with vfat/fat file system. Es ist am besten, ein verstecktes Volume mit dem Dateisystem vfat/fat zu erstellen. WARNING WARNUNG SUCCESS! ERFOLG! insufficient privilege to open a system device in read/write mode, only root user or members of group zulucrypt can do that Unzureichende Rechte um ein Systemgerät im Schreib-/Lesemodus zu öffnen, nur der Benutzer root oder Mitglieder der Gruppe zulucrypt dürfen das %1 not found %1 nicht gefunden cryptfiles Path to source field is empty Das Quellpfadfeld ist leer Invalid path to source file Ungültiger Pfad zur Quelldatei Destination path already taken Zielpfad bereits gewählt First key field is empty Das erste Schlüsselfeld ist leer Second key field is empty Das zweite Schlüsselfeld ist leer Keys do not match Die Schlüssel stimmen nicht überein Invalid path to key file Ungültiger Pfad zur Schlüsseldatei You dont seem to have writing access to the destination folder Sie scheinen keine Schreibrechte für das Zielverzeichnis zu haben These very old encrypted files are no longer supported Diese sehr alten verschlüsselten Dateien werden nicht mehr unterstützt Enter A Key Geben Sie einen Schlüssel ein Enter A Path To A Keyfile Location Geben Sie einen Pfad zu einer Schlüsseldatei an keyfile path Pfad zur Schlüsseldatei Generate a key made up of a passphrase and a keyfile Einen Schlüssel erzeugen, der aus einer Passphrase und einer Schlüsseldatei besteht Select A File You Want To Encrypt Wählen Sie eine Datei zum Verschlüsseln aus Select A File You Want To Decrypt Wählen Sie eine Datei zum Entschlüsseln aus Select A Keyfile Wählen Sie eine Schlüsseldatei aus Encrypted file created successfully Verschlüsselte Datei erfolgreich erstellt Decrypted file created successfully Datei erfolgreich entschlüsselt Could not open keyfile for reading Konnte die Schlüsseldatei nicht zum Lesen öffnen Could not open encryption routines Konnte die Verschlüsselungsroutinen nicht zum Lesen öffnen File or folder already exist at destination address Datei oder Verzeichnis existiert bereits Insufficient privilege to create destination file Unzureichende Rechte zum Erstellen der Zieldatei Presented key did not match the encryption key Der eingegebene Schlüssel stimmt nicht mit dem Verschlüsselungsschlüssel überein Operation terminated per user request Die Operation wurde durch den Benutzer abgebrochen Insufficient privilege to open source file for reading Unzureichende Rechte, um die Quelldatei zum Lesen zu öffnen Decrypted file created successfully but md5 checksum failed,file maybe corrupted Die verschlüsselte Datei wurde erfolgreich erstellt, aber die md5 Prüfsumme stimmt nicht. Die Datei könnte beschädigt sein Could not open reading encryption routines Konnte die Verschlüsselungsroutinen nicht zum Lesen öffnen Could not open writing encryption routines Konnte die Verschlüsselungsroutinen nicht zum Schreiben öffnen Failed to close encryption routine Das Schließen der Verschlüsselungsroutinen ist fehlgeschlagen Create An Encrypted Version Of A File Erstellt eine verschlüsselte Version einer Datei Create A Decrypted Version Of An encrypted File Entschlüsselt eine verschlüsselte Datei Select Path to put destination file Wähle Sie den Pfad zur Zieldatei zuluCrypt encrypted files ( *.zc ) ;; All Files ( * ) mit zuluCrypt verschlüsselte Dateien (*.zc) ;; Alle Dateien ( * ) Destination C&reate &Erstellen Source Quelle Password Passwort Repeat Password Passwort wiederholen TextLabel Textmarkierung &OK Key Schlüssel KeyFile Schlüsseldatei Key+KeyFile Schlüssel + Schlüsseldatei Repeat Key Schlüssel erneut eingeben &Cancel &Abbrechen % Complete % fertig cryptoinfo Greetings Grüße Ok Ok Please consult "menu->help->open zuluCrypt.pdf" to get an introduction on zuluCrypt. Unity users,the menu is on the upper left corner of the screen when zuluCrypt has focus. Project's homepage is at: https://mhogomchungu.github.io/zuluCrypt Recommending reading FAQ page from the project's main page. Konsultieren Sie für eine Einführung in zuluCrypt bitte "menu->help->open zuluCrypt.pdf" FürAnwender von Unity: das Menü ist in der oberen linken Ecke, wenn zuluCrypt den Fokus hat Die Projekt's Webseite ist: https://mhogomchungu.github.io/zuluCrypt Es empfiehlt sich, vorab die FAQ auf der Webseite zu lesen. Do not show this message again. Diese Meldung nicht erneut anzeigen. debugWindow zuluCrypt Debug Window zuluCrypt Debugfenster C&lear &Löschen &Close S&chließen dialogok Dialog Dialog &Ok &Yes &Ja &No &Nein TextLabel Textmarkierung erasedevice Erase Data On The Device By Writing Random Data Over Them Daten auf dem Gerät durch das Überschreiben mit Zufallsdaten löschen Path to Device Pfad zum Gerät % Completed % fertig &Start &Start &Cancel &Abbrechen Average Speed ETA N/A TextLabel Textmarkierung &OK The next dialog will write random data to a device leading to permanent loss of all contents on the device. Are you sure you want to continue? Der nächte Dialog schreibt Zufallsdaten auf das Gerät, wodurch der Inhalt permanent gelöscht wird. Sind Sie sicher, dass Sie fortfahren möchten? Write Random Data Over Existing Data Überschreibe existierende Daten mit Zufallsdaten WARNING WARNUNG Data on the device successfully erased Die Daten auf dem Gerät wurden erfolgreich gelöscht Could not create mapper Es konnte kein Mapper erstellt werden Could not resolve device path Der Gerätpfad konnte nicht aufgelöst werden Random data successfully written Zufallsdaten erfolgreich geschrieben Operation terminated per user choice Die Operation wurde durch den Benutzer abgebrochen Can not write on a device with opened mapper Es kann nicht auf ein Gerät mit geöffnetem Mapper geschrieben werden Policy prevents non root user opening mapper on system partition Die Richtlinien verhindern, dass normale Benutzer Mapper auf Systempartitionen öffnen Device path is invalid Der Gerätepfad ist ungültig Passphrase file does not exist Die Passphrasendatei existiert nicht Could not get enought memory to hold the key file Konnte nicht genügend Speicher zum Speichern der Schlüsseldatei bekommen Insufficient privilege to open key file for reading Unzureichende Rechte zum Öffnen der Schlüsseldatei für das Lesen This device appear to already be in use Dieses Gerät scheint bereits im Einsatz zu sein Can not open a mapper on a mounted device Konnte keinen Mapper auf dem eingehangenen Gerät öffnen Could not write to the device Konnte nicht auf das Gerät schreiben Device path field is empty Das Gerätepfadfeld ist leer Invalid path to device Ungültiger Pfad zum Gerät Failed to enable polkit support Die polkit-Unterstützung konnte nicht aktiviert werden Writing Random Data Over Existing Data Überschreibe existierende Daten mit Zufallsdaten Enter Path To Volume To Be Erased Geben Sie den Pfad zum Volume ein, das gelöscht werden soll Select A Non System Partition To Erase Its Contents Wählen Sie eine Nicht-Systempartition aus, um deren Inhalt zu löschen Are you really sure you want to write random data to "%1" effectively destroying all contents in it? Sind Sie wirklich sicher, dass Sie Zufallsdaten nach "%1" schreiben möchten, um alle Inhalte effektiv zu zerstören? Average Speed: Total Time: WARNING! WARUNG! favorites2 Favorites Favorite List Volume ID Mount Point Add Add A volume Mount Path &Close Mount Options Manage Keys In Wallets Set Default Wallet Internal Wallet Libsecret KWallet None Volume Path Enter Volume Path Below Enter Password Below Change Internal Wallet Password TextLabel Ok fileManager Set File Manager Dateimanager festlegen TextLabel Textmarkierung &Set Fe&stlegen Enter Below The Name Of The Application You Want To Be Used To Open Mount Points. Geben Sie unten den Namen der Anwendung ein, die Sie zum Öffnen von Einhängepunkten verwenden möchten. help Help Hilfe &Close S&chließen <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt;">ZuluCrypt is a simple, feature rich and powerful solution for hard drives encryption for linux.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt supports LUKS, TrueCrypt, VeraCrypt and PLAIN dm-crypt encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These supported encrypted volumes may resides in image files, hard drives and usb sticks, LVM</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volumes as well as in mdraid devices.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of encrypted volumes. Those that use what is commonly know as “a header†and</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">those that do not. TrueCrypt, VeraCry and LUKS volumes use a header. PLAIN dm-crypt volumes do</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">not use a header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a &quot;volume header&quot;.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">The damage to the header is usually caused by accidental formatting of the device or use of</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">some buggy partitioning tools or wrongly reassembled logical volumes.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack'; color:#008000;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of header using encrypted volumes. Those that use an encrypted header and those</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">that do not. TrueCrypt and VeraCrypt use an encrypted header whereas LUKS does not. The use of non</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted header in LUKS makes it obvious to everybody that the volume is an encrypted LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may be problematic to some people. How big the problem may be depends on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">person and their use case for hard drive encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The use of encrypted header as in TrueCrypt or VeraCrypt volumes or no header at all as in PLAIN dm-</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">crypt volumes make these volumes indistinguishable from random noise and this may seem useful at a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">glance but its usefulness may not hold up against scrutiny as the likelihood of being believed that a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">100GB file made up of cryptographically sound random data is just a 100GB file made up of random</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data and not a container file for an encrypted volume is not very high.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With LUKS, TrueCrypt and VeraCrypt volumes, it is very important to have a volume header backup</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">since a valid header is required to unlock the volume. A corrupted or missing header will make the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume unusable causing the loss of all encrypted data.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">LUKS stands for “Linux Unified Key Setupâ€. It is a specification of how to store information necessary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to open a LUKS formatted encryption volume. LUKS encryption format is the standard format in linux</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and a recommended one if the encrypted volume is to be used among linux systems. TrueCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt volumes are better alternative if the encrypted volume is to be shared between linux,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">windows and OSX computers.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can create and open 5 types of encrypted volumes, LUKS, TrueCrypt, VeraCrypt,PLAIN</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dm-crypt and PLAIN dm-crypt volume at a none zero offset. PLAIN dmcrypt volume is a header less</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume and all necessary encryption information is provided by zuluCrypt when it creates or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open these volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; text-decoration: underline;">Pros and cons of the five volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt; text-decoration: underline;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It does not use a volume header and hence its not possible to “brick†the entire volume simply by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over writing a small part of it.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It does not use a header and hence its impossible to know if the volume is made up of only</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">cryptographically sound random data or if its an encrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It does not use a header and hence any tool that opens these volumes must provide the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options that were used when the volume was created. Different tools may use different encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options making these encrypted volumes not very portable between applications or even between</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">different versions of the same application.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt at a none zero offset.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This volume has the same pros and cons as those of a PLAIN dm-crypt volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional pro for this volume is that it can be places anywhere on the device making it possible</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to have this volume on top of any one of the other supported encrypted volume or on top of an</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">unencrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For example, its possible to have an X MB drive that has unencrypted file system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">at the beginning of the device and a “PLAIN dm-crypt volume with an offset†somewhere towards the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">end of the device making it possible to use the drive as unencrypted volume and as encrypted volume</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">simultaneously depending on sensitivity of the data to be stored on the device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this volume type is to be used, preceding part of the drive should be formatted in “FAT†family of file systems.This volume types gives a “hidden volume†type functionality offered by TrueCrypt and VeraCrypt. When creating or unlocking this volume type, the starting offset of the volume will be asked and NOT the volume size as TrueCrypt and VeraCrypt does with the hidden volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above means, if you have a 100 MB drive and you want to create a 30MB “PLAIN dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume at a none zero offsetâ€, you will enter the starting offset of the volume as 70MB. In VeraCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt, you will enter the hidden volume size of 30MB. The starting offset and the size of the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hidden volume are related by a simple formula: starting offset(70MB) = device size(100MB) – hidden</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume size(30MB).</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TrueCrypt</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and hence its not possible to know if the volume is TrueCrypt formatted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume or if the volume is just made up of cryptographically sound random data.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Hidden volume. A TrueCrypt volume can have up to two different encrypted volumes. The first</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume is commonly know as “outer volume†and the second optional one is commonly known as</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“hidden volumeâ€.When a TrueCrypt volume is about to be opened, the user has an option to select</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">which one of the two to open by giving appropriate key.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and it is not possible to open the volume without a valid header. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">use a TrueCrypt volume, make sure you have at least one backup of the volume header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VeraCrypt</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt is an extension of TrueCrypt and it shares the same TrueCrypt’s pros and cons.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Pro for VeraCrypt over TrueCrypt.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It requires stronger effort to unlock VeraCrypt volume and this makes them more secure over</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt volumes.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Cons for VeraCrypt over TrueCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It requires stronger effort to unlock a VeraCrypt volume and this increases the time it takes to unlock</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a VeraCrypt volume. How long it will take depends on the strength of the computer and it may vary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from a few seconds to several minutes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS volume can be opened with up to 8 different keys.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS header is stored unencrypted making it obvious the volume is LUKS formatted encrypted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may not be desirable under certain circumstances. It is possible to create a LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume with a detached header and zuluCrypt can open these volumes using “luks†plugin.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It uses a header. As it is not possible to open a header using encrypted volume without its header, a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">corrupted LUKS header makes it impossible to open the volume. If you use a LUKS volume, make</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sure you have at least one backup of the volume header.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can do two types of encryption. It can do single file encryption/decryption or block device</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">File encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can encrypt and decrypt individual files. This feature is useful when a user just wants to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt a single file and taking the route of creating an encrypted container file to host the file is seen</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as an unnecessary hassle. This functionality is akin to file encryption using gpg with a symmetric key.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">File encryption is done using libgcrypt as a cryptographic backend. Files are encrypted using 256 bit</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">AES in CBC mode. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The encryption key is derived from user pass phrase using pbkdf2 with 10,000</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">rounds of iterations and sha2 as a cryptographic hash function. The resulting encrypted file will have a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file size that equals (64 + 1024 * n) bytes where n is a number starting from zero.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted file:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;encrypt a file†to open a file encryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to store encrypted, enter the password to be used to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt the file and then click “create†and the encrypted version of the file will be created at the path</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by “destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">To decrypt the file created with above steps:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;decrypt a file†to open a file decryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to decrypt, enter the password to be used to decrypt the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file and then click “create†and the decrypted version of the file will be created at the path given by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Block device encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A hard drive or a usb stick are two examples of block devices. A regular file can simulate a block</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">device through a use of devices known as “loop devicesâ€. These devices have a device path that starts</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">with “/dev/loopâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The infrastructure in the linux kernel that deal with block device encryption is called “dm-crypt†and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does its work through a process commonly known as OTF(on the file encryption). Dm-crypt devices</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">are represented by device addresses that starts with “/dev/dm-†and these paths are usually accessed</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">through their soft links that reside in “/dev/mapperâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Below is an example of steps taken in creating a 100MB encrypted container in a file and adding a file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">in it to be stored securely.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Create a 100MB file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Attach a loop device to the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Create an OTF encryption mapper against the loop device.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Put a file system on the encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Mount the file system on the mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Copy The file to be stored securely to the file system through the mount point.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Unmount the file system.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Destroy the OTF encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Detach the loop device from the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">10. Maintain the encrypted volume as a secure holder of files within it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All zuluCrypt does is provide a GUI to make it easy to do above specified tasks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With the above steps:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 1 deal with a path that look like “/home/ink/secret.imgâ€, this is a path to a regular file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 2 converts “/home/ink/secret.img†file to something like “/dev/loop0†loop device path.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 3 converts “/dev/loop0†loop device path to something like “/dev/mapper/secrets.imgâ€. Data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">written to “/dev/mapper/secrets.img†will get encrypted and then passed forward to “/dev/loop0†on its</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">way to “/home/ink/secret.imgâ€. When data is read from “/dev/mapper/secrets.imgâ€, the data will be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">read from “/dev/loop0†who in turn will read it from “/home/ink/secret.imgâ€, decrypted by dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then given to the reader. This process is called “on the fly encryption†because the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mapper does not store or hold on to data, it gets data and then encrypts or decrypts it depending on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">direction of data flow and then passes it along.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in an image file.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a file†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Enter the name of the file to be used to hold the container in the “file name†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the size of the container in the “file size†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Click “createâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Wait for the container file to be created and for the volume creation dialog to show up.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Enter the password to be used to create the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Select the type of volume you want to create from the “volume type†list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Click create to create the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in a partition.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a hard drive†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Click/double click on the hard drive you want to create a volume in and then advance to instruction</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">number 7 in the instruction list above. If the partition you want to put an encrypted container does not</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">show up on the list, then restart zuluCrypt from root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a file using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a file†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click the button to the right of “volume path†field and then browse to where</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the volume is and click it to open it. Alternatively, you can just drag the volume file on zuluCrypt to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">generate a password dialog prompt with the file path already filled in.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a partition using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a partition†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click/double click on the partition with an encrypted volume you want to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With both two steps above, the volume will be opened and mounted at a path whose last component is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by the entry in the field “mount nameâ€. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When the volume is successfully opened, zuluCrypt will</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">automatically open the mount point path. To close the volume, click its entry on the zuluCrypt window</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then click “close†on the pop up window.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can open an encrypted volume using keys derived from different sources. These sources</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">include, a pass phrase, a key file, a key retrieved from kwallet, a key retrieved from Gnome's libsecret,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a key retrieved from an internal secure storage system, a key from gpg encrypted key file among other</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sources.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a pass phrase volume key, make sure the key source option read “key†and then enter the pass</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phrase on the entry field at the bottom.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a keyfile as the source of volume key, click the option bar and then select “keyfile†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring a dialog box that will allow you to browse to where the key</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file is.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a plugin as the source of volume key, click the option bar and then select “plugin†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring up a list of available plugins and then select the one you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want from the list.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Volume keys stored in kwallet, Gnome keyring or internal secure storage system plugins can be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">managed by going to “menu-&gt;options-&gt;manage volumes in internal/kde/gnome walletâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Storage of keys in a gnome wallet/keyring seem most appropriate in a gnome session but this has some security repercussions, the keys are stored in the user keyring and this keyring gets unlocked when the user logs in. This means that once a user is logged in and the keyring is open, any application that runs in that user session can read those keys using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In a kde system, a kwallet secure storage system seem most appropriate but it suffers from the same</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">security problem the gnome secure storage system has, once the wallet is open, any application running in the user session can access it using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The behaviors of the above secure storage systems is by design but this design may not be ideal for</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">some users under certain use cases. The internal secure storage system is powered by libgcrypt and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does not have the behavior of the above two systems. An unlocked internal secured storage system is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">accessible only to the instance of zuluCrypt that unlocked it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Favorites.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For convenience, most used volumes can be easily opened by adding them to the favorite list. Entries</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">on the list are added in the dialog window opened by clicking “menu-&gt;options-&gt;manage favoritesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Favorite entries are added by clicking the “favorite†entry on the menu.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Erase data in a device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It is very important to create encrypted volume over cryptographically strong random data to make it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">impossible to know what part of the encrypted volume has been used and what part has not. If the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume is created over predictable data patterns like on a device with only zeros in it,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">forensic analysis may reveal how much and what part of the encrypted volume are in use.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When creating an encrypted container in a device, zuluCrypt offers an option to first write random data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over the device. This feature can be performed on other devices by activating it through “menu-&gt;erase</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data in a deviceâ€. Random data are written to disk by opening a plain dm-crypt encryption mapper on</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the device with a 64 byte random key and then blasting zeros on the device through the mapper. This</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">technique has proven to be faster compared to alternatives like writing random data on the device read</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from “/dev/urandomâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">System and non system volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To enforce access controls on what user can access what block device and what they can do with the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">access they have, zuluCrypt employes a concept of “system volumes†and “non system volumesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A system volume is defined as a volume that has an active entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/fstabâ€,â€/etc/crypptabâ€,“/etc/zuluCrypt/system_volumes.list†or if udev identify it as such if udev</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">is enabled. Ideally, all volumes inside the computer are to be considers system volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A non system volume is a volume that failed in the above considerations or if it has an entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/zuluCrypt/non_system_volumes.listâ€. Ideally, these volumes are plug gable usb based hard drives</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">or usb sticks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Partitions can be added or removed from the list of system or non system volumes simply by starting</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zuluCrypt from root's account and then going to “menu-&gt;options-&gt;manage system volumes/manage</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">non system volumes†and then adding the volume in the appropriate list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Permissions.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt limits what a user can do on block devices through unix's group based permission system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">using two groups, “zulucrypt†and “zulumountâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, only a root user or a user who is a member of group</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“zulucrypt†can create an encrypted volume in the device or taking/restoring volume headers. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want to create a volume in a device and the device does not show up on the list, restart zuluCrypt from</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, zuluMount will mount it only if the user is root, is a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">member of group “zulumount†or the device has an entry in “/etc/fstab†with either “user†or “usersâ€</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mount options set.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ZuluMount.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount is a general purpose mounting tool that can open zuluCrypt supported encrypted volumes</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as well as non encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also auto detect plugged in devices and auto mount them.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also unlock encfs volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2015-2017 Francis Banyikwa, mhogomchungu@gmail.com</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Open &PDF &PDF öffnen WARNING! WARNUNG! Failed to open zuluCrypt.pdf,make sure your system can open pdf files using "%1" tool and try again zuluCrypt.pdf konnte nicht geöffnet werden. Stellen Sie sicher, dass Ihr System PDF-Dateien mit "%1" öffnen kann und versuchen Sie es erneut luksaddkey Volume Path Volume-Pfad open file Öffne Datei open partition Öffne Partition Password Already In The Encrypted Volume Passwort ist bereits im verschlüsselten Volume vorhanden Password To Be Added To The Encrypted Volume Passwort, das dem verschlüsselten Volume hinzugefügt werden soll Reenter Password Passwort erneut eingeben Password Passwort KeyFile Schlüsseldatei Key+KeyFile Schlüssel + Schlüsseldatei YubiKey Challenge/Response Advanced LUKS2 Options LUKS LUKS TrueCrypt TrueCrypt VeraCrypt VeraCrypt Volume Type Volume-Typ PIM PIM TextLabel Textmarkierung &OK Advanced Luks2 Options Set Pbkdf Type argon2id argon2i pbkdf2 Max Memory (KB) Parallel Threads Unlocking Time Cost(Milliseconds) Forced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) Cancel Abbrechen &Add &Hinzufügen &Cancel &Abbrechen open keyfile Öffne Schlüsseldatei Passphrase Quality: 0% Passphrasenqualität: 0% Passphrase Quality: %1% Passphrasenqualität: %1% Add A Key To A Volume Schlüssel zu Volume hinzufügen Encrypted Volume Path Pfad zum verschlüsselten Volume Enter a path to a keyfile location Geben Sie einen Pfad zu einer Schlüsseldatei an Key Slot Number To Add Key In Enter a key Geben Sie einen Schlüssel ein Passphrase Quality: 100% Passphrasenqualität: 100% Atleast one required field is empty Mindestens ein benötigtes Feld ist leer Failed to enable polkit support Die polkit-Unterstützung konnte nicht aktiviert werden Keys do not match Die Schlüssel stimmen nicht überein Failed To Locate Or Run Yubikey's "ykchalresp" Program. Key added successfully. Schlüssel erfolgreich hinzugefügt. Key added successfully. %1 / %2 slots are now in use Schlüssel erfolgreich hinzugefügt. %1 / %2 Slots sind jetzt in Benutzung Presented key does not match any key in the volume Der vorgelegte Schlüssel stimmt mit keinem Schlüssel im Volume überein Could not open luks volume Das LUKS-Volume konnte nicht geöffnet werden Volume is not a luks volume Das Volume ist kein LUKS-Volume Insufficient privilege to add a key to a system device, only root user or members of group "zulucrypt" can do that Unzureichende Rechte, um einen Schlüssel zu einem Systemgerät hinzuzufügen, nur der Benutzer root oder Mitglieder der Gruppe "zulucrypt" dürfen das Could not open volume in write mode Das Volume konnte nicht im Schreibmodus geöffnet werden All key slots are occupied, can not add any more keys Alle Schlüsselslots sind belegt, es konnte kein weiterer Schlüssel hinzugefügt werden Can not get passphrase in silent mode Konnte die Passphrase nicht im stillen Modus bekommen Insufficient memory to hold passphrase Nicht genügend Speicherplatz zum Speichern der Passphrase New passphrases do not match Die neuen Passphrasen stimmen nicht überein One or more required argument(s) for this operation is missing Ein oder mehrere Argument(e) für diese Operation fehlt/fehlen One or both keyfile(s) does not exist Eine oder beide Schlüsseldatei(en) existieren nicht Insufficient privilege to open key file for reading Unzureichende Rechte zum Öffnen der Schlüsseldatei zum Lesen Couldnt get enought memory to hold the key file Konnte nicht genügend Speicher zum Speichern der Schlüsseldatei bekommen Could not get a key from a socket Konnte keinen Schlüssel vom Socket bekommen Could not get elevated privilege,check binary permissions Konnte keine erhöhten Berechtigungen bekommen, überprüfen Sie die binären Berechtigungen Key slot already occupied Failed to find empty key slot or key slot out of range Can not find a partition that match presented UUID Konnte keine Partition mit der angegebenen UUID finden Device is not a luks device Das Gerät ist kein LUKS-Gerät Error Code: %1 -- StdOut: %2 -- StdError: %3 Fehlercode: %1 -- Standardausgabe: %2 -- Standardfehlerausgabe: %3 ERROR! FEHLER! Enter A Key Geben Sie einen Schlüssel ein KeyFile Path Pfad zur Schlüsseldatei KeyFile path Pfad zur Schlüsseldatei Existing KeyFile Existierende Schlüsseldatei New KeyFile Neue Schlüsseldatei luksdeletekey open a keyfile Öffne eine Schlüsseldatei Remove A Key From A Volume Schlüssel aus einem Volume entfernen LUKS Slot Number Password Passwort &Delete &Löschen &Cancel &Abbrechen Volume Path Volume-Pfad open an encrypted file Eine verschlüsselte Datei öffnen open an encrypted partition Eine verschlüsselte Partition öffnen KeyFile Schlüsseldatei Key+KeyFIle Schlüssel + Schlüsseldatei TextLabel Textmarkierung &OK ERROR! FEHLER! Enter a key Geben Sie einen Schlüssel ein YubiKey Challenge/Response zuluCrypt will have the same behavious as luksKillSlot if a key slot is given zuluCrypt will have the same behavious as luksRemoveKey if a key slot is NOT given Enter a path to a keyfile location Geben Sie einen Pfad zu einer Schlüsseldatei an KeyFile path Pfad zur Schlüsseldatei Key File With A Passphrase To Delete Schlüsseldatei mit einer zu löschenden Passphrase Atleast one required field is empty Mindestens ein benötigtes Feld ist leer Failed to enable polkit support Die polkit-Unterstützung konnte nicht aktiviert werden Volume is not a luks volume Das Volume ist kein LUKS-Volume There is only one last key in the volume. Es gibt nur noch einen letzten Schlüssel im Volume. Deleting it will make the volume unopenable and lost forever. Das Löschen dieses Schlüssels führt dazu, dass das Volume nicht mehr geöffnet werden kann und für immer verloren ist. Are you sure you want to delete this key? Sind Sie sicher, dass Sie diesen Schlüssel löschen möchten? WARNING WARNUNG Failed To Locate Or Run Yubikey's "ykchalresp" Program. Key removed successfully. %1 / %2 slots are now in use Schlüssel erfolgreich gelöscht. %1 / %2 Slots sind nun in Benutzung There is no key in the volume that match the presented key Der eingegebene Schlüssel stimmt mit keinem Schlüssel im Volume überein Could not open the volume Das Volume konnte nicht geöffnet werden Insufficient privilege to open a system device,only root user or members of group zulucrypt can do that Unzureichende Rechte zum Zugriff auf ein Systemgerät, nur der Benutzer root und Mitglieder der Gruppe zulucrypt dürfen das Could not open the volume in write mode Das Volume konnte nicht im Schreibmodus geöffnet werden Insufficient memory to hold your response Nicht genügend Speicherplatz zum Speichern Ihrer Antwort Operation terminated per user request Die Operation wurde durch den Benutzer abgebrochen Can not get passphrase in silent mode Konnte die Passphrase nicht im stillen Modus bekommen Insufficient memory to hold passphrase Nicht genügend Speicherplatz zum Speichern der Passphrase One or more required argument(s) for this operation is missing Ein oder mehrere Argument(e) für diese Operation fehlt/fehlen Keyfile does not exist Die Schlüsseldatei existiert nicht Could not get enough memory to open the key file Konnte nicht genug Speicher zum Halten der Schlüsseldatei bekommen Insufficient privilege to open key file for reading Unzureichende Rechte zum Öffnen der Schlüsseldatei zum Lesen Could not get a key from a socket Konnte keinen Schlüssel vom Socket bekommen Can not find a partition that match presented UUID Konnte keine Partition mit der angegebenen UUID finden Error Code: %1 -- StdOut: %2 -- StdError: %3 Fehlercode: %1 -- Standardausgabe: %2 -- Standardfehlerausgabe: %3 manageSystemVolumes Manage System Volumes System-Volumes verwalten &Done &Fertig Add Fi&le Datei &hinzufügen Add Dev&ice Gerät &hinzufügen Path To System Volumes Pfad zu System-Volumes Remove Selected Entry Entferne markierten Eintrag Cancel Abbrechen Are you sure you want to remove "%1" from the list? Sind Sie sicher, dass Sie "%1" aus der Liste entfernen möchten? Select Path To System Volume Pfad zum System-Volume auswählen WARNING WARNUNG managevolumeheader Backup Volume Header Volume-Kopfdaten sichern Backup Name C&reate &Erstellen &Cancel Abbre&chen Volume Path Volume-Pfad Window System Volume Windows System-Volume Volume Type Volume-Typ Manage A VeraCrypt Header Einen VeraCrypt Header verwalten PIM PIM Password Passwort Password Source Passwortquelle Outer Volume Password ONLY NUR das Passwort für das äußere Volume KeyFile Schlüsseldatei TextLabel Textmarkierung Normal Volume Normales Volume Whole Drive Encrypted Volume Verschlüsseltes Volume über das gesamte Laufwerk Manage A LUKS Header LUKS-Kopfdaten verwalten Manage A TrueCrypt Header TrueCrypt-Kopfdaten verwalten ERROR! FEHLER! Restore volume header Volume-Kopfdaten wiederherstellen &Restore &Wiederherstellen Back up volume header Volume-Kopfdaten sichern &Backup &Backup Atleast one required field is empty Mindestens ein benötigtes Feld ist leer Failed to enable polkit support Die polkit-Unterstützung konnte nicht aktiviert werden Are you sure you want to replace a header on device "%1" with a backup copy at "%2"? Sind Sie sicher, dass Sie die Kopfdaten auf dem Gerät "%1" mit einer Sicherungskopie von "%2" ersetzen möchten? WARNING! Warnung! Select luks container you want to backup its header Wählen Sie den LUKS-Container aus, dessen Kopfdaten Sie sichern möchten Header restored successfully Kopfdaten erfolgreich wiederhergestellt Presented device is not a LUKS device Das präsentierte Gerät ist kein LUKS-Gerät Failed to perform requested operation Konnte die gewählte Aktion nicht ausführen Operation terminater per user request Aktion vom Anwender abgebrochen Path to be used to create a back up file is occupied Der zu verwendende Pfad für eine Sicherung ist belegt Insufficient privilege to open backup header file for reading Unzureichende Rechte zum Öffnen der Sicherung der Kopfdaten zum Lesen Invalid path to back up header file Ungültiger Pfad zum Sichern der Kopfdaten-Datei Insufficient privilege to create a backup header in a destination folder Unzureichende Rechte zum Erstellen einer Sicherung der Kopfdaten in einem Zielordner Invalid path to device Ungültiger Pfad zum Gerät Argument for path to a backup header file is missing Argument für den Pfad zur Sicherung der Kopfdaten-Datei fehlt Only root user and "zulucrypt" members can restore and back up luks headers on system devices Nur der Benutzer root und Miglieder der Gruppe "zulucrypt" können LUKS-Kopfdaten auf Systemgeräten erstellen und wiederherstellen Insufficient privilege to open device for writing Unzureichende Rechte um das Gerät zum Schreiben zu öffnen Could not resolve path to device Konnte den Pfad zum Gerät nicht auflösen Backup file does not appear to contain luks header Die Sicherungsdatei scheint keine LUKS-Kopfdaten zu enthalten Insufficient privilege to open device for reading Unzureichende Rechte um das Gerät zum Lesen zu öffnen Wrong password entered or volume is not a truecrypt volume Falsches Passwort eingegeben oder das Volume ist kein TrueCrypt-Volume Failed to perform requested operation on the LUKS volume Konnte die angeforderte Aktion auf dem LUKS-Volume nicht ausführen Wrong password entered or volume is not a veracrypt volume Falsches Passwort eingegeben oder das Volume ist kein VeraCrypt-Volume Unrecognized ERROR! with status number %1 encountered Ein Unbekannter FEHLER mit der Statusnummer %1 ist aufgetreten SUCCESS ERFOLG Select A File With A LUKS Backup Header Wählen Sie eine Datei mit der Sicherung der LUKS-Kopfdaten aus Select A Folder To Store The Header Wählen Sie einen Ordner zur Sicherung der Kopfdaten aus Header saved successfully. If possible,store it securely. Kopfdaten erfolgreich gespeichert. Wenn möglich, bewahren Sie sie sicher auf. INFO! INFORMATION! oneinstance There seem to be another instance running,exiting this one Es scheint bereits eine Instanz zu laufen, breche ab Previous instance seem to have crashed,trying to clean up before starting Die vorherige Instanz scheint abgestürzt zu sein, versuche sie vor dem Start zu bereinigen openvolume Select A Partition To Open Wählen Sie eine Partition zum Öffnen aus Use UUID UUID verwenden &Help &Hilfe Use &UUID &UUID verwenden &Cancel &Abbrechen partition Partition size Größe label Bezeichnung type Typ uuid UUID &Open &Öffnen A list of all partitions on this system are displayed here. Double click an entry to use it Eine Liste aller Patitionen des Systems wird hier angezeigt. Klicken Sie doppelt auf einen Eintrag, um ihn zu verwenden Restart the tool from root's account or after you have created and added yourself to group "zulucrypt" if the volume you want to use is not on the list. Starten Sie die Anwendung von einem root-Konto aus neu oder nachdem Sie sich der Gruppe "zulucrypt" hinzugefügt haben, wenn das Volume, das Sie verwenden möchten, nicht in der Liste enthalten ist. You are a root user and all partitions are displayed. Double click an entry to use it Sie sind der Benutzer root und alle Partitionen werden angezeigt. Klicken Sie doppelt auf einen Eintrag, um ihn zu verwenden INFO INFORMATION Select A Partition To Create An Encrypted Volume In Wählen Sie eine Partition aus, in der Sie ein verschlüsseltes Volume erstellen möchten Select An Encrypted Partition To Open Wählen Sie eine verschlüsselte Partition zum Öffnen aus Only crypto_LUKS volumes can be selected Es können nur crypto_LUKS-Volumes ausgewählt werden ERROR FEHLER passwordDialog "/" character is not allowed in mount name field Das "/" Zeichen ist im Namensfeld des Einhängepunktes nicht erlaubt Cancel Abbrechen Mount "%1" "%1" einhängen TrueCrypt/VeraCrypt Keys TrueCrypt/VeraCrypt-Schlüssel YubiKey Challenge/Response Check This Box To Make Password Visible Aktivieren Sie dieses Kontrollkästchen, um das Passwort sichtbar zu machen Unlock Encrypted Volume Verschlüsseltes Volume aufschließen PIM Value PIM-Wert Offset Offset Offset Will Be In Sectors If The Entry Is Made Up Of Only Digits And In Bytes If The Entry Ends With "b" And In Kilobytes If The Entry Ends With "k" And In Megabytes If The Entry Ends With "m" And In Terabytes If The Entry Ends With "t" Offset wird in Sektoren sein, wenn die Eingabe nur aus Ziffern besteht oder in Byte, wenn der Eintrag mit "b" endet oder in Kilobyte, wenn der Eintrag mit "k" endet oder in Megabyte, wenn der Eintrag mit "m" endet oder in Terabyte, wenn der Eintrag mit "t" endet Choose A Module From The File System Wählen Sie ein Modul aus dem Dateisystem aus Enter A Module Name To Use To Get Passphrase Geben Sie einen Modulnamen ein, der verwendet werden soll, um die Passphrase zu bekommen Plugin Name Erweiterungsname Password Passwort Select A Key Module Wählen Sie ein Schlüssel-Modul Enter A Key Geben Sie einen Schlüssel ein Select External LUKS Header File LUKS External Header Path Choose A KeyFile From The File System Wählen sie eine Schlüsseldatei aus dem Dateisystem Enter A Path To A Keyfile Location Geben Sie einen Pfad zu einer Schlüsseldatei an KeyFile Path Pfad zur Schlüsseldatei Select A KeyFile Wählen Sie eine schlüsseldatei Select Path To Mount Point Folder Wählen sie den Pfad zum Einhängepunkt des Ordners Select Encrypted volume Verschlüsseltes Volume auswählen ERROR! FEHLER! Internal wallet is not configured Interne Brieftasche ist nicht konfiguriert ERROR FEHLER Failed To Locate Or Run Yubikey's "ykchalresp" Program. Atleast one required field is empty Mindestens ein erforderliches Feld ist leer Volume is not a LUKS volume Volume ist kein LUKS-Volume Failed to get a key from the network Das Abrufen eines Schlüssels aus dem Netzwerk ist fehlgeschlagen Failed to get a key from a plugin Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? Konnte das NTFS/EXFAT-Dateisystem mit ntfs-3g nicht einhängen, ist das ntfs-3g-Paket installiert? There seem to be an open volume accociated with given address Es scheint ein geöffnetes Volumen zu geben, das mit der angegebenen Adresse verknüpft ist No file or device exist on given path Es existiert keine Datei oder Gerät am angegebenen Pfad Volume could not be opened with the presented key Das Volume konnte nicht mit dem eingegebenen Schlüssel geöffnet werden Insufficient privilege to mount the device with given options Unzureichende Rechte zum Einhängen des Geräts mit den angegebenen Optionen Insufficient privilege to open device in read write mode or device does not exist Unzureichende Rechte zum Öffnen des Geräts im Schreib-/Lesemodus oder das Gerät existiert nicht Only root user can perform this operation Nur root kann diese Operation ausführen Could not create mount point, invalid path or path already taken Es konnte kein Einhängepunkt erstellt werden, ungültiger Pfad oder bereits vergebener Pfad Shared mount point path already taken Der gemeinsame Einhängepunktpfad ist bereits vergeben There seem to be an opened mapper associated with the device Es scheint ein geöffneter Mapper mit dem Gerät assoziiert zu sein Could not get a passphrase from the module Konnte keine Passphrase von dem Modul erhalten Could not get passphrase in silent mode Konnte die Passphrase nicht im stillen Modus erhalten Insufficient memory to hold passphrase Nicht genügend Speicherplatz zum Speichern der Passphrase One or more required argument(s) for this operation is missing Ein oder mehrere Argument(e) für diese Operation fehlt/fehlen Invalid path to key file Ungültiger Pfad zur Schlüsseldatei Could not get enought memory to hold the key file Konnte nicht genügend Speicher zum Speichern der Schlüsseldatei bekommen Insufficient privilege to open key file for reading Unzureichende Rechte zum Öffnen der Schlüsseldatei zum Lesen Could not get a passphrase through a local socket Konnte keine Passphrase über den lokalen Socket erhalten Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered Konnte kein Dateisystem einhängen: ungültige/nicht unterstützte Einhängeoption oder nicht unterstütztes Dateisystem entdeckt Could not create a lock on /etc/mtab Konnte keine Sperre für /etc/mtab erstellen Insufficient privilege to open a system volume. Consult menu->help->permission for more informaion Unzureichende Rechte zum Öffnen eines System-Volumes. Siehe Menü->Hilfe->Berechtigung für weitere Informationen A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature Ein nicht unterstütztes Gerät wurde gefunden, das Gerät fehlt oder Sie haben keine Berechtigung. Mögliche Gründe für diesen Fehler sind: 1. Der Gerätepfad ist ungültig. 2. Das Gerät hat eine LVM oder MD-RAID Signatur Error Code: %1 -- StdOut: %2 -- StdError: %3 Fehlercode: %1 -- Standardausgabe: %2 -- Standardfehlerausgabe: %3 -O and -m options can not be used together Die Optionen -O und -m können nicht zusammen verwendet werden plugin Key Generator Using A Passphrase And A KeyFile Schlüsselgenerator unter Verwendung einer Passphrase und einer Schlüsseldatei &Set Key &Schlüssel festlegen &Cancel &Abbrechen Create an encryption key that is made up of a passphrase and a keyfile. A volume created with a key generated here should be opened with "hmac" plugin. Erstellen Sie einen Verschlüsselungscode, der aus einer Passphrase und einer Schlüsseldatei besteht. Ein Volume, das mit einem hier erzeugten Schlüssel erstellt wurde, sollte mit der Erweiterung "hmac" geöffnet werden. Passphrase Passphrase KeyFile Schlüsseldatei ERROR FEHLER KeyFile Not Set Schlüsseldatei nicht angegeben Failed To Generate Key Konnte Schlüssel nicht erstellen readOnlyWarning WARNING WARNUNG Do Not Show This Message Again. Diese Meldung nicht erneut anzeigen. Setting this option will cause the volume to open in read only mode. Wenn Sie diese Option aktivieren, wird das Volume im Nur-Lese-Modus geöffnet. &Ok &OK tcrypt &Open &Öffnen &Cancel &Abbrechen Add &Keyfile &-Schlüsseldatei hinzufügen Keyfile Paths Schlüsseldatei-Pfade Enter A Passphrase Below To Be Used To Open The Volume Geben Sie unten eine Passphrase ein, die zum Öffnen des Volumes verwendet werden soll drag and drop key files to add them to the list Schlüssel-Dateien per Drag-and-Drop der Liste hinzufügen TrueCrypt Keys TrueCeypt-Schlüssel Enter key files below to be used to open the volume Geben Sie unten die Schlüsseldateien ein, die zum Öffnen des Volumes verwendet werden sollen &Set &festlegen TrueCrypt/VeraCrypt Keys TrueCrypt/VeraCrypt-Schlüssel ERROR FEHLER At least one keyfile is required Es wird mindestens eine Schlüssel-Datei benötigt Select A KeyFile Wählen Sie eine Schlüssel-Datei utility::veraCryptWarning Elapsed time: 0 seconds Vergangene Zeit: 0 Sekunden Elapsed time: %0 minutes Vergangene Zeit: %0 Minuten Elapsed time: %0 seconds Vergangene Zeit: %0Sekunden Please be patient as unlocking a VeraCrypt volume may take a very long time. Bitte haben Sie Geduld, da das Aufschließen eines VeraCrypt-Volumes sehr lange dauern kann. warnWhenExtendingContainerFile WARNING!! WARNUNG!! OK OK Dont Show This Warning Again. Diese Warnung nicht erneut anzeigen. Your cover file will be irreversibly changed and we suggest continuing with a backup file and not the original. To unlock the volume about to be created, you will need to enter the password you will choose and the volume offset automatically generated by zuluCrypt. Instructions to unlock the volume are as follows: 1. From the menu, choose Open -> Volume Hosted In A File. 2. Select file, then choose "Volume Type" = PLAIN dm-crypt. 3. Enter the generated offset value along with your password. Ihre Cover-Datei wird unwiderruflich geändert und wir empfehlen, mit einer Sicherungsdatei fortzufahren und nicht mit dem Original. Um das zu erstellende Volume freizuschalten, müssen Sie das von Ihnen gewählte Passwort und den von zuluCrypt automatisch generierten Volume-Offset eingeben. Anweisungen zum Entsperren des Volumes lauten wie folgt: 1. Wählen Sie im Menü Öffnen -> Volume in einer Datei 2. Wählen Sie die Datei aus und wählen Sie dann "Volume-Typ" = PLAIN dm-crypt. 3. Geben Sie den generierten Offset-Wert zusammen mit Ihrem Passwort ein. IMPORTANT!!! WICHTIG!!! zuluCrypt zuluCrypt zuluCrypt Type Typ Optio&ns &Optionen &zC &zC Ctrl+Z Strg+Z Ctrl+X Strg+X Ctrl+A Strg+A Encrypted &Container In A Hard Drive &Verschlüsselter container auf einer Ferstplatte Ctrl+S Strg+S &About &Über Ctrl+R Strg+R &Add A Key To A Volume &Schlüssel zu einem Volume hinzufügen Ctrl+U Strg+U &Delete A Key From A Volume &Schlüssel aus einem Volume löschen Ctrl+W Strg+W crypto info Verschlüsselungsinformation Ctrl+E Strg+E &KeyFile &Schlüssel-Datei Ctrl+D Strg+D &Tray Icon &Systray-Symbol Ctrl+K Strg+K Encrypted Volume Path Pfad zum verschlüsselten Volume Encrypted Volume Mount Point Path Einhängepunktpfad des verschlüsselten Volumes &Open &Öffnen &Create &Erstellen &Help &Hilfe &Volumes &Volumes &Favorites &Favoriten Ctrl+L Strg+L favorite volumes Favorisierte Volumes manage favorites Favoriten verwalten select random number generator Zufallszahlengenerator wählen Ctrl+P Strg+P close application Anwendung schließen Ctrl+C Strg+C Ctrl+T Strg+T Quit Schließen VeraCrypt Container In A File VeraCrypt-Container in einer Datei VeraCrypt Container In A Hard Drive VeraCrypt-Container auf einer Festplatte Shift+I Umschalt+I Select Language Sprache auswählen Ctrl+Y Strg+Y Ctrl+Q Strg+Q Ctrl+G Strg+G Ctrl+F Strg+F &Erase Data In A Device &Daten in einem Gerät löschen Ctrl+N Strg+N &Backup Header Kopfdaten &sichern Ctrl+B Strg+B &Restore Header Kopfdaten wiede&rherstellen Ctrl+I Strg+I Encrypt A &File &Eine Datei verschlüsseln &Decrypt A File &Eine Datei entschlüsseln Ctrl+H Strg+H &Header Backup &Kopfdaten-Sicherung Ctrl+J Strg+J Manag&e System Volumes System-Volumes v&erwalten Manage &Volumes In Internal Wallet &Volumes in interner Brieftasche verwalten configure wallets Brieftaschen konfigurieren Manage &Non System Volumes &Nicht-System-Volumes verwalten Manage Volumes In &KDE Wallet Volumes in &KDE Wallet verwalten Shift+V Umschalt+V Manage Volumes In &GNOME keyring Volumes in &GNOME Keyring verwalten Alt+V Alt+V &Change Internal Wallet Password &Internes Brieftaschenpasswort ändern Ctrl+O Strg+O tcrypt backup header TrueCrypt-Kopfdaten sichern tcrypt restore header TrueCrypt-Kopfdaten wiederherstellen H&elp H&ilfe F1 F1 Show LUKS Key Slots Set Fi&le Manager Dateimanager fest&legen Do Not Minimize To Tray Nicht in das Benachrichtigungsfeld minimieren This Option Will Close The App Instead Of Minimizing It To Tray Diese Option schließt die App, anstatt sie in das Benachrichtigungsfeld zu minimieren Encrypted Container Hidden In Video/Cover File (Steganography) Verschlüsselter Container versteckt in Video/Cover-Datei (Steganographie) Show Debug Window Debugfenster anzeigen Ctrl+Shift+D Strg+Umschalt+D Encrypted Container In An Existing File Verschlüsselter Container in einer vorhandenen Datei Clear Dead Mount Points Contact &Info &Kontakt-Info &Select Language &Sprache auswählen &Auto Open Mount Point &Einhängepunkt automatisch öffnen Select &Icons Symbole aus&wählen Ctrl+V Strg+V &Volume Hosted In A File &Volume in einer Datei Volume &Hosted In A Hard Drive Volume &auf einer Festplatte &Encrypted Container In A New File &Verschlüsselter Container in einer neuen Datei Select &Font &Font wählen &Update Volume List Volume-Liste &erneuern &Minimize To Tray &Ins Systray minimieren &Quit &Schließen &Close All Opened Volumes Alle geöffneten Volumes s&chließen &Manage Favorites &Favoriten verwalten permissions Berechtigungen Ctrl+M Strg+M Restore Volume Header Volume-Kopfdaten wiederherstellen Backup Volume Header Volume-Kopfdaten sichern WARNING! WARNUNG! Resetting font size to %1 because larger font sizes do not fit Die Schriftgröße wird auf %1 zurückgesetzt, weil größere Schriftgrößen nicht passen INFO INFORMATION Important Information On Volume Header Backup Wichtige Informationen zur Sicherung der Volume-Kopfdaten Volume is not open or was opened by a different user Das Volume ist nicht geöffnet oder es wurde von einem anderen Benutzer geöffnet Volume Properties Volume-Eigenschaften Could not open mount point because "%1" tool does not appear to be working correctly Der Einhängepunkt konnte nicht geöffnet werden, weil das Werkzeug "%1" nicht richtig zu funktionieren scheint Properties Eigenschaften Open Folder Ordner öffnen ERROR FEHLER zuluCrypt Failed To Connect To zuluPolkit. Please Report This Serious Bug. Die Verbindung zwischen zuluCrypt und zuluPolkit ist fehlgeschlagen. Bitte melden Sie diesen schwerwiegenden Fehler. Cryptsetup library could not be found and zuluCrypt will most likely not work as expected. Please recompile zuluCrypt to force it to re-discover the new library Path To A File Pfad zu einer Datei Show/Hide Anzeigen/Ausblenden LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a "volume header". A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data. The damage to the header is usually caused by accidental formatting of the device or use of some buggy partitioning tools or wrongly reassembled logical volumes. Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted. LUKS, TrueCrypt und VeraCrypt-basierte verschlüsselte Volumes haben sogenannte "Volume-Kopfdaten". Volume-Kopfdaten sind verantwortlich für die Speicherung von Informationen, die zum Öffnen der Kopfdaten mit verschlüsseltem Volume erforderlich sind, und jede Beschädigung macht es unmöglich, das Volume zu öffnen, was zum dauerhaften Verlust verschlüsselter Daten führt. Die Beschädigung der Kopfdaten wird in der Regel durch versehentliche Formatierung des Geräts oder durch die Verwendung einiger fehlerhafter Partitionierungswerkzeuge oder falscher Zusammenstellungen von logischen Volumes verursacht. Eine Sicherung der Volume-Kopfdaten wird dringend empfohlen, da nur so die verschlüsselten Daten nach der Wiederherstellung der Kopfdaten wieder zugänglich sind, wenn die Kopfdaten auf dem Volume beschädigt werden. Open Private Folder Öffne privates Verzeichnis Open Shared Folder Gemeinsamen Ordner öffnen Add Key Schlüssel hinzufügen Remove Key Schlüssel löschen Show Key Slots Information Backup LUKS Header LUKS-Kopfdaten sichern Add To Favorite Zu Favoriten hinzufügen Unmount Aushängen Cancel Abbrechen Close failed, volume is not open or was opened by a different user Schließen fehlgeschlagen, das Volume ist nicht geöffnet oder es wurde von einem anderen Benutzer geöffnet Close failed, one or more files in the volume are in use. Schließen fehlgeschlagen, eine oder mehrere Dateien im Volume werden verwendet. Close failed, volume does not have an entry in /etc/mtab Schließen fehlgeschlagen, das Volume hat keinen Eintrag in /etc/mstab Close failed, could not get a lock on /etc/mtab~ Schließen fehlgeschlagen, konnte keine Sperre auf /etc/mtab~ erhalten Close failed, volume is unmounted but could not close mapper,advice to close it manually Schließen fehlgeschlagen, das Volume ist nicht eingehängt, aber der Mapper konnte nicht geschlossen werden. Es wird empfohlen, ihn manuell zu schließen Close failed, could not resolve full path of device Schließen fehlgeschlagen, der Pfad zum Gerät konnte nicht aufgelöst werden Close failed, shared mount point appear to be busy Schließen fehlgeschlagen, der gemeinsame Einhängepunkt scheint ausgelastet zu sein Close failed, shared mount point appear to belong to a different user or multiple mount points detected Schließen fehlgeschlagen, der gemeinsame Einhängepunkt scheint einem anderen Benutzer zu gehören oder es wurden mehrere Einhängepunkte erkannt Close failed, shared mount point appear to be in an ambiguous state,advice to unmount manually Schließen fehlgeschlagen, der gemeinsame Einhängepunkt scheint in einem ungewöhnlichen Zustand zu sein. Es wird empfohlen, ihn manuell auszuhängen Close failed, multiple mount points for the volume detected Schließen fehlgeschlagen, für das Volume wurden mehrere Einhängepunkte erkannt Close failed, could not find any partition with the presented UUID Schließen fehlgeschlagen, es wurde keine Partition mit der angegebenen UUID gefunden Unrecognized error with status number %1 encountered Ein unbekannter Fehler mit der Statusnummer %1 ist aufgetreten ERROR! FEHLER! zuluCrypt-6.2.0/translations/zuluCrypt/en_US.qm000066400000000000000000000000201425361753700216570ustar00rootroot00000000000000<¸dÊÍ!¿`¡½ÝzuluCrypt-6.2.0/translations/zuluCrypt/en_US.ts000066400000000000000000010063571425361753700217140ustar00rootroot00000000000000 DialogMsg Dialog &Ok &Yes &No text type cipher key size device loop offset size mode fs used unused used % active slots "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. INFORMATION Insufficient privilege to access a system device, only root user or members of group zulucrypt can do that Insufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that You do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again type: cipher: keysize: offset: device: loop: mode: active slots: file system: total space: used space: free space: used%: UUID: Do not show this dialog again PasswordDialog Open Encrypted Volume &Open &Cancel Mount In &Read Only Mode select mount point path open volume path open key file Password LUKS/TrueCrypt/BitLocker Mount Name &Options Volume Path KeyFile Key+KeyFile Plugin &Share Mount Point VeraCrypt VeraCrypt System PLAIN dm-crypt Volume Type TextLabel &OK Enter Comma Separated Volume's File System Options Below Set Cancel QObject zuluCrypt: Failed To Establish Connection With zuluPolkit options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI If the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2" public mount point: Manage Favorites Mount All about zuluCrypt hmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents) keykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contents gpg plugin. This plugin retrives a key locked in a gpg file with a symmetric key Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit. ERROR Failed to locate pkexec executable "%1" and "%2" Folders Must Be Writable. Could not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin" createVolumeDialog Warning!! &Yes &No This operation will lead to permanent destrunction of all present data in /dev/sdc1. Are you sure you want to continue? This operation will lead to permanent destrunction of all present data in "%1". Are you sure you want to continue? It is advised to create encrypted containers over random data to prevent information leakage. Do you want to write random data to "%1" first before creating an encrypted container in it? You can stop the random data writing process anytime you want if it takes too long and you can no longer wait. createVolumeInExistingFIle Create Volume In Existing File Select Cover File (Video files like mp4 and mkv) Container Size (MB) Volume Properties &Cancel C&reate Volume OffSet (Auto calculated) Create A Plain dm-crypt Container Hidden Inside Cover File (Steganography) Password TextLabel Extending A Host File Size. Enter Path To Existing File Average Speed: ETA: Percentage Completed: %1% ERROR AtLeast One Required Field Is Empty Illegal Character Found In The Container Size Field Failed To Open File In Write Mode Failed To Open "/dev/urandom" Device In Read Mode Creating A Plain DM-Crypt Volume Volume Created Successfully Failed To Create A Volume createfile Create A Container File File Name File Path File Size open a folder dialog box &Cancel % Complete C&reate KB MB GB Do Not Write Random Data To Container(STRONGLY discouraged) TextLabel &OK By default,zuluCrypt creates a volume in a container file over randomly generated data to hide usage patterns of the container. This process takes time and it may take a very,very long time if the volume about to be created is large enough and this option exists to skip the process for the impatient among us but but it comes at a cost and the cost may be too high when it finally reveal itself while infront of an adversary when they look at the encrypted container and manage to derive meaning based on how the container looks from outside. If you know what you are doing,then continue by all means,if in doubt,my advise is to endure the process and be safer in the long run. INFO File name field is empty File path field is empty File size field is empty WARNING Are you really sure you do not want to create a more secured volume? Illegal character in the file size field.Only digits are allowed File with the same name and at the destination folder already exist You dont seem to have writing access to the destination folder Container file must be bigger than 3MB Failed to create volume file Failed to enable polkit support Operation terminated per user choice Could not open cryptographic back end to generate random data Terminating file creation process Are you sure you want to stop file creation process? Average Speed: ETA: Select Path to where the file will be created createkeyfile Create A KeyFile Keyfile Name path to a folder to create a key in open a folder a key file will be created in C&reate &Cancel KeyFile Path RNG TextLabel &OK The key name field is empty Folder path to where the key will be created is empty File with the same name and at the destination folder already exist You dont seem to have writing access to the destination folder Process interrupted,key not fully generated KeyFile successfully created Select A Folder To Create A Key File In createvolume Create A New Volume Path to Device C&reate &Cancel open a key file Key Password Repeat Password Advanced LUKS2 Options Volume Type Volume Size Bytes KiloBytes MegaBytes GigaBytes Iteration Time (milliseconds) Volume Options File System random number generator RNG PIM TextLabel Advanced Luks2 Options Set Label Sub System Pbkdf Type argon2id argon2i pbkdf2 Max Memory (KB) Parallel Threads Unlocking Time Cost(Milliseconds) Allow Discard(TRIM) Forced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) Cancel Options are separated by a "." character. Multiple algorithms are separated by ":" character. Options are in a format of "algorithm.cipher mode.key size in bits.hash" Default option is the first entry on the list KeyFile Key+KeyFile YubiKey Challenge/Response PLAIN dm-crypt PLAIN dm-crypt with offset LUKS1 LUKS1+External Header LUKS2 LUKS2+External Header LUKS LUKS+External Header Normal TrueCrypt Normal+Hidden TrueCrypt Normal VeraCrypt Normal+Hidden VeraCrypt Passphrase Quality: 0% Passphrase Quality: %1% TrueCrypt Keys VeraCrypt Keys Volume Offset Path To Device Path To File Keyfile Path Passphrase Quality: 100% Keys ERROR! Failed to enable polkit support Volume path field is empty Atleast one required field is empty Illegal character detected in the hidden volume size field Hidden passphrases do not match WARNING It is best to create a hidden volume with vfat/fat file system. Passphrases do not match ERROR Failed To Locate Or Run Yubikey's "ykchalresp" Program. Please be patient as creating a VeraCrypt volume may take a very long time. WARNING! Volume created successfully but failed to create an external header SUCCESS! Luks volume created successfully. Luks volume created successfully,external header created successfully but failed to erase header on the device Volume created successfully. Creating a backup of the "%1" volume header is strongly advised. Please read documentation on why this is important. Presented file system is not supported,see documentation for more information insufficient privilege to open a system device in read/write mode, only root user or members of group zulucrypt can do that Could not create an encrypted volume Could not open volume for writing There seem to be an opened mapper associated with the device Can not create a volume on a mounted device Container file must be bigger than 3MB %1 not found Insufficient memory to hold your response Operation terminated per user request Could not get passphrase in silent mode Insufficient memory to hold the passphrase Invalid path to key file Could not get a key from a key file Couldnt get enought memory to hold the key file Could not get a key from a socket One or more required argument(s) for this operation is missing Can not get passphrase in silent mode Insufficient memory to hold passphrase Failed to create a volume Wrong argument detected for tcrypt volume Could not find any partition with the presented UUID Error Code: %1 -- StdOut: %2 -- StdError: %3 cryptfiles Destination C&reate Source Password Repeat Password TextLabel &OK Key KeyFile Key+KeyFile Repeat Key &Cancel % Complete Create An Encrypted Version Of A File Create A Decrypted Version Of An encrypted File Path to source field is empty Invalid path to source file Destination path already taken You dont seem to have writing access to the destination folder Invalid path to key file First key field is empty Second key field is empty Keys do not match These very old encrypted files are no longer supported Select Path to put destination file Enter A Key Enter A Path To A Keyfile Location keyfile path Generate a key made up of a passphrase and a keyfile Select A File You Want To Encrypt zuluCrypt encrypted files ( *.zc ) ;; All Files ( * ) Select A File You Want To Decrypt Select A Keyfile Encrypted file created successfully Decrypted file created successfully Could not open keyfile for reading Could not open encryption routines File or folder already exist at destination address Insufficient privilege to create destination file Presented key did not match the encryption key Operation terminated per user request Insufficient privilege to open source file for reading Decrypted file created successfully but md5 checksum failed,file maybe corrupted Could not open reading encryption routines Could not open writing encryption routines Failed to close encryption routine cryptoinfo Greetings Ok Please consult "menu->help->open zuluCrypt.pdf" to get an introduction on zuluCrypt. Unity users,the menu is on the upper left corner of the screen when zuluCrypt has focus. Project's homepage is at: https://mhogomchungu.github.io/zuluCrypt Recommending reading FAQ page from the project's main page. Do not show this message again. debugWindow zuluCrypt Debug Window C&lear &Close dialogok Dialog &Ok TextLabel &Yes &No erasedevice Erase Data On The Device By Writing Random Data Over Them Path to Device % Completed &Start &Cancel Average Speed ETA N/A TextLabel &OK Write Random Data Over Existing Data The next dialog will write random data to a device leading to permanent loss of all contents on the device. Are you sure you want to continue? WARNING Average Speed: Total Time: Data on the device successfully erased Could not create mapper Could not resolve device path Random data successfully written Operation terminated per user choice Can not write on a device with opened mapper Policy prevents non root user opening mapper on system partition Device path is invalid Passphrase file does not exist Could not get enought memory to hold the key file Insufficient privilege to open key file for reading This device appear to already be in use Can not open a mapper on a mounted device Could not write to the device Device path field is empty Invalid path to device Are you really sure you want to write random data to "%1" effectively destroying all contents in it? WARNING! Failed to enable polkit support Writing Random Data Over Existing Data Enter Path To Volume To Be Erased Select A Non System Partition To Erase Its Contents favorites2 Favorites Favorite List Volume ID Mount Point Add Add A volume Mount Path &Close Mount Options Manage Keys In Wallets Set Default Wallet Internal Wallet Libsecret KWallet None Volume Path Enter Volume Path Below Enter Password Below Change Internal Wallet Password TextLabel Ok fileManager Set File Manager TextLabel &Set Enter Below The Name Of The Application You Want To Be Used To Open Mount Points. help Help &Close <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt;">ZuluCrypt is a simple, feature rich and powerful solution for hard drives encryption for linux.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt supports LUKS, TrueCrypt, VeraCrypt and PLAIN dm-crypt encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These supported encrypted volumes may resides in image files, hard drives and usb sticks, LVM</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volumes as well as in mdraid devices.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of encrypted volumes. Those that use what is commonly know as “a header†and</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">those that do not. TrueCrypt, VeraCry and LUKS volumes use a header. PLAIN dm-crypt volumes do</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">not use a header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a &quot;volume header&quot;.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">The damage to the header is usually caused by accidental formatting of the device or use of</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">some buggy partitioning tools or wrongly reassembled logical volumes.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack'; color:#008000;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of header using encrypted volumes. Those that use an encrypted header and those</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">that do not. TrueCrypt and VeraCrypt use an encrypted header whereas LUKS does not. The use of non</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted header in LUKS makes it obvious to everybody that the volume is an encrypted LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may be problematic to some people. How big the problem may be depends on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">person and their use case for hard drive encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The use of encrypted header as in TrueCrypt or VeraCrypt volumes or no header at all as in PLAIN dm-</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">crypt volumes make these volumes indistinguishable from random noise and this may seem useful at a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">glance but its usefulness may not hold up against scrutiny as the likelihood of being believed that a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">100GB file made up of cryptographically sound random data is just a 100GB file made up of random</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data and not a container file for an encrypted volume is not very high.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With LUKS, TrueCrypt and VeraCrypt volumes, it is very important to have a volume header backup</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">since a valid header is required to unlock the volume. A corrupted or missing header will make the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume unusable causing the loss of all encrypted data.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">LUKS stands for “Linux Unified Key Setupâ€. It is a specification of how to store information necessary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to open a LUKS formatted encryption volume. LUKS encryption format is the standard format in linux</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and a recommended one if the encrypted volume is to be used among linux systems. TrueCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt volumes are better alternative if the encrypted volume is to be shared between linux,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">windows and OSX computers.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can create and open 5 types of encrypted volumes, LUKS, TrueCrypt, VeraCrypt,PLAIN</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dm-crypt and PLAIN dm-crypt volume at a none zero offset. PLAIN dmcrypt volume is a header less</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume and all necessary encryption information is provided by zuluCrypt when it creates or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open these volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; text-decoration: underline;">Pros and cons of the five volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt; text-decoration: underline;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It does not use a volume header and hence its not possible to “brick†the entire volume simply by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over writing a small part of it.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It does not use a header and hence its impossible to know if the volume is made up of only</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">cryptographically sound random data or if its an encrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It does not use a header and hence any tool that opens these volumes must provide the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options that were used when the volume was created. Different tools may use different encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options making these encrypted volumes not very portable between applications or even between</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">different versions of the same application.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt at a none zero offset.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This volume has the same pros and cons as those of a PLAIN dm-crypt volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional pro for this volume is that it can be places anywhere on the device making it possible</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to have this volume on top of any one of the other supported encrypted volume or on top of an</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">unencrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For example, its possible to have an X MB drive that has unencrypted file system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">at the beginning of the device and a “PLAIN dm-crypt volume with an offset†somewhere towards the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">end of the device making it possible to use the drive as unencrypted volume and as encrypted volume</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">simultaneously depending on sensitivity of the data to be stored on the device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this volume type is to be used, preceding part of the drive should be formatted in “FAT†family of file systems.This volume types gives a “hidden volume†type functionality offered by TrueCrypt and VeraCrypt. When creating or unlocking this volume type, the starting offset of the volume will be asked and NOT the volume size as TrueCrypt and VeraCrypt does with the hidden volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above means, if you have a 100 MB drive and you want to create a 30MB “PLAIN dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume at a none zero offsetâ€, you will enter the starting offset of the volume as 70MB. In VeraCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt, you will enter the hidden volume size of 30MB. The starting offset and the size of the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hidden volume are related by a simple formula: starting offset(70MB) = device size(100MB) – hidden</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume size(30MB).</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TrueCrypt</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and hence its not possible to know if the volume is TrueCrypt formatted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume or if the volume is just made up of cryptographically sound random data.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Hidden volume. A TrueCrypt volume can have up to two different encrypted volumes. The first</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume is commonly know as “outer volume†and the second optional one is commonly known as</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“hidden volumeâ€.When a TrueCrypt volume is about to be opened, the user has an option to select</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">which one of the two to open by giving appropriate key.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and it is not possible to open the volume without a valid header. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">use a TrueCrypt volume, make sure you have at least one backup of the volume header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VeraCrypt</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt is an extension of TrueCrypt and it shares the same TrueCrypt’s pros and cons.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Pro for VeraCrypt over TrueCrypt.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It requires stronger effort to unlock VeraCrypt volume and this makes them more secure over</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt volumes.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Cons for VeraCrypt over TrueCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It requires stronger effort to unlock a VeraCrypt volume and this increases the time it takes to unlock</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a VeraCrypt volume. How long it will take depends on the strength of the computer and it may vary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from a few seconds to several minutes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS volume can be opened with up to 8 different keys.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS header is stored unencrypted making it obvious the volume is LUKS formatted encrypted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may not be desirable under certain circumstances. It is possible to create a LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume with a detached header and zuluCrypt can open these volumes using “luks†plugin.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It uses a header. As it is not possible to open a header using encrypted volume without its header, a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">corrupted LUKS header makes it impossible to open the volume. If you use a LUKS volume, make</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sure you have at least one backup of the volume header.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can do two types of encryption. It can do single file encryption/decryption or block device</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">File encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can encrypt and decrypt individual files. This feature is useful when a user just wants to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt a single file and taking the route of creating an encrypted container file to host the file is seen</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as an unnecessary hassle. This functionality is akin to file encryption using gpg with a symmetric key.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">File encryption is done using libgcrypt as a cryptographic backend. Files are encrypted using 256 bit</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">AES in CBC mode. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The encryption key is derived from user pass phrase using pbkdf2 with 10,000</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">rounds of iterations and sha2 as a cryptographic hash function. The resulting encrypted file will have a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file size that equals (64 + 1024 * n) bytes where n is a number starting from zero.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted file:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;encrypt a file†to open a file encryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to store encrypted, enter the password to be used to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt the file and then click “create†and the encrypted version of the file will be created at the path</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by “destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">To decrypt the file created with above steps:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;decrypt a file†to open a file decryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to decrypt, enter the password to be used to decrypt the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file and then click “create†and the decrypted version of the file will be created at the path given by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Block device encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A hard drive or a usb stick are two examples of block devices. A regular file can simulate a block</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">device through a use of devices known as “loop devicesâ€. These devices have a device path that starts</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">with “/dev/loopâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The infrastructure in the linux kernel that deal with block device encryption is called “dm-crypt†and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does its work through a process commonly known as OTF(on the file encryption). Dm-crypt devices</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">are represented by device addresses that starts with “/dev/dm-†and these paths are usually accessed</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">through their soft links that reside in “/dev/mapperâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Below is an example of steps taken in creating a 100MB encrypted container in a file and adding a file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">in it to be stored securely.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Create a 100MB file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Attach a loop device to the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Create an OTF encryption mapper against the loop device.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Put a file system on the encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Mount the file system on the mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Copy The file to be stored securely to the file system through the mount point.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Unmount the file system.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Destroy the OTF encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Detach the loop device from the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">10. Maintain the encrypted volume as a secure holder of files within it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All zuluCrypt does is provide a GUI to make it easy to do above specified tasks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With the above steps:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 1 deal with a path that look like “/home/ink/secret.imgâ€, this is a path to a regular file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 2 converts “/home/ink/secret.img†file to something like “/dev/loop0†loop device path.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 3 converts “/dev/loop0†loop device path to something like “/dev/mapper/secrets.imgâ€. Data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">written to “/dev/mapper/secrets.img†will get encrypted and then passed forward to “/dev/loop0†on its</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">way to “/home/ink/secret.imgâ€. When data is read from “/dev/mapper/secrets.imgâ€, the data will be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">read from “/dev/loop0†who in turn will read it from “/home/ink/secret.imgâ€, decrypted by dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then given to the reader. This process is called “on the fly encryption†because the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mapper does not store or hold on to data, it gets data and then encrypts or decrypts it depending on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">direction of data flow and then passes it along.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in an image file.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a file†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Enter the name of the file to be used to hold the container in the “file name†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the size of the container in the “file size†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Click “createâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Wait for the container file to be created and for the volume creation dialog to show up.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Enter the password to be used to create the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Select the type of volume you want to create from the “volume type†list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Click create to create the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in a partition.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a hard drive†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Click/double click on the hard drive you want to create a volume in and then advance to instruction</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">number 7 in the instruction list above. If the partition you want to put an encrypted container does not</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">show up on the list, then restart zuluCrypt from root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a file using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a file†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click the button to the right of “volume path†field and then browse to where</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the volume is and click it to open it. Alternatively, you can just drag the volume file on zuluCrypt to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">generate a password dialog prompt with the file path already filled in.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a partition using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a partition†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click/double click on the partition with an encrypted volume you want to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With both two steps above, the volume will be opened and mounted at a path whose last component is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by the entry in the field “mount nameâ€. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When the volume is successfully opened, zuluCrypt will</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">automatically open the mount point path. To close the volume, click its entry on the zuluCrypt window</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then click “close†on the pop up window.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can open an encrypted volume using keys derived from different sources. These sources</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">include, a pass phrase, a key file, a key retrieved from kwallet, a key retrieved from Gnome's libsecret,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a key retrieved from an internal secure storage system, a key from gpg encrypted key file among other</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sources.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a pass phrase volume key, make sure the key source option read “key†and then enter the pass</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phrase on the entry field at the bottom.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a keyfile as the source of volume key, click the option bar and then select “keyfile†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring a dialog box that will allow you to browse to where the key</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file is.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a plugin as the source of volume key, click the option bar and then select “plugin†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring up a list of available plugins and then select the one you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want from the list.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Volume keys stored in kwallet, Gnome keyring or internal secure storage system plugins can be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">managed by going to “menu-&gt;options-&gt;manage volumes in internal/kde/gnome walletâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Storage of keys in a gnome wallet/keyring seem most appropriate in a gnome session but this has some security repercussions, the keys are stored in the user keyring and this keyring gets unlocked when the user logs in. This means that once a user is logged in and the keyring is open, any application that runs in that user session can read those keys using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In a kde system, a kwallet secure storage system seem most appropriate but it suffers from the same</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">security problem the gnome secure storage system has, once the wallet is open, any application running in the user session can access it using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The behaviors of the above secure storage systems is by design but this design may not be ideal for</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">some users under certain use cases. The internal secure storage system is powered by libgcrypt and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does not have the behavior of the above two systems. An unlocked internal secured storage system is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">accessible only to the instance of zuluCrypt that unlocked it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Favorites.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For convenience, most used volumes can be easily opened by adding them to the favorite list. Entries</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">on the list are added in the dialog window opened by clicking “menu-&gt;options-&gt;manage favoritesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Favorite entries are added by clicking the “favorite†entry on the menu.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Erase data in a device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It is very important to create encrypted volume over cryptographically strong random data to make it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">impossible to know what part of the encrypted volume has been used and what part has not. If the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume is created over predictable data patterns like on a device with only zeros in it,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">forensic analysis may reveal how much and what part of the encrypted volume are in use.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When creating an encrypted container in a device, zuluCrypt offers an option to first write random data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over the device. This feature can be performed on other devices by activating it through “menu-&gt;erase</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data in a deviceâ€. Random data are written to disk by opening a plain dm-crypt encryption mapper on</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the device with a 64 byte random key and then blasting zeros on the device through the mapper. This</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">technique has proven to be faster compared to alternatives like writing random data on the device read</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from “/dev/urandomâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">System and non system volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To enforce access controls on what user can access what block device and what they can do with the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">access they have, zuluCrypt employes a concept of “system volumes†and “non system volumesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A system volume is defined as a volume that has an active entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/fstabâ€,â€/etc/crypptabâ€,“/etc/zuluCrypt/system_volumes.list†or if udev identify it as such if udev</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">is enabled. Ideally, all volumes inside the computer are to be considers system volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A non system volume is a volume that failed in the above considerations or if it has an entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/zuluCrypt/non_system_volumes.listâ€. Ideally, these volumes are plug gable usb based hard drives</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">or usb sticks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Partitions can be added or removed from the list of system or non system volumes simply by starting</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zuluCrypt from root's account and then going to “menu-&gt;options-&gt;manage system volumes/manage</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">non system volumes†and then adding the volume in the appropriate list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Permissions.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt limits what a user can do on block devices through unix's group based permission system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">using two groups, “zulucrypt†and “zulumountâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, only a root user or a user who is a member of group</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“zulucrypt†can create an encrypted volume in the device or taking/restoring volume headers. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want to create a volume in a device and the device does not show up on the list, restart zuluCrypt from</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, zuluMount will mount it only if the user is root, is a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">member of group “zulumount†or the device has an entry in “/etc/fstab†with either “user†or “usersâ€</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mount options set.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ZuluMount.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount is a general purpose mounting tool that can open zuluCrypt supported encrypted volumes</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as well as non encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also auto detect plugged in devices and auto mount them.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also unlock encfs volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2015-2017 Francis Banyikwa, mhogomchungu@gmail.com</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Open &PDF WARNING! Failed to open zuluCrypt.pdf,make sure your system can open pdf files using "%1" tool and try again luksaddkey Add A Key To A Volume Volume Path open file open partition Advanced LUKS2 Options LUKS TrueCrypt VeraCrypt Volume Type PIM TextLabel Advanced Luks2 Options Set Pbkdf Type argon2id argon2i pbkdf2 Max Memory (KB) Parallel Threads Unlocking Time Cost(Milliseconds) Forced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) Cancel open keyfile Password Already In The Encrypted Volume Password To Be Added To The Encrypted Volume Reenter Password Password KeyFile Key+KeyFile YubiKey Challenge/Response &OK &Add &Cancel Passphrase Quality: 0% Passphrase Quality: %1% Key Slot Number To Add Key In Enter A Key Enter a path to a keyfile location KeyFile Path Enter a key KeyFile path Passphrase Quality: 100% Existing KeyFile New KeyFile Encrypted Volume Path ERROR! Atleast one required field is empty Failed to enable polkit support Keys do not match Failed To Locate Or Run Yubikey's "ykchalresp" Program. Key added successfully. Key added successfully. %1 / %2 slots are now in use Presented key does not match any key in the volume Could not open luks volume Volume is not a luks volume Insufficient privilege to add a key to a system device, only root user or members of group "zulucrypt" can do that Could not open volume in write mode All key slots are occupied, can not add any more keys Can not get passphrase in silent mode Insufficient memory to hold passphrase New passphrases do not match One or more required argument(s) for this operation is missing One or both keyfile(s) does not exist Insufficient privilege to open key file for reading Couldnt get enought memory to hold the key file Could not get a key from a socket Could not get elevated privilege,check binary permissions Key slot already occupied Failed to find empty key slot or key slot out of range Can not find a partition that match presented UUID Device is not a luks device Error Code: %1 -- StdOut: %2 -- StdError: %3 luksdeletekey Remove A Key From A Volume LUKS Slot Number Password open a keyfile &Delete &Cancel Volume Path open an encrypted file open an encrypted partition TextLabel &OK KeyFile Key+KeyFIle Enter a key Enter a path to a keyfile location KeyFile path Key File With A Passphrase To Delete ERROR! Atleast one required field is empty Failed to enable polkit support Volume is not a luks volume There is only one last key in the volume. Deleting it will make the volume unopenable and lost forever. Are you sure you want to delete this key? WARNING Key removed successfully. %1 / %2 slots are now in use YubiKey Challenge/Response zuluCrypt will have the same behavious as luksKillSlot if a key slot is given zuluCrypt will have the same behavious as luksRemoveKey if a key slot is NOT given Failed To Locate Or Run Yubikey's "ykchalresp" Program. There is no key in the volume that match the presented key Could not open the volume Insufficient privilege to open a system device,only root user or members of group zulucrypt can do that Could not open the volume in write mode Insufficient memory to hold your response Operation terminated per user request Can not get passphrase in silent mode Insufficient memory to hold passphrase One or more required argument(s) for this operation is missing Keyfile does not exist Could not get enough memory to open the key file Insufficient privilege to open key file for reading Could not get a key from a socket Can not find a partition that match presented UUID Error Code: %1 -- StdOut: %2 -- StdError: %3 manageSystemVolumes Manage System Volumes &Done Add Fi&le Add Dev&ice Path To System Volumes Remove Selected Entry Cancel Are you sure you want to remove "%1" from the list? WARNING Select Path To System Volume managevolumeheader Backup Volume Header Backup Name C&reate &Cancel Volume Path Window System Volume Volume Type Manage A VeraCrypt Header PIM Password Password Source Outer Volume Password ONLY KeyFile TextLabel Normal Volume Whole Drive Encrypted Volume Manage A LUKS Header Manage A TrueCrypt Header Restore volume header &Restore Back up volume header &Backup Select A File With A LUKS Backup Header Select A Folder To Store The Header ERROR! Atleast one required field is empty Failed to enable polkit support Are you sure you want to replace a header on device "%1" with a backup copy at "%2"? WARNING! Select luks container you want to backup its header SUCCESS Header saved successfully. If possible,store it securely. Header restored successfully Presented device is not a LUKS device Failed to perform requested operation INFO! Operation terminater per user request Path to be used to create a back up file is occupied Insufficient privilege to open backup header file for reading Invalid path to back up header file Insufficient privilege to create a backup header in a destination folder Invalid path to device Argument for path to a backup header file is missing Only root user and "zulucrypt" members can restore and back up luks headers on system devices Insufficient privilege to open device for writing Could not resolve path to device Backup file does not appear to contain luks header Insufficient privilege to open device for reading Wrong password entered or volume is not a truecrypt volume Failed to perform requested operation on the LUKS volume Wrong password entered or volume is not a veracrypt volume Unrecognized ERROR! with status number %1 encountered oneinstance Previous instance seem to have crashed,trying to clean up before starting There seem to be another instance running,exiting this one openvolume Select A Partition To Open Use UUID &Help Use &UUID &Cancel partition size label type uuid &Open A list of all partitions on this system are displayed here. Double click an entry to use it Restart the tool from root's account or after you have created and added yourself to group "zulucrypt" if the volume you want to use is not on the list. You are a root user and all partitions are displayed. Double click an entry to use it INFO Select A Partition To Create An Encrypted Volume In Select An Encrypted Partition To Open ERROR Only crypto_LUKS volumes can be selected passwordDialog TrueCrypt/VeraCrypt Keys Check This Box To Make Password Visible Unlock Encrypted Volume PIM Value Offset Offset Will Be In Sectors If The Entry Is Made Up Of Only Digits And In Bytes If The Entry Ends With "b" And In Kilobytes If The Entry Ends With "k" And In Megabytes If The Entry Ends With "m" And In Terabytes If The Entry Ends With "t" Cancel Mount "%1" Choose A Module From The File System Enter A Module Name To Use To Get Passphrase Plugin Name Password Select A Key Module Enter A Key YubiKey Challenge/Response Select External LUKS Header File LUKS External Header Path Choose A KeyFile From The File System Enter A Path To A Keyfile Location KeyFile Path Select A KeyFile Select Path To Mount Point Folder Select Encrypted volume ERROR! Internal wallet is not configured ERROR Failed To Locate Or Run Yubikey's "ykchalresp" Program. Atleast one required field is empty "/" character is not allowed in mount name field Volume is not a LUKS volume Failed to get a key from the network Failed to get a key from a plugin Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? There seem to be an open volume accociated with given address No file or device exist on given path Volume could not be opened with the presented key Insufficient privilege to mount the device with given options Insufficient privilege to open device in read write mode or device does not exist Only root user can perform this operation -O and -m options can not be used together Could not create mount point, invalid path or path already taken Shared mount point path already taken There seem to be an opened mapper associated with the device Could not get a passphrase from the module Could not get passphrase in silent mode Insufficient memory to hold passphrase One or more required argument(s) for this operation is missing Invalid path to key file Could not get enought memory to hold the key file Insufficient privilege to open key file for reading Could not get a passphrase through a local socket Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered Could not create a lock on /etc/mtab Insufficient privilege to open a system volume. Consult menu->help->permission for more informaion A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature Error Code: %1 -- StdOut: %2 -- StdError: %3 plugin Key Generator Using A Passphrase And A KeyFile &Set Key &Cancel Create an encryption key that is made up of a passphrase and a keyfile. A volume created with a key generated here should be opened with "hmac" plugin. Passphrase KeyFile ERROR KeyFile Not Set Failed To Generate Key readOnlyWarning WARNING Do Not Show This Message Again. Setting this option will cause the volume to open in read only mode. &Ok tcrypt TrueCrypt Keys &Open &Cancel Add &Keyfile drag and drop key files to add them to the list Keyfile Paths Enter key files below to be used to open the volume Enter A Passphrase Below To Be Used To Open The Volume &Set TrueCrypt/VeraCrypt Keys ERROR At least one keyfile is required Select A KeyFile utility::veraCryptWarning Elapsed time: 0 seconds Elapsed time: %0 minutes Elapsed time: %0 seconds Please be patient as unlocking a VeraCrypt volume may take a very long time. warnWhenExtendingContainerFile WARNING!! OK Dont Show This Warning Again. Your cover file will be irreversibly changed and we suggest continuing with a backup file and not the original. To unlock the volume about to be created, you will need to enter the password you will choose and the volume offset automatically generated by zuluCrypt. Instructions to unlock the volume are as follows: 1. From the menu, choose Open -> Volume Hosted In A File. 2. Select file, then choose "Volume Type" = PLAIN dm-crypt. 3. Enter the generated offset value along with your password. IMPORTANT!!! zuluCrypt zuluCrypt Encrypted Volume Path Encrypted Volume Mount Point Path Type &Open &Create &Help &Volumes Optio&ns &Volume Hosted In A File Volume &Hosted In A Hard Drive Encrypted &Container In A Hard Drive &About &Add A Key To A Volume &Delete A Key From A Volume &KeyFile &Tray Icon Select &Font &Update Volume List &Minimize To Tray &Quit &Close All Opened Volumes &Manage Favorites &Erase Data In A Device &Backup Header &Restore Header Encrypt A &File &Decrypt A File &Header Backup Manag&e System Volumes Manage &Volumes In Internal Wallet Manage &Non System Volumes Manage Volumes In &KDE Wallet Manage Volumes In &GNOME keyring &Change Internal Wallet Password H&elp F1 Show LUKS Key Slots Set Fi&le Manager Do Not Minimize To Tray This Option Will Close The App Instead Of Minimizing It To Tray Encrypted Container Hidden In Video/Cover File (Steganography) Show Debug Window Ctrl+Shift+D Encrypted Container In An Existing File Clear Dead Mount Points Contact &Info &Select Language &Auto Open Mount Point Select &Icons &Favorites &zC Ctrl+Z Ctrl+X &Encrypted Container In A New File Ctrl+A Ctrl+S Ctrl+R Ctrl+U Ctrl+W crypto info Ctrl+E Ctrl+D Ctrl+K Ctrl+L favorite volumes manage favorites select random number generator Ctrl+P close application Ctrl+C Ctrl+T Ctrl+Y Quit Ctrl+Q Ctrl+G Ctrl+F Ctrl+N Ctrl+B permissions Ctrl+I Ctrl+H Ctrl+J Ctrl+V configure wallets Ctrl+M Shift+V Alt+V Ctrl+O tcrypt backup header tcrypt restore header VeraCrypt Container In A File VeraCrypt Container In A Hard Drive Shift+I Select Language Restore Volume Header Backup Volume Header INFO Resetting font size to %1 because larger font sizes do not fit LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a "volume header". A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data. The damage to the header is usually caused by accidental formatting of the device or use of some buggy partitioning tools or wrongly reassembled logical volumes. Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted. Important Information On Volume Header Backup ERROR! Volume is not open or was opened by a different user Volume Properties WARNING! Could not open mount point because "%1" tool does not appear to be working correctly Properties Open Folder ERROR zuluCrypt Failed To Connect To zuluPolkit. Please Report This Serious Bug. Cryptsetup library could not be found and zuluCrypt will most likely not work as expected. Please recompile zuluCrypt to force it to re-discover the new library Path To A File Show/Hide Open Private Folder Open Shared Folder Add Key Remove Key Show Key Slots Information Backup LUKS Header Add To Favorite Unmount Cancel Close failed, volume is not open or was opened by a different user Close failed, one or more files in the volume are in use. Close failed, volume does not have an entry in /etc/mtab Close failed, could not get a lock on /etc/mtab~ Close failed, volume is unmounted but could not close mapper,advice to close it manually Close failed, could not resolve full path of device Close failed, shared mount point appear to be busy Close failed, shared mount point appear to belong to a different user or multiple mount points detected Close failed, shared mount point appear to be in an ambiguous state,advice to unmount manually Close failed, multiple mount points for the volume detected Close failed, could not find any partition with the presented UUID Unrecognized error with status number %1 encountered zuluCrypt-6.2.0/translations/zuluCrypt/fr_FR.qm000066400000000000000000005450551425361753700216720ustar00rootroot00000000000000<¸dÊÍ!¿`¡½Ý§fr_FRBˆ‘œ)²S˜òTñU;iL[­Ì[͡Ӭ+;É+;I‰+;YI+;•¼+;´+;Æ¡+;ê{+OÉ+O+ê+O²»+[ò+[²ã+[^6-ãƒG¤ÈÈJ»îQ1¿mQÉx5QÉ£.TÝ‚øTÝßÄTÝ2W']W'‰×YÄíYÄŠ’YÄãÊfî›»§¤Æ8¹ÄϹÄ`o¿Ã¿Ã,¿Ã³ ¨J8¥¨JOâ¯S½â¯(:⯜zì0Äøy«ÜÙyTVEÍtŒ¡¶Àe¨&6`^E¥½¡¡/s¬ô­ÀeÀe/¢É´ªËô/ÍÞjÙ¨5OBa]¯öeÍ.*¶EÁ*ì0&J*ì0]+f¾õ+f¾&x+f¾`A+f¾€Œ+Œ€½2®3u{‡4fôOÏ4fôp4fô½™4fôÓ4fôò4fô @E’®ÜFØóªH7ƒËJ Ãe}Jgz ÜJwB yJwB8eJwBnJwB( JwB;ÐJwB\JwBa‚JwB˜@J  g1JÌ0œMN+zQ az3Q bzÁRx¼{OT}ÕQÜZz ª^Ü„f_ú%#*bƒÉWúd¤t(d¤tƒ"jyet.jyeÕ³jyeò¨jyeCårx¼/sf:ŒtZŠç|ŠG|fE†¨3² HžÎÎq¤Œé'Ö¦ó *¿°U”@º…Ž)½ …)¿ë”(eÅ1õb›ÅÃ…‹UÅÃ…VBÏÇáØ2”˨ßM­¿êÍȹ*úëcµû‰¤À”ɗæs šZ´I]Ž.(g¥”2ãµÓ=7Õ<…FwƒmXîåjÙXîå;]”-£sO¨£êsO¨Üy{˜–ˆì5=i™uÝ\š2NP¡œ%ûœ%x_œ%£Vœ%Û/œd%÷×žÖ’Ž¯ ŽÁ¶4\ ÃÈÕ;žÍΕŠÍÐuQÍÐux³ÍÐu£¨ÍÐuÛÍÐuø,ÍÐu˜ÍÐu]eÝÒeX´ï'×þ¼=¼²ÿP^ðgÅ£5¢¨t¢ùC´sÌñÓ˜"Oµ©¶9ð…:´:4eåâ:4eþ=8RƒîK6ÕíWKìꇥe5âLwu 5P[u%¨PŸuîPé‡7Ú‰Ô}ŒÃå¸SŒÃå:BXUh=§–Äz0ª6•±áª6•È•ª6•Ñ;º¨”´FÅ<NÏacƒæÏacßìÙÆî)èìtŸU3ƒ–Ϭ™ -(ü"£L( h( hÎÉ( håR( hý¸( h ‚(ã¥R(㥎G(ã¥åœ(㥠Ô)Åû:XÃyN‚Å#P„R¤P„Z PP…¶s_ꎒjeôjAjeôË+jeôì¾m©ºðrýõi€¢ †š!´¯C›ÑõŸ³¥%‰w¯¯Ã~h[±·.T¶ÿô£­½("#ÀÃ)´Î{ÊCn€ÊCÑÊCðpÊC=ÿÐDSf¼Ð`Èø×c•ÀÝP=6„á>©}~á>©Ý  R'+ œø+ ÏÍ+ <;ES’i‘U%ÄÂyØ- Ç//K Ð/K ïy1'"®‚3Ü3„ªDêŒ FgŸJ¬>ˆ½MºY?4U€Ô³§[h¥W‚[¥k‹]+‚²i™Õ©5wú™¡“±…˜Ô–ÊÓ˜I¼Ý˜I¼gK˜I¼Êø˜I¼[˜I¼4ݘI¼„xšÒÙ„¢aeΤFŸà§tAnK§tAÏ6§tAïC§tA §tA<§tA˜o§Ð©[«Žñ“Ù«Žò“ý«Žó”!«Žô”E«Žõ”i«Žö”«Ž÷”±«Žø”Õ«Žù”ù«Žú•«Žû•A«Žü•e«Žý•‰«Žþ•­«Žÿ•Ñ«•õ«–«–=«–a«–Ç«–ë«—«—3«—W« —{« —Ÿ¯ƒW=¯ƒW³2²4ʉ߾ïˆK‚ÕÄ{¢Õ$ÉEÛÅÞãUe©ð$c8ò¤Ef›ò¤EÊJò¤Eì ô,u%  Ç•ög÷ó—Z(ëÔóù6°e÷:_y&£>vÔ§ý?ÅÂ7/@Z$ˆBGÔÞ?F›£|:J%O´€\ÆD&N\ÙÄL>`.hÌßbõwgòK?k•¨«ás½þ¸tÌŹÁzßäÚ»‡­Õe׈!2+‹°tÀ(™ÔŽ7Äš”DóšÈú†ïœôÄ…-¦È•© ªI±¬<Žé²?™?¬µýŠÄµ®•`žÀn]»Ëí22Íœ HÎvÔ§YÕf)4OÕf)dÝÕf)ÈéÕf)ê¦Õf) ¢Õf)4;ظå5ZظåK¾ظåYtظåe£ظå•äظå *á³c@Ná³cªÙãœyd}ú£­ñý¨Íq+4Í*gÚEˆ ÜI|™6,Ö%¾ù,Ö%4iáÈDITSèEXIEX•ILü…U`ZcW`Zcd`}¦fÊw¾&fÊwØfÊwõ’fÊwH‡iµÔºJrç!§rç!Æórç!Å[rç!!"rç!¬{ã+€]t$’#é§U™Zƒc‰ nÂ!£¶U§¥ýSUh©U瀬ϕ´¿…ˆrÑÂ݉¡æÈìn+óÌÖ£¡zÑô^ÞŠ¥};ìñ”šžð‚´’lòÌ·ô‰5¤zöi5?úYäÊÔyŒsy䀬5ÿ/®€Ó®¤J®ú$ý5̱*¹T ¥lN=P ®&ª °ÚÞ/9 ¸¬u}ª Å“ƒw ÆSyY× ËK“ËÁ Í¥4m_ ÒÝÛ@L Úì5ó ÜÅé^Å æ ŸP êÿb ø êÿb„ ïÖ©¥J ï×V¥o üX…‘ üX…æ` üX…þÁ üX…Y6 ì:i n›û 7*q› C)U ±å⪠)"° jD`ù !Xc #xBl 0L  5ÞÕªM 6 ädò ?äX BéÈ…‹ GaÞ¥ÿ Pò9¦÷ a&Мœ a@7¡J cöÚ‚^ d ÃVp jà5]ý k)Êg lU¨ nUR” nUcã qõÙî um³d um³Ç” { Q3 €´Ùî €éu‡f €éuâm ‡¢à¾ ‹&Â6 iÕø ˜Iœ ˜Iœ4 ˜IœIS ˜IœY ˜Iœc ˜Iœ•† ˜Iœ³æ ˜IœÆk ˜Iœê ˜Iœú ˜Iœ& ˜IœY¥ ˜Iœ` ¥S„/ø ¦wþ ¦ ¨¸…|± «Ò3¦• ¬,…êB ¶/T]£ Ìùêä Ò¥R$ Ø_èa ÚÉEœ âá5 ñ¸ Ô ò¹2E A%Z >a– ¥sÌ “b0Ñ lÇ–µ f¨X þ•lý !ª$~ó &—Ný 9ÿ‰€! F°ÎÑh N&GÉÝ _DÕa® `ÂEu„ `ÂEóR aJuÑË dþµU; dþµ¿– g.wW\ g.wm g.wƺ g.wþ† g.w} g.w_Ò jP®ÿù j½Ô»z m@c¤ |d¿¬ú ƒÝ©¦R „ÕÍÆ Œöò·î šÛääF ¥LNÐY ¥LNï ¶¥’ + Á¬2m ÊÊc­Ž Õìc­# Ýæ~oI Ýæ~Ò( Ýæ~ñ: Ýæ~>Ê â²Ã ·¹ âæÅ Oå‡ OåÀ° ¯å†C ºEç6 ?èJÅ tÄ+! UM§ 8y„s_ ;I4¼) Oc/ú Tl¨H VL& W½…Å _"M a¤^ˆì e‘´ª g䙊 m> ¬ pQcK q6eΠ w² [ ~x =å ‰ž,r ‘TB{Z •~Î ž°U¡" ¢Ù²Žr ¨o>^c ®i­ ¯yµv* ¯yµ¢% ¯yµIß µ‰”3 µÚ”9v ·¨Ð ¹^­o »~%Å Á7Ahõ ômõ1ž üɇ üëG ($ãk ª.Z š ,ÔGÊT 4ú„zÒ @D) Båt× DYô–… D¦™ü' IŽ5ä N³•šŒ OE³žˆ ZG3r§ ZYs}Ø cÁs‚Þ iFCË" k¦C~É pBqL« y…µ8Ã Ž›„« Ž›à­ œMIЬ °ì7žÃ ¸Ûîž Ø}•!e Úz çþ¾v¯ ïé ñY%˜ô©úÆuû$‰ûû$¦™(¢¹¥*ˆÔUÌ<SyA*pFrzñGrzcP5%yWœUé’5l'’5ÍÌ•ÏÖZ•ýu!æ›n¥…›n¥áœT iÕ¥Heا鴇ÿ­ãŃx¯¤øÏ· rT·ºÎØæ»uŽ9˜¼0ίj¾«…~HÃýD\ßÄÄDG1Æù„ Í®Y\3ÓN™5œÞ²³Œ(Þ²³dJàcfDò Ãp®ž¶EtËX%¢«00¢Yq}0¢YÔ‹Höu‘KE‚h\7eQYpß¾çÛˆøÏiˆø›ÆŠ.¸›/’"|!’"|>Ø’"|W’"|^v’"|‹’"|©Ñ’"|³e’"|Ó’"|Î5’"|Ðö’"|ãú’"|ûØ’"|t–ì$µÚ—m³c·—m³Ç3š?žãå|⢜Ҥӭɨ}¯©ÿ¶|ß{Ó‰Ù¬<é;ä÷ý †ý(ââi°z– "Volumes du système" sont des volumes que udev a identifié comme tel (si udev est activé), ou alors possède une entrée dans "/etc/fstab","/etc/crypttab" ou bien "/etc/zuluCrypt/system_volumes.list" Si vous préférez pour un volume qu'il ne soit pas considéré comme un volume système, démarrez le bilan du compte racine, puis aller à "menu-> options-> gérer des partitions système non" et ajouter le volume à la liste et le volume cessera d'être considéré comme «système». Sinon, vous pouvez vous ajouter au groupe "zulucrypt" et "zulumount" et toutes les restrictions vont disparaître. "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. DialogMsg&Non&No DialogMsgÿÿÿÿ&Ok DialogMsg&Oui&Yes DialogMsgDialogueDialog DialogMsgHNe plus montrer ce message désormaisDo not show this dialog again DialogMsgINFORMATION INFORMATION DialogMsg8Privilèges insuffisants pour accéder à un périphérique en mode lecture/écriture, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le faireƒInsufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that DialogMsgPrivilèges insuffisants pour accéder à un périphérique système, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le fairejInsufficient privilege to access a system device, only root user or members of group zulucrypt can do that DialogMsg UUID:UUID: DialogMsg.Vous ne semblez pas avoir les autorisations nécessaires pour accéder au fichier chiffré en mode %1, vérifiez les droits du fichier et essayez à nouveauwYou do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again DialogMsgslots actifs active slots DialogMsgslots actifs: active slots: DialogMsg$clé de chiffrementcipher DialogMsg&clé de chiffrement:cipher: DialogMsg devicedevice DialogMsgdevice:device: DialogMsg(système de fichiers: file system: DialogMsgespace libre: free space: DialogMsgfsfs DialogMsg taille de la clékey size DialogMsg"taille de la clé:keysize: DialogMsg boucleloop DialogMsgboucle:loop: DialogMsgmodemode DialogMsg mode:mode: DialogMsgdécalageoffset DialogMsgdécalage:offset: DialogMsg taillesize DialogMsg textetext DialogMsgespace total: total space: DialogMsgtypetype DialogMsg type:type: DialogMsginutiliséunused DialogMsgutiliséused DialogMsg% utiliséused % DialogMsgespace utilisé: used space: DialogMsg% utilisé:used%: DialogMsg&Annuler&CancelPasswordDialog&OK&OKPasswordDialog&Ouvrir&OpenPasswordDialog&Options&OptionsPasswordDialogB&Share (Partage) Point de montage&Share Mount PointPasswordDialogAnnulerCancelPasswordDialogŒEntrer un fichier d'options système de volume en séparation à virgules8Enter Comma Separated Volume's File System Options BelowPasswordDialog(Clé + fichier de clé Key+KeyFilePasswordDialogFichier de cléKeyFilePasswordDialog0LUKS/TrueCrypt/BitLockerLUKS/TrueCrypt/BitLockerPasswordDialog:Monter en mode &lecture seuleMount In &Read Only ModePasswordDialogNom du montage Mount NamePasswordDialog0Ouvrir un volume chiffréOpen Encrypted VolumePasswordDialogPLAIN dm-cryptPLAIN dm-cryptPasswordDialogMot de PassePasswordPasswordDialog PluginPluginPasswordDialogDéfinirSetPasswordDialog$Etiquette de texte TextLabelPasswordDialogVeraCrypt VeraCryptPasswordDialog"Système VeraCryptVeraCrypt SystemPasswordDialog Chemin du volume Volume PathPasswordDialogType de Volume Volume TypePasswordDialog0ouvrir un fichier de clé open key filePasswordDialog4ouvrir le chemin du volumeopen volume pathPasswordDialog6choisir le point de montageselect mount point pathPasswordDialogú Options: -d localisation du chemin d'un volume pour être auto déverrouillé / monté -m à utiliser pour ouvrir un gestionnaire de fichiers par défaut (l'outil par défaut est xdg-open) -e démarre l'application sans afficher l'interface graphique Í options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI QObjectt"%1" et "%2" doivent être forcément autorisés en écriture.'"%1" and "%2" Folders Must Be Writable.QObject¢Ne trouve pas de "gpg" executable dans "/usr/local/bin","/usr/bin" ou "/usr/sbin"NCould not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin"QObject ERREURERRORQObjectžEchec du démarrage de l'Application d'Aide. "org.zulucrypt.zulupolkit.policy" le fichier polkit file est mal configuré, zuluPolkit l'exécutable n'est pas trouvé ou pkexec échoue au démarrage de zuluPolkit.´Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit.QObjectnEchec pour trouver l'emplacement de l'exécutable pkexec"Failed to locate pkexec executableQObjectJSi l'option est cochée, un point de montage privé primaire sera créé dans "%1" et un «miroir» secondaire du point de montage accessible au public sera créé dans "%2"ŸIf the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2"QObject"Gérer les FavorisManage FavoritesQObjectTout Monter Mount AllQObject*A propos de zuluCryptabout zuluCryptQObjectÆgpg plugin. Ce plugin récupère une clé de verrouillage dans un fichier gpg avec une clé symétriqueQgpg plugin. This plugin retrives a key locked in a gpg file with a symmetric keyQObjectôhmac plugin. Ce plugin génère une clé en utilisant la formule ci-dessous: key = hmac(sha256,passphrase,keyfile contents)ohmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents)QObjectäkeykeyfile plugin. Ce plugin génère une clé à l'aide de la formule suivante: key = passphrase + keyfile contentsjkeykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contentsQObject2point de montage public: public mount point: QObjecttzuluCrypt a échoué à établir une connexion avec zuluPolkit9zuluCrypt: Failed To Establish Connection With zuluPolkitQObject&Non&NocreateVolumeDialog&Y (Oui)&YescreateVolumeDialogôIl est recommandé de créer les conteneurs cryptés à partir de données aléatoires afin d'éviter une compromission de vos informations. Voulez vous d'abord écrire des données aléatoires sur "%1" avant d'y créer un conteneurs crypté ? Vous pouvez arrêter l'écriture de données aléatoires à n'importe quel moment si vous trouvez que c'est trop long et ne souhaitez pas attendre. -It is advised to create encrypted containers over random data to prevent information leakage. Do you want to write random data to "%1" first before creating an encrypted container in it? You can stop the random data writing process anytime you want if it takes too long and you can no longer wait. createVolumeDialogòCette opération entraînera la destruction de toutes les données présentes sur "%1". Etes vous sûr de vouloir continuer ?sThis operation will lead to permanent destrunction of all present data in "%1". Are you sure you want to continue?createVolumeDialogúCette opération entraînera la destruction de toutes les données présentes sur /dev/sdc1. Etes vous sûr de vouloir continuer ?wThis operation will lead to permanent destrunction of all present data in /dev/sdc1. Are you sure you want to continue?createVolumeDialogAttention!! Warning!!createVolumeDialog&Annuler&CancelcreateVolumeInExistingFIle\Au moins un des champs qui est requis est vide#AtLeast One Required Field Is EmptycreateVolumeInExistingFIle Vitesse moyenne:Average Speed:createVolumeInExistingFIle C&réerC&reatecreateVolumeInExistingFIle0Taille du Conteneur (MB)Container Size (MB)createVolumeInExistingFIle¬Créer un conteneur plain dm-crypt caché dans le fichier de couverture (Stéganographie)JCreate A Plain dm-crypt Container Hidden Inside Cover File (Steganography)createVolumeInExistingFIleZCréer le volume dans un fichier déjà existantCreate Volume In Existing FilecreateVolumeInExistingFIle<Créer un volume Plain DM-Crypt Creating A Plain DM-Crypt VolumecreateVolumeInExistingFIle ERREURERRORcreateVolumeInExistingFIleTemps estimé:ETA:createVolumeInExistingFIle\Entrer le chemin de la localisation du fichierEnter Path To Existing FilecreateVolumeInExistingFIleNExtension de la taille du fichier hôte.Extending A Host File Size.createVolumeInExistingFIle<Echec de la création du volumeFailed To Create A VolumecreateVolumeInExistingFIleŠImpossible d'ouvrir le périphérique "/dev/urandom" en mode de lecture1Failed To Open "/dev/urandom" Device In Read ModecreateVolumeInExistingFIle\Impossible d'ouvrir le volume en mode écriture!Failed To Open File In Write ModecreateVolumeInExistingFIlenCaractère interdit dans le champ de taille du conteneur3Illegal Character Found In The Container Size FieldcreateVolumeInExistingFIleMot de PassePasswordcreateVolumeInExistingFIle4Pourcentage accompli : %1%Percentage Completed: %1%createVolumeInExistingFIle”Sélectionner le fichier de couverture (Fichier Vidéo de format mp4 ou mkv)0Select Cover File (Video files like mp4 and mkv)createVolumeInExistingFIle$Etiquette de texte TextLabelcreateVolumeInExistingFIle.Volume créé avec succèsVolume Created SuccessfullycreateVolumeInExistingFIleTOffset du volume (calculé automatiquement)Volume OffSet (Auto calculated)createVolumeInExistingFIle(Propriétés du volumeVolume PropertiescreateVolumeInExistingFIle˜ Par défaut, zuluCrypt crée un volume dans un fichier conteneur à travers des données générées au hasard pour cacher les habitudes d'utilisation du conteneur. Ce processus prend du temps et il peut prendre vraiment pas mal de temps si le volume créé est assez important, donc cette option existe pour ignorer le processus pour les impatients qui se reconnaîtront mais il a un revers et ce revers finira par se révéler en face d'un lecteur quand il regardera le conteneur chiffré et parviendra à tirer parti sur la façon dont le conteneur apparaît de l'extérieur. Si vous savez ce que vous faites, arrêter si vous souhaitez, en cas de doute, mon conseil est de poursuivre le processus et être plus sûr à long terme.© By default,zuluCrypt creates a volume in a container file over randomly generated data to hide usage patterns of the container. This process takes time and it may take a very,very long time if the volume about to be created is large enough and this option exists to skip the process for the impatient among us but but it comes at a cost and the cost may be too high when it finally reveal itself while infront of an adversary when they look at the encrypted container and manage to derive meaning based on how the container looks from outside. If you know what you are doing,then continue by all means,if in doubt,my advise is to endure the process and be safer in the long run. createfile% Complété % Complete createfile&Annuler&Cancel createfile&OK&OK createfile~Êtes vous sûr de ne pas vouloir créer un volume plus sécurisé ?DAre you really sure you do not want to create a more secured volume? createfileŒÊtes vous sûr de vouloir stopper le processus de création du fichier ?4Are you sure you want to stop file creation process? createfile Vitesse moyenne:Average Speed: createfile C&réerC&reate createfilevLe fichier conteneur doit être supérieur à la taille de 3MB&Container file must be bigger than 3MB createfile Ne peut pas ouvrir le module cryptographique pour générer les données aléatoires=Could not open cryptographic back end to generate random data createfile4Créer un fichier conteneurCreate A Container File createfilešNe pas écrire de données aléatoires vers un conteneur (FORTEMENT déconseillé);Do Not Write Random Data To Container(STRONGLY discouraged) createfileTemps estimé:ETA: createfileREchec de la création du fichier de volumeFailed to create volume file createfileNEchec de l'activation du support polkitFailed to enable polkit support createfileNom de fichier File Name createfile"Chemin du fichier File Path createfile"Taille du fichier File Size createfile@Le champ Nom de Fichier est videFile name field is empty createfileFLe champ Chemin du Fichier est videFile path field is empty createfileFLe champ Taille du Fichier est videFile size field is empty createfile’Un fichier avec le même nom existe déjà dans le répertoire de destinationCFile with the same name and at the destination folder already exist createfileGBGB createfileINFOINFO createfileªcaractère interdit dans le champ taille du fichier. Seuls les chiffres sont autorisés@Illegal character in the file size field.Only digits are allowed createfileKBKB createfileMBMB createfileNOpération interrompue par l'utilisateur$Operation terminated per user choice createfileXChoisir l'emplacement de création du fichier-Select Path to where the file will be created createfile`Finalisation du processus de création du fichier!Terminating file creation process createfile$Etiquette de Texte TextLabel createfileATTENTIONWARNING createfileœVous ne semblez pas avoir les droits d'écriture dans le répertoire destination>You dont seem to have writing access to the destination folder createfileLboîte de dialogue ouvrir un répertoireopen a folder dialog box createfile&Annuler&Cancel createkeyfile&OK&OK createkeyfile C&réerC&reate createkeyfile.Créer un fichier de cléCreate A KeyFile createkeyfile’Un fichier avec le même nom existe déjà dans le répertoire de destinationCFile with the same name and at the destination folder already exist createkeyfileTLe chemin pour la création de clé est vide5Folder path to where the key will be created is empty createkeyfile0Chemin du fichier de clé KeyFile Path createkeyfile@Clé de fichier créée avec succèsKeyFile successfully created createkeyfile*Nom du fichier de clé Keyfile Name createkeyfiledProcessus interrompu, clé non complètement générée+Process interrupted,key not fully generated createkeyfileRNGRNG createkeyfilerSélectionner un répertoire pour y créer le fichier de clé'Select A Folder To Create A Key File In createkeyfile$Etiquette de Texte TextLabel createkeyfileDLe champ du nom de la clé est videThe key name field is empty createkeyfileœVous ne semblez pas avoir les droits d'écriture dans le répertoire destination>You dont seem to have writing access to the destination folder createkeyfilefouvrir le répertoire où sera créé le fichier de clé+open a folder a key file will be created in createkeyfile\emplacement du répertoire où sera créée la clé#path to a folder to create a key in createkeyfile Créer une sauvegarde de l'en-tête "%1" du volume est fortement conseillé. SVP, lire la documentation sur pourquoi cela est important.u Creating a backup of the "%1" volume header is strongly advised. Please read documentation on why this is important. createvolume%1 non trouvé %1 not found createvolume&Annuler&Cancel createvolume,Options avancées LUKS2Advanced LUKS2 Options createvolume,Options avancées LUKS2Advanced Luks2 Options createvolume,Autoriser TRIM continuAllow Discard(TRIM) createvolume\Au moins un des champs qui est requis est vide#Atleast one required field is empty createvolumeÿÿÿÿBytes createvolume C&réerC&reate createvolumexVous ne pouvez pas créer un volume sur le périphérique monté+Can not create a volume on a mounted device createvolumejNe peut pas obtenir une passphrase en mode silencieux%Can not get passphrase in silent mode createvolumeAnnulerCancel createvolumevLe fichier conteneur doit être supérieur à la taille de 3MB&Container file must be bigger than 3MB createvolumeFNe peut pas créer de volume chiffré$Could not create an encrypted volume createvolumerNe trouve pas de partition qui correspond à l'UUID entrée4Could not find any partition with the presented UUID createvolumenImpossible d'obtenir une clé à partir du fichier de clé#Could not get a key from a key file createvolumeVNe peut pas obtenir de clé depuis un socket!Could not get a key from a socket createvolumejNe peut pas obtenir une passphrase en mode silencieux'Could not get passphrase in silent mode createvolumeZImpossible d'ouvrir le volume pour l'écriture!Could not open volume for writing createvolume†Ne peut pas avoir assez de mémoire pour manipuler le fichier de clé/Couldnt get enought memory to hold the key file createvolume.Créer un nouveau volumeCreate A New Volume createvolumelL'option par défaut est la première entrée de la liste-Default option is the first entry on the list createvolume ERREURERROR createvolumeERREUR!ERROR! createvolume|Code Erreur: %1 -- Sortie Standard: %2 -- Erreur de Sortie: %3,Error Code: %1 -- StdOut: %2 -- StdError: %3 createvolume†Echec pour trouver ou exécuter le programme Yubikey's "ykchalresp".7Failed To Locate Or Run Yubikey's "ykchalresp" Program. createvolume<Echec de la création du volumeFailed to create a volume createvolumeNEchec de l'activation du support polkitFailed to enable polkit support createvolume&Système de Fichiers File System createvolume¼Forcer des itérations (dangereux et peut mener à des temps de déverrouillage extrêmement long)MForced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) createvolumeÿÿÿÿ GigaBytes createvolumeNPassphrases cachées non correspondantesHidden passphrases do not match createvolumetcaractère interdit dans le champ de taille du volume caché:Illegal character detected in the hidden volume size field createvolumebMémoire insuffisante pour manipuler la passphrase&Insufficient memory to hold passphrase createvolumebMémoire insuffisante pour manipuler la passphrase*Insufficient memory to hold the passphrase createvolume\Mémoire insuffisante pour manipuler la réponse)Insufficient memory to hold your response createvolumeLChemin invalide vers le fichier de cléInvalid path to key file createvolume Il est préférable de créer un volume caché avec le système de fichiers vfat/fat.?It is best to create a hidden volume with vfat/fat file system. createvolumeHTemps d'itération (en millisecondes)Iteration Time (milliseconds) createvolumeCléKey createvolume(Clé + fichier de clé Key+KeyFile createvolumeFichier de cléKeyFile createvolume0Chemin du fichier de clé Keyfile Path createvolumeClésKeys createvolumeÿÿÿÿ KiloBytes createvolumeLUKSLUKS createvolume&LUKS+Header ExterneLUKS+External Header createvolume LUKS1LUKS1 createvolume(LUKS1+Header ExterneLUKS1+External Header createvolume LUKS2LUKS2 createvolume(LUKS2+Header ExterneLUKS2+External Header createvolumeEtiquetteLabel createvolumeìVolume LUKS créé avec succès, en-tête externe créé avec succès mais échec del'effacement du header sur le périphériquenLuks volume created successfully,external header created successfully but failed to erase header on the device createvolume:Volume LUKS créé avec succès.!Luks volume created successfully. createvolume*Mémoire maximale (Ko)Max Memory (KB) createvolumeÿÿÿÿ MegaBytes createvolumejLes algorithmes multiples sont séparés par des ":". 5Multiple algorithms are separated by ":" character.  createvolumeÿÿÿÿNormal TrueCrypt createvolumeÿÿÿÿNormal VeraCrypt createvolume,Normal+TrueCrypt CachéNormal+Hidden TrueCrypt createvolume,Normal+VeraCrypt CachéNormal+Hidden VeraCrypt createvolumeˆUn ou plusieurs argument(s) requis pour cette opération est manquant>One or more required argument(s) for this operation is missing createvolumeNOpération interrompue par l'utilisateur%Operation terminated per user request createvolumeŒOptions dans le format "algorithm.cipher mode.key size in bits.hash" JOptions are in a format of "algorithm.cipher mode.key size in bits.hash"  createvolumeNLes options sont séparées par un ".". +Options are separated by a "." character.  createvolumePIMPIM createvolumePLAIN dm-cryptPLAIN dm-crypt createvolume>PLAIN dm-crypt avec un décalagePLAIN dm-crypt with offset createvolume$Threads parallèlesParallel Threads createvolume8Force de la Passphrase : %1%Passphrase Quality: %1% createvolume6Force de la Passphrase : 0%Passphrase Quality: 0% createvolume:Force de la Passphrase : 100%Passphrase Quality: 100% createvolume>Passphrases non correspondantesPassphrases do not match createvolumeMot de PassePassword createvolume6Chemin vers le périphériquePath To Device createvolume,Chemin vers le fichier Path To File createvolume6Chemin vers le périphériquePath to Device createvolumeType Pbkdf Pbkdf Type createvolumeªSoyez patient car le chiffrement d'un volume VeraCrypt peut durer un certain temps. MPlease be patient as creating a VeraCrypt volume may take a very long time.  createvolume¬Système de fichiers non pris en charge, voir la documentation pour plus d'informationsMPresented file system is not supported,see documentation for more information createvolumeÿÿÿÿRNG createvolume0Réentrer le mot de passeRepeat Password createvolumeSUCCES!SUCCESS! createvolumeDéfinirSet createvolumeSous système Sub System createvolume$Etiquette de texte TextLabel createvolumevIl semble y avoir un mappeur ouvert associé au périphériqueGénérateur aléatoire de nombresrandom number generator createvolume% Complété % Complete cryptfiles&Annuler&Cancel cryptfiles&OK&OK cryptfiles C&réerC&reate cryptfiles^Impossible d'ouvrir les routines de chiffrement"Could not open encryption routines cryptfilesdImpossible d'ouvrir le fichier clé pour la lecture"Could not open keyfile for reading cryptfilestImpossible d'ouvrir les routines de lecture de chiffrement*Could not open reading encryption routines cryptfilestImpossible d'ouvrir les routines d'écriture de chiffrement*Could not open writing encryption routines cryptfilesfCréer une version non chiffrée d'un fichier chiffré/Create A Decrypted Version Of An encrypted File cryptfilesNCréer une version chiffrée d'un fichier%Create An Encrypted Version Of A File cryptfilesBDéchiffrement réalisé avec succès#Decrypted file created successfully cryptfiles®Fichier déchiffré avec succès mais échec de la somme MD5, le fichier peut être corrompuPDecrypted file created successfully but md5 checksum failed,file maybe corrupted cryptfilesDestination Destination cryptfiles>Chemin de destination déjà prisDestination path already taken cryptfiles@Fichier chiffré créé avec succès#Encrypted file created successfully cryptfilesEntrer une clé Enter A Key cryptfilesjEntrer le chemin de la localisation du fichier de clé"Enter A Path To A Keyfile Location cryptfiles^Échec de la fermeture de routine de chiffrement"Failed to close encryption routine cryptfilesvFichier ou dossier existent déjà à l'adresse de destination3File or folder already exist at destination address cryptfiles,Premier champ clé videFirst key field is empty cryptfiles€Générer une clé en utilisant une passphrase et un fichier de clé4Generate a key made up of a passphrase and a keyfile cryptfilestPrivilège insuffisant pour créer le fichier de destination1Insufficient privilege to create destination file cryptfiles†Privilège insuffisant pour ouvrir le fichier source pour la lecture6Insufficient privilege to open source file for reading cryptfilesLChemin invalide vers le fichier de cléInvalid path to key file cryptfilesLChemin invalide vers le fichier sourceInvalid path to source file cryptfilesCléKey cryptfiles(Clé + fichier de clé Key+KeyFile cryptfilesFichier de cléKeyFile cryptfiles0Clés non correspondantesKeys do not match cryptfilesNOpération interrompue par l'utilisateur%Operation terminated per user request cryptfilesMot de PassePassword cryptfiles4Chemin vers la source videPath to source field is empty cryptfileszclé entrée ne semble pas correspondre à la clé de chiffrement.Presented key did not match the encryption key cryptfilesRéentrer la clé Repeat Key cryptfiles0Réentrer le mot de passeRepeat Password cryptfiles*Second champ clé videSecond key field is empty cryptfilesdSélectionner un fichier que vous voulez déchiffrer!Select A File You Want To Decrypt cryptfiles`Sélectionner un fichier que vous voulez chiffrer!Select A File You Want To Encrypt cryptfiles<Sélectionner un fichier de cléSelect A Keyfile cryptfilesVchoisir le chemin du fichier de destination#Select Path to put destination file cryptfiles SourceSource cryptfiles$Etiquette de texte TextLabel cryptfiles€Ces fichiers chiffrés de manière obsolète ne sont plus supportés6These very old encrypted files are no longer supported cryptfiles’Vous ne semblez pas avoir accès d'écriture dans le dossier de destination>You dont seem to have writing access to the destination folder cryptfiles0chemin du fichier de clé keyfile path cryptfilesvfichiers chiffrés zuluCrypt ( *.zc ) ;; Tous fichiers ( * )5zuluCrypt encrypted files ( *.zc ) ;; All Files ( * ) cryptfilesJNe plus montrer ce message désormais.Do not show this message again. cryptoinfoSalutations Greetings cryptoinfoOkOk cryptoinfo¢Veuillez consulter "menu->aide->lire zuluCrypt.pdf" pour une présentation de zuluCrypt. Utilisateurs d'Unity, le menu est dans le coin haut gauche de l'écran quand zuluCrypt est sélectionné. La page officielle du projet est sur : https://mhogomchungu.github.io/zuluCrypt Recommandations de lecture FAQ de la page officielle du projet./Please consult "menu->help->open zuluCrypt.pdf" to get an introduction on zuluCrypt. Unity users,the menu is on the upper left corner of the screen when zuluCrypt has focus. Project's homepage is at: https://mhogomchungu.github.io/zuluCrypt Recommending reading FAQ page from the project's main page. cryptoinfo&Fermer&Close debugWindow&EffacerC&lear debugWindow:Fenêtre de Débogage ZuluCryptzuluCrypt Debug Window debugWindow&Non&Nodialogok&Ok&Okdialogok&Oui&YesdialogokDialogueDialogdialogokEtiquetteTexte TextLabeldialogok% Complété % Completed erasedevice&Annuler&Cancel erasedevice&OK&OK erasedevice&Commencer&Start erasedeviceÖÊtes-vous vraiment sûr que vous voulez écrire des données aléatoires sur "%1" et détruire tout son contenu?dAre you really sure you want to write random data to "%1" effectively destroying all contents in it? erasedeviceVitesse moyenne Average Speed erasedevice Vitesse moyenne:Average Speed: erasedevicelImpossible d'ouvrir un mappeur sur un dispositif monté)Can not open a mapper on a mounted device erasedevicezNe peut pas ouvrir sur un périphérique avec un mappeur ouvert,Can not write on a device with opened mapper erasedevice.Ne pas créer de mappeurCould not create mapper erasedevice†Ne peut pas avoir assez de mémoire pour manipuler le fichier de clé1Could not get enought memory to hold the key file erasedeviceZNe peut pas trouver le chemin du périphériqueCould not resolve device path erasedeviceLNe peut pas écrire sur le périphériqueCould not write to the device erasedevice`Données sur le périphérique effacées avec succès&Data on the device successfully erased erasedevicePLe champ Chemin du périphérique est videDevice path field is empty erasedevice>Chemin de périphérique invalideDevice path is invalid erasedeviceTemps estiméETA erasedeviceHEntrer le chemin du volume à effacer!Enter Path To Volume To Be Erased erasedeviceŽÉcrire des données aléatoire sur les données existantes du périphérique9Erase Data On The Device By Writing Random Data Over Them erasedeviceNEchec de l'activation du support polkitFailed to enable polkit support erasedevice€Privilège insuffisant pour ouvrir le fichier clé pour la lecture3Insufficient privilege to open key file for reading erasedevice>Chemin de périphérique invalideInvalid path to device erasedeviceN/AN/A erasedeviceNOpération interrompue par l'utilisateur$Operation terminated per user choice erasedeviceJFichiers de Passphrase n'existent pasPassphrase file does not exist erasedevice6Chemin vers le périphériquePath to Device erasedeviceÂPolitique système empêche les utilisateurs non root d'ouvrir un mappeur sur une partition système@Policy prevents non root user opening mapper on system partition erasedeviceLDonnées aléatoires écrites avec succès Random data successfully written erasedevice~Sélectionner une partition non système pour effacer son contenu3Select A Non System Partition To Erase Its Contents erasedevice$Etiquette de texte TextLabel erasedevice^La boîte de dialogue suivante va écrire des données aléatoires sur le périphérique conduisant à la perte permanente de tous ses contenus. Êtes vous sûr de vouloir continuer? The next dialog will write random data to a device leading to permanent loss of all contents on the device. Are you sure you want to continue?  erasedevice@Le périphérique est déjà utilisé'This device appear to already be in use erasedeviceDurée totale: Total Time: erasedeviceATTENTIONWARNING erasedeviceATTENTION!WARNING! erasedevicenÉcrire des données aléatoire sur les données existantes$Write Random Data Over Existing Data erasedevicenÉcrire des données aléatoire sur les données existantes&Writing Random Data Over Existing Data erasedevice&Fermer&Close favorites2AjouterAdd favorites2"Ajouter un volume Add A volume favorites2ZModifier le mot de passe du trousseau interneChange Internal Wallet Password favorites2DEntrer le moit de passe ci dessousEnter Password Below favorites2JEntrer le chemin du volume ci dessousEnter Volume Path Below favorites2"Liste des favoris Favorite List favorites2Favoris Favorites favorites2"Trousseau interneInternal Wallet favorites2KWalletKWallet favorites2Libsecret Libsecret favorites2DGérer les clés dans des trousseauxManage Keys In Wallets favorites2$Options de montage Mount Options favorites2"Chemin du montage Mount Path favorites2 Point de montage Mount Point favorites2 AucunNone favorites2OKOk favorites2>Définir le trousseau par défautSet Default Wallet favorites2Etiquette texte TextLabel favorites2&Étiquette du volume Volume ID favorites2 Chemin du volume Volume Path favorites2&Définir&Set fileManagerÈTapez ci dessous le nom de l'application que vous voulez utiliser pour ouvrir les points de montage.QEnter Below The Name Of The Application You Want To Be Used To Open Mount Points. fileManagerFChoisir le gestionnaire de fichiersSet File Manager fileManagerEtiquetteTexte TextLabel fileManager&Fermer&Closehelpÿÿÿÿñï

ZuluCrypt is a simple, feature rich and powerful solution for hard drives encryption for linux.


ZuluCrypt supports LUKS, TrueCrypt, VeraCrypt and PLAIN dm-crypt encrypted volumes.


These supported encrypted volumes may resides in image files, hard drives and usb sticks, LVM

volumes as well as in mdraid devices.


There are two kinds of encrypted volumes. Those that use what is commonly know as “a header†and

those that do not. TrueCrypt, VeraCry and LUKS volumes use a header. PLAIN dm-crypt volumes do

not use a header.


LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a "volume header".

A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data.


The damage to the header is usually caused by accidental formatting of the device or use of

some buggy partitioning tools or wrongly reassembled logical volumes.

Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted.


There are two kinds of header using encrypted volumes. Those that use an encrypted header and those

that do not. TrueCrypt and VeraCrypt use an encrypted header whereas LUKS does not. The use of non

encrypted header in LUKS makes it obvious to everybody that the volume is an encrypted LUKS

volume and this may be problematic to some people. How big the problem may be depends on the

person and their use case for hard drive encryption.


The use of encrypted header as in TrueCrypt or VeraCrypt volumes or no header at all as in PLAIN dm-

crypt volumes make these volumes indistinguishable from random noise and this may seem useful at a

glance but its usefulness may not hold up against scrutiny as the likelihood of being believed that a

100GB file made up of cryptographically sound random data is just a 100GB file made up of random

data and not a container file for an encrypted volume is not very high.


With LUKS, TrueCrypt and VeraCrypt volumes, it is very important to have a volume header backup

since a valid header is required to unlock the volume. A corrupted or missing header will make the

volume unusable causing the loss of all encrypted data.


LUKS stands for “Linux Unified Key Setupâ€. It is a specification of how to store information necessary

to open a LUKS formatted encryption volume. LUKS encryption format is the standard format in linux

and a recommended one if the encrypted volume is to be used among linux systems. TrueCrypt or

VeraCrypt volumes are better alternative if the encrypted volume is to be shared between linux,

windows and OSX computers.


ZuluCrypt can create and open 5 types of encrypted volumes, LUKS, TrueCrypt, VeraCrypt,PLAIN

dm-crypt and PLAIN dm-crypt volume at a none zero offset. PLAIN dmcrypt volume is a header less

encrypted volume and all necessary encryption information is provided by zuluCrypt when it creates or

open these volumes.


Pros and cons of the five volumes.


PLAIN dm-crypt:

Pro:

1. It does not use a volume header and hence its not possible to “brick†the entire volume simply by

over writing a small part of it.

2. It does not use a header and hence its impossible to know if the volume is made up of only

cryptographically sound random data or if its an encrypted volume.


Cons:

It does not use a header and hence any tool that opens these volumes must provide the encryption

options that were used when the volume was created. Different tools may use different encryption

options making these encrypted volumes not very portable between applications or even between

different versions of the same application.


PLAIN dm-crypt at a none zero offset.


This volume has the same pros and cons as those of a PLAIN dm-crypt volume.


Additional pro for this volume is that it can be places anywhere on the device making it possible

to have this volume on top of any one of the other supported encrypted volume or on top of an

unencrypted volume.


For example, its possible to have an X MB drive that has unencrypted file system

at the beginning of the device and a “PLAIN dm-crypt volume with an offset†somewhere towards the

end of the device making it possible to use the drive as unencrypted volume and as encrypted volume

simultaneously depending on sensitivity of the data to be stored on the device.


If this volume type is to be used, preceding part of the drive should be formatted in “FAT†family of file systems.This volume types gives a “hidden volume†type functionality offered by TrueCrypt and VeraCrypt. When creating or unlocking this volume type, the starting offset of the volume will be asked and NOT the volume size as TrueCrypt and VeraCrypt does with the hidden volume.


The above means, if you have a 100 MB drive and you want to create a 30MB “PLAIN dm-crypt

volume at a none zero offsetâ€, you will enter the starting offset of the volume as 70MB. In VeraCrypt or

TrueCrypt, you will enter the hidden volume size of 30MB. The starting offset and the size of the

hidden volume are related by a simple formula: starting offset(70MB) = device size(100MB) – hidden

volume size(30MB).


TrueCrypt

Pro:

1. It uses an encrypted header and hence its not possible to know if the volume is TrueCrypt formatted

encrypted volume or if the volume is just made up of cryptographically sound random data.

2. Hidden volume. A TrueCrypt volume can have up to two different encrypted volumes. The first

volume is commonly know as “outer volume†and the second optional one is commonly known as

“hidden volumeâ€.When a TrueCrypt volume is about to be opened, the user has an option to select

which one of the two to open by giving appropriate key.


Cons:

1. It uses an encrypted header and it is not possible to open the volume without a valid header. If you

use a TrueCrypt volume, make sure you have at least one backup of the volume header.


VeraCrypt


VeraCrypt is an extension of TrueCrypt and it shares the same TrueCrypt’s pros and cons.

Additional Pro for VeraCrypt over TrueCrypt.


1. It requires stronger effort to unlock VeraCrypt volume and this makes them more secure over

TrueCrypt volumes.

Additional Cons for VeraCrypt over TrueCrypt.

2. It requires stronger effort to unlock a VeraCrypt volume and this increases the time it takes to unlock

a VeraCrypt volume. How long it will take depends on the strength of the computer and it may vary

from a few seconds to several minutes.


LUKS


Pro:

1. A LUKS volume can be opened with up to 8 different keys.


Cons:

1. A LUKS header is stored unencrypted making it obvious the volume is LUKS formatted encrypted

volume and this may not be desirable under certain circumstances. It is possible to create a LUKS

volume with a detached header and zuluCrypt can open these volumes using “luks†plugin.

2. It uses a header. As it is not possible to open a header using encrypted volume without its header, a

corrupted LUKS header makes it impossible to open the volume. If you use a LUKS volume, make

sure you have at least one backup of the volume header.

ZuluCrypt can do two types of encryption. It can do single file encryption/decryption or block device

encryption.


File encryption.


ZuluCrypt can encrypt and decrypt individual files. This feature is useful when a user just wants to

encrypt a single file and taking the route of creating an encrypted container file to host the file is seen

as an unnecessary hassle. This functionality is akin to file encryption using gpg with a symmetric key.

File encryption is done using libgcrypt as a cryptographic backend. Files are encrypted using 256 bit

AES in CBC mode.


The encryption key is derived from user pass phrase using pbkdf2 with 10,000

rounds of iterations and sha2 as a cryptographic hash function. The resulting encrypted file will have a

file size that equals (64 + 1024 * n) bytes where n is a number starting from zero.


How to create an encrypted file:


1. Start zuluCrypt.

2. Go to the menu and then click “zC->encrypt a file†to open a file encryption dialog window.

3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file

dialog will show up, select the file you want to store encrypted, enter the password to be used to

encrypt the file and then click “create†and the encrypted version of the file will be created at the path

given by “destination path†field.


To decrypt the file created with above steps:


1. Start zuluCrypt.

2. Go to the menu and then click “zC->decrypt a file†to open a file decryption dialog window.

3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file

dialog will show up, select the file you want to decrypt, enter the password to be used to decrypt the

file and then click “create†and the decrypted version of the file will be created at the path given by

“destination path†field.


Block device encryption.


A hard drive or a usb stick are two examples of block devices. A regular file can simulate a block

device through a use of devices known as “loop devicesâ€. These devices have a device path that starts

with “/dev/loopâ€.


The infrastructure in the linux kernel that deal with block device encryption is called “dm-crypt†and it

does its work through a process commonly known as OTF(on the file encryption). Dm-crypt devices

are represented by device addresses that starts with “/dev/dm-†and these paths are usually accessed

through their soft links that reside in “/dev/mapperâ€.


Below is an example of steps taken in creating a 100MB encrypted container in a file and adding a file

in it to be stored securely.


1. Create a 100MB file.

2. Attach a loop device to the file.

3. Create an OTF encryption mapper against the loop device.

4. Put a file system on the encryption mapper.

5. Mount the file system on the mapper.

6. Copy The file to be stored securely to the file system through the mount point.

7. Unmount the file system.

8. Destroy the OTF encryption mapper.

9. Detach the loop device from the file.

10. Maintain the encrypted volume as a secure holder of files within it.


All zuluCrypt does is provide a GUI to make it easy to do above specified tasks.


With the above steps:


Step 1 deal with a path that look like “/home/ink/secret.imgâ€, this is a path to a regular file.

Step 2 converts “/home/ink/secret.img†file to something like “/dev/loop0†loop device path.

Step 3 converts “/dev/loop0†loop device path to something like “/dev/mapper/secrets.imgâ€. Data

written to “/dev/mapper/secrets.img†will get encrypted and then passed forward to “/dev/loop0†on its

way to “/home/ink/secret.imgâ€. When data is read from “/dev/mapper/secrets.imgâ€, the data will be

read from “/dev/loop0†who in turn will read it from “/home/ink/secret.imgâ€, decrypted by dm-crypt

and then given to the reader. This process is called “on the fly encryption†because the encryption

mapper does not store or hold on to data, it gets data and then encrypts or decrypts it depending on the

direction of data flow and then passes it along.


How to create an encrypted container in an image file.


1. Start zuluCrypt.

2. Go to “menu->create->encrypted container in a file†to open a dialog window.

3. Enter the name of the file to be used to hold the container in the “file name†field.

4. Enter the size of the container in the “file size†field.

5. Click “createâ€.

6. Wait for the container file to be created and for the volume creation dialog to show up.

7. Enter the password to be used to create the volume.

8. Select the type of volume you want to create from the “volume type†list.

9. Click create to create the volume.


How to create an encrypted container in a partition.


1. Start zuluCrypt.

2. Go to “menu->create->encrypted container in a hard drive†to open a dialog window.

3. Click/double click on the hard drive you want to create a volume in and then advance to instruction

number 7 in the instruction list above. If the partition you want to put an encrypted container does not

show up on the list, then restart zuluCrypt from root's account and try again.


How to open an encrypted container that reside in a file using zuluCrypt.


1. Start zuluCrypt.

2. Go to “menu->open->encrypted container in a file†to bring up a dialog window.

3. On the dialog window, click the button to the right of “volume path†field and then browse to where

the volume is and click it to open it. Alternatively, you can just drag the volume file on zuluCrypt to

generate a password dialog prompt with the file path already filled in.

4. Enter the volume key in the volume key field and then click “open†to open the volume.


How to open an encrypted container that reside in a partition using zuluCrypt.


1. Start zuluCrypt.

2. Go to “menu->open->encrypted container in a partition†to bring up a dialog window.

3. On the dialog window, click/double click on the partition with an encrypted volume you want to

open.

4. Enter the volume key in the volume key field and then click “open†to open the volume.

With both two steps above, the volume will be opened and mounted at a path whose last component is

given by the entry in the field “mount nameâ€.


When the volume is successfully opened, zuluCrypt will

automatically open the mount point path. To close the volume, click its entry on the zuluCrypt window

and then click “close†on the pop up window.


ZuluCrypt can open an encrypted volume using keys derived from different sources. These sources

include, a pass phrase, a key file, a key retrieved from kwallet, a key retrieved from Gnome's libsecret,

a key retrieved from an internal secure storage system, a key from gpg encrypted key file among other

sources.


To use a pass phrase volume key, make sure the key source option read “key†and then enter the pass

phrase on the entry field at the bottom.


To use a keyfile as the source of volume key, click the option bar and then select “keyfile†and then

press the button on the lower right to bring a dialog box that will allow you to browse to where the key

file is.


To use a plugin as the source of volume key, click the option bar and then select “plugin†and then

press the button on the lower right to bring up a list of available plugins and then select the one you

want from the list.


Volume keys stored in kwallet, Gnome keyring or internal secure storage system plugins can be

managed by going to “menu->options->manage volumes in internal/kde/gnome walletâ€.


Storage of keys in a gnome wallet/keyring seem most appropriate in a gnome session but this has some security repercussions, the keys are stored in the user keyring and this keyring gets unlocked when the user logs in. This means that once a user is logged in and the keyring is open, any application that runs in that user session can read those keys using public APIs exposed by the storage system.


In a kde system, a kwallet secure storage system seem most appropriate but it suffers from the same

security problem the gnome secure storage system has, once the wallet is open, any application running in the user session can access it using public APIs exposed by the storage system.


The behaviors of the above secure storage systems is by design but this design may not be ideal for

some users under certain use cases. The internal secure storage system is powered by libgcrypt and it

does not have the behavior of the above two systems. An unlocked internal secured storage system is

accessible only to the instance of zuluCrypt that unlocked it.


Favorites.


For convenience, most used volumes can be easily opened by adding them to the favorite list. Entries

on the list are added in the dialog window opened by clicking “menu->options->manage favoritesâ€.

Favorite entries are added by clicking the “favorite†entry on the menu.

Erase data in a device.


It is very important to create encrypted volume over cryptographically strong random data to make it

impossible to know what part of the encrypted volume has been used and what part has not. If the

encrypted volume is created over predictable data patterns like on a device with only zeros in it,

forensic analysis may reveal how much and what part of the encrypted volume are in use.

When creating an encrypted container in a device, zuluCrypt offers an option to first write random data

over the device. This feature can be performed on other devices by activating it through “menu->erase

data in a deviceâ€. Random data are written to disk by opening a plain dm-crypt encryption mapper on

the device with a 64 byte random key and then blasting zeros on the device through the mapper. This

technique has proven to be faster compared to alternatives like writing random data on the device read

from “/dev/urandomâ€.


System and non system volumes.


To enforce access controls on what user can access what block device and what they can do with the

access they have, zuluCrypt employes a concept of “system volumes†and “non system volumesâ€.

A system volume is defined as a volume that has an active entry in

“/etc/fstabâ€,â€/etc/crypptabâ€,“/etc/zuluCrypt/system_volumes.list†or if udev identify it as such if udev

is enabled. Ideally, all volumes inside the computer are to be considers system volumes.


A non system volume is a volume that failed in the above considerations or if it has an entry in

“/etc/zuluCrypt/non_system_volumes.listâ€. Ideally, these volumes are plug gable usb based hard drives

or usb sticks.


Partitions can be added or removed from the list of system or non system volumes simply by starting

zuluCrypt from root's account and then going to “menu->options->manage system volumes/manage

non system volumes†and then adding the volume in the appropriate list.

Permissions.


ZuluCrypt limits what a user can do on block devices through unix's group based permission system

using two groups, “zulucrypt†and “zulumountâ€.


If a device is identified as a system device, only a root user or a user who is a member of group

“zulucrypt†can create an encrypted volume in the device or taking/restoring volume headers. If you

want to create a volume in a device and the device does not show up on the list, restart zuluCrypt from

root's account and try again.


If a device is identified as a system device, zuluMount will mount it only if the user is root, is a

member of group “zulumount†or the device has an entry in “/etc/fstab†with either “user†or “usersâ€

mount options set.


ZuluMount.

ZuluMount is a general purpose mounting tool that can open zuluCrypt supported encrypted volumes

as well as non encrypted volumes.


ZuluMount can also auto detect plugged in devices and auto mount them.

ZuluMount can also unlock encfs volumes.


Copyright (c) 2015-2017 Francis Banyikwa, mhogomchungu@gmail.com


help Impossible de lire zuluCrypt.pdf, assurez vous que votre système puisse lire les fichiers PDF utilisant "%1" tool et essayez à nouveaucFailed to open zuluCrypt.pdf,make sure your system can open pdf files using "%1" tool and try againhelpAideHelphelpOuvrir le &PDF Open &PDFhelpATTENTION!WARNING!help\ Mot de passe à ajouter dans le volume chiffré- Password To Be Added To The Encrypted Volume luksaddkey&Ajouter&Add luksaddkey&Annuler&Cancel luksaddkey&OK&OK luksaddkey6Ajouter une clé à un volumeAdd A Key To A Volume luksaddkey,Options avancées LUKS2Advanced LUKS2 Options luksaddkey,Options avancées LUKS2Advanced Luks2 Options luksaddkey Tous les emplacements de clés sont occupés, ne peut pas ouvrir davantage de clés5All key slots are occupied, can not add any more keys luksaddkey\Au moins un des champs qui est requis est vide#Atleast one required field is empty luksaddkeyrNe trouve pas de partition qui correspond à l'UUID entrée2Can not find a partition that match presented UUID luksaddkeyjNe peut pas obtenir une passphrase en mode silencieux%Can not get passphrase in silent mode luksaddkeyAnnulerCancel luksaddkeyVNe peut pas obtenir de clé depuis un socket!Could not get a key from a socket luksaddkey˜Ne peut obtenir d'élévations de privilèges, tester les droits et permissions9Could not get elevated privilege,check binary permissions luksaddkeyDImpossible d'ouvrir le volume luksCould not open luks volume luksaddkey\Impossible d'ouvrir le volume en mode écriture#Could not open volume in write mode luksaddkey†Ne peut pas avoir assez de mémoire pour manipuler le fichier de clé/Couldnt get enought memory to hold the key file luksaddkey\Le périphérique n'est pas un périphérique luksDevice is not a luks device luksaddkeyERREUR!ERROR! luksaddkey0Chemin du volume chiffréEncrypted Volume Path luksaddkeyEntrer une clé Enter A Key luksaddkeyEntrer une clé Enter a key luksaddkeyjEntrer le chemin de la localisation du fichier de clé"Enter a path to a keyfile location luksaddkey|Code Erreur: %1 -- Sortie Standard: %2 -- Erreur de Sortie: %3,Error Code: %1 -- StdOut: %2 -- StdError: %3 luksaddkey.Fichier de clé existantExisting KeyFile luksaddkey†Echec pour trouver ou exécuter le programme Yubikey's "ykchalresp".7Failed To Locate Or Run Yubikey's "ykchalresp" Program. luksaddkeyNEchec de l'activation du support polkitFailed to enable polkit support luksaddkey¦Echec à trouver un emplacement de clé vide ou bien l'emplacement est hors de portée6Failed to find empty key slot or key slot out of range luksaddkey¼Forcer des itérations (dangereux et peut mener à des temps de déverrouillage extrêmement long)MForced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) luksaddkeybMémoire insuffisante pour manipuler la passphrase&Insufficient memory to hold passphrase luksaddkey(Privilèges insuffisants pour ajouter une clé à un périphérique système, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le faire sInsufficient privilege to add a key to a system device, only root user or members of group "zulucrypt" can do that  luksaddkey€Privilège insuffisant pour ouvrir le fichier clé pour la lecture3Insufficient privilege to open key file for reading luksaddkeybNuméro d'emplacement de clé pour y ajouter la cléKey Slot Number To Add Key In luksaddkey4Clés ajoutées avec succès.Key added successfully. luksaddkeyzClés ajoutées avec succès. %1 / %2 emplacements sont utilisés4Key added successfully. %1 / %2 slots are now in use luksaddkey<Emplacement de clé déjà occupéKey slot already occupied luksaddkey(Clé + fichier de clé Key+KeyFile luksaddkeyFichier de cléKeyFile luksaddkey0Chemin du fichier de clé KeyFile Path luksaddkey0Chemin du fichier de clé KeyFile path luksaddkey0Clés non correspondantesKeys do not match luksaddkeyLUKSLUKS luksaddkey*Mémoire maximale (Ko)Max Memory (KB) luksaddkey,Nouveau Fichier de clé New KeyFile luksaddkeyRNouvelles Passphrases non correspondantesNew passphrases do not match luksaddkey\Un ou plusieurs fichiers de clé n'existent pas%One or both keyfile(s) does not exist luksaddkeyˆUn ou plusieurs argument(s) requis pour cette opération est manquant>One or more required argument(s) for this operation is missing luksaddkeyPIMPIM luksaddkey$Threads parallèlesParallel Threads luksaddkey8Force de la Passphrase : %1%Passphrase Quality: %1% luksaddkey6Force de la Passphrase : 0%Passphrase Quality: 0% luksaddkey:Force de la Passphrase : 100%Passphrase Quality: 100% luksaddkeyMot de PassePassword luksaddkey^Mot de passe déjà inclus dans le volume chiffré(Password Already In The Encrypted Volume luksaddkeyType Pbkdf Pbkdf Type luksaddkeypLes clés entrées ne correspondent à aucune clé du volume2Presented key does not match any key in the volume luksaddkey0Réentrer le mot de passeReenter Password luksaddkeyDéfinirSet luksaddkey$Etiquette de texte TextLabel luksaddkeyTrueCrypt TrueCrypt luksaddkeyXCoût temps de déverrouillage (millisecondes)!Unlocking Time Cost(Milliseconds) luksaddkeyVeraCrypt VeraCrypt luksaddkey Chemin du volume Volume Path luksaddkeyType de Volume Volume Type luksaddkeyDLe volume n'est pas un volume LUKSVolume is not a luks volume luksaddkey2YubiKey Challenge/RéponseYubiKey Challenge/Response luksaddkeyargon2iargon2i luksaddkeyargon2idargon2id luksaddkey"Ouvrir un fichier open file luksaddkey0ouvrir un fichier de clé open keyfile luksaddkey(Ouvrir une partitionopen partition luksaddkey pbkdf2pbkdf2 luksaddkeyX Êtes vous sûr de vouloir effacer cette clé?* Are you sure you want to delete this key? luksdeletekey¤ Cet effacement rendra le volume impossible à ouvrir et donc perdu définitivement.> Deleting it will make the volume unopenable and lost forever. luksdeletekey&Annuler&Cancel luksdeletekey&Effacer&Delete luksdeletekey&OK&OK luksdeletekey\Au moins un des champs qui est requis est vide#Atleast one required field is empty luksdeletekeyrNe trouve pas de partition qui correspond à l'UUID entrée2Can not find a partition that match presented UUID luksdeletekeyjNe peut pas obtenir une passphrase en mode silencieux%Can not get passphrase in silent mode luksdeletekeyVNe peut pas obtenir de clé depuis un socket!Could not get a key from a socket luksdeletekey€Ne peut pas avoir assez de mémoire pour ouvrir le fichier de clé0Could not get enough memory to open the key file luksdeletekey:Impossible d'ouvrir le volumeCould not open the volume luksdeletekey\Impossible d'ouvrir le volume en mode écriture'Could not open the volume in write mode luksdeletekeyERREUR!ERROR! luksdeletekeyEntrer une clé Enter a key luksdeletekeyjEntrer le chemin de la localisation du fichier de clé"Enter a path to a keyfile location luksdeletekey|Code Erreur: %1 -- Sortie Standard: %2 -- Erreur de Sortie: %3,Error Code: %1 -- StdOut: %2 -- StdError: %3 luksdeletekey†Echec pour trouver ou exécuter le programme Yubikey's "ykchalresp".7Failed To Locate Or Run Yubikey's "ykchalresp" Program. luksdeletekeyNEchec de l'activation du support polkitFailed to enable polkit support luksdeletekeybMémoire insuffisante pour manipuler la passphrase&Insufficient memory to hold passphrase luksdeletekey\Mémoire insuffisante pour manipuler la réponse)Insufficient memory to hold your response luksdeletekeyPrivilèges insuffisants pour ouvrir un périphérique système, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le fairegInsufficient privilege to open a system device,only root user or members of group zulucrypt can do that luksdeletekey€Privilège insuffisant pour ouvrir le fichier clé pour la lecture3Insufficient privilege to open key file for reading luksdeletekeyXFichier de clé avec une passphrase à effacer$Key File With A Passphrase To Delete luksdeletekeyzClés enlevées avec succès. %1 / %2 emplacements sont utilisés6Key removed successfully. %1 / %2 slots are now in use luksdeletekey(Clé + fichier de clé Key+KeyFIle luksdeletekeyFichier de cléKeyFile luksdeletekey0Chemin du fichier de clé KeyFile path luksdeletekey<Fichiers de clé n'existent pasKeyfile does not exist luksdeletekey2LUKS numéro d'emplacementLUKS Slot Number luksdeletekeyˆUn ou plusieurs argument(s) requis pour cette opération est manquant>One or more required argument(s) for this operation is missing luksdeletekeyNOpération interrompue par l'utilisateur%Operation terminated per user request luksdeletekeyMot de PassePassword luksdeletekey6Enlever une clé d'un volumeRemove A Key From A Volume luksdeletekey$Etiquette de texte TextLabel luksdeletekeyŠIl n'y a pas de clé dans le volume qui corresponde avec la clé entrée:There is no key in the volume that match the presented key luksdeletekey`Il reste encore une dernière clé dans le volume.)There is only one last key in the volume. luksdeletekey Chemin du volume Volume Path luksdeletekeyDLe volume n'est pas un volume LUKSVolume is not a luks volume luksdeletekeyATTENTIONWARNING luksdeletekey2YubiKey Challenge/RéponseYubiKey Challenge/Response luksdeletekey0ouvrir un fichier de cléopen a keyfile luksdeletekey2Ouvrir un fichier chiffréopen an encrypted file luksdeletekey:Ouvrir une partition chiffréeopen an encrypted partition luksdeletekey°zuluCrypt aura le même comportement que LUKSKillSlot si un emplacement de clé est fourniMzuluCrypt will have the same behavious as luksKillSlot if a key slot is given luksdeletekey¾zuluCrypt aura le même comportement que LUKSRemoveKey si un emplacement de clé n'est PAS fourniRzuluCrypt will have the same behavious as luksRemoveKey if a key slot is NOT given luksdeletekey &Fini&DonemanageSystemVolumes*Ajouter &Périphérique Add Dev&icemanageSystemVolumes Ajouter &Fichier Add Fi&lemanageSystemVolumesXÊtes vous sûr de retirer "%1" de la liste?5Are you sure you want to remove "%1" from the list?manageSystemVolumesAnnulerCancelmanageSystemVolumes4Gérer les volumes systèmesManage System VolumesmanageSystemVolumes6Chemins des volumes SystèmePath To System VolumesmanageSystemVolumes:Enlever l'entrée sélectionnéeRemove Selected EntrymanageSystemVolumesFChoisir le chemin du volume SystèmeSelect Path To System VolumemanageSystemVolumesATTENTIONWARNINGmanageSystemVolumes&Backup&Backupmanagevolumeheader&Annuler&Cancelmanagevolumeheader&Restaurer&RestoremanagevolumeheaderØEtes-vous sûr de vouloir remplacer un en-tête sur le périphérique "%1" avec une copie de sauvegarde de "%2"?TAre you sure you want to replace a header on device "%1" with a backup copy at "%2"?managevolumeheaderxArgument pour le chemin de sauvegarde du header est manquant5Argument for path to a backup header file is missingmanagevolumeheader\Au moins un des champs qui est requis est vide#Atleast one required field is emptymanagevolumeheader(Backup Header VolumeBack up volume headermanagevolumeheaderNom du Backup Backup Namemanagevolumeheader(Backup Header VolumeBackup Volume HeadermanagevolumeheadervLe fichier sauvegardé ne semble pas contenir de header LUKS2Backup file does not appear to contain luks headermanagevolumeheader &CréerC&reatemanagevolumeheaderZNe peut pas trouver le chemin du périphérique Could not resolve path to devicemanagevolumeheaderERREUR!ERROR!managevolumeheaderNEchec de l'activation du support polkitFailed to enable polkit supportmanagevolumeheader:Echec de l'opération demandée%Failed to perform requested operationmanagevolumeheader`Echec de l'opération demandée sur le volume LUKS8Failed to perform requested operation on the LUKS volumemanagevolumeheader6Header restauré avec succèsHeader restored successfullymanagevolumeheaderˆHeader sauvé avec succès. Si possible, stockez le en toute sécurité.9Header saved successfully. If possible,store it securely.managevolumeheader INFO!INFO!managevolumeheaderšPrivilège insuffisant pour sauver un backup dans le répertoire de destinationHInsufficient privilege to create a backup header in a destination foldermanagevolumeheader¨Privilège insuffisant pour ouvrir le fichier d'en-tête de sauvegarde pour la lecture=Insufficient privilege to open backup header file for readingmanagevolumeheader‚Privilège insuffisant pour ouvrir le périphérique pour la lecture1Insufficient privilege to open device for readingmanagevolumeheader‚Privilège insuffisant pour ouvrir le périphérique pour l'écriture1Insufficient privilege to open device for writingmanagevolumeheaderZChemin invalide pour sauver le fichier header#Invalid path to back up header filemanagevolumeheader>Chemin de périphérique invalideInvalid path to devicemanagevolumeheaderFichier de cléKeyFilemanagevolumeheader(Gérer un LUKS HeaderManage A LUKS Headermanagevolumeheader2Gérer un TrueCrypt HeaderManage A TrueCrypt Headermanagevolumeheader2Gérer un VeraCrypt HeaderManage A VeraCrypt HeadermanagevolumeheaderVolume Normal Normal Volumemanagevolumeheader Seul l'utilisateur root ou les membres du groupe zulucrypt peuvent restaurer et sauver les luks headers sur les périphériques systèmes]Only root user and "zulucrypt" members can restore and back up luks headers on system devicesmanagevolumeheaderNOpération interrompue par l'utilisateur%Operation terminater per user requestmanagevolumeheaderPMot de passe du volume Externe SEULEMENTOuter Volume Password ONLYmanagevolumeheaderPIMPIMmanagevolumeheaderÿÿÿÿPasswordmanagevolumeheader,Source du mot de passePassword SourcemanagevolumeheaderŠChemin d'accès utilisé pour créer le fichier de sauvegarde est occupé4Path to be used to create a back up file is occupiedmanagevolumeheaderjLe périphérique choisi n'est pas un périphérique LUKS%Presented device is not a LUKS devicemanagevolumeheader.Restaurer Header VolumeRestore volume headermanagevolumeheader SUCCESSUCCESSmanagevolumeheaderdSélectionner un fichier avec un LUKS Backup Header'Select A File With A LUKS Backup HeadermanagevolumeheaderbSélectionner un répertoire pour stocker le Header#Select A Folder To Store The HeadermanagevolumeheaderŠSélectionner un conteneur LUKS dont vous voulez sauvegarder le header3Select luks container you want to backup its headermanagevolumeheaderEtiquetteTexte TextLabelmanagevolumeheaderfErreur inconnue avec numéro de statut %1 rencontrée5Unrecognized ERROR! with status number %1 encounteredmanagevolumeheader Chemin du volume Volume PathmanagevolumeheaderType de Volume Volume TypemanagevolumeheaderATTENTION!WARNING!managevolumeheader>Disque Entier en Volume ChiffréWhole Drive Encrypted Volumemanagevolumeheader,Volume Système WindowsWindow System Volumemanagevolumeheader|Mot de passe erroné ou le volume n'est pas un volume Truecrypt:Wrong password entered or volume is not a truecrypt volumemanagevolumeheader|Mot de passe erroné ou le volume n'est pas un volume Veracrypt:Wrong password entered or volume is not a veracrypt volumemanagevolumeheader°L'instance précédente semble avoir crashé, tentative de réinitialisation avant démarrageIPrevious instance seem to have crashed,trying to clean up before starting oneinstancešIl semble y avoir une autre instance en cours d'exécution, sortie de celle-ci:There seem to be another instance running,exiting this one oneinstance&Annuler&Cancel openvolume &Aide&Help openvolume&Ouvrir&Open openvolumeæUne liste de toutes les partitions sur ce système est affichée ici. Double-cliquez sur l'une d'elle pour l'utiliser[A list of all partitions on this system are displayed here. Double click an entry to use it openvolume ERREURERROR openvolumeINFOINFO openvolumenSeuls les volumes crypto_LUKS peuvent être séléctionnés(Only crypto_LUKS volumes can be selected openvolumePRedémarrez l'outil de compte root ou bien après avoir créé / vous être ajouté au groupe "zulucrypt" si le volume que vous souhaitez utiliser ne figure pas sur la liste.˜Restart the tool from root's account or after you have created and added yourself to group "zulucrypt" if the volume you want to use is not on the list. openvolume€Sélectionner la partition où vous voulez créer le volume chiffré3Select A Partition To Create An Encrypted Volume In openvolumeFSélectionner une partition à ouvrirSelect A Partition To Open openvolumeXSélectionner une partition chiffrée à ouvrir%Select An Encrypted Partition To Open openvolume$Utiliser les &UUID Use &UUID openvolume"Utiliser les UUIDUse UUID openvolumeìVous êtes un utilisateur root et toutes les partitions sont affichées. Double-cliquez sur l'une d'elle pour l'utiliserUYou are a root user and all partitions are displayed. Double click an entry to use it openvolumeEtiquettelabel openvolumepartition partition openvolume taillesize openvolumetypetype openvolumeuuiduuid openvolume†Le caractère "/" n'est pas autorisé dans le champ du nom de montage0"/" character is not allowed in mount name fieldpasswordDialog€Les options -O et -m ne peuvent pas être utilisées conjointement*-O and -m options can not be used togetherpasswordDialogÂUn périphérique est non supporté ou manquant ou permission refusée Les raisons possibles pour corriger l'erreur sont les suivantes: 1. Chemin du périphérique invalide. 2. le périphérique possède un LVM ou une signature MDRAID¸A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signaturepasswordDialog\Au moins un des champs qui est requis est vide#Atleast one required field is emptypasswordDialogAnnulerCancelpasswordDialogjCocher cette case pour rendre le mot de passe visible'Check This Box To Make Password VisiblepasswordDialogtChoisissez un fichier de clé depuis le système de fichiers%Choose A KeyFile From The File SystempasswordDialogdChoisissez un module depuis le système de fichiers$Choose A Module From The File SystempasswordDialogNNe peut pas créer un lock sur /etc/mtab$Could not create a lock on /etc/mtabpasswordDialogœImpossible de créer le point de montage, chemin non valide ou chemin déjà pris@Could not create mount point, invalid path or path already takenpasswordDialogfNe peut pas obtenir une passphrase depuis ce module*Could not get a passphrase from the modulepasswordDialogxNe peut pas obtenir une passphrase à travers un socket local1Could not get a passphrase through a local socketpasswordDialog†Ne peut pas avoir assez de mémoire pour manipuler le fichier de clé1Could not get enought memory to hold the key filepasswordDialogjNe peut pas obtenir une passphrase en mode silencieux'Could not get passphrase in silent modepasswordDialog ERREURERRORpasswordDialogERREUR!ERROR!passwordDialogEntrer une clé Enter A KeypasswordDialog|Entrez un nom de module à utiliser pour obtenir une Passphrase,Enter A Module Name To Use To Get PassphrasepasswordDialogjEntrer le chemin de la localisation du fichier de clé"Enter A Path To A Keyfile LocationpasswordDialog|Code Erreur: %1 -- Sortie Standard: %2 -- Erreur de Sortie: %3,Error Code: %1 -- StdOut: %2 -- StdError: %3passwordDialog†Echec pour trouver ou exécuter le programme Yubikey's "ykchalresp".7Failed To Locate Or Run Yubikey's "ykchalresp" Program.passwordDialog^Echec de l'obtention de la clé depuis le plugin!Failed to get a key from a pluginpasswordDialog^Echec de l'obtention de la clé depuis le réseau$Failed to get a key from the networkpasswordDialogôEchec du montage du système de fichier : option de montage invalide/non supportée ou bien système de fichiers non supportédFailed to mount a filesystem:invalid/unsupported mount option or unsupported file system encounteredpasswordDialogþImpossible de monter le système de fichiers ntfs / exfat en utilisant ntfs-3g, est ce que le paquet ntfs-3g/exfat est installé?XFailed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed?passwordDialogbMémoire insuffisante pour manipuler la passphrase&Insufficient memory to hold passphrasepasswordDialog˜Privilèges insuffisants pour monter le périphérique avec des options données=Insufficient privilege to mount the device with given optionspasswordDialog"Privilèges insuffisants pour opérer sur un volume système. Consultez le menu ->Aide-> Zulucrypt.pdf - Permissions pour davantage d'informations dInsufficient privilege to open a system volume. Consult menu->help->permission for more informaion passwordDialogâPrivilèges insuffisants pour ouvrir le périphérique en mode lecture-écriture ou bien le périphérique n'existe pasQInsufficient privilege to open device in read write mode or device does not existpasswordDialog€Privilège insuffisant pour ouvrir le fichier clé pour la lecture3Insufficient privilege to open key file for readingpasswordDialog>Trousseau interne non configuré!Internal wallet is not configuredpasswordDialogLChemin invalide vers le fichier de cléInvalid path to key filepasswordDialog0Chemin du fichier de clé KeyFile PathpasswordDialog>Chemin de l'entête LUKS ExterneLUKS External Header PathpasswordDialogMonter "%1" Mount "%1"passwordDialogtAucun fichier ou périphérique existant sur le chemin donné%No file or device exist on given pathpasswordDialogDécalageOffsetpasswordDialog2l'emplacement pourrait être en "secteurs" si la définition se compose de chiffres uniquement ou en octets si l'entrée se termine par "b" ou en kilo-octets si l'entrée se termine par "k" ou en mégaoctets si l'entrée se termine par "m" ou en téraoctets si l'entrée se termine par "t"ìOffset Will Be In Sectors If The Entry Is Made Up Of Only Digits And In Bytes If The Entry Ends With "b" And In Kilobytes If The Entry Ends With "k" And In Megabytes If The Entry Ends With "m" And In Terabytes If The Entry Ends With "t"passwordDialogˆUn ou plusieurs argument(s) requis pour cette opération est manquant>One or more required argument(s) for this operation is missingpasswordDialoglSeul l'utilisateur root peut effectuer cette opération)Only root user can perform this operationpasswordDialogValeur PIM PIM ValuepasswordDialogMot de PassePasswordpasswordDialogNom de Plugin Plugin NamepasswordDialog:Sélectionner un Module de CléSelect A Key ModulepasswordDialog<Sélectionner un fichier de cléSelect A KeyFilepasswordDialog<Sélectionner un volume chiffréSelect Encrypted volumepasswordDialog\Sélectionner un entête de fichier LUKS Externe Select External LUKS Header FilepasswordDialogfchoisir le chemin du point de montage du répertoire!Select Path To Mount Point FolderpasswordDialog^Chemin de point de montage du partage déjà pris%Shared mount point path already takenpasswordDialogzIl semble y avoir un volume ouvert associé à l'adresse donnée=There seem to be an open volume accociated with given addresspasswordDialogvIl semble y avoir un mappeur ouvert associé au périphériqueDéverrouiller un volume chiffréUnlock Encrypted VolumepasswordDialogfLe volume n'a pas pu être ouvert avec la clé entrée1Volume could not be opened with the presented keypasswordDialogDLe volume n'est pas un volume LUKSVolume is not a LUKS volumepasswordDialog2YubiKey Challenge/RéponseYubiKey Challenge/ResponsepasswordDialog&Annuler&Cancelplugin &Définir une clé&Set Keyplugin:Créer une clé de chiffrement qui est composée d'une phrase et d'un keyfile. Un volume créé avec une clé générée ici devra être ouvert avec le plugin "hmac".˜Create an encryption key that is made up of a passphrase and a keyfile. A volume created with a key generated here should be opened with "hmac" plugin.plugin ERREURERRORplugin:Echec de la génération de cléFailed To Generate Keyplugin~Générateur de clé utilisant une passphrase et un fichier de clé.Key Generator Using A Passphrase And A KeyFilepluginFichier de cléKeyFileplugin0Fichier de clé non actifKeyFile Not SetpluginPassphrase Passphraseplugin&Ok&OkreadOnlyWarningJNe plus montrer ce message désormais.Do Not Show This Message Again.readOnlyWarningzDéfinir cette option ouvrira le volume en mode lecture seule.DSetting this option will cause the volume to open in read only mode.readOnlyWarningATTENTIONWARNINGreadOnlyWarning&Annuler&Canceltcrypt&Ouvrir&Opentcrypt&Définir&Settcrypt4Ajouter un &fichier de clé Add &KeyfiletcryptNAu moins une clé de fichier est requise At least one keyfile is requiredtcrypt ERREURERRORtcryptœEntrer ci dessous une Passphrase pour être utilisée dans l'ouverture du volume6Enter A Passphrase Below To Be Used To Open The Volumetcrypt Entrez les fichiers clés ci-dessous pour les utiliser dans l'ouverture de volume3Enter key files below to be used to open the volumetcrypt2Chemins du fichier de clé Keyfile Pathstcrypt<Sélectionner un fichier de cléSelect A KeyFiletcryptClés TrueCryptTrueCrypt Keystcrypt0Clés TrueCrypt/VeraCryptTrueCrypt/VeraCrypt Keystcrypt’Faire un glisser/déposer des fichiers de clés pour les ajouter à la liste/drag and drop key files to add them to the listtcrypt0Temps écoulé: %0 minutesElapsed time: %0 minutesutility::veraCryptWarning2Temps écoulé: %0 secondesElapsed time: %0 secondsutility::veraCryptWarning0Temps écoulé: 0 secondesElapsed time: 0 secondsutility::veraCryptWarning®Soyez patient car le déchiffrement d'un volume VeraCrypt peut durer un certain temps. NPlease be patient as unlocking a VeraCrypt volume may take a very long time. utility::veraCryptWarningJNe plus montrer ce message désormais.Dont Show This Warning Again.warnWhenExtendingContainerFileIMPORTANT!!! IMPORTANT!!!warnWhenExtendingContainerFileOKOKwarnWhenExtendingContainerFileATTENTION! WARNING!!warnWhenExtendingContainerFile’Votre fichier de couverture sera irrémédiablement modifié et nous vous conseillons de poursuivre avec une sauvegarde plutôt que le fichier original. Pour déchiffrer le volume à créer, vous aurez besoin d'entrer un mot de passe de votre choix et l'offset (décalage) de volume généré automatiquement par ZuluCrypt. Les instructions pour déchiffrer le volume sont les suivantes: 1. Depuis le menu Ouvrir, choisir -> Volume localisé dans un fichier. 2. Sélectionner votre fichier puis sélectionner "Type de Volume" = PLAIN dm-crypt. 3. Entrer le décalage (offset) et votre mot de passe. òYour cover file will be irreversibly changed and we suggest continuing with a backup file and not the original. To unlock the volume about to be created, you will need to enter the password you will choose and the volume offset automatically generated by zuluCrypt. Instructions to unlock the volume are as follows: 1. From the menu, choose Open -> Volume Hosted In A File. 2. Select file, then choose "Volume Type" = PLAIN dm-crypt. 3. Enter the generated offset value along with your password. warnWhenExtendingContainerFileª Merci de recompiler zuluCrypt pour le forcer à redécouvrir la nouvelle bibliothèqueG Please recompile zuluCrypt to force it to re-discover the new library zuluCryptØ Les volumes cryptés LUKS, TrueCrypt et VeraCrypt ont ce que l'on appelle un «header = en-tête de volume». Un en-tête de volume est chargé de stocker les informations nécessaires pour ouvrir un volume crypté à en-tête et tout dommage sur celui ci rend impossible l'ouverture du volume provoquant ainsi la perte permanente de données cryptées. Les dommages causés à l'en-tête sont habituellement causés par un formatage accidentel de l'appareil ou l'utilisation de certains outils de partitionnement bogués ou bien de volumes logiques mal réassemblés. Avoir une sauvegarde de l'en-tête de volume est fortement recommandé car elle est la seule façon de rendre accessible à nouveau les données chiffrées si l'en-tête sur le volume est corrompue. Ÿ LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a "volume header". A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data. The damage to the header is usually caused by accidental formatting of the device or use of some buggy partitioning tools or wrongly reassembled logical volumes. Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted.  zuluCrypt&A propos&About zuluCrypt8&Ajouter une clé à un volume&Add A Key To A Volume zuluCryptT&Ouverture automatique du point de montage&Auto Open Mount Point zuluCrypt&Backup Header&Backup Header zuluCryptZ&Changer le mot de passe du Trousseau Interne &Change Internal Wallet Password zuluCrypt@&Fermer tous les volumes ouverts&Close All Opened Volumes zuluCrypt &Créer&Create zuluCrypt,&Déchiffrer un fichier&Decrypt A File zuluCrypt6&Effacer la clé d'un volume&Delete A Key From A Volume zuluCrypt^Conteneur &chiffré dans un tout nouveau fichier"&Encrypted Container In A New File zuluCryptL&Effacer les données d'un périphérique&Erase Data In A Device zuluCrypt&Favoris &Favorites zuluCrypt0&Header (En-tête) Backup&Header Backup zuluCrypt &Aide&Help zuluCrypt&Fichier de clé&KeyFile zuluCrypt$&Gérer les Favoris&Manage Favorites zuluCrypt<&Minimiser en barre des tâches&Minimize To Tray zuluCrypt&Ouvrir&Open zuluCrypt&Quitter&Quit zuluCrypt"&Restaurer Header&Restore Header zuluCrypt.&Sélectionner la langue&Select Language zuluCrypt4&Icône de barre des tâches &Tray Icon zuluCrypt@&Actualiser la liste des volumes&Update Volume List zuluCrypt@&Volume localisé dans un fichier&Volume Hosted In A File zuluCrypt&Volumes&Volumes zuluCryptÿÿÿÿ&zC zuluCryptAjouter une cléAdd Key zuluCrypt&Ajouter aux FavorisAdd To Favorite zuluCryptÿÿÿÿAlt+V zuluCryptÿÿÿÿBackup LUKS Header zuluCrypt(Backup Header VolumeBackup Volume Header zuluCryptAnnulerCancel zuluCryptNEffacer les points de montage invalidesClear Dead Mount Points zuluCrypt˜Echec de la fermeture, ne trouve aucune partition avec l'UUID correspondanteBClose failed, could not find any partition with the presented UUID zuluCrypt|Echec de la fermeture, ne peut pas créer un lock sur /etc/mtab0Close failed, could not get a lock on /etc/mtab~ zuluCrypt¾Echec de la fermeture, ne peut pas trouver la totalité du chemin d'emplacement du périphérique 4Close failed, could not resolve full path of device  zuluCrypt”Echec de la fermeture, plusieurs points de montage détectés pour le volume;Close failed, multiple mount points for the volume detected zuluCryptœEchec de la fermeture, un ou plusieurs fichiers encore en cours d'utilisation.9Close failed, one or more files in the volume are in use. zuluCrypt|Echec de la fermeture, le point de montage semble être occupé 3Close failed, shared mount point appear to be busy  zuluCryptøEchec de la fermeture, le point de montage semble être dans un état incohérent, il est conseillé de le démonter manuellement^Close failed, shared mount point appear to be in an ambiguous state,advice to unmount manually zuluCryptðEchec de la fermeture, le point de montage semble appartenir à un autre utilisateur ou bien points de montage multiples hClose failed, shared mount point appear to belong to a different user or multiple mount points detected  zuluCrypt†Echec de la fermeture, le volume n'a pas d'entrée dans le /etc/mtab8Close failed, volume does not have an entry in /etc/mtab zuluCrypt´Echec de la fermeture, le volume n'est pas ouvert ou a été ouvert par un autre utilisateurBClose failed, volume is not open or was opened by a different user zuluCryptþEchec de la fermeture, le volume est démonté, mais ne pouvait pas fermer le mappeur, il est conseillé de le fermer manuellementXClose failed, volume is unmounted but could not close mapper,advice to close it manually zuluCrypt0&Informations de contact Contact &Info zuluCryptºImpossible d'ouvrir le point de montage parce que "%1" ne semble pas fonctionner correctementTCould not open mount point because "%1" tool does not appear to be working correctly zuluCryptàLa bibliothèque Cryptsetup n'a pas été trouvée et ZuluCrypt risque évidemment de ne pas fonctionner comme prévu.ZCryptsetup library could not be found and zuluCrypt will most likely not work as expected. zuluCryptÿÿÿÿCtrl+A zuluCryptÿÿÿÿCtrl+B zuluCryptÿÿÿÿCtrl+C zuluCryptÿÿÿÿCtrl+D zuluCryptÿÿÿÿCtrl+E zuluCryptÿÿÿÿCtrl+F zuluCryptÿÿÿÿCtrl+G zuluCryptÿÿÿÿCtrl+H zuluCryptÿÿÿÿCtrl+I zuluCryptÿÿÿÿCtrl+J zuluCryptÿÿÿÿCtrl+K zuluCryptÿÿÿÿCtrl+L zuluCryptÿÿÿÿCtrl+M zuluCryptÿÿÿÿCtrl+N zuluCryptÿÿÿÿCtrl+O zuluCryptÿÿÿÿCtrl+P zuluCryptÿÿÿÿCtrl+Q zuluCryptÿÿÿÿCtrl+R zuluCryptÿÿÿÿCtrl+S zuluCryptCtrl+Shift+D Ctrl+Shift+D zuluCryptÿÿÿÿCtrl+T zuluCryptÿÿÿÿCtrl+U zuluCryptÿÿÿÿCtrl+V zuluCryptÿÿÿÿCtrl+W zuluCryptÿÿÿÿCtrl+X zuluCryptÿÿÿÿCtrl+Y zuluCryptÿÿÿÿCtrl+Z zuluCryptHNe pas minimiser en barre des tâchesDo Not Minimize To Tray zuluCrypt ERREURERROR zuluCryptERREUR!ERROR! zuluCrypt&Chiffrer un &ficherEncrypt A &File zuluCryptTConteneur &chiffré dans un disque matériel$Encrypted &Container In A Hard Drive zuluCrypt¦Conteneur chiffré masqué dans une vidéo / un fichier de couverture (Stéganographie)>Encrypted Container Hidden In Video/Cover File (Steganography) zuluCrypt^Conteneur chiffré dans un fichier déjà existant'Encrypted Container In An Existing File zuluCryptXChemin du point de montage du volume chiffré!Encrypted Volume Mount Point Path zuluCrypt0Chemin du volume chiffréEncrypted Volume Path zuluCryptF1F1 zuluCrypt &AideH&elp zuluCryptÿÿÿÿINFO zuluCryptdInformation Importante sur le Volume Header Backup-Important Information On Volume Header Backup zuluCrypt6&Gérer les volumes systèmesManag&e System Volumes zuluCrypt>&Gérer des volumes non systèmesManage &Non System Volumes zuluCryptX&Gérer les volumes dans le Trousseau Interne"Manage &Volumes In Internal Wallet zuluCryptTGérer les volumes dans le trousseau &GNOME Manage Volumes In &GNOME keyring zuluCryptPGérer les volumes dans le trousseau &KDEManage Volumes In &KDE Wallet zuluCrypt"Ouvrir Répertoire Open Folder zuluCrypt.Ouvrir Répertoire PrivéOpen Private Folder zuluCrypt2Ouvrir Répertoire PartagéOpen Shared Folder zuluCryptOptio&nsOptio&ns zuluCrypt,Chemin vers le fichierPath To A File zuluCryptPropriétés Properties zuluCryptQuitterQuit zuluCryptEnlever une clé Remove Key zuluCryptÄRéinitialisation à une taille de police de %1 car des tailles trop importantes ne s'adapteront pas>Resetting font size to %1 because larger font sizes do not fit zuluCrypt.Restaurer Header VolumeRestore Volume Header zuluCryptF&Sélectionner la police d'affichage Select &Font zuluCrypt2Choisir le type d'&icônes Select &Icons zuluCrypt,Sélectionner la langueSelect Language zuluCryptHChoisir le gestionnaire de &fichiersSet Fi&le Manager zuluCryptÿÿÿÿShift+I zuluCryptÿÿÿÿShift+V zuluCrypt<Montrer la Fenêtre de DébogageShow Debug Window zuluCrypt^Montrer les informations d'emplacement des clésShow Key Slots Information zuluCryptHMontrer les emplacements de clé LUKSShow LUKS Key Slots zuluCrypt Afficher/Masquer Show/Hide zuluCrypttCette option fermera l'application au lieu de la minimiser?This Option Will Close The App Instead Of Minimizing It To Tray zuluCryptÿÿÿÿType zuluCryptDémonterUnmount zuluCryptfErreur inconnue avec numéro de statut %1 rencontrée4Unrecognized error with status number %1 encountered zuluCryptFVeraCrypt Conteneur dans un fichierVeraCrypt Container In A File zuluCryptVVeraCrypt Conteneur dans un disque matériel#VeraCrypt Container In A Hard Drive zuluCryptPVolume &localisé dans un disque matérielVolume &Hosted In A Hard Drive zuluCrypt(Propriétés du volumeVolume Properties zuluCrypt†Le volume n'est pas ouvert ou a été ouvert par un autre utilisateur4Volume is not open or was opened by a different user zuluCryptATTENTION!WARNING! zuluCrypt(Fermer l'applicationclose application zuluCrypt2configurer les trousseauxconfigure wallets zuluCryptÿÿÿÿ crypto info zuluCryptVolumes Favorisfavorite volumes zuluCrypt"Gérer les favorismanage favorites zuluCryptpermissions permissions zuluCryptHSélectionner un générateur aléatoireselect random number generator zuluCrypt(tcrypt backup headertcrypt backup header zuluCrypt4tcrypt restauration headertcrypt restore header zuluCryptÿÿÿÿ zuluCrypt zuluCrypt¨zuluCrypt a échoué à la connexion de zuluPolkit. Merci de reporter ce bug important.JzuluCrypt Failed To Connect To zuluPolkit. Please Report This Serious Bug. zuluCryptˆzuluCrypt-6.2.0/translations/zuluCrypt/fr_FR.ts000066400000000000000000010536761425361753700217070ustar00rootroot00000000000000 DialogMsg Dialog Dialogue &Ok &Yes &Oui &No &Non text texte type type cipher clé de chiffrement key size taille de la clé device device loop boucle offset décalage size taille mode mode fs fs used utilisé unused inutilisé used % % utilisé active slots slots actifs "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. "Volumes du système" sont des volumes que udev a identifié comme tel (si udev est activé), ou alors possède une entrée dans "/etc/fstab","/etc/crypttab" ou bien "/etc/zuluCrypt/system_volumes.list" Si vous préférez pour un volume qu'il ne soit pas considéré comme un volume système, démarrez le bilan du compte racine, puis aller à "menu-> options-> gérer des partitions système non" et ajouter le volume à la liste et le volume cessera d'être considéré comme «système». Sinon, vous pouvez vous ajouter au groupe "zulucrypt" et "zulumount" et toutes les restrictions vont disparaître. INFORMATION INFORMATION Insufficient privilege to access a system device, only root user or members of group zulucrypt can do that Privilèges insuffisants pour accéder à un périphérique système, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le faire Insufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that Privilèges insuffisants pour accéder à un périphérique en mode lecture/écriture, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le faire You do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again Vous ne semblez pas avoir les autorisations nécessaires pour accéder au fichier chiffré en mode %1, vérifiez les droits du fichier et essayez à nouveau type: type: cipher: clé de chiffrement: keysize: taille de la clé: offset: décalage: device: device: loop: boucle: mode: mode: active slots: slots actifs: file system: système de fichiers: total space: espace total: used space: espace utilisé: free space: espace libre: used%: % utilisé: UUID: UUID: Do not show this dialog again Ne plus montrer ce message désormais PasswordDialog Open Encrypted Volume Ouvrir un volume chiffré &Open &Ouvrir &Cancel &Annuler Mount In &Read Only Mode Monter en mode &lecture seule select mount point path choisir le point de montage open volume path ouvrir le chemin du volume Password Mot de Passe LUKS/TrueCrypt/BitLocker LUKS/TrueCrypt/BitLocker &OK &OK Mount Name Nom du montage &Options &Options Volume Path Chemin du volume KeyFile Fichier de clé Key+KeyFile Clé + fichier de clé Plugin Plugin &Share Mount Point &Share (Partage) Point de montage VeraCrypt VeraCrypt VeraCrypt System Système VeraCrypt PLAIN dm-crypt PLAIN dm-crypt Volume Type Type de Volume TextLabel Etiquette de texte Enter Comma Separated Volume's File System Options Below Entrer un fichier d'options système de volume en séparation à virgules Set Définir Cancel Annuler open key file ouvrir un fichier de clé QObject zuluCrypt: Failed To Establish Connection With zuluPolkit zuluCrypt a échoué à établir une connexion avec zuluPolkit options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI Options: -d localisation du chemin d'un volume pour être auto déverrouillé / monté -m à utiliser pour ouvrir un gestionnaire de fichiers par défaut (l'outil par défaut est xdg-open) -e démarre l'application sans afficher l'interface graphique If the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2" Si l'option est cochée, un point de montage privé primaire sera créé dans "%1" et un «miroir» secondaire du point de montage accessible au public sera créé dans "%2" public mount point: point de montage public: Manage Favorites Gérer les Favoris Mount All Tout Monter about zuluCrypt A propos de zuluCrypt hmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents) hmac plugin. Ce plugin génère une clé en utilisant la formule ci-dessous: key = hmac(sha256,passphrase,keyfile contents) keykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contents keykeyfile plugin. Ce plugin génère une clé à l'aide de la formule suivante: key = passphrase + keyfile contents gpg plugin. This plugin retrives a key locked in a gpg file with a symmetric key gpg plugin. Ce plugin récupère une clé de verrouillage dans un fichier gpg avec une clé symétrique Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit. Echec du démarrage de l'Application d'Aide. "org.zulucrypt.zulupolkit.policy" le fichier polkit file est mal configuré, zuluPolkit l'exécutable n'est pas trouvé ou pkexec échoue au démarrage de zuluPolkit. ERROR ERREUR Failed to locate pkexec executable Echec pour trouver l'emplacement de l'exécutable pkexec "%1" and "%2" Folders Must Be Writable. "%1" et "%2" doivent être forcément autorisés en écriture. Could not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin" Ne trouve pas de "gpg" executable dans "/usr/local/bin","/usr/bin" ou "/usr/sbin" createVolumeDialog Warning!! Attention!! &Yes &Y (Oui) &No &Non This operation will lead to permanent destrunction of all present data in /dev/sdc1. Are you sure you want to continue? Cette opération entraînera la destruction de toutes les données présentes sur /dev/sdc1. Etes vous sûr de vouloir continuer ? This operation will lead to permanent destrunction of all present data in "%1". Are you sure you want to continue? Cette opération entraînera la destruction de toutes les données présentes sur "%1". Etes vous sûr de vouloir continuer ? It is advised to create encrypted containers over random data to prevent information leakage. Do you want to write random data to "%1" first before creating an encrypted container in it? You can stop the random data writing process anytime you want if it takes too long and you can no longer wait. Il est recommandé de créer les conteneurs cryptés à partir de données aléatoires afin d'éviter une compromission de vos informations. Voulez vous d'abord écrire des données aléatoires sur "%1" avant d'y créer un conteneurs crypté ? Vous pouvez arrêter l'écriture de données aléatoires à n'importe quel moment si vous trouvez que c'est trop long et ne souhaitez pas attendre. createVolumeInExistingFIle Create Volume In Existing File Créer le volume dans un fichier déjà existant Select Cover File (Video files like mp4 and mkv) Sélectionner le fichier de couverture (Fichier Vidéo de format mp4 ou mkv) Container Size (MB) Taille du Conteneur (MB) Volume Properties Propriétés du volume &Cancel &Annuler C&reate C&réer Volume OffSet (Auto calculated) Offset du volume (calculé automatiquement) Create A Plain dm-crypt Container Hidden Inside Cover File (Steganography) Créer un conteneur plain dm-crypt caché dans le fichier de couverture (Stéganographie) Password Mot de Passe TextLabel Etiquette de texte Extending A Host File Size. Extension de la taille du fichier hôte. Enter Path To Existing File Entrer le chemin de la localisation du fichier Average Speed: Vitesse moyenne: ETA: Temps estimé: Percentage Completed: %1% Pourcentage accompli : %1% ERROR ERREUR AtLeast One Required Field Is Empty Au moins un des champs qui est requis est vide Illegal Character Found In The Container Size Field Caractère interdit dans le champ de taille du conteneur Failed To Open File In Write Mode Impossible d'ouvrir le volume en mode écriture Failed To Open "/dev/urandom" Device In Read Mode Impossible d'ouvrir le périphérique "/dev/urandom" en mode de lecture Creating A Plain DM-Crypt Volume Créer un volume Plain DM-Crypt Volume Created Successfully Volume créé avec succès Failed To Create A Volume Echec de la création du volume createfile open a folder dialog box boîte de dialogue ouvrir un répertoire Create A Container File Créer un fichier conteneur File Name Nom de fichier File Path Chemin du fichier File Size Taille du fichier &Cancel &Annuler % Complete % Complété C&reate C&réer KB KB MB MB GB GB Do Not Write Random Data To Container(STRONGLY discouraged) Ne pas écrire de données aléatoires vers un conteneur (FORTEMENT déconseillé) TextLabel Etiquette de Texte &OK &OK File name field is empty Le champ Nom de Fichier est vide File path field is empty Le champ Chemin du Fichier est vide File size field is empty Le champ Taille du Fichier est vide WARNING ATTENTION Are you really sure you do not want to create a more secured volume? Êtes vous sûr de ne pas vouloir créer un volume plus sécurisé ? File with the same name and at the destination folder already exist Un fichier avec le même nom existe déjà dans le répertoire de destination You dont seem to have writing access to the destination folder Vous ne semblez pas avoir les droits d'écriture dans le répertoire destination Container file must be bigger than 3MB Le fichier conteneur doit être supérieur à la taille de 3MB Failed to create volume file Echec de la création du fichier de volume Failed to enable polkit support Echec de l'activation du support polkit Operation terminated per user choice Opération interrompue par l'utilisateur Could not open cryptographic back end to generate random data Ne peut pas ouvrir le module cryptographique pour générer les données aléatoires Terminating file creation process Finalisation du processus de création du fichier Are you sure you want to stop file creation process? Êtes vous sûr de vouloir stopper le processus de création du fichier ? Average Speed: Vitesse moyenne: ETA: Temps estimé: Illegal character in the file size field.Only digits are allowed caractère interdit dans le champ taille du fichier. Seuls les chiffres sont autorisés By default,zuluCrypt creates a volume in a container file over randomly generated data to hide usage patterns of the container. This process takes time and it may take a very,very long time if the volume about to be created is large enough and this option exists to skip the process for the impatient among us but but it comes at a cost and the cost may be too high when it finally reveal itself while infront of an adversary when they look at the encrypted container and manage to derive meaning based on how the container looks from outside. If you know what you are doing,then continue by all means,if in doubt,my advise is to endure the process and be safer in the long run. Par défaut, zuluCrypt crée un volume dans un fichier conteneur à travers des données générées au hasard pour cacher les habitudes d'utilisation du conteneur. Ce processus prend du temps et il peut prendre vraiment pas mal de temps si le volume créé est assez important, donc cette option existe pour ignorer le processus pour les impatients qui se reconnaîtront mais il a un revers et ce revers finira par se révéler en face d'un lecteur quand il regardera le conteneur chiffré et parviendra à tirer parti sur la façon dont le conteneur apparaît de l'extérieur. Si vous savez ce que vous faites, arrêter si vous souhaitez, en cas de doute, mon conseil est de poursuivre le processus et être plus sûr à long terme. INFO INFO Select Path to where the file will be created Choisir l'emplacement de création du fichier createkeyfile Create A KeyFile Créer un fichier de clé Keyfile Name Nom du fichier de clé path to a folder to create a key in emplacement du répertoire où sera créée la clé open a folder a key file will be created in ouvrir le répertoire où sera créé le fichier de clé C&reate C&réer &Cancel &Annuler KeyFile Path Chemin du fichier de clé RNG RNG TextLabel Etiquette de Texte &OK &OK Folder path to where the key will be created is empty Le chemin pour la création de clé est vide File with the same name and at the destination folder already exist Un fichier avec le même nom existe déjà dans le répertoire de destination You dont seem to have writing access to the destination folder Vous ne semblez pas avoir les droits d'écriture dans le répertoire destination Process interrupted,key not fully generated Processus interrompu, clé non complètement générée KeyFile successfully created Clé de fichier créée avec succès Select A Folder To Create A Key File In Sélectionner un répertoire pour y créer le fichier de clé The key name field is empty Le champ du nom de la clé est vide createvolume Create A New Volume Créer un nouveau volume Path to Device Chemin vers le périphérique C&reate C&réer &Cancel &Annuler open a key file ouvrir un fichier de clé Key Clé Password Mot de Passe Repeat Password Réentrer le mot de passe Advanced LUKS2 Options Options avancées LUKS2 Volume Type Type de Volume Volume Size Taille du Volume Bytes KiloBytes MegaBytes GigaBytes Iteration Time (milliseconds) Temps d'itération (en millisecondes) Volume Options Options de Volume File System Système de Fichiers random number generator Générateur aléatoire de nombres RNG PIM PIM TextLabel Etiquette de texte Advanced Luks2 Options Options avancées LUKS2 Set Définir Label Etiquette Sub System Sous système Pbkdf Type Type Pbkdf argon2id argon2id argon2i argon2i pbkdf2 pbkdf2 Max Memory (KB) Mémoire maximale (Ko) Parallel Threads Threads parallèles Unlocking Time Cost(Milliseconds) Coût temps de déverrouillage (millisecondes) Allow Discard(TRIM) Autoriser TRIM continu Forced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) Forcer des itérations (dangereux et peut mener à des temps de déverrouillage extrêmement long) Cancel Annuler Options are separated by a "." character. Les options sont séparées par un ".". Multiple algorithms are separated by ":" character. Les algorithmes multiples sont séparés par des ":". Options are in a format of "algorithm.cipher mode.key size in bits.hash" Options dans le format "algorithm.cipher mode.key size in bits.hash" Default option is the first entry on the list L'option par défaut est la première entrée de la liste KeyFile Fichier de clé YubiKey Challenge/Response YubiKey Challenge/Réponse PLAIN dm-crypt PLAIN dm-crypt PLAIN dm-crypt with offset PLAIN dm-crypt avec un décalage LUKS1 LUKS1 LUKS1+External Header LUKS1+Header Externe LUKS2 LUKS2 LUKS2+External Header LUKS2+Header Externe LUKS LUKS LUKS+External Header LUKS+Header Externe Normal TrueCrypt Normal+Hidden TrueCrypt Normal+TrueCrypt Caché Normal VeraCrypt Normal+Hidden VeraCrypt Normal+VeraCrypt Caché Passphrase Quality: 0% Force de la Passphrase : 0% Passphrase Quality: %1% Force de la Passphrase : %1% TrueCrypt Keys Clés TrueCrypt VeraCrypt Keys Clés VeraCrypt Volume Offset Décalage du Volume Path To Device Chemin vers le périphérique Path To File Chemin vers le fichier Keyfile Path Chemin du fichier de clé Passphrase Quality: 100% Force de la Passphrase : 100% Keys Clés ERROR! ERREUR! Failed to enable polkit support Echec de l'activation du support polkit Volume path field is empty Le champ Chemin du Volume est vide Atleast one required field is empty Au moins un des champs qui est requis est vide Illegal character detected in the hidden volume size field caractère interdit dans le champ de taille du volume caché Hidden passphrases do not match Passphrases cachées non correspondantes WARNING ATTENTION It is best to create a hidden volume with vfat/fat file system. Il est préférable de créer un volume caché avec le système de fichiers vfat/fat. Passphrases do not match Passphrases non correspondantes ERROR ERREUR Failed To Locate Or Run Yubikey's "ykchalresp" Program. Echec pour trouver ou exécuter le programme Yubikey's "ykchalresp". Please be patient as creating a VeraCrypt volume may take a very long time. Soyez patient car le chiffrement d'un volume VeraCrypt peut durer un certain temps. WARNING! ATTENTION! Volume created successfully but failed to create an external header Volume créé avec succès, mais n'a pas réussi à créer un en-tête externe Luks volume created successfully. Volume LUKS créé avec succès. Luks volume created successfully,external header created successfully but failed to erase header on the device Volume LUKS créé avec succès, en-tête externe créé avec succès mais échec del'effacement du header sur le périphérique Volume created successfully. Volume créé avec succès. Creating a backup of the "%1" volume header is strongly advised. Please read documentation on why this is important. Créer une sauvegarde de l'en-tête "%1" du volume est fortement conseillé. SVP, lire la documentation sur pourquoi cela est important. Presented file system is not supported,see documentation for more information Système de fichiers non pris en charge, voir la documentation pour plus d'informations insufficient privilege to open a system device in read/write mode, only root user or members of group zulucrypt can do that Privilèges insuffisants pour accéder à un périphérique en mode lecture/écriture, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le faire Could not create an encrypted volume Ne peut pas créer de volume chiffré Could not open volume for writing Impossible d'ouvrir le volume pour l'écriture There seem to be an opened mapper associated with the device Il semble y avoir un mappeur ouvert associé au périphérique Can not create a volume on a mounted device Vous ne pouvez pas créer un volume sur le périphérique monté Container file must be bigger than 3MB Le fichier conteneur doit être supérieur à la taille de 3MB Insufficient memory to hold your response Mémoire insuffisante pour manipuler la réponse Operation terminated per user request Opération interrompue par l'utilisateur Could not get passphrase in silent mode Ne peut pas obtenir une passphrase en mode silencieux Insufficient memory to hold the passphrase Mémoire insuffisante pour manipuler la passphrase Invalid path to key file Chemin invalide vers le fichier de clé Could not get a key from a key file Impossible d'obtenir une clé à partir du fichier de clé Couldnt get enought memory to hold the key file Ne peut pas avoir assez de mémoire pour manipuler le fichier de clé Could not get a key from a socket Ne peut pas obtenir de clé depuis un socket One or more required argument(s) for this operation is missing Un ou plusieurs argument(s) requis pour cette opération est manquant Can not get passphrase in silent mode Ne peut pas obtenir une passphrase en mode silencieux Insufficient memory to hold passphrase Mémoire insuffisante pour manipuler la passphrase Failed to create a volume Echec de la création du volume Wrong argument detected for tcrypt volume Mauvais argument détecté pour le volume TrueCrypt Could not find any partition with the presented UUID Ne trouve pas de partition qui correspond à l'UUID entrée Error Code: %1 -- StdOut: %2 -- StdError: %3 Code Erreur: %1 -- Sortie Standard: %2 -- Erreur de Sortie: %3 SUCCESS! SUCCES! Key+KeyFile Clé + fichier de clé %1 not found %1 non trouvé cryptfiles Create An Encrypted Version Of A File Créer une version chiffrée d'un fichier Create A Decrypted Version Of An encrypted File Créer une version non chiffrée d'un fichier chiffré Path to source field is empty Chemin vers la source vide Invalid path to source file Chemin invalide vers le fichier source Destination path already taken Chemin de destination déjà pris You dont seem to have writing access to the destination folder Vous ne semblez pas avoir accès d'écriture dans le dossier de destination Invalid path to key file Chemin invalide vers le fichier de clé First key field is empty Premier champ clé vide Second key field is empty Second champ clé vide Keys do not match Clés non correspondantes These very old encrypted files are no longer supported Ces fichiers chiffrés de manière obsolète ne sont plus supportés Enter A Key Entrer une clé Enter A Path To A Keyfile Location Entrer le chemin de la localisation du fichier de clé keyfile path chemin du fichier de clé Generate a key made up of a passphrase and a keyfile Générer une clé en utilisant une passphrase et un fichier de clé Select A File You Want To Encrypt Sélectionner un fichier que vous voulez chiffrer Select A File You Want To Decrypt Sélectionner un fichier que vous voulez déchiffrer Select A Keyfile Sélectionner un fichier de clé Encrypted file created successfully Fichier chiffré créé avec succès Decrypted file created successfully Déchiffrement réalisé avec succès Could not open keyfile for reading Impossible d'ouvrir le fichier clé pour la lecture Could not open encryption routines Impossible d'ouvrir les routines de chiffrement File or folder already exist at destination address Fichier ou dossier existent déjà à l'adresse de destination Insufficient privilege to create destination file Privilège insuffisant pour créer le fichier de destination Presented key did not match the encryption key clé entrée ne semble pas correspondre à la clé de chiffrement Operation terminated per user request Opération interrompue par l'utilisateur Insufficient privilege to open source file for reading Privilège insuffisant pour ouvrir le fichier source pour la lecture Decrypted file created successfully but md5 checksum failed,file maybe corrupted Fichier déchiffré avec succès mais échec de la somme MD5, le fichier peut être corrompu Could not open reading encryption routines Impossible d'ouvrir les routines de lecture de chiffrement Could not open writing encryption routines Impossible d'ouvrir les routines d'écriture de chiffrement Failed to close encryption routine Échec de la fermeture de routine de chiffrement Select Path to put destination file choisir le chemin du fichier de destination zuluCrypt encrypted files ( *.zc ) ;; All Files ( * ) fichiers chiffrés zuluCrypt ( *.zc ) ;; Tous fichiers ( * ) Destination Destination C&reate C&réer Source Source Password Mot de Passe Repeat Password Réentrer le mot de passe TextLabel Etiquette de texte &OK &OK Key Clé KeyFile Fichier de clé Key+KeyFile Clé + fichier de clé Repeat Key Réentrer la clé &Cancel &Annuler % Complete % Complété cryptoinfo Greetings Salutations Ok Ok Please consult "menu->help->open zuluCrypt.pdf" to get an introduction on zuluCrypt. Unity users,the menu is on the upper left corner of the screen when zuluCrypt has focus. Project's homepage is at: https://mhogomchungu.github.io/zuluCrypt Recommending reading FAQ page from the project's main page. Veuillez consulter "menu->aide->lire zuluCrypt.pdf" pour une présentation de zuluCrypt. Utilisateurs d'Unity, le menu est dans le coin haut gauche de l'écran quand zuluCrypt est sélectionné. La page officielle du projet est sur : https://mhogomchungu.github.io/zuluCrypt Recommandations de lecture FAQ de la page officielle du projet. Do not show this message again. Ne plus montrer ce message désormais. debugWindow zuluCrypt Debug Window Fenêtre de Débogage ZuluCrypt C&lear &Effacer &Close &Fermer dialogok Dialog Dialogue &Ok &Ok &Yes &Oui &No &Non TextLabel EtiquetteTexte erasedevice Write Random Data Over Existing Data Écrire des données aléatoire sur les données existantes The next dialog will write random data to a device leading to permanent loss of all contents on the device. Are you sure you want to continue? La boîte de dialogue suivante va écrire des données aléatoires sur le périphérique conduisant à la perte permanente de tous ses contenus. Êtes vous sûr de vouloir continuer? WARNING ATTENTION Data on the device successfully erased Données sur le périphérique effacées avec succès Could not create mapper Ne pas créer de mappeur Could not resolve device path Ne peut pas trouver le chemin du périphérique Random data successfully written Données aléatoires écrites avec succès Operation terminated per user choice Opération interrompue par l'utilisateur Can not write on a device with opened mapper Ne peut pas ouvrir sur un périphérique avec un mappeur ouvert Policy prevents non root user opening mapper on system partition Politique système empêche les utilisateurs non root d'ouvrir un mappeur sur une partition système Device path is invalid Chemin de périphérique invalide Passphrase file does not exist Fichiers de Passphrase n'existent pas Could not get enought memory to hold the key file Ne peut pas avoir assez de mémoire pour manipuler le fichier de clé Insufficient privilege to open key file for reading Privilège insuffisant pour ouvrir le fichier clé pour la lecture This device appear to already be in use Le périphérique est déjà utilisé Can not open a mapper on a mounted device Impossible d'ouvrir un mappeur sur un dispositif monté Could not write to the device Ne peut pas écrire sur le périphérique Device path field is empty Le champ Chemin du périphérique est vide Invalid path to device Chemin de périphérique invalide Failed to enable polkit support Echec de l'activation du support polkit Writing Random Data Over Existing Data Écrire des données aléatoire sur les données existantes Enter Path To Volume To Be Erased Entrer le chemin du volume à effacer Select A Non System Partition To Erase Its Contents Sélectionner une partition non système pour effacer son contenu Are you really sure you want to write random data to "%1" effectively destroying all contents in it? Êtes-vous vraiment sûr que vous voulez écrire des données aléatoires sur "%1" et détruire tout son contenu? Average Speed: Vitesse moyenne: Total Time: Durée totale: WARNING! ATTENTION! Erase Data On The Device By Writing Random Data Over Them Écrire des données aléatoire sur les données existantes du périphérique Path to Device Chemin vers le périphérique % Completed % Complété &Start &Commencer &Cancel &Annuler Average Speed Vitesse moyenne ETA Temps estimé N/A N/A TextLabel Etiquette de texte &OK &OK favorites2 Favorites Favoris Favorite List Liste des favoris Volume ID Étiquette du volume Mount Point Point de montage Add Ajouter Add A volume Ajouter un volume Mount Path Chemin du montage &Close &Fermer Mount Options Options de montage Manage Keys In Wallets Gérer les clés dans des trousseaux Set Default Wallet Définir le trousseau par défaut Internal Wallet Trousseau interne Libsecret Libsecret KWallet KWallet None Aucun Volume Path Chemin du volume Enter Volume Path Below Entrer le chemin du volume ci dessous Enter Password Below Entrer le moit de passe ci dessous Change Internal Wallet Password Modifier le mot de passe du trousseau interne TextLabel Etiquette texte Ok OK fileManager Set File Manager Choisir le gestionnaire de fichiers TextLabel EtiquetteTexte &Set &Définir Enter Below The Name Of The Application You Want To Be Used To Open Mount Points. Tapez ci dessous le nom de l'application que vous voulez utiliser pour ouvrir les points de montage. help Help Aide &Close &Fermer <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt;">ZuluCrypt is a simple, feature rich and powerful solution for hard drives encryption for linux.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt supports LUKS, TrueCrypt, VeraCrypt and PLAIN dm-crypt encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These supported encrypted volumes may resides in image files, hard drives and usb sticks, LVM</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volumes as well as in mdraid devices.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of encrypted volumes. Those that use what is commonly know as “a header†and</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">those that do not. TrueCrypt, VeraCry and LUKS volumes use a header. PLAIN dm-crypt volumes do</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">not use a header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a &quot;volume header&quot;.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">The damage to the header is usually caused by accidental formatting of the device or use of</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">some buggy partitioning tools or wrongly reassembled logical volumes.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack'; color:#008000;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of header using encrypted volumes. Those that use an encrypted header and those</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">that do not. TrueCrypt and VeraCrypt use an encrypted header whereas LUKS does not. The use of non</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted header in LUKS makes it obvious to everybody that the volume is an encrypted LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may be problematic to some people. How big the problem may be depends on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">person and their use case for hard drive encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The use of encrypted header as in TrueCrypt or VeraCrypt volumes or no header at all as in PLAIN dm-</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">crypt volumes make these volumes indistinguishable from random noise and this may seem useful at a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">glance but its usefulness may not hold up against scrutiny as the likelihood of being believed that a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">100GB file made up of cryptographically sound random data is just a 100GB file made up of random</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data and not a container file for an encrypted volume is not very high.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With LUKS, TrueCrypt and VeraCrypt volumes, it is very important to have a volume header backup</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">since a valid header is required to unlock the volume. A corrupted or missing header will make the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume unusable causing the loss of all encrypted data.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">LUKS stands for “Linux Unified Key Setupâ€. It is a specification of how to store information necessary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to open a LUKS formatted encryption volume. LUKS encryption format is the standard format in linux</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and a recommended one if the encrypted volume is to be used among linux systems. TrueCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt volumes are better alternative if the encrypted volume is to be shared between linux,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">windows and OSX computers.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can create and open 5 types of encrypted volumes, LUKS, TrueCrypt, VeraCrypt,PLAIN</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dm-crypt and PLAIN dm-crypt volume at a none zero offset. PLAIN dmcrypt volume is a header less</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume and all necessary encryption information is provided by zuluCrypt when it creates or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open these volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; text-decoration: underline;">Pros and cons of the five volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt; text-decoration: underline;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It does not use a volume header and hence its not possible to “brick†the entire volume simply by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over writing a small part of it.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It does not use a header and hence its impossible to know if the volume is made up of only</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">cryptographically sound random data or if its an encrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It does not use a header and hence any tool that opens these volumes must provide the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options that were used when the volume was created. Different tools may use different encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options making these encrypted volumes not very portable between applications or even between</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">different versions of the same application.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt at a none zero offset.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This volume has the same pros and cons as those of a PLAIN dm-crypt volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional pro for this volume is that it can be places anywhere on the device making it possible</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to have this volume on top of any one of the other supported encrypted volume or on top of an</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">unencrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For example, its possible to have an X MB drive that has unencrypted file system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">at the beginning of the device and a “PLAIN dm-crypt volume with an offset†somewhere towards the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">end of the device making it possible to use the drive as unencrypted volume and as encrypted volume</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">simultaneously depending on sensitivity of the data to be stored on the device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this volume type is to be used, preceding part of the drive should be formatted in “FAT†family of file systems.This volume types gives a “hidden volume†type functionality offered by TrueCrypt and VeraCrypt. When creating or unlocking this volume type, the starting offset of the volume will be asked and NOT the volume size as TrueCrypt and VeraCrypt does with the hidden volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above means, if you have a 100 MB drive and you want to create a 30MB “PLAIN dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume at a none zero offsetâ€, you will enter the starting offset of the volume as 70MB. In VeraCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt, you will enter the hidden volume size of 30MB. The starting offset and the size of the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hidden volume are related by a simple formula: starting offset(70MB) = device size(100MB) – hidden</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume size(30MB).</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TrueCrypt</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and hence its not possible to know if the volume is TrueCrypt formatted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume or if the volume is just made up of cryptographically sound random data.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Hidden volume. A TrueCrypt volume can have up to two different encrypted volumes. The first</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume is commonly know as “outer volume†and the second optional one is commonly known as</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“hidden volumeâ€.When a TrueCrypt volume is about to be opened, the user has an option to select</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">which one of the two to open by giving appropriate key.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and it is not possible to open the volume without a valid header. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">use a TrueCrypt volume, make sure you have at least one backup of the volume header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VeraCrypt</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt is an extension of TrueCrypt and it shares the same TrueCrypt’s pros and cons.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Pro for VeraCrypt over TrueCrypt.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It requires stronger effort to unlock VeraCrypt volume and this makes them more secure over</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt volumes.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Cons for VeraCrypt over TrueCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It requires stronger effort to unlock a VeraCrypt volume and this increases the time it takes to unlock</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a VeraCrypt volume. How long it will take depends on the strength of the computer and it may vary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from a few seconds to several minutes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS volume can be opened with up to 8 different keys.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS header is stored unencrypted making it obvious the volume is LUKS formatted encrypted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may not be desirable under certain circumstances. It is possible to create a LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume with a detached header and zuluCrypt can open these volumes using “luks†plugin.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It uses a header. As it is not possible to open a header using encrypted volume without its header, a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">corrupted LUKS header makes it impossible to open the volume. If you use a LUKS volume, make</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sure you have at least one backup of the volume header.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can do two types of encryption. It can do single file encryption/decryption or block device</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">File encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can encrypt and decrypt individual files. This feature is useful when a user just wants to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt a single file and taking the route of creating an encrypted container file to host the file is seen</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as an unnecessary hassle. This functionality is akin to file encryption using gpg with a symmetric key.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">File encryption is done using libgcrypt as a cryptographic backend. Files are encrypted using 256 bit</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">AES in CBC mode. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The encryption key is derived from user pass phrase using pbkdf2 with 10,000</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">rounds of iterations and sha2 as a cryptographic hash function. The resulting encrypted file will have a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file size that equals (64 + 1024 * n) bytes where n is a number starting from zero.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted file:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;encrypt a file†to open a file encryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to store encrypted, enter the password to be used to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt the file and then click “create†and the encrypted version of the file will be created at the path</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by “destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">To decrypt the file created with above steps:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;decrypt a file†to open a file decryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to decrypt, enter the password to be used to decrypt the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file and then click “create†and the decrypted version of the file will be created at the path given by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Block device encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A hard drive or a usb stick are two examples of block devices. A regular file can simulate a block</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">device through a use of devices known as “loop devicesâ€. These devices have a device path that starts</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">with “/dev/loopâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The infrastructure in the linux kernel that deal with block device encryption is called “dm-crypt†and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does its work through a process commonly known as OTF(on the file encryption). Dm-crypt devices</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">are represented by device addresses that starts with “/dev/dm-†and these paths are usually accessed</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">through their soft links that reside in “/dev/mapperâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Below is an example of steps taken in creating a 100MB encrypted container in a file and adding a file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">in it to be stored securely.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Create a 100MB file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Attach a loop device to the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Create an OTF encryption mapper against the loop device.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Put a file system on the encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Mount the file system on the mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Copy The file to be stored securely to the file system through the mount point.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Unmount the file system.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Destroy the OTF encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Detach the loop device from the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">10. Maintain the encrypted volume as a secure holder of files within it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All zuluCrypt does is provide a GUI to make it easy to do above specified tasks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With the above steps:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 1 deal with a path that look like “/home/ink/secret.imgâ€, this is a path to a regular file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 2 converts “/home/ink/secret.img†file to something like “/dev/loop0†loop device path.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 3 converts “/dev/loop0†loop device path to something like “/dev/mapper/secrets.imgâ€. Data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">written to “/dev/mapper/secrets.img†will get encrypted and then passed forward to “/dev/loop0†on its</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">way to “/home/ink/secret.imgâ€. When data is read from “/dev/mapper/secrets.imgâ€, the data will be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">read from “/dev/loop0†who in turn will read it from “/home/ink/secret.imgâ€, decrypted by dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then given to the reader. This process is called “on the fly encryption†because the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mapper does not store or hold on to data, it gets data and then encrypts or decrypts it depending on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">direction of data flow and then passes it along.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in an image file.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a file†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Enter the name of the file to be used to hold the container in the “file name†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the size of the container in the “file size†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Click “createâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Wait for the container file to be created and for the volume creation dialog to show up.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Enter the password to be used to create the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Select the type of volume you want to create from the “volume type†list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Click create to create the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in a partition.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a hard drive†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Click/double click on the hard drive you want to create a volume in and then advance to instruction</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">number 7 in the instruction list above. If the partition you want to put an encrypted container does not</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">show up on the list, then restart zuluCrypt from root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a file using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a file†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click the button to the right of “volume path†field and then browse to where</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the volume is and click it to open it. Alternatively, you can just drag the volume file on zuluCrypt to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">generate a password dialog prompt with the file path already filled in.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a partition using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a partition†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click/double click on the partition with an encrypted volume you want to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With both two steps above, the volume will be opened and mounted at a path whose last component is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by the entry in the field “mount nameâ€. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When the volume is successfully opened, zuluCrypt will</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">automatically open the mount point path. To close the volume, click its entry on the zuluCrypt window</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then click “close†on the pop up window.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can open an encrypted volume using keys derived from different sources. These sources</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">include, a pass phrase, a key file, a key retrieved from kwallet, a key retrieved from Gnome's libsecret,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a key retrieved from an internal secure storage system, a key from gpg encrypted key file among other</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sources.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a pass phrase volume key, make sure the key source option read “key†and then enter the pass</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phrase on the entry field at the bottom.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a keyfile as the source of volume key, click the option bar and then select “keyfile†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring a dialog box that will allow you to browse to where the key</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file is.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a plugin as the source of volume key, click the option bar and then select “plugin†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring up a list of available plugins and then select the one you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want from the list.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Volume keys stored in kwallet, Gnome keyring or internal secure storage system plugins can be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">managed by going to “menu-&gt;options-&gt;manage volumes in internal/kde/gnome walletâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Storage of keys in a gnome wallet/keyring seem most appropriate in a gnome session but this has some security repercussions, the keys are stored in the user keyring and this keyring gets unlocked when the user logs in. This means that once a user is logged in and the keyring is open, any application that runs in that user session can read those keys using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In a kde system, a kwallet secure storage system seem most appropriate but it suffers from the same</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">security problem the gnome secure storage system has, once the wallet is open, any application running in the user session can access it using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The behaviors of the above secure storage systems is by design but this design may not be ideal for</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">some users under certain use cases. The internal secure storage system is powered by libgcrypt and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does not have the behavior of the above two systems. An unlocked internal secured storage system is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">accessible only to the instance of zuluCrypt that unlocked it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Favorites.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For convenience, most used volumes can be easily opened by adding them to the favorite list. Entries</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">on the list are added in the dialog window opened by clicking “menu-&gt;options-&gt;manage favoritesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Favorite entries are added by clicking the “favorite†entry on the menu.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Erase data in a device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It is very important to create encrypted volume over cryptographically strong random data to make it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">impossible to know what part of the encrypted volume has been used and what part has not. If the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume is created over predictable data patterns like on a device with only zeros in it,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">forensic analysis may reveal how much and what part of the encrypted volume are in use.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When creating an encrypted container in a device, zuluCrypt offers an option to first write random data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over the device. This feature can be performed on other devices by activating it through “menu-&gt;erase</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data in a deviceâ€. Random data are written to disk by opening a plain dm-crypt encryption mapper on</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the device with a 64 byte random key and then blasting zeros on the device through the mapper. This</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">technique has proven to be faster compared to alternatives like writing random data on the device read</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from “/dev/urandomâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">System and non system volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To enforce access controls on what user can access what block device and what they can do with the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">access they have, zuluCrypt employes a concept of “system volumes†and “non system volumesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A system volume is defined as a volume that has an active entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/fstabâ€,â€/etc/crypptabâ€,“/etc/zuluCrypt/system_volumes.list†or if udev identify it as such if udev</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">is enabled. Ideally, all volumes inside the computer are to be considers system volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A non system volume is a volume that failed in the above considerations or if it has an entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/zuluCrypt/non_system_volumes.listâ€. Ideally, these volumes are plug gable usb based hard drives</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">or usb sticks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Partitions can be added or removed from the list of system or non system volumes simply by starting</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zuluCrypt from root's account and then going to “menu-&gt;options-&gt;manage system volumes/manage</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">non system volumes†and then adding the volume in the appropriate list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Permissions.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt limits what a user can do on block devices through unix's group based permission system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">using two groups, “zulucrypt†and “zulumountâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, only a root user or a user who is a member of group</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“zulucrypt†can create an encrypted volume in the device or taking/restoring volume headers. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want to create a volume in a device and the device does not show up on the list, restart zuluCrypt from</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, zuluMount will mount it only if the user is root, is a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">member of group “zulumount†or the device has an entry in “/etc/fstab†with either “user†or “usersâ€</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mount options set.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ZuluMount.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount is a general purpose mounting tool that can open zuluCrypt supported encrypted volumes</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as well as non encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also auto detect plugged in devices and auto mount them.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also unlock encfs volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2015-2017 Francis Banyikwa, mhogomchungu@gmail.com</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Open &PDF Ouvrir le &PDF WARNING! ATTENTION! Failed to open zuluCrypt.pdf,make sure your system can open pdf files using "%1" tool and try again Impossible de lire zuluCrypt.pdf, assurez vous que votre système puisse lire les fichiers PDF utilisant "%1" tool et essayez à nouveau luksaddkey Add A Key To A Volume Ajouter une clé à un volume Volume Path Chemin du volume open file Ouvrir un fichier open partition Ouvrir une partition Password Already In The Encrypted Volume Mot de passe déjà inclus dans le volume chiffré Password To Be Added To The Encrypted Volume Mot de passe à ajouter dans le volume chiffré Reenter Password Réentrer le mot de passe Password Mot de Passe KeyFile Fichier de clé Key+KeyFile Clé + fichier de clé YubiKey Challenge/Response YubiKey Challenge/Réponse Advanced LUKS2 Options Options avancées LUKS2 LUKS LUKS TrueCrypt TrueCrypt VeraCrypt VeraCrypt Volume Type Type de Volume PIM PIM TextLabel Etiquette de texte &OK &OK Advanced Luks2 Options Options avancées LUKS2 Set Définir Pbkdf Type Type Pbkdf argon2id argon2id argon2i argon2i pbkdf2 pbkdf2 Max Memory (KB) Mémoire maximale (Ko) Parallel Threads Threads parallèles Unlocking Time Cost(Milliseconds) Coût temps de déverrouillage (millisecondes) Forced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) Forcer des itérations (dangereux et peut mener à des temps de déverrouillage extrêmement long) Cancel Annuler &Add &Ajouter &Cancel &Annuler open keyfile ouvrir un fichier de clé Passphrase Quality: 0% Force de la Passphrase : 0% Passphrase Quality: %1% Force de la Passphrase : %1% Key Slot Number To Add Key In Numéro d'emplacement de clé pour y ajouter la clé Enter A Key Entrer une clé Enter a path to a keyfile location Entrer le chemin de la localisation du fichier de clé KeyFile Path Chemin du fichier de clé Enter a key Entrer une clé KeyFile path Chemin du fichier de clé Passphrase Quality: 100% Force de la Passphrase : 100% Existing KeyFile Fichier de clé existant New KeyFile Nouveau Fichier de clé Encrypted Volume Path Chemin du volume chiffré ERROR! ERREUR! Atleast one required field is empty Au moins un des champs qui est requis est vide Failed to enable polkit support Echec de l'activation du support polkit Keys do not match Clés non correspondantes Failed To Locate Or Run Yubikey's "ykchalresp" Program. Echec pour trouver ou exécuter le programme Yubikey's "ykchalresp". Key added successfully. Clés ajoutées avec succès. Key added successfully. %1 / %2 slots are now in use Clés ajoutées avec succès. %1 / %2 emplacements sont utilisés Presented key does not match any key in the volume Les clés entrées ne correspondent à aucune clé du volume Could not open luks volume Impossible d'ouvrir le volume luks Volume is not a luks volume Le volume n'est pas un volume LUKS Insufficient privilege to add a key to a system device, only root user or members of group "zulucrypt" can do that Privilèges insuffisants pour ajouter une clé à un périphérique système, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le faire Could not open volume in write mode Impossible d'ouvrir le volume en mode écriture All key slots are occupied, can not add any more keys Tous les emplacements de clés sont occupés, ne peut pas ouvrir davantage de clés Can not get passphrase in silent mode Ne peut pas obtenir une passphrase en mode silencieux Insufficient memory to hold passphrase Mémoire insuffisante pour manipuler la passphrase New passphrases do not match Nouvelles Passphrases non correspondantes One or more required argument(s) for this operation is missing Un ou plusieurs argument(s) requis pour cette opération est manquant One or both keyfile(s) does not exist Un ou plusieurs fichiers de clé n'existent pas Insufficient privilege to open key file for reading Privilège insuffisant pour ouvrir le fichier clé pour la lecture Couldnt get enought memory to hold the key file Ne peut pas avoir assez de mémoire pour manipuler le fichier de clé Could not get a key from a socket Ne peut pas obtenir de clé depuis un socket Could not get elevated privilege,check binary permissions Ne peut obtenir d'élévations de privilèges, tester les droits et permissions Key slot already occupied Emplacement de clé déjà occupé Failed to find empty key slot or key slot out of range Echec à trouver un emplacement de clé vide ou bien l'emplacement est hors de portée Can not find a partition that match presented UUID Ne trouve pas de partition qui correspond à l'UUID entrée Device is not a luks device Le périphérique n'est pas un périphérique luks Error Code: %1 -- StdOut: %2 -- StdError: %3 Code Erreur: %1 -- Sortie Standard: %2 -- Erreur de Sortie: %3 luksdeletekey open a keyfile ouvrir un fichier de clé Remove A Key From A Volume Enlever une clé d'un volume LUKS Slot Number LUKS numéro d'emplacement Password Mot de Passe &Delete &Effacer &Cancel &Annuler Volume Path Chemin du volume open an encrypted file Ouvrir un fichier chiffré open an encrypted partition Ouvrir une partition chiffrée TextLabel Etiquette de texte &OK &OK KeyFile Fichier de clé Key+KeyFIle Clé + fichier de clé ERROR! ERREUR! Enter a key Entrer une clé YubiKey Challenge/Response YubiKey Challenge/Réponse zuluCrypt will have the same behavious as luksKillSlot if a key slot is given zuluCrypt aura le même comportement que LUKSKillSlot si un emplacement de clé est fourni zuluCrypt will have the same behavious as luksRemoveKey if a key slot is NOT given zuluCrypt aura le même comportement que LUKSRemoveKey si un emplacement de clé n'est PAS fourni Enter a path to a keyfile location Entrer le chemin de la localisation du fichier de clé KeyFile path Chemin du fichier de clé Key File With A Passphrase To Delete Fichier de clé avec une passphrase à effacer Atleast one required field is empty Au moins un des champs qui est requis est vide Failed to enable polkit support Echec de l'activation du support polkit Volume is not a luks volume Le volume n'est pas un volume LUKS There is only one last key in the volume. Il reste encore une dernière clé dans le volume. Deleting it will make the volume unopenable and lost forever. Cet effacement rendra le volume impossible à ouvrir et donc perdu définitivement. Are you sure you want to delete this key? Êtes vous sûr de vouloir effacer cette clé? WARNING ATTENTION Failed To Locate Or Run Yubikey's "ykchalresp" Program. Echec pour trouver ou exécuter le programme Yubikey's "ykchalresp". Key removed successfully. %1 / %2 slots are now in use Clés enlevées avec succès. %1 / %2 emplacements sont utilisés There is no key in the volume that match the presented key Il n'y a pas de clé dans le volume qui corresponde avec la clé entrée Could not open the volume Impossible d'ouvrir le volume Insufficient privilege to open a system device,only root user or members of group zulucrypt can do that Privilèges insuffisants pour ouvrir un périphérique système, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le faire Could not open the volume in write mode Impossible d'ouvrir le volume en mode écriture Insufficient memory to hold your response Mémoire insuffisante pour manipuler la réponse Operation terminated per user request Opération interrompue par l'utilisateur Can not get passphrase in silent mode Ne peut pas obtenir une passphrase en mode silencieux Insufficient memory to hold passphrase Mémoire insuffisante pour manipuler la passphrase One or more required argument(s) for this operation is missing Un ou plusieurs argument(s) requis pour cette opération est manquant Keyfile does not exist Fichiers de clé n'existent pas Could not get enough memory to open the key file Ne peut pas avoir assez de mémoire pour ouvrir le fichier de clé Insufficient privilege to open key file for reading Privilège insuffisant pour ouvrir le fichier clé pour la lecture Could not get a key from a socket Ne peut pas obtenir de clé depuis un socket Can not find a partition that match presented UUID Ne trouve pas de partition qui correspond à l'UUID entrée Error Code: %1 -- StdOut: %2 -- StdError: %3 Code Erreur: %1 -- Sortie Standard: %2 -- Erreur de Sortie: %3 manageSystemVolumes Remove Selected Entry Enlever l'entrée sélectionnée Cancel Annuler Are you sure you want to remove "%1" from the list? Êtes vous sûr de retirer "%1" de la liste? Select Path To System Volume Choisir le chemin du volume Système WARNING ATTENTION Manage System Volumes Gérer les volumes systèmes &Done &Fini Add Fi&le Ajouter &Fichier Add Dev&ice Ajouter &Périphérique Path To System Volumes Chemins des volumes Système managevolumeheader Backup Volume Header Backup Header Volume Backup Name Nom du Backup C&reate &Créer &Cancel &Annuler Volume Path Chemin du volume Window System Volume Volume Système Windows Volume Type Type de Volume Manage A VeraCrypt Header Gérer un VeraCrypt Header PIM PIM Password Password Source Source du mot de passe Outer Volume Password ONLY Mot de passe du volume Externe SEULEMENT KeyFile Fichier de clé TextLabel EtiquetteTexte Normal Volume Volume Normal Whole Drive Encrypted Volume Disque Entier en Volume Chiffré Manage A LUKS Header Gérer un LUKS Header Manage A TrueCrypt Header Gérer un TrueCrypt Header Restore volume header Restaurer Header Volume &Restore &Restaurer Back up volume header Backup Header Volume &Backup &Backup Select A File With A LUKS Backup Header Sélectionner un fichier avec un LUKS Backup Header Select A Folder To Store The Header Sélectionner un répertoire pour stocker le Header ERROR! ERREUR! Atleast one required field is empty Au moins un des champs qui est requis est vide Failed to enable polkit support Echec de l'activation du support polkit Are you sure you want to replace a header on device "%1" with a backup copy at "%2"? Etes-vous sûr de vouloir remplacer un en-tête sur le périphérique "%1" avec une copie de sauvegarde de "%2"? WARNING! ATTENTION! Select luks container you want to backup its header Sélectionner un conteneur LUKS dont vous voulez sauvegarder le header SUCCESS SUCCES Header saved successfully. If possible,store it securely. Header sauvé avec succès. Si possible, stockez le en toute sécurité. Header restored successfully Header restauré avec succès Presented device is not a LUKS device Le périphérique choisi n'est pas un périphérique LUKS Failed to perform requested operation Echec de l'opération demandée INFO! INFO! Operation terminater per user request Opération interrompue par l'utilisateur Path to be used to create a back up file is occupied Chemin d'accès utilisé pour créer le fichier de sauvegarde est occupé Insufficient privilege to open backup header file for reading Privilège insuffisant pour ouvrir le fichier d'en-tête de sauvegarde pour la lecture Invalid path to back up header file Chemin invalide pour sauver le fichier header Insufficient privilege to create a backup header in a destination folder Privilège insuffisant pour sauver un backup dans le répertoire de destination Invalid path to device Chemin de périphérique invalide Argument for path to a backup header file is missing Argument pour le chemin de sauvegarde du header est manquant Only root user and "zulucrypt" members can restore and back up luks headers on system devices Seul l'utilisateur root ou les membres du groupe zulucrypt peuvent restaurer et sauver les luks headers sur les périphériques systèmes Insufficient privilege to open device for writing Privilège insuffisant pour ouvrir le périphérique pour l'écriture Could not resolve path to device Ne peut pas trouver le chemin du périphérique Backup file does not appear to contain luks header Le fichier sauvegardé ne semble pas contenir de header LUKS Insufficient privilege to open device for reading Privilège insuffisant pour ouvrir le périphérique pour la lecture Wrong password entered or volume is not a truecrypt volume Mot de passe erroné ou le volume n'est pas un volume Truecrypt Failed to perform requested operation on the LUKS volume Echec de l'opération demandée sur le volume LUKS Wrong password entered or volume is not a veracrypt volume Mot de passe erroné ou le volume n'est pas un volume Veracrypt Unrecognized ERROR! with status number %1 encountered Erreur inconnue avec numéro de statut %1 rencontrée oneinstance Previous instance seem to have crashed,trying to clean up before starting L'instance précédente semble avoir crashé, tentative de réinitialisation avant démarrage There seem to be another instance running,exiting this one Il semble y avoir une autre instance en cours d'exécution, sortie de celle-ci openvolume Select A Partition To Open Sélectionner une partition à ouvrir Use UUID Utiliser les UUID &Help &Aide Use &UUID Utiliser les &UUID &Cancel &Annuler partition partition size taille label Etiquette type type uuid uuid &Open &Ouvrir A list of all partitions on this system are displayed here. Double click an entry to use it Une liste de toutes les partitions sur ce système est affichée ici. Double-cliquez sur l'une d'elle pour l'utiliser Restart the tool from root's account or after you have created and added yourself to group "zulucrypt" if the volume you want to use is not on the list. Redémarrez l'outil de compte root ou bien après avoir créé / vous être ajouté au groupe "zulucrypt" si le volume que vous souhaitez utiliser ne figure pas sur la liste. You are a root user and all partitions are displayed. Double click an entry to use it Vous êtes un utilisateur root et toutes les partitions sont affichées. Double-cliquez sur l'une d'elle pour l'utiliser INFO INFO Select A Partition To Create An Encrypted Volume In Sélectionner la partition où vous voulez créer le volume chiffré Select An Encrypted Partition To Open Sélectionner une partition chiffrée à ouvrir ERROR ERREUR Only crypto_LUKS volumes can be selected Seuls les volumes crypto_LUKS peuvent être séléctionnés passwordDialog "/" character is not allowed in mount name field Le caractère "/" n'est pas autorisé dans le champ du nom de montage Cancel Annuler Mount "%1" Monter "%1" TrueCrypt/VeraCrypt Keys TrueCrypt/VeraCrypt Clés YubiKey Challenge/Response YubiKey Challenge/Réponse Check This Box To Make Password Visible Cocher cette case pour rendre le mot de passe visible Unlock Encrypted Volume Déverrouiller un volume chiffré PIM Value Valeur PIM Offset Décalage Offset Will Be In Sectors If The Entry Is Made Up Of Only Digits And In Bytes If The Entry Ends With "b" And In Kilobytes If The Entry Ends With "k" And In Megabytes If The Entry Ends With "m" And In Terabytes If The Entry Ends With "t" l'emplacement pourrait être en "secteurs" si la définition se compose de chiffres uniquement ou en octets si l'entrée se termine par "b" ou en kilo-octets si l'entrée se termine par "k" ou en mégaoctets si l'entrée se termine par "m" ou en téraoctets si l'entrée se termine par "t" Choose A Module From The File System Choisissez un module depuis le système de fichiers Enter A Module Name To Use To Get Passphrase Entrez un nom de module à utiliser pour obtenir une Passphrase Plugin Name Nom de Plugin Password Mot de Passe Select A Key Module Sélectionner un Module de Clé Enter A Key Entrer une clé Select External LUKS Header File Sélectionner un entête de fichier LUKS Externe LUKS External Header Path Chemin de l'entête LUKS Externe Choose A KeyFile From The File System Choisissez un fichier de clé depuis le système de fichiers Enter A Path To A Keyfile Location Entrer le chemin de la localisation du fichier de clé KeyFile Path Chemin du fichier de clé Select A KeyFile Sélectionner un fichier de clé Select Path To Mount Point Folder choisir le chemin du point de montage du répertoire Select Encrypted volume Sélectionner un volume chiffré ERROR! ERREUR! Internal wallet is not configured Trousseau interne non configuré ERROR ERREUR Failed To Locate Or Run Yubikey's "ykchalresp" Program. Echec pour trouver ou exécuter le programme Yubikey's "ykchalresp". Atleast one required field is empty Au moins un des champs qui est requis est vide Volume is not a LUKS volume Le volume n'est pas un volume LUKS Failed to get a key from the network Echec de l'obtention de la clé depuis le réseau Failed to get a key from a plugin Echec de l'obtention de la clé depuis le plugin Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? Impossible de monter le système de fichiers ntfs / exfat en utilisant ntfs-3g, est ce que le paquet ntfs-3g/exfat est installé? There seem to be an open volume accociated with given address Il semble y avoir un volume ouvert associé à l'adresse donnée No file or device exist on given path Aucun fichier ou périphérique existant sur le chemin donné Volume could not be opened with the presented key Le volume n'a pas pu être ouvert avec la clé entrée Insufficient privilege to mount the device with given options Privilèges insuffisants pour monter le périphérique avec des options données Insufficient privilege to open device in read write mode or device does not exist Privilèges insuffisants pour ouvrir le périphérique en mode lecture-écriture ou bien le périphérique n'existe pas Only root user can perform this operation Seul l'utilisateur root peut effectuer cette opération Could not create mount point, invalid path or path already taken Impossible de créer le point de montage, chemin non valide ou chemin déjà pris Shared mount point path already taken Chemin de point de montage du partage déjà pris There seem to be an opened mapper associated with the device Il semble y avoir un mappeur ouvert associé au périphérique Could not get a passphrase from the module Ne peut pas obtenir une passphrase depuis ce module Could not get passphrase in silent mode Ne peut pas obtenir une passphrase en mode silencieux Insufficient memory to hold passphrase Mémoire insuffisante pour manipuler la passphrase One or more required argument(s) for this operation is missing Un ou plusieurs argument(s) requis pour cette opération est manquant Invalid path to key file Chemin invalide vers le fichier de clé Could not get enought memory to hold the key file Ne peut pas avoir assez de mémoire pour manipuler le fichier de clé Insufficient privilege to open key file for reading Privilège insuffisant pour ouvrir le fichier clé pour la lecture Could not get a passphrase through a local socket Ne peut pas obtenir une passphrase à travers un socket local Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered Echec du montage du système de fichier : option de montage invalide/non supportée ou bien système de fichiers non supporté Could not create a lock on /etc/mtab Ne peut pas créer un lock sur /etc/mtab Insufficient privilege to open a system volume. Consult menu->help->permission for more informaion Privilèges insuffisants pour opérer sur un volume système. Consultez le menu ->Aide-> Zulucrypt.pdf - Permissions pour davantage d'informations A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature Un périphérique est non supporté ou manquant ou permission refusée Les raisons possibles pour corriger l'erreur sont les suivantes: 1. Chemin du périphérique invalide. 2. le périphérique possède un LVM ou une signature MDRAID Error Code: %1 -- StdOut: %2 -- StdError: %3 Code Erreur: %1 -- Sortie Standard: %2 -- Erreur de Sortie: %3 -O and -m options can not be used together Les options -O et -m ne peuvent pas être utilisées conjointement plugin Key Generator Using A Passphrase And A KeyFile Générateur de clé utilisant une passphrase et un fichier de clé &Set Key &Définir une clé &Cancel &Annuler Create an encryption key that is made up of a passphrase and a keyfile. A volume created with a key generated here should be opened with "hmac" plugin. Créer une clé de chiffrement qui est composée d'une phrase et d'un keyfile. Un volume créé avec une clé générée ici devra être ouvert avec le plugin "hmac". Passphrase Passphrase KeyFile Fichier de clé ERROR ERREUR KeyFile Not Set Fichier de clé non actif Failed To Generate Key Echec de la génération de clé readOnlyWarning WARNING ATTENTION Do Not Show This Message Again. Ne plus montrer ce message désormais. Setting this option will cause the volume to open in read only mode. Définir cette option ouvrira le volume en mode lecture seule. &Ok &Ok tcrypt TrueCrypt Keys Clés TrueCrypt &Open &Ouvrir &Cancel &Annuler Add &Keyfile Ajouter un &fichier de clé drag and drop key files to add them to the list Faire un glisser/déposer des fichiers de clés pour les ajouter à la liste Keyfile Paths Chemins du fichier de clé Enter key files below to be used to open the volume Entrez les fichiers clés ci-dessous pour les utiliser dans l'ouverture de volume Enter A Passphrase Below To Be Used To Open The Volume Entrer ci dessous une Passphrase pour être utilisée dans l'ouverture du volume &Set &Définir TrueCrypt/VeraCrypt Keys Clés TrueCrypt/VeraCrypt ERROR ERREUR At least one keyfile is required Au moins une clé de fichier est requise Select A KeyFile Sélectionner un fichier de clé utility::veraCryptWarning Elapsed time: 0 seconds Temps écoulé: 0 secondes Elapsed time: %0 minutes Temps écoulé: %0 minutes Elapsed time: %0 seconds Temps écoulé: %0 secondes Please be patient as unlocking a VeraCrypt volume may take a very long time. Soyez patient car le déchiffrement d'un volume VeraCrypt peut durer un certain temps. warnWhenExtendingContainerFile WARNING!! ATTENTION! OK OK Dont Show This Warning Again. Ne plus montrer ce message désormais. Your cover file will be irreversibly changed and we suggest continuing with a backup file and not the original. To unlock the volume about to be created, you will need to enter the password you will choose and the volume offset automatically generated by zuluCrypt. Instructions to unlock the volume are as follows: 1. From the menu, choose Open -> Volume Hosted In A File. 2. Select file, then choose "Volume Type" = PLAIN dm-crypt. 3. Enter the generated offset value along with your password. Votre fichier de couverture sera irrémédiablement modifié et nous vous conseillons de poursuivre avec une sauvegarde plutôt que le fichier original. Pour déchiffrer le volume à créer, vous aurez besoin d'entrer un mot de passe de votre choix et l'offset (décalage) de volume généré automatiquement par ZuluCrypt. Les instructions pour déchiffrer le volume sont les suivantes: 1. Depuis le menu Ouvrir, choisir -> Volume localisé dans un fichier. 2. Sélectionner votre fichier puis sélectionner "Type de Volume" = PLAIN dm-crypt. 3. Entrer le décalage (offset) et votre mot de passe. IMPORTANT!!! IMPORTANT!!! zuluCrypt zuluCrypt Type Optio&ns Optio&ns &zC Ctrl+Z Ctrl+X Ctrl+A Encrypted &Container In A Hard Drive Conteneur &chiffré dans un disque matériel Ctrl+S &About &A propos Ctrl+R &Add A Key To A Volume &Ajouter une clé à un volume Ctrl+U &Delete A Key From A Volume &Effacer la clé d'un volume Ctrl+W crypto info Ctrl+E Ctrl+D Ctrl+K Encrypted Volume Path Chemin du volume chiffré Encrypted Volume Mount Point Path Chemin du point de montage du volume chiffré &Open &Ouvrir &Create &Créer &Help &Aide &Volumes &Volumes &Favorites &Favoris Ctrl+L favorite volumes Volumes Favoris manage favorites Gérer les favoris select random number generator Sélectionner un générateur aléatoire Ctrl+P close application Fermer l'application Ctrl+C Quit Quitter permissions permissions configure wallets configurer les trousseaux Shift+V Alt+V tcrypt backup header tcrypt backup header tcrypt restore header tcrypt restauration header VeraCrypt Container In A File VeraCrypt Conteneur dans un fichier VeraCrypt Container In A Hard Drive VeraCrypt Conteneur dans un disque matériel Shift+I Select Language Sélectionner la langue Ctrl+T Ctrl+Y Ctrl+Q Ctrl+G Ctrl+F Ctrl+N Ctrl+B Ctrl+I Ctrl+H Ctrl+J Manage Volumes In &KDE Wallet Gérer les volumes dans le trousseau &KDE Manage Volumes In &GNOME keyring Gérer les volumes dans le trousseau &GNOME &Change Internal Wallet Password &Changer le mot de passe du Trousseau Interne Ctrl+O Ctrl+V &Volume Hosted In A File &Volume localisé dans un fichier Volume &Hosted In A Hard Drive Volume &localisé dans un disque matériel &Encrypted Container In A New File Conteneur &chiffré dans un tout nouveau fichier &KeyFile &Fichier de clé &Tray Icon &Icône de barre des tâches Select &Font &Sélectionner la police d'affichage &Update Volume List &Actualiser la liste des volumes &Minimize To Tray &Minimiser en barre des tâches &Quit &Quitter &Close All Opened Volumes &Fermer tous les volumes ouverts &Manage Favorites &Gérer les Favoris &Erase Data In A Device &Effacer les données d'un périphérique &Backup Header &Backup Header &Restore Header &Restaurer Header Encrypt A &File Chiffrer un &ficher &Decrypt A File &Déchiffrer un fichier &Header Backup &Header (En-tête) Backup Manag&e System Volumes &Gérer les volumes systèmes Manage &Volumes In Internal Wallet &Gérer les volumes dans le Trousseau Interne Manage &Non System Volumes &Gérer des volumes non systèmes Ctrl+M H&elp &Aide F1 F1 Show LUKS Key Slots Montrer les emplacements de clé LUKS Set Fi&le Manager Choisir le gestionnaire de &fichiers Do Not Minimize To Tray Ne pas minimiser en barre des tâches This Option Will Close The App Instead Of Minimizing It To Tray Cette option fermera l'application au lieu de la minimiser Encrypted Container Hidden In Video/Cover File (Steganography) Conteneur chiffré masqué dans une vidéo / un fichier de couverture (Stéganographie) Show Debug Window Montrer la Fenêtre de Débogage Ctrl+Shift+D Ctrl+Shift+D Encrypted Container In An Existing File Conteneur chiffré dans un fichier déjà existant Clear Dead Mount Points Effacer les points de montage invalides Contact &Info &Informations de contact &Select Language &Sélectionner la langue &Auto Open Mount Point &Ouverture automatique du point de montage Select &Icons Choisir le type d'&icônes INFO Restore Volume Header Restaurer Header Volume Backup Volume Header Backup Header Volume WARNING! ATTENTION! Resetting font size to %1 because larger font sizes do not fit Réinitialisation à une taille de police de %1 car des tailles trop importantes ne s'adapteront pas Show/Hide Afficher/Masquer LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a "volume header". A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data. The damage to the header is usually caused by accidental formatting of the device or use of some buggy partitioning tools or wrongly reassembled logical volumes. Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted. Les volumes cryptés LUKS, TrueCrypt et VeraCrypt ont ce que l'on appelle un «header = en-tête de volume». Un en-tête de volume est chargé de stocker les informations nécessaires pour ouvrir un volume crypté à en-tête et tout dommage sur celui ci rend impossible l'ouverture du volume provoquant ainsi la perte permanente de données cryptées. Les dommages causés à l'en-tête sont habituellement causés par un formatage accidentel de l'appareil ou l'utilisation de certains outils de partitionnement bogués ou bien de volumes logiques mal réassemblés. Avoir une sauvegarde de l'en-tête de volume est fortement recommandé car elle est la seule façon de rendre accessible à nouveau les données chiffrées si l'en-tête sur le volume est corrompue. Important Information On Volume Header Backup Information Importante sur le Volume Header Backup ERROR! ERREUR! Volume is not open or was opened by a different user Le volume n'est pas ouvert ou a été ouvert par un autre utilisateur Volume Properties Propriétés du volume Could not open mount point because "%1" tool does not appear to be working correctly Impossible d'ouvrir le point de montage parce que "%1" ne semble pas fonctionner correctement Properties Propriétés Open Folder Ouvrir Répertoire ERROR ERREUR zuluCrypt Failed To Connect To zuluPolkit. Please Report This Serious Bug. zuluCrypt a échoué à la connexion de zuluPolkit. Merci de reporter ce bug important. Cryptsetup library could not be found and zuluCrypt will most likely not work as expected. La bibliothèque Cryptsetup n'a pas été trouvée et ZuluCrypt risque évidemment de ne pas fonctionner comme prévu. Please recompile zuluCrypt to force it to re-discover the new library Merci de recompiler zuluCrypt pour le forcer à redécouvrir la nouvelle bibliothèque Path To A File Chemin vers le fichier Open Private Folder Ouvrir Répertoire Privé Open Shared Folder Ouvrir Répertoire Partagé Add Key Ajouter une clé Remove Key Enlever une clé Show Key Slots Information Montrer les informations d'emplacement des clés Backup LUKS Header Add To Favorite Ajouter aux Favoris Unmount Démonter Cancel Annuler Close failed, volume is not open or was opened by a different user Echec de la fermeture, le volume n'est pas ouvert ou a été ouvert par un autre utilisateur Close failed, one or more files in the volume are in use. Echec de la fermeture, un ou plusieurs fichiers encore en cours d'utilisation. Close failed, volume does not have an entry in /etc/mtab Echec de la fermeture, le volume n'a pas d'entrée dans le /etc/mtab Close failed, could not get a lock on /etc/mtab~ Echec de la fermeture, ne peut pas créer un lock sur /etc/mtab Close failed, volume is unmounted but could not close mapper,advice to close it manually Echec de la fermeture, le volume est démonté, mais ne pouvait pas fermer le mappeur, il est conseillé de le fermer manuellement Close failed, could not resolve full path of device Echec de la fermeture, ne peut pas trouver la totalité du chemin d'emplacement du périphérique Close failed, shared mount point appear to be busy Echec de la fermeture, le point de montage semble être occupé Close failed, shared mount point appear to belong to a different user or multiple mount points detected Echec de la fermeture, le point de montage semble appartenir à un autre utilisateur ou bien points de montage multiples Close failed, shared mount point appear to be in an ambiguous state,advice to unmount manually Echec de la fermeture, le point de montage semble être dans un état incohérent, il est conseillé de le démonter manuellement Close failed, multiple mount points for the volume detected Echec de la fermeture, plusieurs points de montage détectés pour le volume Close failed, could not find any partition with the presented UUID Echec de la fermeture, ne trouve aucune partition avec l'UUID correspondante Unrecognized error with status number %1 encountered Erreur inconnue avec numéro de statut %1 rencontrée zuluCrypt-6.2.0/translations/zuluCrypt/messages.pot000066400000000000000000000724201425361753700226570ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-11-25 17:53-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: ../../zuluCrypt-cli/bin/add_key.c:73 #, c-format msgid "SUCCESS: key added successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:74 #, c-format msgid "ERROR: presented key does not match any key in the volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:75 #, c-format msgid "ERROR: could not open luks volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:76 #, c-format msgid "ERROR: volume is not a luks volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:77 #, c-format msgid "" "ERROR: insufficient privilege to open a system device,\n" "only root user or members of group \"zulucrypt\" can do that\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:79 #, c-format msgid "ERROR: could not open volume in write mode\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:80 #, c-format msgid "ERROR: all key slots are occupied, can not add any more keys\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:81 #: ../../zuluCrypt-cli/bin/create_volumes.c:55 #: ../../zuluCrypt-cli/bin/crypt_file.c:47 #: ../../zuluCrypt-cli/bin/remove_key.c:69 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:79 #, c-format msgid "ERROR: can not get passphrase in silent mode\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:82 #: ../../zuluCrypt-cli/bin/create_volumes.c:56 #: ../../zuluCrypt-cli/bin/crypt_file.c:48 #: ../../zuluCrypt-cli/bin/open_volume.c:107 #: ../../zuluCrypt-cli/bin/remove_key.c:70 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:80 #, c-format msgid "ERROR: insufficient memory to hold passphrase\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:83 #, c-format msgid "ERROR: new passphrases do not match\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:84 #: ../../zuluCrypt-cli/bin/create_volumes.c:54 #: ../../zuluCrypt-cli/bin/open_volume.c:108 #: ../../zuluCrypt-cli/bin/remove_key.c:71 #, c-format msgid "ERROR: one or more required argument(s) for this operation is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:85 #, c-format msgid "ERROR: one or both keyfile(s) does not exist\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:86 #: ../../zuluCrypt-cli/bin/open_volume.c:111 #: ../../zuluCrypt-cli/bin/remove_key.c:74 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:75 #, c-format msgid "ERROR: insufficient privilege to open key file for reading\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:87 #: ../../zuluCrypt-cli/bin/create_volumes.c:52 #, c-format msgid "ERROR: couldnt get enought memory to hold the key file\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:88 #: ../../zuluCrypt-cli/bin/create_volumes.c:53 #: ../../zuluCrypt-cli/bin/remove_key.c:75 #, c-format msgid "ERROR: could not get a key from a socket\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:89 #, c-format msgid "ERROR: could not get elevated privilege,check binary permissions\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:90 #: ../../zuluCrypt-cli/bin/close_volume.c:41 #: ../../zuluCrypt-cli/bin/create_volumes.c:60 #: ../../zuluCrypt-cli/bin/remove_key.c:76 #, c-format msgid "ERROR: unrecognized error with status number %d encountered\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:98 #: ../../zuluCrypt-cli/bin/remove_key.c:83 #, c-format msgid "ERROR: device \"%s\" is not a luks device\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:109 #, c-format msgid "Enter an existing passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:114 #, c-format msgid "" "\n" "Enter the new passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:120 #, c-format msgid "" "\n" "Re enter the new passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:31 #, c-format msgid "SUCCESS: volume closed successfully \n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:32 #, c-format msgid "" "ERROR: close failed, volume is not open or was opened by a different user\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:33 #, c-format msgid "" "ERROR: close failed, the mount point and/or one or more files are in use\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:34 #, c-format msgid "ERROR: close failed, volume does not have an entry in /etc/mtab\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:35 #, c-format msgid "ERROR: close failed, could not get a lock on /etc/mtab~\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:36 #, c-format msgid "" "ERROR: close failed, volume is unmounted but could not close mapper,advice " "to close it manually\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:37 #, c-format msgid "ERROR: close failed, could not resolve full path of device\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:38 #, c-format msgid "ERROR: close failed, shared mount point appear to be busy\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:39 #, c-format msgid "" "ERROR: close failed, shared mount point appear to belong to a different " "user\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:40 #, c-format msgid "" "ERROR: close failed, shared mount point appear to be in an ambiguous state," "advice to unmount manually" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:35 #: ../../zuluCrypt-cli/bin/create_volumes.c:69 #, c-format msgid "SUCCESS: volume created successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:36 #, c-format msgid "" "ERROR: presented file system is not supported,see documentation for more " "information\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:37 #, c-format msgid "" "ERROR: insufficient privilege to open a system device in read/write mode,\n" "only root user or members of group zulucrypt-system can do that\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:39 #, c-format msgid "ERROR: could not create an encrypted volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:40 #, c-format msgid "ERROR: could not open volume for writing\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:41 #: ../../zuluCrypt-cli/bin/open_volume.c:104 #, c-format msgid "ERROR: there seem to be an opened mapper associated with the device\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:42 #, c-format msgid "ERROR: can not create a volume on a mounted device\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:43 #, c-format msgid "ERROR: container file must be bigger than 3MB\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:45 #: ../../zuluCrypt-cli/bin/remove_key.c:67 #, c-format msgid "ERROR: insufficient memory to hold your response\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:46 #: ../../zuluCrypt-cli/bin/remove_key.c:68 #, c-format msgid "INFO: operation terminated per user request\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:47 #, c-format msgid "ERROR: could not get passphrase in silent mode\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:48 #, c-format msgid "ERROR: insufficient memory to hold the passphrase\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:49 #: ../../zuluCrypt-cli/bin/create_volumes.c:57 #: ../../zuluCrypt-cli/bin/crypt_file.c:43 #, c-format msgid "ERROR: passphrases do not match\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:50 #: ../../zuluCrypt-cli/bin/open_volume.c:109 #, c-format msgid "ERROR: invalid path to key file\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:51 #, c-format msgid "ERROR: could not get a key from a key file\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:58 #, c-format msgid "ERROR: failed to create a volume" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:59 #, c-format msgid "ERROR: wrong argument detected for tcrypt volume" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:72 #, c-format msgid "" "\n" "creating a backup of the luks header is strongly adviced.\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:73 #, c-format msgid "" "Please read documentation on why this is important\n" "\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:210 #, c-format msgid "" "\n" "This operation will destroy all data in a device at: \"%s\"\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:211 #, c-format msgid "Are you sure you want to proceed?\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:212 #, c-format msgid "Type \"YES\" and press enter if you want to process: " msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:218 #: ../../zuluCrypt-cli/bin/remove_key.c:141 #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:272 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:300 msgid "YES" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:224 #: ../../zuluCrypt-cli/bin/crypt_file.c:109 #: ../../zuluCrypt-cli/bin/open_volume.c:287 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:169 #, c-format msgid "Enter passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:233 #: ../../zuluCrypt-cli/bin/crypt_file.c:118 #, c-format msgid "" "\n" "Re enter passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:296 #, c-format msgid "Enter tcrypt hidden passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:305 #, c-format msgid "" "\n" "Re enter tcrypt hidden passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:35 #, c-format msgid "SUCCESS: encrypted file created successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:36 #, c-format msgid "SUCCESS: decrypted file created successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:37 #, c-format msgid "ERROR: could not open key file for reading\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:38 #, c-format msgid "ERROR: missing key source\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:39 #, c-format msgid "ERROR: could not open encryption routines\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:40 #, c-format msgid "ERROR: file or folder already exist at destination address\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:41 #, c-format msgid "ERROR: invalid path to source\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:42 #, c-format msgid "ERROR: could not resolve path to destination file\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:44 #, c-format msgid "ERROR: destination path is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:45 #, c-format msgid "ERROR: insufficient privilege to create destination file\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:46 #, c-format msgid "ERROR: presented key did not match the encryption key\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:49 #, c-format msgid "ERROR: source path is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:50 #, c-format msgid "ERROR: insufficient privilege to open source file for reading\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:51 #, c-format msgid "INFORMATION: functionality currently disabled\n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:44 msgid "" "\tusage: zuluCrypt-cli < operation > < options specific to the operation >\n" "\tmeaning of symbols:\n" "\t<> = required option\n" "\t[] = optional argument\n" "\t* = default option\n" "\t| = alternatives for the same option\n" "\t{} = not allowed option\n" "\t\n" "\tzuluCrypt-cli -E \n" "\tzuluCrypt-cli -D \n" "\tzuluCrypt-cli -o [-e] \n" "\tzuluCrypt-cli -O {-m} [-e] \n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:58 msgid "" "\tzuluCrypt-cli -q \n" "\tzuluCrypt-cli -i \n" "\tzuluCrypt-cli -c [ktzg]\n" "\tzuluCrypt-cli -r \n" "\tzuluCrypt-cli -a < >|\n" "\tzuluCrypt-cli -b \n" "\tzuluCrypt-cli -w d argument must be something like: UUID=" "\"2468d6a7-9a71-4312-8bd9-662f982fade5\" ( or without quotes )\n" "\tzuluCrypt-cli -P d device must be mapper path at /dev/mapper/\n" "\tzuluCrypt-cli -X \n" "\tzuluCrypt-cli -J \n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:70 msgid "" "\tzuluCrypt-cli -R \n" "\tzuluCrypt-cli -B \n" "\tzuluCrypt-cli -A\n" "\tzuluCrypt-cli -S\n" "\tzuluCrypt-cli -N\n" "\texamples:\n" "\tcreate volume: zuluCrypt-cli -c -d /dev/sdc1 -z ext4 -t luks -p xxx\n" "\topen volume : zuluCrypt-cli -o -d /dev/sdc1 -m sdc1 -e ro -p xxx\n" "\tclose volume ; zuluCrypt-cli -q -d /dev/sdc1\n" "\tremove key ; zuluCrypt-cli -r -d /dev/sdc1 -p xxx\n" "\tadd key : zuluCrypt-cli -a -d /dev/sdc1 -y xxx -l yyy\n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:83 msgid "" "\tget device path from mapper : zuluCrypt-cli -P -d /dev/mapper/zuluCrypt-" "sdc1\n" "\tcheck if partition with UUID is present : zuluCrypt-cli -w -d UUID=" "\"d2d210b8-0b1f-419f-9172-9d509ea9af0c\"\n" "\toperation list\n" "\n" "\t--test run a test program\n" "\t-c create an encrypted volume\n" "\t-o open and encrypted volume\n" "\t-O open an encrypted volume but do not mount it( -m therefore not " "needed )\n" "\t-q close an opened encrypted volume\n" "\t-r remove a key from luks volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:94 msgid "" "\t-i check if a device contain a luks volume\n" "\t-s check if a device is opened and print its properties if it is\n" "\t-b show status of each slot of luks volume.\"0\"=empty," "\"1\"=occupied,\"2\"=invalid slot,\"3\"=last occupied\n" "\t-A print the list of all partitions on the system\n" "\t-N print a list of non system partitions on the system( partitions " "with no active entries in /etc/fstab and /etc/crypttab\n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:101 msgid "" "\t-T print a detailed list of mounted partitions.Must be used with -" "A or -S or -N\n" "\t-Z print a detailed list of unmounted partitions.Must be used with " "-A or -S or -N\n" "\t-S print a list of system partitions on the system( partitions " "with active entries in /etc/fstab and /etc/crypttab\n" "\t-w check if UUID matches UUID of any partition\n" "\t-P get device path from mapper( located at /dev/mapper )\n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:108 msgid "" "\t-L print a list of all opened volumes and their mount point.The " "list is not formatted\n" "\t-X open a device pointed by argument -d and write random data to " "it hiding data previously written to device\n" "\t-W check if a device is a truecrypt device or not,required " "argument are -p or -f\n" "\t-U print UUID of a given device,required argument: -d\n" "\t-H compare a header on a luks device to a backup header,required " "arg: -d and -f\n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:115 msgid "" "\t-M create a publicly accessible \"mirror\" of the mount point in " "\"/run/media/public/\" from the original\n" "\t\t created in \"/run/media/private/$USER/\"\n" "\t-a add a key to luks volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:120 msgid "" "\t-J create a plain mapper owned by the user who run the command on " "a device pointed by argument -d\n" "\t-B create a luks header backup\n" "\t-R restore a luks header on a device from backup\n" "\t-E encrypt a single file\n" "\t-D decrypt a single file\n" "\t\n" "\toptions that goes with above operations:\n" "\t-G \t module name to use to get a passphrase to open a volume\n" " " msgstr "" #: ../../zuluCrypt-cli/bin/help.c:130 msgid "" "\t-k do not ask for confirmation when doing dangerous operations\n" "\t-d path to a file or partition with encrypted volume\n" "\t-m path component to be added to mount point prefix(/run/media/" "private/$USER)\n" "\t-z file system type installed(ext2,ext3,ext4* etc)\n" "\t-t type of volume (plain/luks*)\n" "\t-g random number generator (/dev/random or /dev/urandom*)\n" "\t-h get passphrase interactively\n" "\t-p passphrase \n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:140 msgid "" "\t-f path to keyfile or luks header backup\n" "\t-y passphrase already in the volume(required by -a if -u is absent " "and -h is also absent)\n" "\t-n path to keyfile with a passphrase to be added (required by -a " "if -l is absent and -h is also absent)\n" msgstr "" #: ../../zuluCrypt-cli/bin/help.c:145 msgid "" "\t-u path to keyfile with passphrase already in the volume(required " "by -a if -y is absent and -h is also absent)\n" "\t\t truecrypt hidden volume passphrase from keyfile when used with -c\n" "\t-l passphrase to be added(required by -a if -n is absent and -h is " "also absent)\n" "\t\t truecrypt hidden volume passphrase when used with -c\n" "\t-e mode for opening volumes(ro*/rw) when used with -o/-O. path to " "destination file when used with -E/-D\n" "\t\t truecrypt hidden volume size when used with -c\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:50 #, c-format msgid "ERROR: could not get device address from mapper address\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:74 #, c-format msgid "device is a luks volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:76 #, c-format msgid "device is not a luks volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:90 #, c-format msgid "ERROR: key argument is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:94 #, c-format msgid "ERROR: key source argument is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:103 ../../zuluCrypt-cli/bin/main.c:116 #, c-format msgid "\"%s\" is a tcrypt device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:119 #, c-format msgid "\"%s\" is a not tcrypt device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:125 ../../zuluCrypt-cli/bin/main.c:132 #, c-format msgid "\"%s\" is not a tcrypt device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:151 #, c-format msgid "device \"%s\" is not a luks device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:177 #, c-format msgid "ERROR: insufficient privilges to operate on a system device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:186 #, c-format msgid "header backup match the one on the device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:189 #, c-format msgid "header backup does not match the one on the device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:217 #, c-format msgid "ERROR!!!!!!!!!!: cli option missed!\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:238 #, c-format msgid "unexpected exiting because you have run out of memory\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:331 msgid "ERROR: setgroups() failed" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:334 msgid "ERROR: setegid() failed" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:478 msgid "ERROR: \"action\" argument is missing" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:481 msgid "ERROR: required option( device path ) is missing for this operation" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:508 msgid "ERROR: could not find any partition with the presented UUID" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:516 msgid "ERROR: devices in /dev/shm/ path is not suppored" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:517 msgid "ERROR: given path is a directory" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:518 msgid "ERROR: a file can have only one hard link" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:519 msgid "ERROR: insufficient privilges to access the device" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:520 msgid "" "ERROR: a non supported device encountered,device is missing or permission " "denied\n" "Possible reasons for getting the error are:\n" "1.Device path is invalid.\n" "2.The device has LVM or MDRAID signature" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:531 msgid "ERROR: could not resolve path to device" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:75 #: ../../zuluCrypt-cli/bin/open_volume.c:77 #: ../../zuluCrypt-cli/bin/open_volume.c:79 #, c-format msgid "SUCCESS: %s volume opened successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:81 #, c-format msgid "SUCCESS: volume opened successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:86 #, c-format msgid "volume mounted at: %s\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:94 #, c-format msgid "" "ERROR: failed to mount ntfs file system using ntfs-3g,is ntfs-3g package " "installed?\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:95 #, c-format msgid "ERROR: there seem to be an open volume accociated with given address\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:96 #, c-format msgid "ERROR: no file or device exist on given path\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:97 #, c-format msgid "ERROR: volume could not be opened with the presented key\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:98 #, c-format msgid "ERROR: insufficient privilege to mount the device with given options\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:99 #, c-format msgid "" "ERROR: insufficient privilege to open device in read write mode or device " "does not exist\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:100 #, c-format msgid "ERROR: only root user can perform this operation\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:101 #, c-format msgid "ERROR: -O and -m options can not be used together\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:102 #, c-format msgid "" "ERROR: could not create mount point, invalid path or path already taken\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:103 #, c-format msgid "ERROR: shared mount point path aleady taken\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:105 #, c-format msgid "ERROR: could not get a passphrase from the module\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:106 #, c-format msgid "ERROR: could not get passphrase in sikey_lent mode\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:110 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:74 #, c-format msgid "ERROR: could not get enought memory to hold the key file\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:112 #, c-format msgid "ERROR: could not get a passphrase through a local socket\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:113 #, c-format msgid "" "ERROR: failed to mount a filesystem:invalid/unsupported mount option or " "unsupported file system encountered\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:114 #, c-format msgid "ERROR: could not create a lock on /etc/mtab\n" msgstr "" #: ../../zuluCrypt-cli/bin/partitions.c:523 #, c-format msgid "ERROR: unable to print requested list of partitions\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:61 #, c-format msgid "SUCCESS: key removed successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:62 #, c-format msgid "ERROR: there is no key in the volume that match the presented key\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:63 #, c-format msgid "ERROR: could not open the volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:64 #, c-format msgid "" "ERROR: insufficient privilege to open a system device,only root user or " "members of group zulucrypt-system can do that\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:66 #, c-format msgid "ERROR: could not open the volume in write mode\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:72 #, c-format msgid "ERROR: keyfile does not exist\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:73 #, c-format msgid "ERROR: could not get enough memory to open the key file\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:135 #, c-format msgid "" "WARNING: there is only one key in the volume and all data in it will be lost " "if you continue.\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:136 #, c-format msgid "Do you still want to continue? Type \"YES\" if you do: " msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:149 #, c-format msgid "Enter a key to be removed: " msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:39 #, c-format msgid "SUCCESS: header saved successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:40 #, c-format msgid "SUCCESS: header restored successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:41 #, c-format msgid "ERROR: presented device is not a LUKS device\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:42 #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:43 #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:46 #, c-format msgid "ERROR: failed to perform requested operation\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:44 #, c-format msgid "INFO: operation terminater per user request\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:45 #, c-format msgid "" "ERROR: path to be used to create a back up file is occupied or permission " "denied\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:47 #, c-format msgid "ERROR: insufficient privilege to open backup header file for reading\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:48 #, c-format msgid "ERROR: invalid path to back up header file\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:49 #, c-format msgid "" "ERROR: insufficient privilege to create a backup header in a destination " "folder\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:50 #, c-format msgid "ERROR: invalid path to device\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:51 #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:52 #, c-format msgid "ERROR: argument for path to a backup header file is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:53 #, c-format msgid "" "ERROR: only root and \"zulucrypt\" group members can restore and back up " "luks headers on system devices\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:54 #, c-format msgid "ERROR: insufficient privilege to open device for writing\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:55 #, c-format msgid "ERROR: could not resolve path to device\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:56 #, c-format msgid "ERROR: backup file does not appear to contain luks header\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:57 #, c-format msgid "ERROR: insufficient privilege to open device for reading\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:58 #, c-format msgid "ERROR: insufficient memory to hold your responce\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:262 #, c-format msgid "" "Are you sure you want to replace a header on device \"%s\" with a backup " "copy at \"%s\"?\n" "Type \"YES\" and press Enter to continue: " msgstr "" #: ../../zuluCrypt-cli/bin/volume_info.c:48 #, c-format msgid "" "ERROR: could not get volume properties,volume is not open or was opened by a " "different user\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:60 #, c-format msgid "SUCCESS: mapper created successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:63 #, c-format msgid "opened mapper path: " msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:67 #, c-format msgid "ERROR: could not create mapper\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:68 #, c-format msgid "ERROR: could not resolve device path\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:69 #, c-format msgid "" "\n" "SUCCESS: random data successfully written\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:70 #, c-format msgid "INFO: user chose not to proceed\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:71 #, c-format msgid "ERROR: insufficitied privilege to oped device \n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:72 #, c-format msgid "ERROR: device path is invalid\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:73 #, c-format msgid "ERROR: passphrase file does not exist\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:76 #, c-format msgid "ERROR: can not open a mapper on a device with an opened mapper\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:77 #, c-format msgid "ERROR: can not open a mapper on a mounted device\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:78 #, c-format msgid "INFO: signal caught,exiting prematurely\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:81 #, c-format msgid "ERROR: insufficient memory to hold 3 characters?really?\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:82 #, c-format msgid "ERROR: insufficient privilege to open the file with your privileges?\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:293 #, c-format msgid "" "\n" "WARNING, device \"%s\" will be overwritten with random data destroying all " "present data.\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:294 #, c-format msgid "" "Are you sure you want to proceed? Type \"YES\" and press enter if you are " "sure: " msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:331 msgid "percentage complete: " msgstr "" zuluCrypt-6.2.0/translations/zuluCrypt/pl_PL.ts000066400000000000000000007726631425361753700217220ustar00rootroot00000000000000 DialogMsg Dialog &Ok &Yes &No text type cipher key size device loop offset size mode fs used unused used % active slots "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. INFORMATION Insufficient privilege to access a system device, only root user or members of group zulucrypt can do that Insufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that You do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again type: cipher: keysize: offset: device: loop: mode: active slots: file system: total space: used space: free space: used%: UUID: Do not show this dialog again PasswordDialog Open Encrypted Volume &Open &Cancel Mount In &Read Only Mode select mount point path open volume path open key file Password LUKS/TrueCrypt/BitLocker Mount Name Volume Path KeyFile Key+KeyFile Plugin &Share Mount Point VeraCrypt VeraCrypt System PLAIN dm-crypt Volume Type TextLabel &OK QObject zuluCrypt: Failed To Establish Connection With zuluPolkit options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI If the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2" public mount point: Manage Favorites Mount All about zuluCrypt hmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents) keykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contents gpg plugin. This plugin retrives a key locked in a gpg file with a symmetric key Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit. ERROR Failed to locate pkexec executable "%1" and "%2" Folders Must Be Writable. Could not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin" Network Request Failed To Respond Within %1 Seconds. Failed To Check For Update. Installed Version Is : %1. Latest Version Is : %2. Update Available Version Info createVolumeDialog Warning!! &Yes &No This operation will lead to permanent destrunction of all present data in /dev/sdc1. Are you sure you want to continue? This operation will lead to permanent destrunction of all present data in "%1". Are you sure you want to continue? It is advised to create encrypted containers over random data to prevent information leakage. Do you want to write random data to "%1" first before creating an encrypted container in it? You can stop the random data writing process anytime you want if it takes too long and you can no longer wait. createVolumeInExistingFIle Create Volume In Existing File Select Cover File (Video files like mp4 and mkv) Container Size (MB) Volume Properties &Cancel C&reate Volume OffSet (Auto calculated) Create A Plain dm-crypt Container Hidden Inside Cover File (Steganography) Password TextLabel Extending A Host File Size. Enter Path To Existing File Average Speed: ETA: Percentage Completed: %1% ERROR AtLeast One Required Field Is Empty Illegal Character Found In The Container Size Field Failed To Open File In Write Mode Failed To Open "/dev/urandom" Device In Read Mode Creating A Plain DM-Crypt Volume Volume Created Successfully Failed To Create A Volume createfile Create A Container File File Name File Path File Size open a folder dialog box &Cancel % Complete C&reate KB MB GB Do Not Write Random Data To Container(STRONGLY discouraged) TextLabel &OK By default,zuluCrypt creates a volume in a container file over randomly generated data to hide usage patterns of the container. This process takes time and it may take a very,very long time if the volume about to be created is large enough and this option exists to skip the process for the impatient among us but but it comes at a cost and the cost may be too high when it finally reveal itself while infront of an adversary when they look at the encrypted container and manage to derive meaning based on how the container looks from outside. If you know what you are doing,then continue by all means,if in doubt,my advise is to endure the process and be safer in the long run. INFO File name field is empty File path field is empty File size field is empty WARNING Are you really sure you do not want to create a more secured volume? Illegal character in the file size field.Only digits are allowed File with the same name and at the destination folder already exist You dont seem to have writing access to the destination folder Container file must be bigger than 3MB Failed to create volume file Failed to enable polkit support Operation terminated per user choice Could not open cryptographic back end to generate random data Terminating file creation process Are you sure you want to stop file creation process? Average Speed: ETA: Select Path to where the file will be created createkeyfile Create A KeyFile Keyfile Name path to a folder to create a key in open a folder a key file will be created in C&reate &Cancel KeyFile Path RNG TextLabel &OK The key name field is empty Folder path to where the key will be created is empty File with the same name and at the destination folder already exist You dont seem to have writing access to the destination folder Process interrupted,key not fully generated KeyFile successfully created Select A Folder To Create A Key File In createvolume Create A New Volume Path to Device C&reate &Cancel open a key file Key Password Repeat Password Volume Type Volume Size Bytes KiloBytes MegaBytes GigaBytes Volume Options File System random number generator RNG PIM TextLabel Options are separated by a "." character. Multiple algorithms are separated by ":" character. Options are in a format of "algorithm.cipher mode.key size in bits.hash" Default option is the first entry on the list KeyFile Key+KeyFile PLAIN dm-crypt PLAIN dm-crypt with offset LUKS1 LUKS1+External Header LUKS2 LUKS2+External Header LUKS LUKS+External Header Normal TrueCrypt Normal+Hidden TrueCrypt Normal VeraCrypt Normal+Hidden VeraCrypt Passphrase Quality: 0% Passphrase Quality: %1% TrueCrypt Keys VeraCrypt Keys Volume Offset Path To Device Path To File Keyfile Path Passphrase Quality: 100% Keys ERROR! Failed to enable polkit support Volume path field is empty Atleast one required field is empty Illegal character detected in the hidden volume size field Hidden passphrases do not match WARNING It is best to create a hidden volume with vfat/fat file system. Passphrases do not match Please be patient as creating a VeraCrypt volume may take a very long time. WARNING! Volume created successfully but failed to create an external header SUCCESS! Luks volume created successfully. Luks volume created successfully,external header created successfully but failed to erase header on the device Volume created successfully. Creating a backup of the "%1" volume header is strongly advised. Please read documentation on why this is important. Presented file system is not supported,see documentation for more information insufficient privilege to open a system device in read/write mode, only root user or members of group zulucrypt can do that Could not create an encrypted volume Could not open volume for writing There seem to be an opened mapper associated with the device Can not create a volume on a mounted device Container file must be bigger than 3MB %1 not found Insufficient memory to hold your response Operation terminated per user request Could not get passphrase in silent mode Insufficient memory to hold the passphrase Invalid path to key file Could not get a key from a key file Couldnt get enought memory to hold the key file Could not get a key from a socket One or more required argument(s) for this operation is missing Can not get passphrase in silent mode Insufficient memory to hold passphrase Failed to create a volume Wrong argument detected for tcrypt volume Could not find any partition with the presented UUID Error Code: %1 -- StdOut: %2 -- StdError: %3 cryptfiles Destination C&reate Source Password Repeat Password TextLabel &OK Key KeyFile Key+KeyFile Repeat Key &Cancel % Complete Create An Encrypted Version Of A File Create A Decrypted Version Of An encrypted File Path to source field is empty Invalid path to source file Destination path already taken You dont seem to have writing access to the destination folder Invalid path to key file First key field is empty Second key field is empty Keys do not match These very old encrypted files are no longer supported Select Path to put destination file Enter A Key Enter A Path To A Keyfile Location keyfile path Generate a key made up of a passphrase and a keyfile Select A File You Want To Encrypt zuluCrypt encrypted files ( *.zc ) ;; All Files ( * ) Select A File You Want To Decrypt Select A Keyfile Encrypted file created successfully Decrypted file created successfully Could not open keyfile for reading Could not open encryption routines File or folder already exist at destination address Insufficient privilege to create destination file Presented key did not match the encryption key Operation terminated per user request Insufficient privilege to open source file for reading Decrypted file created successfully but md5 checksum failed,file maybe corrupted Could not open reading encryption routines Could not open writing encryption routines Failed to close encryption routine cryptoinfo Greetings Ok Please consult "menu->help->open zuluCrypt.pdf" to get an introduction on zuluCrypt. Unity users,the menu is on the upper left corner of the screen when zuluCrypt has focus. Project's homepage is at: https://mhogomchungu.github.io/zuluCrypt Recommending reading FAQ page from the project's main page. Do not show this message again. debugWindow zuluCrypt Debug Window C&lear &Close dialogok Dialog &Ok TextLabel &Yes &No erasedevice Erase Data On The Device By Writing Random Data Over Them Path to Device % Completed &Start &Cancel Average Speed ETA N/A TextLabel &OK Write Random Data Over Existing Data The next dialog will write random data to a device leading to permanent loss of all contents on the device. Are you sure you want to continue? WARNING Average Speed: Total Time: Data on the device successfully erased Could not create mapper Could not resolve device path Random data successfully written Operation terminated per user choice Can not write on a device with opened mapper Policy prevents non root user opening mapper on system partition Device path is invalid Passphrase file does not exist Could not get enought memory to hold the key file Insufficient privilege to open key file for reading This device appear to already be in use Can not open a mapper on a mounted device Could not write to the device Device path field is empty Invalid path to device Are you really sure you want to write random data to "%1" effectively destroying all contents in it? WARNING! Failed to enable polkit support Writing Random Data Over Existing Data Enter Path To Volume To Be Erased Select A Non System Partition To Erase Its Contents favorites Manage Favorites &Add Volume ID Mount Point open partition dialog open file dialog &Done Remove Selected Entry Cancel ERROR! Device address field is empty Mount point path field is empty Path To An Encrypted Volume fileManager Set File Manager TextLabel &Set Enter Below The Name Of The Application You Want To Be Used To Open Mount Points. help Help &Close <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt;">ZuluCrypt is a simple, feature rich and powerful solution for hard drives encryption for linux.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt supports LUKS, TrueCrypt, VeraCrypt and PLAIN dm-crypt encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These supported encrypted volumes may resides in image files, hard drives and usb sticks, LVM</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volumes as well as in mdraid devices.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of encrypted volumes. Those that use what is commonly know as “a header†and</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">those that do not. TrueCrypt, VeraCry and LUKS volumes use a header. PLAIN dm-crypt volumes do</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">not use a header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a &quot;volume header&quot;.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">The damage to the header is usually caused by accidental formatting of the device or use of</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">some buggy partitioning tools or wrongly reassembled logical volumes.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack'; color:#008000;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of header using encrypted volumes. Those that use an encrypted header and those</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">that do not. TrueCrypt and VeraCrypt use an encrypted header whereas LUKS does not. The use of non</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted header in LUKS makes it obvious to everybody that the volume is an encrypted LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may be problematic to some people. How big the problem may be depends on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">person and their use case for hard drive encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The use of encrypted header as in TrueCrypt or VeraCrypt volumes or no header at all as in PLAIN dm-</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">crypt volumes make these volumes indistinguishable from random noise and this may seem useful at a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">glance but its usefulness may not hold up against scrutiny as the likelihood of being believed that a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">100GB file made up of cryptographically sound random data is just a 100GB file made up of random</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data and not a container file for an encrypted volume is not very high.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With LUKS, TrueCrypt and VeraCrypt volumes, it is very important to have a volume header backup</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">since a valid header is required to unlock the volume. A corrupted or missing header will make the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume unusable causing the loss of all encrypted data.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">LUKS stands for “Linux Unified Key Setupâ€. It is a specification of how to store information necessary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to open a LUKS formatted encryption volume. LUKS encryption format is the standard format in linux</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and a recommended one if the encrypted volume is to be used among linux systems. TrueCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt volumes are better alternative if the encrypted volume is to be shared between linux,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">windows and OSX computers.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can create and open 5 types of encrypted volumes, LUKS, TrueCrypt, VeraCrypt,PLAIN</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dm-crypt and PLAIN dm-crypt volume at a none zero offset. PLAIN dmcrypt volume is a header less</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume and all necessary encryption information is provided by zuluCrypt when it creates or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open these volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; text-decoration: underline;">Pros and cons of the five volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt; text-decoration: underline;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It does not use a volume header and hence its not possible to “brick†the entire volume simply by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over writing a small part of it.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It does not use a header and hence its impossible to know if the volume is made up of only</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">cryptographically sound random data or if its an encrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It does not use a header and hence any tool that opens these volumes must provide the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options that were used when the volume was created. Different tools may use different encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options making these encrypted volumes not very portable between applications or even between</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">different versions of the same application.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt at a none zero offset.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This volume has the same pros and cons as those of a PLAIN dm-crypt volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional pro for this volume is that it can be places anywhere on the device making it possible</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to have this volume on top of any one of the other supported encrypted volume or on top of an</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">unencrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For example, its possible to have an X MB drive that has unencrypted file system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">at the beginning of the device and a “PLAIN dm-crypt volume with an offset†somewhere towards the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">end of the device making it possible to use the drive as unencrypted volume and as encrypted volume</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">simultaneously depending on sensitivity of the data to be stored on the device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this volume type is to be used, preceding part of the drive should be formatted in “FAT†family of file systems.This volume types gives a “hidden volume†type functionality offered by TrueCrypt and VeraCrypt. When creating or unlocking this volume type, the starting offset of the volume will be asked and NOT the volume size as TrueCrypt and VeraCrypt does with the hidden volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above means, if you have a 100 MB drive and you want to create a 30MB “PLAIN dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume at a none zero offsetâ€, you will enter the starting offset of the volume as 70MB. In VeraCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt, you will enter the hidden volume size of 30MB. The starting offset and the size of the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hidden volume are related by a simple formula: starting offset(70MB) = device size(100MB) – hidden</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume size(30MB).</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TrueCrypt</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and hence its not possible to know if the volume is TrueCrypt formatted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume or if the volume is just made up of cryptographically sound random data.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Hidden volume. A TrueCrypt volume can have up to two different encrypted volumes. The first</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume is commonly know as “outer volume†and the second optional one is commonly known as</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“hidden volumeâ€.When a TrueCrypt volume is about to be opened, the user has an option to select</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">which one of the two to open by giving appropriate key.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and it is not possible to open the volume without a valid header. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">use a TrueCrypt volume, make sure you have at least one backup of the volume header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VeraCrypt</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt is an extension of TrueCrypt and it shares the same TrueCrypt’s pros and cons.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Pro for VeraCrypt over TrueCrypt.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It requires stronger effort to unlock VeraCrypt volume and this makes them more secure over</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt volumes.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Cons for VeraCrypt over TrueCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It requires stronger effort to unlock a VeraCrypt volume and this increases the time it takes to unlock</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a VeraCrypt volume. How long it will take depends on the strength of the computer and it may vary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from a few seconds to several minutes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS volume can be opened with up to 8 different keys.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS header is stored unencrypted making it obvious the volume is LUKS formatted encrypted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may not be desirable under certain circumstances. It is possible to create a LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume with a detached header and zuluCrypt can open these volumes using “luks†plugin.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It uses a header. As it is not possible to open a header using encrypted volume without its header, a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">corrupted LUKS header makes it impossible to open the volume. If you use a LUKS volume, make</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sure you have at least one backup of the volume header.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can do two types of encryption. It can do single file encryption/decryption or block device</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">File encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can encrypt and decrypt individual files. This feature is useful when a user just wants to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt a single file and taking the route of creating an encrypted container file to host the file is seen</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as an unnecessary hassle. This functionality is akin to file encryption using gpg with a symmetric key.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">File encryption is done using libgcrypt as a cryptographic backend. Files are encrypted using 256 bit</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">AES in CBC mode. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The encryption key is derived from user pass phrase using pbkdf2 with 10,000</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">rounds of iterations and sha2 as a cryptographic hash function. The resulting encrypted file will have a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file size that equals (64 + 1024 * n) bytes where n is a number starting from zero.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted file:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;encrypt a file†to open a file encryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to store encrypted, enter the password to be used to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt the file and then click “create†and the encrypted version of the file will be created at the path</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by “destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">To decrypt the file created with above steps:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;decrypt a file†to open a file decryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to decrypt, enter the password to be used to decrypt the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file and then click “create†and the decrypted version of the file will be created at the path given by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Block device encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A hard drive or a usb stick are two examples of block devices. A regular file can simulate a block</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">device through a use of devices known as “loop devicesâ€. These devices have a device path that starts</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">with “/dev/loopâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The infrastructure in the linux kernel that deal with block device encryption is called “dm-crypt†and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does its work through a process commonly known as OTF(on the file encryption). Dm-crypt devices</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">are represented by device addresses that starts with “/dev/dm-†and these paths are usually accessed</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">through their soft links that reside in “/dev/mapperâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Below is an example of steps taken in creating a 100MB encrypted container in a file and adding a file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">in it to be stored securely.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Create a 100MB file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Attach a loop device to the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Create an OTF encryption mapper against the loop device.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Put a file system on the encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Mount the file system on the mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Copy The file to be stored securely to the file system through the mount point.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Unmount the file system.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Destroy the OTF encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Detach the loop device from the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">10. Maintain the encrypted volume as a secure holder of files within it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All zuluCrypt does is provide a GUI to make it easy to do above specified tasks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With the above steps:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 1 deal with a path that look like “/home/ink/secret.imgâ€, this is a path to a regular file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 2 converts “/home/ink/secret.img†file to something like “/dev/loop0†loop device path.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 3 converts “/dev/loop0†loop device path to something like “/dev/mapper/secrets.imgâ€. Data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">written to “/dev/mapper/secrets.img†will get encrypted and then passed forward to “/dev/loop0†on its</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">way to “/home/ink/secret.imgâ€. When data is read from “/dev/mapper/secrets.imgâ€, the data will be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">read from “/dev/loop0†who in turn will read it from “/home/ink/secret.imgâ€, decrypted by dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then given to the reader. This process is called “on the fly encryption†because the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mapper does not store or hold on to data, it gets data and then encrypts or decrypts it depending on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">direction of data flow and then passes it along.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in an image file.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a file†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Enter the name of the file to be used to hold the container in the “file name†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the size of the container in the “file size†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Click “createâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Wait for the container file to be created and for the volume creation dialog to show up.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Enter the password to be used to create the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Select the type of volume you want to create from the “volume type†list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Click create to create the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in a partition.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a hard drive†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Click/double click on the hard drive you want to create a volume in and then advance to instruction</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">number 7 in the instruction list above. If the partition you want to put an encrypted container does not</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">show up on the list, then restart zuluCrypt from root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a file using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a file†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click the button to the right of “volume path†field and then browse to where</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the volume is and click it to open it. Alternatively, you can just drag the volume file on zuluCrypt to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">generate a password dialog prompt with the file path already filled in.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a partition using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a partition†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click/double click on the partition with an encrypted volume you want to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With both two steps above, the volume will be opened and mounted at a path whose last component is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by the entry in the field “mount nameâ€. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When the volume is successfully opened, zuluCrypt will</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">automatically open the mount point path. To close the volume, click its entry on the zuluCrypt window</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then click “close†on the pop up window.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can open an encrypted volume using keys derived from different sources. These sources</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">include, a pass phrase, a key file, a key retrieved from kwallet, a key retrieved from Gnome's libsecret,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a key retrieved from an internal secure storage system, a key from gpg encrypted key file among other</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sources.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a pass phrase volume key, make sure the key source option read “key†and then enter the pass</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phrase on the entry field at the bottom.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a keyfile as the source of volume key, click the option bar and then select “keyfile†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring a dialog box that will allow you to browse to where the key</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file is.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a plugin as the source of volume key, click the option bar and then select “plugin†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring up a list of available plugins and then select the one you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want from the list.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Volume keys stored in kwallet, Gnome keyring or internal secure storage system plugins can be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">managed by going to “menu-&gt;options-&gt;manage volumes in internal/kde/gnome walletâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Storage of keys in a gnome wallet/keyring seem most appropriate in a gnome session but this has some security repercussions, the keys are stored in the user keyring and this keyring gets unlocked when the user logs in. This means that once a user is logged in and the keyring is open, any application that runs in that user session can read those keys using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In a kde system, a kwallet secure storage system seem most appropriate but it suffers from the same</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">security problem the gnome secure storage system has, once the wallet is open, any application running in the user session can access it using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The behaviors of the above secure storage systems is by design but this design may not be ideal for</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">some users under certain use cases. The internal secure storage system is powered by libgcrypt and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does not have the behavior of the above two systems. An unlocked internal secured storage system is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">accessible only to the instance of zuluCrypt that unlocked it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Favorites.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For convenience, most used volumes can be easily opened by adding them to the favorite list. Entries</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">on the list are added in the dialog window opened by clicking “menu-&gt;options-&gt;manage favoritesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Favorite entries are added by clicking the “favorite†entry on the menu.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Erase data in a device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It is very important to create encrypted volume over cryptographically strong random data to make it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">impossible to know what part of the encrypted volume has been used and what part has not. If the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume is created over predictable data patterns like on a device with only zeros in it,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">forensic analysis may reveal how much and what part of the encrypted volume are in use.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When creating an encrypted container in a device, zuluCrypt offers an option to first write random data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over the device. This feature can be performed on other devices by activating it through “menu-&gt;erase</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data in a deviceâ€. Random data are written to disk by opening a plain dm-crypt encryption mapper on</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the device with a 64 byte random key and then blasting zeros on the device through the mapper. This</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">technique has proven to be faster compared to alternatives like writing random data on the device read</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from “/dev/urandomâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">System and non system volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To enforce access controls on what user can access what block device and what they can do with the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">access they have, zuluCrypt employes a concept of “system volumes†and “non system volumesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A system volume is defined as a volume that has an active entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/fstabâ€,â€/etc/crypptabâ€,“/etc/zuluCrypt/system_volumes.list†or if udev identify it as such if udev</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">is enabled. Ideally, all volumes inside the computer are to be considers system volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A non system volume is a volume that failed in the above considerations or if it has an entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/zuluCrypt/non_system_volumes.listâ€. Ideally, these volumes are plug gable usb based hard drives</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">or usb sticks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Partitions can be added or removed from the list of system or non system volumes simply by starting</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zuluCrypt from root's account and then going to “menu-&gt;options-&gt;manage system volumes/manage</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">non system volumes†and then adding the volume in the appropriate list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Permissions.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt limits what a user can do on block devices through unix's group based permission system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">using two groups, “zulucrypt†and “zulumountâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, only a root user or a user who is a member of group</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“zulucrypt†can create an encrypted volume in the device or taking/restoring volume headers. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want to create a volume in a device and the device does not show up on the list, restart zuluCrypt from</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, zuluMount will mount it only if the user is root, is a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">member of group “zulumount†or the device has an entry in “/etc/fstab†with either “user†or “usersâ€</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mount options set.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ZuluMount.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount is a general purpose mounting tool that can open zuluCrypt supported encrypted volumes</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as well as non encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also auto detect plugged in devices and auto mount them.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also unlock encfs volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2015-2017 Francis Banyikwa, mhogomchungu@gmail.com</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Open &PDF WARNING! Failed to open zuluCrypt.pdf,make sure your system can open pdf files using "%1" tool and try again luksaddkey Add A Key To A Volume Volume Path open file open partition Key LUKS TrueCrypt VeraCrypt Volume Type PIM TextLabel open keyfile Password Already In The Encrypted Volume Password To Be Added To The Encrypted Volume Reenter Password Password KeyFile Key+KeyFile YubiKey Challenge/Response &OK &Add &Cancel Passphrase Quality: 0% Passphrase Quality: %1% Enter A Key Enter a path to a keyfile location KeyFile Path Enter a key KeyFile path Passphrase Quality: 100% Existing KeyFile New KeyFile Encrypted Volume Path ERROR! Atleast one required field is empty Failed to enable polkit support Keys do not match Failed To Locate Or Run Yubikey's "ykchalresp" Program. Key added successfully. Key added successfully. %1 / %2 slots are now in use Presented key does not match any key in the volume Could not open luks volume Volume is not a luks volume Insufficient privilege to add a key to a system device, only root user or members of group "zulucrypt" can do that Could not open volume in write mode All key slots are occupied, can not add any more keys Can not get passphrase in silent mode Insufficient memory to hold passphrase New passphrases do not match One or more required argument(s) for this operation is missing One or both keyfile(s) does not exist Insufficient privilege to open key file for reading Couldnt get enought memory to hold the key file Could not get a key from a socket Could not get elevated privilege,check binary permissions Can not find a partition that match presented UUID Device is not a luks device Error Code: %1 -- StdOut: %2 -- StdError: %3 luksdeletekey Remove A Key From A Volume Password open a keyfile &Delete &Cancel Volume Path open an encrypted file open an encrypted partition TextLabel &OK Key KeyFile Key+KeyFIle Enter a key Enter a path to a keyfile location KeyFile path Key File With A Passphrase To Delete ERROR! Atleast one required field is empty Failed to enable polkit support Volume is not a luks volume There is only one last key in the volume. Deleting it will make the volume unopenable and lost forever. Are you sure you want to delete this key? WARNING Key removed successfully. %1 / %2 slots are now in use YubiKey Challenge/Response Failed To Locate Or Run Yubikey's "ykchalresp" Program. There is no key in the volume that match the presented key Could not open the volume Insufficient privilege to open a system device,only root user or members of group zulucrypt can do that Could not open the volume in write mode Insufficient memory to hold your response Operation terminated per user request Can not get passphrase in silent mode Insufficient memory to hold passphrase One or more required argument(s) for this operation is missing Keyfile does not exist Could not get enough memory to open the key file Insufficient privilege to open key file for reading Could not get a key from a socket Can not find a partition that match presented UUID Error Code: %1 -- StdOut: %2 -- StdError: %3 manageSystemVolumes Manage System Volumes &Done Add Fi&le Add Dev&ice Path To System Volumes Remove Selected Entry Cancel Are you sure you want to remove "%1" from the list? WARNING Select Path To System Volume managevolumeheader Backup Volume Header Backup Name C&reate &Cancel Volume Path Window System Volume Volume Type Manage A VeraCrypt Header PIM Password Password Source Outer Volume Password ONLY KeyFile TextLabel Normal Volume Whole Drive Encrypted Volume Manage A LUKS Header Manage A TrueCrypt Header Restore volume header &Restore Back up volume header &Backup Select A File With A LUKS Backup Header Select A Folder To Store The Header ERROR! Atleast one required field is empty Failed to enable polkit support Are you sure you want to replace a header on device "%1" with a backup copy at "%2"? WARNING! Select luks container you want to backup its header SUCCESS Header saved successfully. If possible,store it securely. Header restored successfully Presented device is not a LUKS device Failed to perform requested operation INFO! Operation terminater per user request Path to be used to create a back up file is occupied Insufficient privilege to open backup header file for reading Invalid path to back up header file Insufficient privilege to create a backup header in a destination folder Invalid path to device Argument for path to a backup header file is missing Only root user and "zulucrypt" members can restore and back up luks headers on system devices Insufficient privilege to open device for writing Could not resolve path to device Backup file does not appear to contain luks header Insufficient privilege to open device for reading Wrong password entered or volume is not a truecrypt volume Failed to perform requested operation on the LUKS volume Wrong password entered or volume is not a veracrypt volume Unrecognized ERROR! with status number %1 encountered oneinstance Previous instance seem to have crashed,trying to clean up before starting There seem to be another instance running,exiting this one openvolume Select A Partition To Open Use UUID &Help Use &UUID &Cancel partition size label type uuid &Open A list of all partitions on this system are displayed here. Double click an entry to use it Restart the tool from root's account or after you have created and added yourself to group "zulucrypt" if the volume you want to use is not on the list. You are a root user and all partitions are displayed. Double click an entry to use it INFO Select A Partition To Create An Encrypted Volume In Select An Encrypted Partition To Open ERROR Only crypto_LUKS volumes can be selected passwordDialog TrueCrypt/VeraCrypt Keys Check This Box To Make Password Visible Unlock Encrypted Volume PIM Value Offset Offset Will Be In Sectors If The Entry Is Made Up Of Only Digits And In Bytes If The Entry Ends With "b" And In Kilobytes If The Entry Ends With "k" And In Megabytes If The Entry Ends With "m" And In Terabytes If The Entry Ends With "t" Cancel Mount "%1" Choose A Module From The File System Enter A Module Name To Use To Get Passphrase Plugin Name Password Select A Key Module Enter A Key YubiKey Challenge/Response Choose A KeyFile From The File System Enter A Path To A Keyfile Location KeyFile Path Select A KeyFile Select Path To Mount Point Folder Select Encrypted volume ERROR! Internal wallet is not configured The volume does not appear to have an entry in the wallet ERROR Failed To Locate Or Run Yubikey's "ykchalresp" Program. Atleast one required field is empty "/" character is not allowed in mount name field Volume is not a LUKS volume Failed to get a key from the network Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? There seem to be an open volume accociated with given address No file or device exist on given path Volume could not be opened with the presented key Insufficient privilege to mount the device with given options Insufficient privilege to open device in read write mode or device does not exist Only root user can perform this operation -O and -m options can not be used together Could not create mount point, invalid path or path already taken Shared mount point path already taken There seem to be an opened mapper associated with the device Could not get a passphrase from the module Could not get passphrase in silent mode Insufficient memory to hold passphrase One or more required argument(s) for this operation is missing Invalid path to key file Could not get enought memory to hold the key file Insufficient privilege to open key file for reading Could not get a passphrase through a local socket Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered Could not create a lock on /etc/mtab Insufficient privilege to open a system volume. Consult menu->help->permission for more informaion A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature Error Code: %1 -- StdOut: %2 -- StdError: %3 plugin Key Generator Using A Passphrase And A KeyFile &Set Key &Cancel Create an encryption key that is made up of a passphrase and a keyfile. A volume created with a key generated here should be opened with "hmac" plugin. Passphrase KeyFile ERROR KeyFile Not Set Failed To Generate Key readOnlyWarning WARNING Do Not Show This Message Again. Setting this option will cause the volume to open in read only mode. &Ok tcrypt TrueCrypt Keys &Open &Cancel Add &Keyfile drag and drop key files to add them to the list Keyfile Paths Enter key files below to be used to open the volume Enter A Passphrase Below To Be Used To Open The Volume &Set TrueCrypt/VeraCrypt Keys ERROR At least one keyfile is required Select A KeyFile utility::veraCryptWarning Elapsed time: 0 seconds Elapsed time: %0 minutes Elapsed time: %0 seconds Please be patient as unlocking a VeraCrypt volume may take a very long time. walletconfig Manage Volumes In A Wallet &Add &Delete Do&ne Volume ID Comment Delete Entry WARNING! Are you sure you want to delete a volume with an id of "%1"? ERROR! Failed To Add the Key In The Wallet. walletconfiginput Add An Entry To Wallet &Add &Cancel Volume ID Comment Key Repeat Key ERROR! Atleast one required field is empty Passphrases do not match Select A Volume warnWhenExtendingContainerFile WARNING!! OK Dont Show This Warning Again. Your cover file will be irreversibly changed and we suggest continuing with a backup file and not the original. To unlock the volume about to be created, you will need to enter the password you will choose and the volume offset automatically generated by zuluCrypt. Instructions to unlock the volume are as follows: 1. From the menu, choose Open -> Volume Hosted In A File. 2. Select file, then choose "Volume Type" = PLAIN dm-crypt. 3. Enter the generated offset value along with your password. IMPORTANT!!! zuluCrypt zuluCrypt Encrypted Volume Path Encrypted Volume Mount Point Path Type &Open &Create &Help &Volumes Optio&ns &Volume Hosted In A File Volume &Hosted In A Hard Drive Encrypted &Container In A Hard Drive &About &Add A Key To A Volume &Delete A Key From A Volume &KeyFile &Tray Icon Select &Font &Update Volume List &Minimize To Tray &Quit &Close All Opened Volumes &Manage Favorites &Erase Data In A Device &Backup Header &Restore Header Encrypt A &File &Decrypt A File &Header Backup Manag&e System Volumes Manage &Volumes In Internal Wallet Manage &Non System Volumes Manage Volumes In &KDE Wallet Manage Volumes In &GNOME keyring &Change Internal Wallet Password H&elp F1 C&heck For Update Set Fi&le Manager Do Not Minimize To Tray This Option Will Close The App Instead Of Minimizing It To Tray Encrypted Container Hidden In Video/Cover File (Steganography) Show Debug Window Ctrl+Shift+D Encrypted Container In An Existing File Clear Dead Mount Points Contact &Info &Select Language &Auto Open Mount Point Select &Icons &Favorites &zC Ctrl+Z Ctrl+X &Encrypted Container In A New File Ctrl+A Ctrl+S Ctrl+R Ctrl+U Ctrl+W crypto info Ctrl+E Ctrl+D Ctrl+K Ctrl+L favorite volumes manage favorites select random number generator Ctrl+P close application Ctrl+C Ctrl+T Ctrl+Y Quit Ctrl+Q Ctrl+G Ctrl+F Ctrl+N Ctrl+B permissions Ctrl+I Ctrl+H Ctrl+J Ctrl+V configure wallets Ctrl+M Shift+V Alt+V Ctrl+O tcrypt backup header tcrypt restore header VeraCrypt Container In A File VeraCrypt Container In A Hard Drive Shift+U Shift+I Select Language Restore Volume Header Backup Volume Header INFO Resetting font size to %1 because larger font sizes do not fit LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a "volume header". A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data. The damage to the header is usually caused by accidental formatting of the device or use of some buggy partitioning tools or wrongly reassembled logical volumes. Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted. Important Information On Volume Header Backup ERROR! Volume is not open or was opened by a different user Volume Properties WARNING! Could not open mount point because "%1" tool does not appear to be working correctly Properties Open Folder ERROR zuluCrypt Failed To Connect To zuluPolkit. Please Report This Serious Bug. Path To A File Show/Hide Open Private Folder Open Shared Folder Add Key Remove Key Backup LUKS Header Add To Favorite Unmount Cancel Close failed, volume is not open or was opened by a different user Close failed, one or more files in the volume are in use. Close failed, volume does not have an entry in /etc/mtab Close failed, could not get a lock on /etc/mtab~ Close failed, volume is unmounted but could not close mapper,advice to close it manually Close failed, could not resolve full path of device Close failed, shared mount point appear to be busy Close failed, shared mount point appear to belong to a different user or multiple mount points detected Close failed, shared mount point appear to be in an ambiguous state,advice to unmount manually Close failed, multiple mount points for the volume detected Close failed, could not find any partition with the presented UUID Unrecognized error with status number %1 encountered zuluCrypt-6.2.0/translations/zuluCrypt/zuluCrypt-cli.mo000066400000000000000000000504231425361753700234460ustar00rootroot00000000000000Þ•£4ßL È É å $ü !+@;lX¨;=Zs"N³}5€$¶#Û2ÿ)2¿\==Z:˜3Ó-?51u8§;à:eWM½I @UJ–`á.B,q,žËHë;4+p)œ2Æ9ù83Al8®9ç/!\Q*®+Ù"!(/J)z+¤%Ð2ö')(Q7z#²(Öÿ0lOT¼-;? {8œ.Õ2171iP›9ìE&‰lrövi Eà -&!9T!9Ž!;È!>"EC"2‰"<¼"/ù"+)#U# t#•#´#&Ô#û#$$5$-Z$-ˆ$F¶$fý$1d%&–% ½%QÞ%-0&U^&6´&:ë&C&'j'‚',œ'É'Bè'E+(Dq(<¶(9ó(#-)Q)m)Œ) Ÿ),À),í)(* C*.d*4“*-È*-ö*&$+#K+ o+"+)³+%Ý+*,+.,%Z,%€,$¦,3Ë,^ÿ,^-!b-„--3º-*î-.%..T.6j.¡.k¸.$0@0$W0|0+›0;Ç0X1;\1˜1µ1Î1"ë1N2}]25Û2$3#632Z3)3¿·3=w4=µ4:ó43.5-b5?51Ð586;;6:w6e²6M7If7@°7Jñ7`<8.8,Ì8,ù8&9HF9;9+Ë9)÷92!:9T:8Ž:AÇ:8 ;9B;/|;\¬;* <+4<"`<!ƒ</¥<)Õ<+ÿ<%+=2Q='„=(¬=7Õ=# >(1>Z>0y>lª>T?-l?;š? Ö?8÷?.0@2_@1’@1Ä@Pö@9GAEA‰ÇArQBvÄBE;C-C9¯C9éC;#D>_DEžD2äD<E/TE+„E°E ÏEðEF&/FVFuF$F-µF-ãFFGfXG1¿G&ñG HQ9H-‹HU¹H6I:FICIÅIÝI,÷I$JBCJE†JDÌJ<K9NK#ˆK¬KÈKçK úK,L,HL(uL žL.¿L4îL-#M-QM&M#¦M ÊM"ëM)N%8N*^N+‰N%µN%ÛN$O3&O^ZO¹O!½OßOøO3P*IPtP%‰P¯P6ÅPüP9)VMXd8Fo‹O#fš†%‘'.Œ˜Ÿ?=pƒ’ vA+‚/‡y@TlœLrzUbeŠg•*nKY  ~1 R”!žcSm…&¡ N;3$5Žx^sQa›(¢[}-2\—Ej„ hP‰qW£"I7G|{HkiJ,–Bˆ>u€]“`tD0 w™4_6:ZC< Enter the new passphrase: Re enter passphrase: Re enter tcrypt hidden passphrase: Re enter the new passphrase: SUCCESS: random data successfully written This operation will destroy all data in a device at: "%s" WARNING, device "%s" will be overwritten with random data destroying all present data. creating a backup of the luks header is strongly adviced. "%s" is a not tcrypt device "%s" is a tcrypt device "%s" is not a tcrypt device Are you sure you want to proceed? Are you sure you want to proceed? Type "YES" and press enter if you are sure: Are you sure you want to replace a header on device "%s" with a backup copy at "%s"? Type "YES" and press Enter to continue: Do you still want to continue? Type "YES" if you do: ERROR!!!!!!!!!!: cli option missed! ERROR: "action" argument is missingERROR: -O and -m options can not be used together ERROR: a file can have only one hard linkERROR: a non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signatureERROR: all key slots are occupied, can not add any more keys ERROR: argument for path to a backup header file is missing ERROR: backup file does not appear to contain luks header ERROR: can not create a volume on a mounted device ERROR: can not get passphrase in silent mode ERROR: can not open a mapper on a device with an opened mapper ERROR: can not open a mapper on a mounted device ERROR: close failed, could not get a lock on /etc/mtab~ ERROR: close failed, could not resolve full path of device ERROR: close failed, shared mount point appear to be busy ERROR: close failed, shared mount point appear to be in an ambiguous state,advice to unmount manuallyERROR: close failed, shared mount point appear to belong to a different user ERROR: close failed, the mount point and/or one or more files are in use ERROR: close failed, volume does not have an entry in /etc/mtab ERROR: close failed, volume is not open or was opened by a different user ERROR: close failed, volume is unmounted but could not close mapper,advice to close it manually ERROR: container file must be bigger than 3MB ERROR: could not create a lock on /etc/mtab ERROR: could not create an encrypted volume ERROR: could not create mapper ERROR: could not create mount point, invalid path or path already taken ERROR: could not find any partition with the presented UUIDERROR: could not get a key from a key file ERROR: could not get a key from a socket ERROR: could not get a passphrase from the module ERROR: could not get a passphrase through a local socket ERROR: could not get device address from mapper address ERROR: could not get elevated privilege,check binary permissions ERROR: could not get enough memory to open the key file ERROR: could not get enought memory to hold the key file ERROR: could not get passphrase in silent mode ERROR: could not get volume properties,volume is not open or was opened by a different user ERROR: could not open encryption routines ERROR: could not open key file for reading ERROR: could not open luks volume ERROR: could not open the volume ERROR: could not open the volume in write mode ERROR: could not open volume for writing ERROR: could not open volume in write mode ERROR: could not resolve device path ERROR: could not resolve path to destination file ERROR: could not resolve path to deviceERROR: could not resolve path to device ERROR: couldnt get enought memory to hold the key file ERROR: destination path is missing ERROR: device "%s" is not a luks device ERROR: device path is invalid ERROR: devices in /dev/shm/ path is not supporedERROR: failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered ERROR: failed to mount ntfs file system using ntfs-3g,is ntfs-3g package installed? ERROR: failed to perform requested operation ERROR: file or folder already exist at destination address ERROR: given path is a directoryERROR: insufficient memory to hold 3 characters?really? ERROR: insufficient memory to hold passphrase ERROR: insufficient memory to hold the passphrase ERROR: insufficient memory to hold your responce ERROR: insufficient memory to hold your response ERROR: insufficient privilege to create a backup header in a destination folder ERROR: insufficient privilege to create destination file ERROR: insufficient privilege to mount the device with given options ERROR: insufficient privilege to open a system device in read/write mode, only root user or members of group zulucrypt-system can do thatERROR: insufficient privilege to open a system device, only root user or members of group "zulucrypt" can do that ERROR: insufficient privilege to open a system device,only root user or members of group zulucrypt-system can do that ERROR: insufficient privilege to open backup header file for reading ERROR: insufficient privilege to open device ERROR: insufficient privilege to open device for reading ERROR: insufficient privilege to open device for writing ERROR: insufficient privilege to open key file for reading ERROR: insufficient privilege to open source file for reading ERROR: insufficient privilege to open the file with your privileges? ERROR: insufficient privilges to access the deviceERROR: insufficient privilges to operate on a system device ERROR: insufficitied privilege to oped device ERROR: invalid path to back up header file ERROR: invalid path to device ERROR: invalid path to key file ERROR: invalid path to source ERROR: key argument is missing ERROR: key source argument is missing ERROR: keyfile does not exist ERROR: missing key source ERROR: new passphrases do not match ERROR: no file or device exist on given path ERROR: one or both keyfile(s) does not exist ERROR: one or more required argument(s) for this operation is missing ERROR: only root and "zulucrypt" group members can restore and back up luks headers on system devices ERROR: only root user can perform this operation ERROR: passphrase file does not exist ERROR: passphrases do not match ERROR: path to be used to create a back up file is occupied or permission denied ERROR: presented device is not a LUKS device ERROR: presented file system is not supported,see documentation for more information ERROR: presented key did not match the encryption key ERROR: presented key does not match any key in the volume ERROR: required option( device path ) is missing for this operationERROR: setegid() failedERROR: setgroups() failedERROR: shared mount point path aleady taken ERROR: source path is missing ERROR: there is no key in the volume that match the presented key ERROR: there seem to be an open volume accociated with given address ERROR: there seem to be an opened mapper associated with the device ERROR: unrecognized error with status number %d encountered ERROR: volume could not be opened with the presented key ERROR: volume is not a luks volume Enter a key to be removed: Enter an existing passphrase: Enter passphrase: Enter tcrypt hidden passphrase: INFO: operation terminated per user request INFO: operation terminater per user request INFO: signal caught,exiting prematurely INFO: user chose not to proceed INFORMATION: functionality currently disabled Please read documentation on why this is important SUCCESS: decrypted file created successfully SUCCESS: encrypted file created successfully SUCCESS: header restored successfully SUCCESS: header saved successfully SUCCESS: key added successfully SUCCESS: key removed successfully SUCCESS: luks volume opened successfully SUCCESS: mapper created successfully SUCCESS: plain volume opened successfully SUCCESS: tcrypt volume opened successfully SUCCESS: volume closed successfully SUCCESS: volume created successfully SUCCESS: volume opened successfully Type "YES" and press enter if you want to process: WARNING: there is only one key in the volume and all data in it will be lost if you continue. YESdevice "%s" is not a luks device device is a luks volume device is not a luks volume header backup does not match the one on the device header backup match the one on the device opened mapper path: path "%s" does not point to a device percentage complete: unexpected exiting because you have run out of memory volume mounted at: %s Project-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: POT-Creation-Date: 2013-07-15 02:49-0400 PO-Revision-Date: 2013-07-15 02:49-0400 Last-Translator: ink Language-Team: English Language: en_US MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); Enter the new passphrase: Re enter passphrase: Re enter tcrypt hidden passphrase: Re enter the new passphrase: SUCCESS: random data successfully written This operation will destroy all data in a device at: "%s" WARNING, device "%s" will be overwritten with random data destroying all present data. creating a backup of the luks header is strongly adviced. "%s" is a not tcrypt device "%s" is a tcrypt device "%s" is not a tcrypt device Are you sure you want to proceed? Are you sure you want to proceed? Type "YES" and press enter if you are sure: Are you sure you want to replace a header on device "%s" with a backup copy at "%s"? Type "YES" and press Enter to continue: Do you still want to continue? Type "YES" if you do: ERROR!!!!!!!!!!: cli option missed! ERROR: "action" argument is missingERROR: -O and -m options can not be used together ERROR: a file can have only one hard linkERROR: a non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signatureERROR: all key slots are occupied, can not add any more keys ERROR: argument for path to a backup header file is missing ERROR: backup file does not appear to contain luks header ERROR: can not create a volume on a mounted device ERROR: can not get passphrase in silent mode ERROR: can not open a mapper on a device with an opened mapper ERROR: can not open a mapper on a mounted device ERROR: close failed, could not get a lock on /etc/mtab~ ERROR: close failed, could not resolve full path of device ERROR: close failed, shared mount point appear to be busy ERROR: close failed, shared mount point appear to be in an ambiguous state,advice to unmount manuallyERROR: close failed, shared mount point appear to belong to a different user ERROR: close failed, the mount point and/or one or more files are in use ERROR: close failed, volume does not have an entry in /etc/mtab ERROR: close failed, volume is not open or was opened by a different user ERROR: close failed, volume is unmounted but could not close mapper,advice to close it manually ERROR: container file must be bigger than 3MB ERROR: could not create a lock on /etc/mtab ERROR: could not create an encrypted volume ERROR: could not create mapper ERROR: could not create mount point, invalid path or path already taken ERROR: could not find any partition with the presented UUIDERROR: could not get a key from a key file ERROR: could not get a key from a socket ERROR: could not get a passphrase from the module ERROR: could not get a passphrase through a local socket ERROR: could not get device address from mapper address ERROR: could not get elevated privilege,check binary permissions ERROR: could not get enough memory to open the key file ERROR: could not get enought memory to hold the key file ERROR: could not get passphrase in silent mode ERROR: could not get volume properties,volume is not open or was opened by a different user ERROR: could not open encryption routines ERROR: could not open key file for reading ERROR: could not open luks volume ERROR: could not open the volume ERROR: could not open the volume in write mode ERROR: could not open volume for writing ERROR: could not open volume in write mode ERROR: could not resolve device path ERROR: could not resolve path to destination file ERROR: could not resolve path to deviceERROR: could not resolve path to device ERROR: couldnt get enought memory to hold the key file ERROR: destination path is missing ERROR: device "%s" is not a luks device ERROR: device path is invalid ERROR: devices in /dev/shm/ path is not supporedERROR: failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered ERROR: failed to mount ntfs file system using ntfs-3g,is ntfs-3g package installed? ERROR: failed to perform requested operation ERROR: file or folder already exist at destination address ERROR: given path is a directoryERROR: insufficient memory to hold 3 characters?really? ERROR: insufficient memory to hold passphrase ERROR: insufficient memory to hold the passphrase ERROR: insufficient memory to hold your responce ERROR: insufficient memory to hold your response ERROR: insufficient privilege to create a backup header in a destination folder ERROR: insufficient privilege to create destination file ERROR: insufficient privilege to mount the device with given options ERROR: insufficient privilege to open a system device in read/write mode, only root user or members of group zulucrypt-system can do thatERROR: insufficient privilege to open a system device, only root user or members of group "zulucrypt" can do that ERROR: insufficient privilege to open a system device,only root user or members of group zulucrypt-system can do that ERROR: insufficient privilege to open backup header file for reading ERROR: insufficient privilege to open device ERROR: insufficient privilege to open device for reading ERROR: insufficient privilege to open device for writing ERROR: insufficient privilege to open key file for reading ERROR: insufficient privilege to open source file for reading ERROR: insufficient privilege to open the file with your privileges? ERROR: insufficient privilges to access the deviceERROR: insufficient privilges to operate on a system device ERROR: insufficitied privilege to oped device ERROR: invalid path to back up header file ERROR: invalid path to device ERROR: invalid path to key file ERROR: invalid path to source ERROR: key argument is missing ERROR: key source argument is missing ERROR: keyfile does not exist ERROR: missing key source ERROR: new passphrases do not match ERROR: no file or device exist on given path ERROR: one or both keyfile(s) does not exist ERROR: one or more required argument(s) for this operation is missing ERROR: only root and "zulucrypt" group members can restore and back up luks headers on system devices ERROR: only root user can perform this operation ERROR: passphrase file does not exist ERROR: passphrases do not match ERROR: path to be used to create a back up file is occupied or permission denied ERROR: presented device is not a LUKS device ERROR: presented file system is not supported,see documentation for more information ERROR: presented key did not match the encryption key ERROR: presented key does not match any key in the volume ERROR: required option( device path ) is missing for this operationERROR: setegid() failedERROR: setgroups() failedERROR: shared mount point path aleady taken ERROR: source path is missing ERROR: there is no key in the volume that match the presented key ERROR: there seem to be an open volume accociated with given address ERROR: there seem to be an opened mapper associated with the device ERROR: unrecognized error with status number %d encountered ERROR: volume could not be opened with the presented key ERROR: volume is not a luks volume Enter a key to be removed: Enter an existing passphrase: Enter passphrase: Enter tcrypt hidden passphrase: INFO: operation terminated per user request INFO: operation terminater per user request INFO: signal caught,exiting prematurely INFO: user chose not to proceed INFORMATION: functionality currently disabled Please read documentation on why this is important SUCCESS: decrypted file created successfully SUCCESS: encrypted file created successfully SUCCESS: header restored successfully SUCCESS: header saved successfully SUCCESS: key added successfully SUCCESS: key removed successfully SUCCESS: luks volume opened successfully SUCCESS: mapper created successfully SUCCESS: plain volume opened successfully SUCCESS: tcrypt volume opened successfully SUCCESS: volume closed successfully SUCCESS: volume created successfully SUCCESS: volume opened successfully Type "YES" and press enter if you want to process: WARNING: there is only one key in the volume and all data in it will be lost if you continue. YESdevice "%s" is not a luks device device is a luks volume device is not a luks volume header backup does not match the one on the device header backup match the one on the device opened mapper path: path "%s" does not point to a device percentage complete: unexpected exiting because you have run out of memory volume mounted at: %s zuluCrypt-6.2.0/translations/zuluCrypt/zuluCrypt-cli.po000066400000000000000000000760221425361753700234540ustar00rootroot00000000000000# English translations for PACKAGE package. # Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # ink , 2013. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-07-15 02:49-0400\n" "PO-Revision-Date: 2013-07-15 02:49-0400\n" "Last-Translator: ink \n" "Language-Team: English\n" "Language: en_US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../zuluCrypt-cli/bin/add_key.c:110 #, c-format msgid "" "\n" "Enter the new passphrase: " msgstr "" "\n" "Enter the new passphrase: " #: ../zuluCrypt-cli/bin/create_volumes.c:226 #: ../zuluCrypt-cli/bin/crypt_file.c:112 #, c-format msgid "" "\n" "Re enter passphrase: " msgstr "" "\n" "Re enter passphrase: " #: ../zuluCrypt-cli/bin/create_volumes.c:293 #, c-format msgid "" "\n" "Re enter tcrypt hidden passphrase: " msgstr "" "\n" "Re enter tcrypt hidden passphrase: " #: ../zuluCrypt-cli/bin/add_key.c:116 #, c-format msgid "" "\n" "Re enter the new passphrase: " msgstr "" "\n" "Re enter the new passphrase: " #: ../zuluCrypt-cli/bin/write_device_with_junk.c:65 #, c-format msgid "" "\n" "SUCCESS: random data successfully written\n" msgstr "" "\n" "SUCCESS: random data successfully written\n" #: ../zuluCrypt-cli/bin/create_volumes.c:203 #, c-format msgid "" "\n" "This operation will destroy all data in a device at: \"%s\"\n" msgstr "" "\n" "This operation will destroy all data in a device at: \"%s\"\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:289 #, c-format msgid "" "\n" "WARNING, device \"%s\" will be overwritten with random data destroying all " "present data.\n" msgstr "" "\n" "WARNING, device \"%s\" will be overwritten with random data destroying all " "present data.\n" #: ../zuluCrypt-cli/bin/create_volumes.c:66 #, c-format msgid "" "\n" "creating a backup of the luks header is strongly adviced.\n" msgstr "" "\n" "creating a backup of the luks header is strongly adviced.\n" #: ../zuluCrypt-cli/bin/main.c:111 #, c-format msgid "\"%s\" is a not tcrypt device\n" msgstr "\"%s\" is a not tcrypt device\n" #: ../zuluCrypt-cli/bin/main.c:95 ../zuluCrypt-cli/bin/main.c:108 #, c-format msgid "\"%s\" is a tcrypt device\n" msgstr "\"%s\" is a tcrypt device\n" #: ../zuluCrypt-cli/bin/main.c:117 ../zuluCrypt-cli/bin/main.c:124 #, c-format msgid "\"%s\" is not a tcrypt device\n" msgstr "\"%s\" is not a tcrypt device\n" #: ../zuluCrypt-cli/bin/create_volumes.c:204 #, c-format msgid "Are you sure you want to proceed?\n" msgstr "Are you sure you want to proceed?\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:290 #, c-format msgid "" "Are you sure you want to proceed? Type \"YES\" and press enter if you are " "sure: " msgstr "" "Are you sure you want to proceed? Type \"YES\" and press enter if you are " "sure: " #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:256 #, c-format msgid "" "Are you sure you want to replace a header on device \"%s\" with a backup " "copy at \"%s\"?\n" "Type \"YES\" and press Enter to continue: " msgstr "" "Are you sure you want to replace a header on device \"%s\" with a backup " "copy at \"%s\"?\n" "Type \"YES\" and press Enter to continue: " #: ../zuluCrypt-cli/bin/remove_key.c:131 #, c-format msgid "Do you still want to continue? Type \"YES\" if you do: " msgstr "Do you still want to continue? Type \"YES\" if you do: " #: ../zuluCrypt-cli/bin/main.c:216 #, c-format msgid "ERROR!!!!!!!!!!: cli option missed!\n" msgstr "ERROR!!!!!!!!!!: cli option missed!\n" #: ../zuluCrypt-cli/bin/main.c:470 msgid "ERROR: \"action\" argument is missing" msgstr "ERROR: \"action\" argument is missing" #: ../zuluCrypt-cli/bin/open_volume.c:73 #, c-format msgid "ERROR: -O and -m options can not be used together\n" msgstr "ERROR: -O and -m options can not be used together\n" #: ../zuluCrypt-cli/bin/main.c:510 msgid "ERROR: a file can have only one hard link" msgstr "ERROR: a file can have only one hard link" #: ../zuluCrypt-cli/bin/main.c:512 msgid "" "ERROR: a non supported device encountered,device is missing or permission " "denied\n" "Possible reasons for getting the error are:\n" "1.Device path is invalid.\n" "2.The device has LVM or MDRAID signature" msgstr "" "ERROR: a non supported device encountered,device is missing or permission " "denied\n" "Possible reasons for getting the error are:\n" "1.Device path is invalid.\n" "2.The device has LVM or MDRAID signature" #: ../zuluCrypt-cli/bin/add_key.c:76 #, c-format msgid "ERROR: all key slots are occupied, can not add any more keys\n" msgstr "ERROR: all key slots are occupied, can not add any more keys\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:45 #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:46 #, c-format msgid "ERROR: argument for path to a backup header file is missing\n" msgstr "ERROR: argument for path to a backup header file is missing\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:50 #, c-format msgid "ERROR: backup file does not appear to contain luks header\n" msgstr "ERROR: backup file does not appear to contain luks header\n" #: ../zuluCrypt-cli/bin/create_volumes.c:38 #, c-format msgid "ERROR: can not create a volume on a mounted device\n" msgstr "ERROR: can not create a volume on a mounted device\n" #: ../zuluCrypt-cli/bin/add_key.c:77 ../zuluCrypt-cli/bin/create_volumes.c:51 #: ../zuluCrypt-cli/bin/crypt_file.c:41 ../zuluCrypt-cli/bin/remove_key.c:67 #: ../zuluCrypt-cli/bin/write_device_with_junk.c:75 #, c-format msgid "ERROR: can not get passphrase in silent mode\n" msgstr "ERROR: can not get passphrase in silent mode\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:72 #, c-format msgid "ERROR: can not open a mapper on a device with an opened mapper\n" msgstr "ERROR: can not open a mapper on a device with an opened mapper\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:73 #, c-format msgid "ERROR: can not open a mapper on a mounted device\n" msgstr "ERROR: can not open a mapper on a mounted device\n" #: ../zuluCrypt-cli/bin/close_volume.c:31 #, c-format msgid "ERROR: close failed, could not get a lock on /etc/mtab~\n" msgstr "ERROR: close failed, could not get a lock on /etc/mtab~\n" #: ../zuluCrypt-cli/bin/close_volume.c:33 #, c-format msgid "ERROR: close failed, could not resolve full path of device\n" msgstr "ERROR: close failed, could not resolve full path of device\n" #: ../zuluCrypt-cli/bin/close_volume.c:34 #, c-format msgid "ERROR: close failed, shared mount point appear to be busy\n" msgstr "ERROR: close failed, shared mount point appear to be busy\n" #: ../zuluCrypt-cli/bin/close_volume.c:36 #, c-format msgid "" "ERROR: close failed, shared mount point appear to be in an ambiguous state," "advice to unmount manually" msgstr "" "ERROR: close failed, shared mount point appear to be in an ambiguous state," "advice to unmount manually" #: ../zuluCrypt-cli/bin/close_volume.c:35 #, c-format msgid "" "ERROR: close failed, shared mount point appear to belong to a different " "user\n" msgstr "" "ERROR: close failed, shared mount point appear to belong to a different " "user\n" #: ../zuluCrypt-cli/bin/close_volume.c:29 #, c-format msgid "" "ERROR: close failed, the mount point and/or one or more files are in use\n" msgstr "" "ERROR: close failed, the mount point and/or one or more files are in use\n" #: ../zuluCrypt-cli/bin/close_volume.c:30 #, c-format msgid "ERROR: close failed, volume does not have an entry in /etc/mtab\n" msgstr "ERROR: close failed, volume does not have an entry in /etc/mtab\n" #: ../zuluCrypt-cli/bin/close_volume.c:28 #, c-format msgid "" "ERROR: close failed, volume is not open or was opened by a different user\n" msgstr "" "ERROR: close failed, volume is not open or was opened by a different user\n" #: ../zuluCrypt-cli/bin/close_volume.c:32 #, c-format msgid "" "ERROR: close failed, volume is unmounted but could not close mapper,advice " "to close it manually\n" msgstr "" "ERROR: close failed, volume is unmounted but could not close mapper,advice " "to close it manually\n" #: ../zuluCrypt-cli/bin/create_volumes.c:39 #, c-format msgid "ERROR: container file must be bigger than 3MB\n" msgstr "ERROR: container file must be bigger than 3MB\n" #: ../zuluCrypt-cli/bin/open_volume.c:86 #, c-format msgid "ERROR: could not create a lock on /etc/mtab\n" msgstr "ERROR: could not create a lock on /etc/mtab\n" #: ../zuluCrypt-cli/bin/create_volumes.c:35 #, c-format msgid "ERROR: could not create an encrypted volume\n" msgstr "ERROR: could not create an encrypted volume\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:63 #, c-format msgid "ERROR: could not create mapper\n" msgstr "ERROR: could not create mapper\n" #: ../zuluCrypt-cli/bin/open_volume.c:74 #, c-format msgid "" "ERROR: could not create mount point, invalid path or path already taken\n" msgstr "" "ERROR: could not create mount point, invalid path or path already taken\n" #: ../zuluCrypt-cli/bin/main.c:500 msgid "ERROR: could not find any partition with the presented UUID" msgstr "ERROR: could not find any partition with the presented UUID" #: ../zuluCrypt-cli/bin/create_volumes.c:47 #, c-format msgid "ERROR: could not get a key from a key file\n" msgstr "ERROR: could not get a key from a key file\n" #: ../zuluCrypt-cli/bin/add_key.c:84 ../zuluCrypt-cli/bin/create_volumes.c:49 #: ../zuluCrypt-cli/bin/remove_key.c:73 #, c-format msgid "ERROR: could not get a key from a socket\n" msgstr "ERROR: could not get a key from a socket\n" #: ../zuluCrypt-cli/bin/open_volume.c:77 #, c-format msgid "ERROR: could not get a passphrase from the module\n" msgstr "ERROR: could not get a passphrase from the module\n" #: ../zuluCrypt-cli/bin/open_volume.c:84 #, c-format msgid "ERROR: could not get a passphrase through a local socket\n" msgstr "ERROR: could not get a passphrase through a local socket\n" #: ../zuluCrypt-cli/bin/main.c:42 #, c-format msgid "ERROR: could not get device address from mapper address\n" msgstr "ERROR: could not get device address from mapper address\n" #: ../zuluCrypt-cli/bin/add_key.c:85 #, c-format msgid "ERROR: could not get elevated privilege,check binary permissions\n" msgstr "ERROR: could not get elevated privilege,check binary permissions\n" #: ../zuluCrypt-cli/bin/remove_key.c:71 #, c-format msgid "ERROR: could not get enough memory to open the key file\n" msgstr "ERROR: could not get enough memory to open the key file\n" #: ../zuluCrypt-cli/bin/open_volume.c:82 #: ../zuluCrypt-cli/bin/write_device_with_junk.c:70 #, c-format msgid "ERROR: could not get enought memory to hold the key file\n" msgstr "ERROR: could not get enought memory to hold the key file\n" #: ../zuluCrypt-cli/bin/create_volumes.c:43 #: ../zuluCrypt-cli/bin/open_volume.c:78 #, c-format msgid "ERROR: could not get passphrase in silent mode\n" msgstr "ERROR: could not get passphrase in silent mode\n" #: ../zuluCrypt-cli/bin/volume_info.c:46 #, c-format msgid "" "ERROR: could not get volume properties,volume is not open or was opened by a " "different user\n" msgstr "" "ERROR: could not get volume properties,volume is not open or was opened by a " "different user\n" #: ../zuluCrypt-cli/bin/crypt_file.c:33 #, c-format msgid "ERROR: could not open encryption routines\n" msgstr "ERROR: could not open encryption routines\n" #: ../zuluCrypt-cli/bin/crypt_file.c:31 #, c-format msgid "ERROR: could not open key file for reading\n" msgstr "ERROR: could not open key file for reading\n" #: ../zuluCrypt-cli/bin/add_key.c:71 #, c-format msgid "ERROR: could not open luks volume\n" msgstr "ERROR: could not open luks volume\n" #: ../zuluCrypt-cli/bin/remove_key.c:61 #, c-format msgid "ERROR: could not open the volume\n" msgstr "ERROR: could not open the volume\n" #: ../zuluCrypt-cli/bin/remove_key.c:64 #, c-format msgid "ERROR: could not open the volume in write mode\n" msgstr "ERROR: could not open the volume in write mode\n" #: ../zuluCrypt-cli/bin/create_volumes.c:36 #, c-format msgid "ERROR: could not open volume for writing\n" msgstr "ERROR: could not open volume for writing\n" #: ../zuluCrypt-cli/bin/add_key.c:75 #, c-format msgid "ERROR: could not open volume in write mode\n" msgstr "ERROR: could not open volume in write mode\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:64 #, c-format msgid "ERROR: could not resolve device path\n" msgstr "ERROR: could not resolve device path\n" #: ../zuluCrypt-cli/bin/crypt_file.c:36 #, c-format msgid "ERROR: could not resolve path to destination file\n" msgstr "ERROR: could not resolve path to destination file\n" #: ../zuluCrypt-cli/bin/main.c:523 msgid "ERROR: could not resolve path to device" msgstr "ERROR: could not resolve path to device" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:49 #, c-format msgid "ERROR: could not resolve path to device\n" msgstr "ERROR: could not resolve path to device\n" #: ../zuluCrypt-cli/bin/add_key.c:83 ../zuluCrypt-cli/bin/create_volumes.c:48 #, c-format msgid "ERROR: couldnt get enought memory to hold the key file\n" msgstr "ERROR: couldnt get enought memory to hold the key file\n" #: ../zuluCrypt-cli/bin/crypt_file.c:38 #, c-format msgid "ERROR: destination path is missing\n" msgstr "ERROR: destination path is missing\n" #: ../zuluCrypt-cli/bin/add_key.c:94 ../zuluCrypt-cli/bin/remove_key.c:81 #, c-format msgid "ERROR: device \"%s\" is not a luks device\n" msgstr "ERROR: device \"%s\" is not a luks device\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:68 #, c-format msgid "ERROR: device path is invalid\n" msgstr "ERROR: device path is invalid\n" #: ../zuluCrypt-cli/bin/main.c:508 msgid "ERROR: devices in /dev/shm/ path is not suppored" msgstr "ERROR: devices in /dev/shm/ path is not suppored" #: ../zuluCrypt-cli/bin/open_volume.c:85 #, c-format msgid "" "ERROR: failed to mount a filesystem:invalid/unsupported mount option or " "unsupported file system encountered\n" msgstr "" "ERROR: failed to mount a filesystem:invalid/unsupported mount option or " "unsupported file system encountered\n" #: ../zuluCrypt-cli/bin/open_volume.c:66 #, c-format msgid "" "ERROR: failed to mount ntfs file system using ntfs-3g,is ntfs-3g package " "installed?\n" msgstr "" "ERROR: failed to mount ntfs file system using ntfs-3g,is ntfs-3g package " "installed?\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:36 #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:37 #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:40 #, c-format msgid "ERROR: failed to perform requested operation\n" msgstr "ERROR: failed to perform requested operation\n" #: ../zuluCrypt-cli/bin/crypt_file.c:34 #, c-format msgid "ERROR: file or folder already exist at destination address\n" msgstr "ERROR: file or folder already exist at destination address\n" #: ../zuluCrypt-cli/bin/main.c:509 msgid "ERROR: given path is a directory" msgstr "ERROR: given path is a directory" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:77 #, c-format msgid "ERROR: insufficient memory to hold 3 characters?really?\n" msgstr "ERROR: insufficient memory to hold 3 characters?really?\n" #: ../zuluCrypt-cli/bin/add_key.c:78 ../zuluCrypt-cli/bin/create_volumes.c:52 #: ../zuluCrypt-cli/bin/crypt_file.c:42 ../zuluCrypt-cli/bin/open_volume.c:79 #: ../zuluCrypt-cli/bin/remove_key.c:68 #: ../zuluCrypt-cli/bin/write_device_with_junk.c:76 #, c-format msgid "ERROR: insufficient memory to hold passphrase\n" msgstr "ERROR: insufficient memory to hold passphrase\n" #: ../zuluCrypt-cli/bin/create_volumes.c:44 #, c-format msgid "ERROR: insufficient memory to hold the passphrase\n" msgstr "ERROR: insufficient memory to hold the passphrase\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:52 #, c-format msgid "ERROR: insufficient memory to hold your responce\n" msgstr "ERROR: insufficient memory to hold your responce\n" #: ../zuluCrypt-cli/bin/create_volumes.c:41 #: ../zuluCrypt-cli/bin/remove_key.c:65 #, c-format msgid "ERROR: insufficient memory to hold your response\n" msgstr "ERROR: insufficient memory to hold your response\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:43 #, c-format msgid "" "ERROR: insufficient privilege to create a backup header in a destination " "folder\n" msgstr "" "ERROR: insufficient privilege to create a backup header in a destination " "folder\n" #: ../zuluCrypt-cli/bin/crypt_file.c:39 #, c-format msgid "ERROR: insufficient privilege to create destination file\n" msgstr "ERROR: insufficient privilege to create destination file\n" #: ../zuluCrypt-cli/bin/open_volume.c:70 #, c-format msgid "ERROR: insufficient privilege to mount the device with given options\n" msgstr "ERROR: insufficient privilege to mount the device with given options\n" #: ../zuluCrypt-cli/bin/create_volumes.c:33 #, c-format msgid "" "ERROR: insufficient privilege to open a system device in read/write mode,\n" "only root user or members of group zulucrypt-system can do that" msgstr "" "ERROR: insufficient privilege to open a system device in read/write mode,\n" "only root user or members of group zulucrypt-system can do that" #: ../zuluCrypt-cli/bin/add_key.c:73 #, c-format msgid "" "ERROR: insufficient privilege to open a system device,\n" "only root user or members of group \"zulucrypt\" can do that\n" msgstr "" "ERROR: insufficient privilege to open a system device,\n" "only root user or members of group \"zulucrypt\" can do that\n" #: ../zuluCrypt-cli/bin/remove_key.c:62 #, c-format msgid "" "ERROR: insufficient privilege to open a system device,only root user or " "members of group zulucrypt-system can do that\n" msgstr "" "ERROR: insufficient privilege to open a system device,only root user or " "members of group zulucrypt-system can do that\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:41 #, c-format msgid "ERROR: insufficient privilege to open backup header file for reading\n" msgstr "ERROR: insufficient privilege to open backup header file for reading\n" #: ../zuluCrypt-cli/bin/open_volume.c:71 #, c-format msgid "ERROR: insufficient privilege to open device\n" msgstr "ERROR: insufficient privilege to open device\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:51 #, c-format msgid "ERROR: insufficient privilege to open device for reading\n" msgstr "ERROR: insufficient privilege to open device for reading\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:48 #, c-format msgid "ERROR: insufficient privilege to open device for writing\n" msgstr "ERROR: insufficient privilege to open device for writing\n" #: ../zuluCrypt-cli/bin/add_key.c:82 ../zuluCrypt-cli/bin/open_volume.c:83 #: ../zuluCrypt-cli/bin/remove_key.c:72 #: ../zuluCrypt-cli/bin/write_device_with_junk.c:71 #, c-format msgid "ERROR: insufficient privilege to open key file for reading\n" msgstr "ERROR: insufficient privilege to open key file for reading\n" #: ../zuluCrypt-cli/bin/crypt_file.c:44 #, c-format msgid "ERROR: insufficient privilege to open source file for reading\n" msgstr "ERROR: insufficient privilege to open source file for reading\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:78 #, c-format msgid "ERROR: insufficient privilege to open the file with your privileges?\n" msgstr "ERROR: insufficient privilege to open the file with your privileges?\n" #: ../zuluCrypt-cli/bin/main.c:511 msgid "ERROR: insufficient privilges to access the device" msgstr "ERROR: insufficient privilges to access the device" #: ../zuluCrypt-cli/bin/main.c:176 #, c-format msgid "ERROR: insufficient privilges to operate on a system device\n" msgstr "ERROR: insufficient privilges to operate on a system device\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:67 #, c-format msgid "ERROR: insufficitied privilege to oped device \n" msgstr "ERROR: insufficitied privilege to oped device \n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:42 #, c-format msgid "ERROR: invalid path to back up header file\n" msgstr "ERROR: invalid path to back up header file\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:44 #, c-format msgid "ERROR: invalid path to device\n" msgstr "ERROR: invalid path to device\n" #: ../zuluCrypt-cli/bin/create_volumes.c:46 #: ../zuluCrypt-cli/bin/open_volume.c:81 #, c-format msgid "ERROR: invalid path to key file\n" msgstr "ERROR: invalid path to key file\n" #: ../zuluCrypt-cli/bin/crypt_file.c:35 #, c-format msgid "ERROR: invalid path to source\n" msgstr "ERROR: invalid path to source\n" #: ../zuluCrypt-cli/bin/main.c:82 #, c-format msgid "ERROR: key argument is missing\n" msgstr "ERROR: key argument is missing\n" #: ../zuluCrypt-cli/bin/main.c:86 #, c-format msgid "ERROR: key source argument is missing\n" msgstr "ERROR: key source argument is missing\n" #: ../zuluCrypt-cli/bin/remove_key.c:70 #, c-format msgid "ERROR: keyfile does not exist\n" msgstr "ERROR: keyfile does not exist\n" #: ../zuluCrypt-cli/bin/crypt_file.c:32 #, c-format msgid "ERROR: missing key source\n" msgstr "ERROR: missing key source\n" #: ../zuluCrypt-cli/bin/add_key.c:79 #, c-format msgid "ERROR: new passphrases do not match\n" msgstr "ERROR: new passphrases do not match\n" #: ../zuluCrypt-cli/bin/open_volume.c:68 #, c-format msgid "ERROR: no file or device exist on given path\n" msgstr "ERROR: no file or device exist on given path\n" #: ../zuluCrypt-cli/bin/add_key.c:81 #, c-format msgid "ERROR: one or both keyfile(s) does not exist\n" msgstr "ERROR: one or both keyfile(s) does not exist\n" #: ../zuluCrypt-cli/bin/add_key.c:80 ../zuluCrypt-cli/bin/create_volumes.c:50 #: ../zuluCrypt-cli/bin/open_volume.c:80 ../zuluCrypt-cli/bin/remove_key.c:69 #, c-format msgid "ERROR: one or more required argument(s) for this operation is missing\n" msgstr "" "ERROR: one or more required argument(s) for this operation is missing\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:47 #, c-format msgid "" "ERROR: only root and \"zulucrypt\" group members can restore and back up " "luks headers on system devices\n" msgstr "" "ERROR: only root and \"zulucrypt\" group members can restore and back up " "luks headers on system devices\n" #: ../zuluCrypt-cli/bin/open_volume.c:72 #, c-format msgid "ERROR: only root user can perform this operation\n" msgstr "ERROR: only root user can perform this operation\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:69 #, c-format msgid "ERROR: passphrase file does not exist\n" msgstr "ERROR: passphrase file does not exist\n" #: ../zuluCrypt-cli/bin/create_volumes.c:45 #: ../zuluCrypt-cli/bin/create_volumes.c:53 #: ../zuluCrypt-cli/bin/crypt_file.c:37 #, c-format msgid "ERROR: passphrases do not match\n" msgstr "ERROR: passphrases do not match\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:39 #, c-format msgid "" "ERROR: path to be used to create a back up file is occupied or permission " "denied\n" msgstr "" "ERROR: path to be used to create a back up file is occupied or permission " "denied\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:35 #, c-format msgid "ERROR: presented device is not a LUKS device\n" msgstr "ERROR: presented device is not a LUKS device\n" #: ../zuluCrypt-cli/bin/create_volumes.c:32 #, c-format msgid "" "ERROR: presented file system is not supported,see documentation for more " "information\n" msgstr "" "ERROR: presented file system is not supported,see documentation for more " "information\n" #: ../zuluCrypt-cli/bin/crypt_file.c:40 #, c-format msgid "ERROR: presented key did not match the encryption key\n" msgstr "ERROR: presented key did not match the encryption key\n" #: ../zuluCrypt-cli/bin/add_key.c:70 #, c-format msgid "ERROR: presented key does not match any key in the volume\n" msgstr "ERROR: presented key does not match any key in the volume\n" #: ../zuluCrypt-cli/bin/main.c:473 msgid "ERROR: required option( device path ) is missing for this operation" msgstr "ERROR: required option( device path ) is missing for this operation" #: ../zuluCrypt-cli/bin/main.c:326 msgid "ERROR: setegid() failed" msgstr "ERROR: setegid() failed" #: ../zuluCrypt-cli/bin/main.c:323 msgid "ERROR: setgroups() failed" msgstr "ERROR: setgroups() failed" #: ../zuluCrypt-cli/bin/open_volume.c:75 #, c-format msgid "ERROR: shared mount point path aleady taken\n" msgstr "ERROR: shared mount point path aleady taken\n" #: ../zuluCrypt-cli/bin/crypt_file.c:43 #, c-format msgid "ERROR: source path is missing\n" msgstr "ERROR: source path is missing\n" #: ../zuluCrypt-cli/bin/remove_key.c:60 #, c-format msgid "ERROR: there is no key in the volume that match the presented key\n" msgstr "ERROR: there is no key in the volume that match the presented key\n" #: ../zuluCrypt-cli/bin/open_volume.c:67 #, c-format msgid "ERROR: there seem to be an open volume accociated with given address\n" msgstr "ERROR: there seem to be an open volume accociated with given address\n" #: ../zuluCrypt-cli/bin/create_volumes.c:37 #: ../zuluCrypt-cli/bin/open_volume.c:76 #, c-format msgid "ERROR: there seem to be an opened mapper associated with the device\n" msgstr "ERROR: there seem to be an opened mapper associated with the device\n" #: ../zuluCrypt-cli/bin/add_key.c:86 ../zuluCrypt-cli/bin/close_volume.c:37 #: ../zuluCrypt-cli/bin/create_volumes.c:54 #: ../zuluCrypt-cli/bin/remove_key.c:74 #, c-format msgid "ERROR: unrecognized error with status number %d encountered\n" msgstr "ERROR: unrecognized error with status number %d encountered\n" #: ../zuluCrypt-cli/bin/open_volume.c:69 #, c-format msgid "ERROR: volume could not be opened with the presented key\n" msgstr "ERROR: volume could not be opened with the presented key\n" #: ../zuluCrypt-cli/bin/add_key.c:72 #, c-format msgid "ERROR: volume is not a luks volume\n" msgstr "ERROR: volume is not a luks volume\n" #: ../zuluCrypt-cli/bin/remove_key.c:144 #, c-format msgid "Enter a key to be removed: " msgstr "Enter a key to be removed: " #: ../zuluCrypt-cli/bin/add_key.c:105 #, c-format msgid "Enter an existing passphrase: " msgstr "Enter an existing passphrase: " #: ../zuluCrypt-cli/bin/create_volumes.c:217 #: ../zuluCrypt-cli/bin/crypt_file.c:103 #: ../zuluCrypt-cli/bin/open_volume.c:248 #: ../zuluCrypt-cli/bin/write_device_with_junk.c:165 #, c-format msgid "Enter passphrase: " msgstr "Enter passphrase: " #: ../zuluCrypt-cli/bin/create_volumes.c:284 #, c-format msgid "Enter tcrypt hidden passphrase: " msgstr "Enter tcrypt hidden passphrase: " #: ../zuluCrypt-cli/bin/create_volumes.c:42 #: ../zuluCrypt-cli/bin/remove_key.c:66 #, c-format msgid "INFO: operation terminated per user request\n" msgstr "INFO: operation terminated per user request\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:38 #, c-format msgid "INFO: operation terminater per user request\n" msgstr "INFO: operation terminater per user request\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:74 #, c-format msgid "INFO: signal caught,exiting prematurely\n" msgstr "INFO: signal caught,exiting prematurely\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:66 #, c-format msgid "INFO: user chose not to proceed\n" msgstr "INFO: user chose not to proceed\n" #: ../zuluCrypt-cli/bin/crypt_file.c:45 #, c-format msgid "INFORMATION: functionality currently disabled\n" msgstr "INFORMATION: functionality currently disabled\n" #: ../zuluCrypt-cli/bin/create_volumes.c:67 #, c-format msgid "" "Please read documentation on why this is important\n" "\n" msgstr "" "Please read documentation on why this is important\n" "\n" #: ../zuluCrypt-cli/bin/crypt_file.c:30 #, c-format msgid "SUCCESS: decrypted file created successfully\n" msgstr "SUCCESS: decrypted file created successfully\n" #: ../zuluCrypt-cli/bin/crypt_file.c:29 #, c-format msgid "SUCCESS: encrypted file created successfully\n" msgstr "SUCCESS: encrypted file created successfully\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:34 #, c-format msgid "SUCCESS: header restored successfully\n" msgstr "SUCCESS: header restored successfully\n" #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:33 #, c-format msgid "SUCCESS: header saved successfully\n" msgstr "SUCCESS: header saved successfully\n" #: ../zuluCrypt-cli/bin/add_key.c:69 #, c-format msgid "SUCCESS: key added successfully\n" msgstr "SUCCESS: key added successfully\n" #: ../zuluCrypt-cli/bin/remove_key.c:59 #, c-format msgid "SUCCESS: key removed successfully\n" msgstr "SUCCESS: key removed successfully\n" #: ../zuluCrypt-cli/bin/open_volume.c:47 #, c-format msgid "SUCCESS: luks volume opened successfully\n" msgstr "SUCCESS: luks volume opened successfully\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:56 #, c-format msgid "SUCCESS: mapper created successfully\n" msgstr "SUCCESS: mapper created successfully\n" #: ../zuluCrypt-cli/bin/open_volume.c:49 #, c-format msgid "SUCCESS: plain volume opened successfully\n" msgstr "SUCCESS: plain volume opened successfully\n" #: ../zuluCrypt-cli/bin/open_volume.c:51 #, c-format msgid "SUCCESS: tcrypt volume opened successfully\n" msgstr "SUCCESS: tcrypt volume opened successfully\n" #: ../zuluCrypt-cli/bin/close_volume.c:27 #, c-format msgid "SUCCESS: volume closed successfully \n" msgstr "SUCCESS: volume closed successfully \n" #: ../zuluCrypt-cli/bin/create_volumes.c:31 #: ../zuluCrypt-cli/bin/create_volumes.c:63 #, c-format msgid "SUCCESS: volume created successfully\n" msgstr "SUCCESS: volume created successfully\n" #: ../zuluCrypt-cli/bin/open_volume.c:53 #, c-format msgid "SUCCESS: volume opened successfully\n" msgstr "SUCCESS: volume opened successfully\n" #: ../zuluCrypt-cli/bin/create_volumes.c:205 #, c-format msgid "Type \"YES\" and press enter if you want to process: " msgstr "Type \"YES\" and press enter if you want to process: " #: ../zuluCrypt-cli/bin/remove_key.c:130 #, c-format msgid "" "WARNING: there is only one key in the volume and all data in it will be lost " "if you continue.\n" msgstr "" "WARNING: there is only one key in the volume and all data in it will be lost " "if you continue.\n" #: ../zuluCrypt-cli/bin/create_volumes.c:211 #: ../zuluCrypt-cli/bin/remove_key.c:136 #: ../zuluCrypt-cli/bin/save_and_restore_luks_header.c:266 #: ../zuluCrypt-cli/bin/write_device_with_junk.c:296 msgid "YES" msgstr "YES" #: ../zuluCrypt-cli/bin/main.c:150 #, c-format msgid "device \"%s\" is not a luks device\n" msgstr "device \"%s\" is not a luks device\n" #: ../zuluCrypt-cli/bin/main.c:66 #, c-format msgid "device is a luks volume\n" msgstr "device is a luks volume\n" #: ../zuluCrypt-cli/bin/main.c:68 #, c-format msgid "device is not a luks volume\n" msgstr "device is not a luks volume\n" #: ../zuluCrypt-cli/bin/main.c:188 #, c-format msgid "header backup does not match the one on the device\n" msgstr "header backup does not match the one on the device\n" #: ../zuluCrypt-cli/bin/main.c:185 #, c-format msgid "header backup match the one on the device\n" msgstr "header backup match the one on the device\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:59 #, c-format msgid "opened mapper path: " msgstr "opened mapper path: " #: ../zuluCrypt-cli/bin/main.c:139 #, c-format msgid "path \"%s\" does not point to a device\n" msgstr "path \"%s\" does not point to a device\n" #: ../zuluCrypt-cli/bin/write_device_with_junk.c:327 msgid "percentage complete: " msgstr "percentage complete: " #: ../zuluCrypt-cli/bin/main.c:237 #, c-format msgid "unexpected exiting because you have run out of memory\n" msgstr "unexpected exiting because you have run out of memory\n" #: ../zuluCrypt-cli/bin/open_volume.c:58 #, c-format msgid "volume mounted at: %s\n" msgstr "volume mounted at: %s\n" zuluCrypt-6.2.0/translations/zuluCrypt/zuluCrypt-cli.pot000066400000000000000000000562511425361753700236420ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-07-15 07:13-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: ../../zuluCrypt-cli/bin/add_key.c:110 #, c-format msgid "" "\n" "Enter the new passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:226 #: ../../zuluCrypt-cli/bin/crypt_file.c:112 #, c-format msgid "" "\n" "Re enter passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:293 #, c-format msgid "" "\n" "Re enter tcrypt hidden passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:116 #, c-format msgid "" "\n" "Re enter the new passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:65 #, c-format msgid "" "\n" "SUCCESS: random data successfully written\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:203 #, c-format msgid "" "\n" "This operation will destroy all data in a device at: \"%s\"\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:289 #, c-format msgid "" "\n" "WARNING, device \"%s\" will be overwritten with random data destroying all " "present data.\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:66 #, c-format msgid "" "\n" "creating a backup of the luks header is strongly adviced.\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:111 #, c-format msgid "\"%s\" is a not tcrypt device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:95 ../../zuluCrypt-cli/bin/main.c:108 #, c-format msgid "\"%s\" is a tcrypt device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:117 ../../zuluCrypt-cli/bin/main.c:124 #, c-format msgid "\"%s\" is not a tcrypt device\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:204 #, c-format msgid "Are you sure you want to proceed?\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:290 #, c-format msgid "" "Are you sure you want to proceed? Type \"YES\" and press enter if you are " "sure: " msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:256 #, c-format msgid "" "Are you sure you want to replace a header on device \"%s\" with a backup " "copy at \"%s\"?\n" "Type \"YES\" and press Enter to continue: " msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:131 #, c-format msgid "Do you still want to continue? Type \"YES\" if you do: " msgstr "" #: ../../zuluCrypt-cli/bin/main.c:216 #, c-format msgid "ERROR!!!!!!!!!!: cli option missed!\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:470 msgid "ERROR: \"action\" argument is missing" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:73 #, c-format msgid "ERROR: -O and -m options can not be used together\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:510 msgid "ERROR: a file can have only one hard link" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:512 msgid "" "ERROR: a non supported device encountered,device is missing or permission " "denied\n" "Possible reasons for getting the error are:\n" "1.Device path is invalid.\n" "2.The device has LVM or MDRAID signature" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:76 #, c-format msgid "ERROR: all key slots are occupied, can not add any more keys\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:45 #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:46 #, c-format msgid "ERROR: argument for path to a backup header file is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:50 #, c-format msgid "ERROR: backup file does not appear to contain luks header\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:38 #, c-format msgid "ERROR: can not create a volume on a mounted device\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:77 #: ../../zuluCrypt-cli/bin/create_volumes.c:51 #: ../../zuluCrypt-cli/bin/crypt_file.c:41 #: ../../zuluCrypt-cli/bin/remove_key.c:67 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:75 #, c-format msgid "ERROR: can not get passphrase in silent mode\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:72 #, c-format msgid "ERROR: can not open a mapper on a device with an opened mapper\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:73 #, c-format msgid "ERROR: can not open a mapper on a mounted device\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:31 #, c-format msgid "ERROR: close failed, could not get a lock on /etc/mtab~\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:33 #, c-format msgid "ERROR: close failed, could not resolve full path of device\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:34 #, c-format msgid "ERROR: close failed, shared mount point appear to be busy\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:36 #, c-format msgid "" "ERROR: close failed, shared mount point appear to be in an ambiguous state," "advice to unmount manually" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:35 #, c-format msgid "" "ERROR: close failed, shared mount point appear to belong to a different " "user\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:29 #, c-format msgid "" "ERROR: close failed, the mount point and/or one or more files are in use\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:30 #, c-format msgid "ERROR: close failed, volume does not have an entry in /etc/mtab\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:28 #, c-format msgid "" "ERROR: close failed, volume is not open or was opened by a different user\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:32 #, c-format msgid "" "ERROR: close failed, volume is unmounted but could not close mapper,advice " "to close it manually\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:39 #, c-format msgid "ERROR: container file must be bigger than 3MB\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:86 #, c-format msgid "ERROR: could not create a lock on /etc/mtab\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:35 #, c-format msgid "ERROR: could not create an encrypted volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:63 #, c-format msgid "ERROR: could not create mapper\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:74 #, c-format msgid "" "ERROR: could not create mount point, invalid path or path already taken\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:500 msgid "ERROR: could not find any partition with the presented UUID" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:47 #, c-format msgid "ERROR: could not get a key from a key file\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:84 #: ../../zuluCrypt-cli/bin/create_volumes.c:49 #: ../../zuluCrypt-cli/bin/remove_key.c:73 #, c-format msgid "ERROR: could not get a key from a socket\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:77 #, c-format msgid "ERROR: could not get a passphrase from the module\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:84 #, c-format msgid "ERROR: could not get a passphrase through a local socket\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:42 #, c-format msgid "ERROR: could not get device address from mapper address\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:85 #, c-format msgid "ERROR: could not get elevated privilege,check binary permissions\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:71 #, c-format msgid "ERROR: could not get enough memory to open the key file\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:82 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:70 #, c-format msgid "ERROR: could not get enought memory to hold the key file\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:43 #: ../../zuluCrypt-cli/bin/open_volume.c:78 #, c-format msgid "ERROR: could not get passphrase in silent mode\n" msgstr "" #: ../../zuluCrypt-cli/bin/volume_info.c:46 #, c-format msgid "" "ERROR: could not get volume properties,volume is not open or was opened by a " "different user\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:33 #, c-format msgid "ERROR: could not open encryption routines\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:31 #, c-format msgid "ERROR: could not open key file for reading\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:71 #, c-format msgid "ERROR: could not open luks volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:61 #, c-format msgid "ERROR: could not open the volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:64 #, c-format msgid "ERROR: could not open the volume in write mode\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:36 #, c-format msgid "ERROR: could not open volume for writing\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:75 #, c-format msgid "ERROR: could not open volume in write mode\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:64 #, c-format msgid "ERROR: could not resolve device path\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:36 #, c-format msgid "ERROR: could not resolve path to destination file\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:523 msgid "ERROR: could not resolve path to device" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:49 #, c-format msgid "ERROR: could not resolve path to device\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:83 #: ../../zuluCrypt-cli/bin/create_volumes.c:48 #, c-format msgid "ERROR: couldnt get enought memory to hold the key file\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:38 #, c-format msgid "ERROR: destination path is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:94 #: ../../zuluCrypt-cli/bin/remove_key.c:81 #, c-format msgid "ERROR: device \"%s\" is not a luks device\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:68 #, c-format msgid "ERROR: device path is invalid\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:508 msgid "ERROR: devices in /dev/shm/ path is not suppored" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:85 #, c-format msgid "" "ERROR: failed to mount a filesystem:invalid/unsupported mount option or " "unsupported file system encountered\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:66 #, c-format msgid "" "ERROR: failed to mount ntfs file system using ntfs-3g,is ntfs-3g package " "installed?\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:36 #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:37 #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:40 #, c-format msgid "ERROR: failed to perform requested operation\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:34 #, c-format msgid "ERROR: file or folder already exist at destination address\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:509 msgid "ERROR: given path is a directory" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:77 #, c-format msgid "ERROR: insufficient memory to hold 3 characters?really?\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:78 #: ../../zuluCrypt-cli/bin/create_volumes.c:52 #: ../../zuluCrypt-cli/bin/crypt_file.c:42 #: ../../zuluCrypt-cli/bin/open_volume.c:79 #: ../../zuluCrypt-cli/bin/remove_key.c:68 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:76 #, c-format msgid "ERROR: insufficient memory to hold passphrase\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:44 #, c-format msgid "ERROR: insufficient memory to hold the passphrase\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:52 #, c-format msgid "ERROR: insufficient memory to hold your responce\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:41 #: ../../zuluCrypt-cli/bin/remove_key.c:65 #, c-format msgid "ERROR: insufficient memory to hold your response\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:43 #, c-format msgid "" "ERROR: insufficient privilege to create a backup header in a destination " "folder\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:39 #, c-format msgid "ERROR: insufficient privilege to create destination file\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:70 #, c-format msgid "ERROR: insufficient privilege to mount the device with given options\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:33 #, c-format msgid "" "ERROR: insufficient privilege to open a system device in read/write mode,\n" "only root user or members of group zulucrypt-system can do that" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:73 #, c-format msgid "" "ERROR: insufficient privilege to open a system device,\n" "only root user or members of group \"zulucrypt\" can do that\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:62 #, c-format msgid "" "ERROR: insufficient privilege to open a system device,only root user or " "members of group zulucrypt-system can do that\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:41 #, c-format msgid "ERROR: insufficient privilege to open backup header file for reading\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:71 #, c-format msgid "ERROR: insufficient privilege to open device\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:51 #, c-format msgid "ERROR: insufficient privilege to open device for reading\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:48 #, c-format msgid "ERROR: insufficient privilege to open device for writing\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:82 #: ../../zuluCrypt-cli/bin/open_volume.c:83 #: ../../zuluCrypt-cli/bin/remove_key.c:72 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:71 #, c-format msgid "ERROR: insufficient privilege to open key file for reading\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:44 #, c-format msgid "ERROR: insufficient privilege to open source file for reading\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:78 #, c-format msgid "ERROR: insufficient privilege to open the file with your privileges?\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:511 msgid "ERROR: insufficient privilges to access the device" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:176 #, c-format msgid "ERROR: insufficient privilges to operate on a system device\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:67 #, c-format msgid "ERROR: insufficitied privilege to oped device \n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:42 #, c-format msgid "ERROR: invalid path to back up header file\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:44 #, c-format msgid "ERROR: invalid path to device\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:46 #: ../../zuluCrypt-cli/bin/open_volume.c:81 #, c-format msgid "ERROR: invalid path to key file\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:35 #, c-format msgid "ERROR: invalid path to source\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:82 #, c-format msgid "ERROR: key argument is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:86 #, c-format msgid "ERROR: key source argument is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:70 #, c-format msgid "ERROR: keyfile does not exist\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:32 #, c-format msgid "ERROR: missing key source\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:79 #, c-format msgid "ERROR: new passphrases do not match\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:68 #, c-format msgid "ERROR: no file or device exist on given path\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:81 #, c-format msgid "ERROR: one or both keyfile(s) does not exist\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:80 #: ../../zuluCrypt-cli/bin/create_volumes.c:50 #: ../../zuluCrypt-cli/bin/open_volume.c:80 #: ../../zuluCrypt-cli/bin/remove_key.c:69 #, c-format msgid "ERROR: one or more required argument(s) for this operation is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:47 #, c-format msgid "" "ERROR: only root and \"zulucrypt\" group members can restore and back up " "luks headers on system devices\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:72 #, c-format msgid "ERROR: only root user can perform this operation\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:69 #, c-format msgid "ERROR: passphrase file does not exist\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:45 #: ../../zuluCrypt-cli/bin/create_volumes.c:53 #: ../../zuluCrypt-cli/bin/crypt_file.c:37 #, c-format msgid "ERROR: passphrases do not match\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:39 #, c-format msgid "" "ERROR: path to be used to create a back up file is occupied or permission " "denied\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:35 #, c-format msgid "ERROR: presented device is not a LUKS device\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:32 #, c-format msgid "" "ERROR: presented file system is not supported,see documentation for more " "information\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:40 #, c-format msgid "ERROR: presented key did not match the encryption key\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:70 #, c-format msgid "ERROR: presented key does not match any key in the volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:473 msgid "ERROR: required option( device path ) is missing for this operation" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:326 msgid "ERROR: setegid() failed" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:323 msgid "ERROR: setgroups() failed" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:75 #, c-format msgid "ERROR: shared mount point path aleady taken\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:43 #, c-format msgid "ERROR: source path is missing\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:60 #, c-format msgid "ERROR: there is no key in the volume that match the presented key\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:67 #, c-format msgid "ERROR: there seem to be an open volume accociated with given address\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:37 #: ../../zuluCrypt-cli/bin/open_volume.c:76 #, c-format msgid "ERROR: there seem to be an opened mapper associated with the device\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:86 #: ../../zuluCrypt-cli/bin/close_volume.c:37 #: ../../zuluCrypt-cli/bin/create_volumes.c:54 #: ../../zuluCrypt-cli/bin/remove_key.c:74 #, c-format msgid "ERROR: unrecognized error with status number %d encountered\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:69 #, c-format msgid "ERROR: volume could not be opened with the presented key\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:72 #, c-format msgid "ERROR: volume is not a luks volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:144 #, c-format msgid "Enter a key to be removed: " msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:105 #, c-format msgid "Enter an existing passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:217 #: ../../zuluCrypt-cli/bin/crypt_file.c:103 #: ../../zuluCrypt-cli/bin/open_volume.c:248 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:165 #, c-format msgid "Enter passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:284 #, c-format msgid "Enter tcrypt hidden passphrase: " msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:42 #: ../../zuluCrypt-cli/bin/remove_key.c:66 #, c-format msgid "INFO: operation terminated per user request\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:38 #, c-format msgid "INFO: operation terminater per user request\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:74 #, c-format msgid "INFO: signal caught,exiting prematurely\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:66 #, c-format msgid "INFO: user chose not to proceed\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:45 #, c-format msgid "INFORMATION: functionality currently disabled\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:67 #, c-format msgid "" "Please read documentation on why this is important\n" "\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:30 #, c-format msgid "SUCCESS: decrypted file created successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/crypt_file.c:29 #, c-format msgid "SUCCESS: encrypted file created successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:34 #, c-format msgid "SUCCESS: header restored successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:33 #, c-format msgid "SUCCESS: header saved successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/add_key.c:69 #, c-format msgid "SUCCESS: key added successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:59 #, c-format msgid "SUCCESS: key removed successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:47 #, c-format msgid "SUCCESS: luks volume opened successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:56 #, c-format msgid "SUCCESS: mapper created successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:49 #, c-format msgid "SUCCESS: plain volume opened successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:51 #, c-format msgid "SUCCESS: tcrypt volume opened successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/close_volume.c:27 #, c-format msgid "SUCCESS: volume closed successfully \n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:31 #: ../../zuluCrypt-cli/bin/create_volumes.c:63 #, c-format msgid "SUCCESS: volume created successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:53 #, c-format msgid "SUCCESS: volume opened successfully\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:205 #, c-format msgid "Type \"YES\" and press enter if you want to process: " msgstr "" #: ../../zuluCrypt-cli/bin/remove_key.c:130 #, c-format msgid "" "WARNING: there is only one key in the volume and all data in it will be lost " "if you continue.\n" msgstr "" #: ../../zuluCrypt-cli/bin/create_volumes.c:211 #: ../../zuluCrypt-cli/bin/remove_key.c:136 #: ../../zuluCrypt-cli/bin/save_and_restore_luks_header.c:266 #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:296 msgid "YES" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:150 #, c-format msgid "device \"%s\" is not a luks device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:66 #, c-format msgid "device is a luks volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:68 #, c-format msgid "device is not a luks volume\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:188 #, c-format msgid "header backup does not match the one on the device\n" msgstr "" #: ../../zuluCrypt-cli/bin/main.c:185 #, c-format msgid "header backup match the one on the device\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:59 #, c-format msgid "opened mapper path: " msgstr "" #: ../../zuluCrypt-cli/bin/main.c:139 #, c-format msgid "path \"%s\" does not point to a device\n" msgstr "" #: ../../zuluCrypt-cli/bin/write_device_with_junk.c:327 msgid "percentage complete: " msgstr "" #: ../../zuluCrypt-cli/bin/main.c:237 #, c-format msgid "unexpected exiting because you have run out of memory\n" msgstr "" #: ../../zuluCrypt-cli/bin/open_volume.c:58 #, c-format msgid "volume mounted at: %s\n" msgstr "" zuluCrypt-6.2.0/translations/zuluMount/000077500000000000000000000000001425361753700203205ustar00rootroot00000000000000zuluCrypt-6.2.0/translations/zuluMount/README000066400000000000000000000001601425361753700211750ustar00rootroot00000000000000 messages.ts has zuluMount-gui strings to be translated messages.pot has zuluMount-cli strings to be translated zuluCrypt-6.2.0/translations/zuluMount/ar_SA.qm000066400000000000000000000755361425361753700216640ustar00rootroot00000000000000<¸dÊÍ!¿`¡½Ý§ar_SABPÓ +O…+[ªQÉ7ï¹Ä$¿ÃÑ[èc(Œg¡n6` žE¥ õ¡«¬ôÓÀeAÉ´ÌÞjù*É´UÚ+f¾+G–ÄV®Jgz xJwBÆJwBUJwBGÛJwB\QJ  TòRx¼bdR}Õ=GSÀÕbTlTb¼WñÕ¨Zz –^Ü„V^Ü„EWaŒE]¤bƒÉ@Èjye3sf: ÈtZŠ|Šiˆ¬Ä[˜ž#)ižÎÎ'¤Œé¦ó  ÅÃ…?Èð¬Ã\Ó¦s 2Z´71ëFŠXîå%¯cÛ>Nhš2N<œ%8ÍÐu8eï'×'P»IMÔ|ÚjóŒÃå% ŸÃDcx´lTDñ¸rYq˜àJÛ( hpÜB-Bp/N‚ÅíR"S`¬UJjlçte^ŒªÞEݤë”s›½("¤µöÐDSTÓÏóiè ÷>Xå’iZ" çÉjoQ‘W•S0ùrxg€‡–ʵ˜I¼!ܘI¼E®¢aS•¤FÂed§tA&F§tA\z¯ƒWù¾ïˆ:¶Õ³"b!ðD‚qbô,uRÍ&ÌQ7:_y=ï<¸?ÅÂ"FZFA¿OŠåVGP-G€\ÆDÙa¤Â9©bõ:xbõN%s½þ=~­ô0 ™ÔŽ#œôÄXÍœ vÕf)!má³cqý?´( ý¨Í`kgÚ4RÔ0÷- 8oñB"é`Zc@dfÊw6q{ãE ›Èž n Á£¶UmÝ¥ýS?#¬³îgǬϕ ÌÖ£gkÑô^ô‰5j.äBjX§~šX§~oX§~a°\ÙÄHk•¨8ü€T(t€TH;¯J‰8 ·—aQÅÉ´”ɶ%úɶŠ}Ëòú ¹Úâê0ë—nØì>R9F½Î ×&ß;m1¤1©QüÃ3—X•wQö\aòeòn•d-¼™ø½O»vå=†½Ž(V~ØÌikx ™: •~> q™5WÝ ‡>óW< ¶æ fD ÖžÉCà ç””^¾ ø>‡ øP~ úMRaç ì: í CZ ¿þJw !XQ #x)Š #xIZ ,ßÞ]C WãÔC4 \ tiƒ l “P wE€&r wE€H wE€\¦ ‘ô*¢ ˜Iœð ˜Iœ ˜IœDÁ Ìùê H âá" “bñ YT/T “T, ¶¥’e£ Á¬2À × ®op ú 42v Lo´ TloE VL¤ ¯yµ7… µ‰”Ñ µÚ”$w ·¨ & º|Òbå »~X ¾'Ž&Ÿ îÈòl< ômõ“ š b lt+S 2„V× =ìNcù iFC`2 j'd.v k¦CV y…µ#å {C;; ‰Psl Úz y æÃ‡n‰.%pˆŽõd”œA]§W3M · rOœÄÄD5†Æù„PÞN[àcT %¢qè/œ6aP™´\’"|¾’"|Q¨%_sðV4,ØüFÔnoptions->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. DialogMsgD'&No DialogMsgF9E&Ok DialogMsgF9E&Yes DialogMsg F'A0)Dialog DialogMsg8D' *8G1 G0G 'DF'A0) E1) #.1IDo not show this dialog again DialogMsgE9DHE'* INFORMATION DialogMsgÞ5D'-J'* :J1 C'AJ) DD/.HD 9DI B15 'DF8'E DDB1'!) H'DC*'() AB7 E3*./E E/J1 H96H AJ E,EH9) 2HDH C1(* JECFG A9D 0DCƒInsufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that DialogMsg¾5D'-J'* :J1 C'AJ) DD/.HD 9DI B15 'DF8'E. AB7 E3*./E E/J1 H96H AJ E,EH9) 2HDH C1(* JECFG A9D 0DCjInsufficient privilege to access a system device, only root user or members of group zulucrypt can do that DialogMsg'D1BE 'D*91JAJ:UUID: DialogMsgÆDJ3 D/JC 'D#0HF'* 'DEF'3() DD/.HD 9DI 'DEDA 'DE4A1 AJ 7H1 1%. *#C/ EF #0HF'* 'DEDA +E -'HD E1) #.1IwYou do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again DialogMsg'DEF'A0 'DF47) active slots DialogMsg'DEF'A0 'DF47): active slots: DialogMsg4A1)cipher DialogMsg 4A1):cipher: DialogMsg,G'2device DialogMsg 'DB15:device: DialogMsgF8'E EDA'*: file system: DialogMsg 'DE3'-) 'DE*'-): free space: DialogMsgfsfs DialogMsg-,E 'DEA*'-key size DialogMsg-,E 'DEA*'-keysize: DialogMsg/H1)loop DialogMsg /H1):loop: DialogMsg7H1mode DialogMsg7H1:mode: DialogMsg %2'-)offset DialogMsg'D%2'-):offset: DialogMsg-,Esize DialogMsgF5text DialogMsg'DE3'-) 'DCDJ): total space: DialogMsgFH9type DialogMsgFH9:type: DialogMsg:J1 E3*./Eunused DialogMsg E3*./Eused DialogMsg%'DE3*./Eused % DialogMsg$'DE3'-) 'DE3*./E): used space: DialogMsg'DE3*./E%:used%: DialogMsg"'D.J'1'* d..'DE3'1 %DI 'DE,D/ D*-EJDG *DB'&J'/AC *4AJ1G m..'D#/') 'DE3*./E) CE/J1 EDA'* ('D'A*1'6J GH xdg-open) e..%(/# 'D*7(JB (/HF H',G) 13HEJ)Í options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI QObjectœDE JECF *9JJF EDA pgp 'D*FAJ0J AJ "/usr/local/bin","/usr/bin" and "/usr/sbin"NCould not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin"QObject.7#ERRORQObjectDA4D AJ *9JJF 'DEDA 'D*FAJ0J pkexec"Failed to locate pkexec executableQObjectE9DHE'* INFORMATIONQObject¶%0' *E *A9JD 'D.J'1 A3HA JF4J! FB7) *-EJD 1&J3J) AJ "1%" H +'FHJ DD/.HD 'D9'E JF4# AJ "2%"ŸIf the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2"QObject'DB'&E) A'1:) List Is EmptyQObject *-CE AJ 'DEA6D'*Manage FavoritesQObject-ED 'DCD Mount AllQObject9F 2HDH C1(*about zuluCryptQObject’%6'A) pgp> G0G 'D%6'A) *3*9J/ 'DEA*'- 'DE4A1 /'.D EDA pgp (EA*'- *E'+DJQgpg plugin. This plugin retrives a key locked in a gpg file with a symmetric keyQObject´%6'A) hmac *HD/ 'DEA*'- ('3*./'E 'D5J:): 'DEA*'-=hmac(sha256,CDE) 'D31 E-*HI EDA 'DEA*'-)ohmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents)QObjectÀ%6'A) EDA 'DEA*'-. G0G 'D%6'A) *HD/ EA*'- ('3*./'E 'D5J:): 'DEA*'-=CDE) 'D31+E-*HI EDA 'DEA*'-jkeykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contentsQObject FB7) *-EJD 9'E):public mount point: QObject#D:&CancelVeraCryptPIMDialog-//&SetVeraCryptPIMDialog.7#ERRORVeraCryptPIMDialog<A4D AJ *-HJD 'DBJE) D#1B'E AB7+Failed to convert the value to digits only VeraCryptPIMDialogT-// 'D1BE 'D3-1J D7H1 AJ1' C1(* 'D/JF'EJCJ.Set VeraCrypt dynamic mode magic number below.VeraCryptPIMDialog'DF5 TextLabelVeraCryptPIMDialog*BJE) PIM AJ AJ1' C1(*VeraCrypt PIM valueVeraCryptPIMDialogTG0' 'D1E2 "/" :J1 EB(HD AJ -BD '3E 'D*-EJD4"/" character is not allowed in the mount name field keyDialog#D:&Cancel keyDialog'A*-&Open keyDialog"4'1C FB7) 'D*-EJD&Share Mount Point keyDialogE,D/ AJ1'C1(*&VeraCrypt Volume keyDialogZG0'F 'D.J'1'F D' JECF '3*./'EGE' E9': -O H -m*-O and -m options can not be used together keyDialogB15 :J1 E/9HE #H B15 EABH/ #H #0HF'* E1AH6). 'D#3('( 'DE-*ED) DG0' 'D.7#: 1- E3'1 'DB15 :J1 5-J- 2- 'DB15 9DJG *HBJ9 LVM or MDRAID¸A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature keyDialog.-BD H'-/ A'1: 9DI 'D#BD#Atleast one required field is empty keyDialog#D:Cancel keyDialogB'.*1 G0' 'D.J'1 CJ *8G1 CDE) 'D31'Check This Box To Make Password Visible keyDialogDDE JECF %F4'! BAD DDE3'1 /etc/mtab$Could not create a lock on /etc/mtab keyDialogtDE JECF %F4'! FB7) *-EJD. E3'1 .'7& #H B/ *E *9JJFG EF B(D@Could not create mount point, invalid path or path already taken keyDialogJDE JECF '3*1,'9 CDE) 'D31 EF 'D(1F'E,*Could not get a passphrase from the module keyDialogZDE JECF 'D-5HD 9DI CDE) 'D31 EF 'DEFA0 'DE-DJ1Could not get a passphrase through a local socket keyDialog@0'C1) :J1 C'AJ) D-A8 EDA 'DEA*'-1Could not get enought memory to hold the key file keyDialogRDE JECF '3*1,'9 CDE) 'D31 AJ 'DFE7 'D5'E*'Could not get passphrase in silent mode keyDialog.7#!ERROR! keyDialog.7#:ERROR:  keyDialogR#/.D 'D%2'-) ('D#3AD DDE,D/ 'DE3*G/A A*-GAEnter Below The Offset Location Of The Volume About To Be Opened. keyDialogf#/.D .J'1'* F8'E 'D*4:JD ('D#3AD H'A5D (JFG' (A'5D)8Enter Comma Separated Volume's File System Options Below keyDialog.A4D AJ %F4'! FB7) *-EJDFailed to create mount point keyDialog”A4D AJ *-EJD F8'E 'DEDA'* #H FB7) *-EJD :J1 E/9HE) #H F8'E *4:JD :J1 E/9HEdFailed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered keyDialog¢A4D AJ *-EJD F8'E EDA'* ntfs #H exfat ('3*./'E ntfs-3g. GD -2E) ntfs/exfat E+(*)XFailed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? keyDialog\A4D AJ A*- E,D/ cryfs. #/.D* CDE) 31 :J1 5-J-)7Failed to unlock a cryfs volume. Wrong password entered keyDialogjA4D AJ A*- E,D/ cryfs. DE J9+1 9DI EDA cryfs 'D*FAJ0JDFailed to unlock a cryfs volume. cryfs executable could not be found keyDialog`A4D AJ A*- E,D/ gocryfs. #/.D* CDE) 31 :J1 5-J-);Failed to unlock a gocryptfs volume. Wrong password entered keyDialogzA4D AJ A*- E,D/ gocryptfs. DE J9+1 9DI EDA gocryptfs 'D*FAJ0JLFailed to unlock a gocryptfs volume. gocryptfs executable could not be found keyDialogbA4D AJ A*- E,D/ securefs. #/.D* CDE) 31 :J1 5-J-):Failed to unlock a securefs volume. Wrong password entered keyDialogvA4D AJ A*- E,D/ securefs. DE J9+1 9DI EDA securefs 'D*FAJ0JJFailed to unlock a securefs volume. securefs executable could not be found keyDialog`A4D AJ A*- E,D/ ecrytfs. #/.D* CDE) 31 :J1 5-J-);Failed to unlock an ecryptfs volume. Wrong password entered keyDialogzA4D AJ A*- E,D/ encryptfs. DE J9+1 9DI EDA encryptfs 'D*FAJ0JRFailed to unlock an ecryptfs volume. ecryptfs-simple executable could not be found keyDialog\A4D AJ A*- E,D/ encfs. #/.D* CDE) 31 :J1 5-J-)8Failed to unlock an encfs volume. Wrong password entered keyDialogjA4D AJ A*- E,D/ encfs. DE J9+1 9DI EDA encfs 'D*FAJ0JEFailed to unlock an encfs volume. encfs executable could not be found keyDialogFA4D AJ A*- 'DE,D/. 'DE,D/ :J1 E/9HE=Failed to unlock the volume. Not supported volume encountered keyDialog<0'C1) :J1 C'AJ) D-A8 CDE) 'D31&Insufficient memory to hold passphrase keyDialog`5D'-J'* :J1 C'AJ) D*-EJD 'DB15 ('D.J'1'* 'DE97')=Insufficient privilege to mount the device with given options keyDialog²5D'-J'* :J1 C'AJ) DA*- E,D/ 'DF8'E. DDE2J/ EF 'DE9DHE'* 1',9 B'&E) 'DE3'9/) +E 'DD#0HF'*dInsufficient privilege to open a system volume. Consult menu->help->permission for more informaion  keyDialog|5D'-J'* :J1 C'AJ) DA*- 'DB15 DDB1'!) AB7 #H #F 'DB15 :J1 EH,H/QInsufficient privilege to open device in read write mode or device does not exist keyDialogT5D'-J'* :J1 C'AJ) DA*- EDA 'DEA*'- DDB1'!)3Insufficient privilege to open key file for reading keyDialog0DE J*E *GJ&) .2F) /'.DJ)!Internal wallet is not configured keyDialog4E3'1 :J1 5-J- DEDA 'DEA*'-Invalid path to key file keyDialog EA*'-Key keyDialog"EA*'-+EDA 'DEA*'- Key+KeyFile keyDialogEDA 'DEA*'-KeyFile keyDialog(-BD EDA 'DEA*'- A'1:Keyfile field is empty keyDialog E3'1 EDA 'DEA*'- Keyfile path keyDialog*-ED E,D/ DHC3 AJ "1%"Mount A LUKS volume in "%1" keyDialog.-ED E,D/' E4A1' AJ "1%"!Mount An Encrypted Volume In "%1" keyDialog,-ED (H69J) 'DB1'!) AB7Mount In &Read Only Mode keyDialog'3E 'D*-EJD Mount Name keyDialogBD' JH,/ EDA #H B15 ('DE3'1 'DE97I%No file or device exist on given path keyDialog .J'1'*O&ptions keyDialog>E97I #H #C+1 E7DH( DCFG DE JHA1>One or more required argument(s) for this operation is missing keyDialogjAB7 'DE3*./E (5D'-J'* 'DE/J1 J3*7J9 *FAJ0 G0G 'D9EDJ))Only root user can perform this operation keyDialog(-BD '3E 'D%6'A) A'1:Plug in name field is empty keyDialog %6'A)Plugin keyDialog'3E 'D%6'A) Plugin name keyDialog:-// EDA' D'3*./'EG CEDA EA*'-%Select A File To Be Used As A Keyfile keyDialog<-// E,D/ D%F4'! FB7) *-EJD AJG*Select A Folder To Create A Mount Point In keyDialogZFB7) 'D*-EJD.'DE4*1C) E3'1G' *E *9JJFG EF B(D$Shared mount point path aleady taken keyDialogJJ(/H #F E,D/' EA*H-' AJ 'D9H'F 'DE97I=There seem to be an open volume accociated with given address keyDialogB'DE.77 'DEB*1F ('DB15 J(/H EA*H-'FB7) 'D*-EJD 'DE4*1C) 3(B #.0G'$Shared mount point path aleady takenmountPartition'DF5 TextLabelmountPartition,'3*./E 'DED5B 'D*91JAJ Use La&belmountPartition,#/.D E3'1 FB7) 'D*-EJDselect mount point pathmountPartitionn'DF3.) 'D3'(B) J(/H #FG' 'FG'1*. -'HD 'D*F8JA B(D 'D(/!IPrevious instance seem to have crashed,trying to clean up before starting oneinstancenJ(/H #FG *H,/ F3.) #.1I BJ/ 'D*4:JD. '.1, EF G0G 'DF3.):There seem to be another instance running,exiting this one oneinstance0'DHB* 'DE3*:1B: 0% /BJB)Elapsed time: %0 minutesutility::veraCryptWarning0'DHB* 'DE3*:1B: 0% +'FJ)Elapsed time: %0 secondsutility::veraCryptWarning,'DHB* 'DE3*:1B: 0 +H'FElapsed time: 0 secondsutility::veraCryptWarninglJ1,I 'D'F*8'1 D#F A*- E,D/ AJ1' C1(* J3*:1B HB*' 7HJD'NPlease be patient as unlocking a VeraCrypt volume may take a very long time. utility::veraCryptWarning%E3*./E%Used zuluMount&'D*A6JD'* &Favorites zuluMount-ED EDA &Mount File zuluMount *-/J+&Refresh zuluMount-HDAbout zuluMount2'A*- FB7) 'D*-EJD *DB'&J'Auto Open Mount Point zuluMount**-EJD *DB'&J DDE,D/'*Automount Volumes zuluMount-,E 'D(DHC: 1%Block Size: %1 zuluMount#:DB 'DB'&E) Close Menu zuluMounthA4D AJ 'D%:D'B. DE JECF 'D9+H1 9DI B3E (FA3 1BE UUIDBClose failed, could not find any partition with the presented UUID zuluMountLDE JECF 'D-5HD 9DI BAD 9DI /etc/mtab~"Could not get a lock on /etc/mtab~ zuluMount>DE JECF 'D-5HD 9DI .5'&5 'DE,D/UCould not get volume properties. volume is not open or was opened by a different user zuluMount~DE JECF A*- FB7) 'D*-EJD D#F 'D#/') "1%" D' *(/H *9ED (4CD 3DJETCould not open mount point because "%1" tool does not appear to be working correctly zuluMountBDE JECF E91A) 'DE3'1 'DC'ED DDB15&Could not resolve full path of device  zuluMount&'DB15 D' J(/H E-ED'$Device does not appear to be mounted zuluMount'DB15 :J1 EH,H/Device does not exist zuluMount.7#ERROR zuluMount.7#!ERROR! zuluMount.7#:ERROR:  zuluMount2A4D AJ B1'!) .5'&5 'DE,D/ Failed To Read Volume Properties zuluMount$A4D AJ *F2JD 'DB3EFailed to unmount the partition zuluMount&A4D AJ *F2JD 'DE,D/Failed to unmount volume zuluMountlA4D AJ 'D*F2JD. DE JECF 'D-5HD 9DI BAD 9DI /etc/mtab~4Failed to unmount,could not get a lock on /etc/mtab~ zuluMountXA4D AJ 'D*F2JD. 'C*4A* 9/) FB'7 *-EJD DDE,D/?Failed to unmount,multiple mount points for the volume detected zuluMount\A4D AJ *F2JD 'DE,D/. EDA #H #C+1 BJ/ 'D'3*./'EEFailed to unmount,the mount point and/or one or more files are in use zuluMount'D*A6JD'* Favorites zuluMountF8'E 'DEDA'* File System zuluMount('D(DHC'* 'D4':1): 3%Free Blocks: %3 zuluMount$'DE3'-) 'D4':1) 6%Free Space: %6 zuluMount,#.A 'DE,D/ EF 'DE9'JF)Hide Volume From View zuluMountE9DHE'* INFORMATION zuluMountED5B="1%" LABEL="%1" zuluMountED5B="1%" 2% LABEL="%1" %2 zuluMountED5BLabel zuluMount B'&E)Men&u zuluMount-EDMount zuluMount*-EJD 'DE,D/ Mount F&older zuluMount"E3'1 FB7) 'D*-EJDMount Point Path zuluMount6'C*4A* 9/) FB'7 *-EJD DDB15-Multiple mount points for the volume detected zuluMountREDA #H #C+1 AJ 'DE,D/ BJ/ 'D'3*./'E -'DJ'+One or more files in the volume are in use. zuluMountlAB7 E3*./E E/J1 EF E,EH9) 2HDH C1(* JECFG *F2JD 'DE,D/FOnly root user of members of group "zulumount" can unmount this volume zuluMount'A*- 'DE,D/ Open Folder zuluMount'A*- E,D/' .'5'Open Private Folder zuluMount"'A*- E,D/' E4*1C'Open Shared Folder zuluMount¢'D#0HF'* D' *3E- ('D/.HD 9DI 'DE,D/ #H 'DE,D/ :J1 E/9HE (D' JH,/ *HBJ9LVM/MDRAID)gPermission to access the volume was denied or the volume is not supported (LVM/MDRAID signatures found) zuluMount .5'&5 Properties zuluMount.1H,Quit zuluMount¾B1'!) .5'&5 'DB3E #.0 HB*' #C+1 EF 'DE*HB9 H9DJG *E %FG'! 'D9EDJ). '6:7 *-/J+ DDE-'HD) E1) #.1InReading partition properties took longer than expected and operation was terminated,click refresh to try again zuluMount0'.*1 /DJD' DDE,D/ 'DE4A1$Select An Encrypted Volume Directory zuluMount*'.*1 EDA 5H1) DD*-EJDSelect An Image File To Mount zuluMount'.*1 'D#JBHF'* Select Icons zuluMount'.*1 'DD:)Select Language zuluMountBFB7) 'D*-EJD 'DE4*1C) *(/H E4:HD)$Shared mount point appear to be busy zuluMountBFB7) 'D*-EJD 'DE4*1C) *(/H E4:HD)%Shared mount point appear to be busy  zuluMountVFB7) 'D*-EJD AJ -'D) :'E6). F2D 'DB15 J/HJ'PShared mount point appear to be in an ambiguous state,advice to unmount manually zuluMountVFB7) 'D*-EJD 'DE4*1C) *(/H **(9 E3*./E' ".17Shared mount point appear to belong to a different user zuluMount~FB7) 'D*-EJD 'DE4*1C) **(9 DE3*./E ".1 #H 'C*4A* 9/) FB'7 *-EJDZShared mount point appear to belong to a different user or multiple mount points detected  zuluMount#8G1/#.A Show/Hide zuluMount-,ESize zuluMount E,EH9 'D(DC'* 4%Total Blocks %4 zuluMount"'DE3'-) 'DCDJ) 7%Total Space: %7 zuluMount8#D: %.A'! 'DE,D/ EF 'DE9'JF)Unhide Volume From View zuluMountF2DUnmount zuluMountF2D H#7A&Unmount + Power Down zuluMountF2D 'D,EJ9 Unmount All zuluMount'DE3*./E 8% Used %: %8 zuluMount,'D(DHC'* 'DE3*./E): 2%Used Blocks: %2 zuluMount('DE3'-) 'DE3*./E) 5%Used Space: %5 zuluMountE3'1 'DE,D/ Volume Path zuluMount.5'&5 'DE,D/Volume Properties zuluMount>'DE,D/ DJ3 DG 3,D AJ /etc/mtab*Volume does not have an entry in /etc/mtab zuluMountV'DE,D/ :J1 EA*H- #H EA*H- EF B(D E3*./E ".14Volume is not open or was opened by a different user zuluMountt'DE,D/ :J1 EF2D DCF D' JECF %:D'B 'DE.77. #:DB 'DB15 J/HJ'JVolume is unmounted but could not close mapper,advice to close it manually zuluMount *-0J1Warning zuluMount2HDH E'HF* zuluMount zuluMountˆÿÿÿ$ ÿ* zuluCrypt-6.2.0/translations/zuluMount/ar_SA.ts000066400000000000000000002131431425361753700216610ustar00rootroot00000000000000 DialogMsg Dialog Ù†Ø§ÙØ°Ø© &Ok نعم &Yes نعم &No لا text نص type نوع cipher Ø´ÙØ±Ø© key size حجم Ø§Ù„Ù…ÙØªØ§Ø­ device جهاز loop دورة offset إزاحة size حجم mode طور fs fs used مستخدم unused غير مستخدم used % %المستخدم active slots Ø§Ù„Ù…Ù†Ø§ÙØ° النشطة "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. مجلدات النظام هي مجلدات هي التي عرÙها udev كذلك إذا كانت Ù…ÙØ¹Ù„Ø© أو هناك بند بذلك ÙÙŠ "/etc/fstab","/etc/crypttab" أو "/etc/zuluCrypt/system_volumes.list". إذا كنت ØªÙØ¶Ù„ ألا يعتبر مجلد كمجلد نظام، شغل البرنامج بصلاحيات مدير ثم من قائمة الخيارات اختر "تحكم ÙÙŠ غير مجلدات النظام" Ùˆ أض٠المجلد لتلك القائمة ومن ثم لن يعتبر المجلد كمجلد نظام. وكحل بديل، أض٠حسابك لمجموعة زولو كربت Ùˆ مجموعة زولو كربت ماونت ومن ثم هذا القيد سيزول. INFORMATION معلومات Insufficient privilege to access a system device, only root user or members of group zulucrypt can do that صلاحيات غير كاÙية للدخول على قرص النظام. Ùقط مستخدم مدير وعضو ÙÙŠ مجموعة زولو كربت يمكنه ÙØ¹Ù„ ذلك Insufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that صلاحيات غير كاÙية للدخول على قرص النظام للقراءة والكتابة Ùقط مستخدم مدير وعضو ÙÙŠ مجموعة زولو كربت يمكنه ÙØ¹Ù„ ذلك You do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again ليس لديك الأذونات المناسبة للدخول على Ø§Ù„Ù…Ù„Ù Ø§Ù„Ù…Ø´ÙØ± ÙÙŠ طور 1%. تأكد من أذونات المل٠ثم حاول مرة أخرى type: نوع: cipher: Ø´ÙØ±Ø©: keysize: حجم Ø§Ù„Ù…ÙØªØ§Ø­ offset: الإزاحة: device: القرص: loop: دورة: mode: طور: active slots: Ø§Ù„Ù…Ù†Ø§ÙØ° النشطة: file system: نظام Ù…Ù„ÙØ§Øª: total space: المساحة الكلية: used space: المساحة المستخدمة: free space: المساحة المتاحة: used%: المستخدم%: UUID: الرقم التعريÙÙŠ: Do not show this dialog again لا تظهر هذه Ø§Ù„Ù†Ø§ÙØ°Ø© مرة أخرى QObject options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI الخيارات d..المسار إلى المجلد لتحميله تلقائيا/ÙÙƒ تشÙيره m..الأداة المستخدمة كمدير Ù…Ù„ÙØ§Øª (Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠ Ù‡Ùˆ xdg-open) e..إبدأ التطبيق بدون واجهة رسومية If the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2" إذا تم ØªÙØ¹ÙŠÙ„ الخيار، ÙØ³ÙˆÙ ينشيء نقطة تحميل رئيسية ÙÙŠ "1%" Ùˆ ثانوي للدخول العام ينشأ ÙÙŠ "2%" public mount point: نقطة تحميل عامة: Manage Favorites تحكم ÙÙŠ Ø§Ù„Ù…ÙØ¶Ù„ات Mount All حمل الكل about zuluCrypt عن زولو كربت hmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents) Ø¥Ø¶Ø§ÙØ© hmac تولد Ø§Ù„Ù…ÙØªØ§Ø­ باستخدام الصيغة: Ø§Ù„Ù…ÙØªØ§Ø­=hmac(sha256,كلمة السر،محتوى Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­) keykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contents Ø¥Ø¶Ø§ÙØ© Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­. هذه Ø§Ù„Ø¥Ø¶Ø§ÙØ© تولد Ù…ÙØªØ§Ø­ باستخدام الصيغة: Ø§Ù„Ù…ÙØªØ§Ø­=كلمة السر+محتوى Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ gpg plugin. This plugin retrives a key locked in a gpg file with a symmetric key Ø¥Ø¶Ø§ÙØ© pgp> هذه Ø§Ù„Ø¥Ø¶Ø§ÙØ© تستعيد Ø§Ù„Ù…ÙØªØ§Ø­ Ø§Ù„Ù…Ø´ÙØ± داخل مل٠pgp Ø¨Ù…ÙØªØ§Ø­ تماثلي ERROR خطأ zuluCrypt: Failed To Establish Connection With zuluPolkit Failed to locate pkexec executable ÙØ´Ù„ ÙÙŠ تعيين المل٠التنÙيذي pkexec "%1" and "%2" Folders Must Be Writable. Could not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin" لم يمكن تعيين مل٠pgp التنÙيذي ÙÙŠ "/usr/local/bin","/usr/bin" and "/usr/sbin" Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit. List Is Empty القائمة ÙØ§Ø±ØºØ© Failed To Find %1 Executable INFORMATION معلومات Failed To Get Volume Properties VeraCryptPIMDialog VeraCrypt PIM value قيمة PIM ÙÙŠ Ùيرا كربت &Set حدد &Cancel ألغ TextLabel النص Set VeraCrypt dynamic mode magic number below. حدد الرقم السحري لطور Ùيرا كربت الديناميكي ERROR خطأ Failed to convert the value to digits only ÙØ´Ù„ ÙÙŠ تحويل القيمة لأرقام Ùقط keyDialog unlock and mount a luks volume Ø§ÙØªØ­ وحمل مجلد لوكس &Open Ø§ÙØªØ­ &Cancel ألغ Key Ù…ÙØªØ§Ø­ Mount Name اسم التحميل Mount In &Read Only Mode حمل بوضعية القراءة Ùقط &Share Mount Point شارك نقطة التحميل O&ptions خيارات &VeraCrypt Volume مجلد Ùيراكربت VeraCrypt System Volume VeraCrypt PIM Value &OK Enter Below The Offset Location Of The Volume About To Be Opened. أدخل الإزاحة بالأسÙÙ„ للمجلد Ø§Ù„Ù…Ø³ØªÙ‡Ø¯Ù ÙØªØ­Ù‡ Enter Comma Separated Volume's File System Options Below أدخل خيارات نظام التشغيل بالأسÙÙ„ ÙˆØ§ÙØµÙ„ بينها Ø¨ÙØ§ØµÙ„Ø© Set Mount A LUKS volume in "%1" حمل مجلد لوكس ÙÙŠ "1%" Mount An Encrypted Volume In "%1" حمل مجلدا Ù…Ø´ÙØ±Ø§ ÙÙŠ "1%" Check This Box To Make Password Visible اختر هذا الخيار كي تظهر كلمة السر KeyFile Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Key+KeyFile Ù…ÙØªØ§Ø­+Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Plugin Ø¥Ø¶Ø§ÙØ© TrueCrypt/VeraCrypt Keys Ù…ÙØ§ØªÙŠØ­ Ùيراكربت/تروكربت YubiKey Challenge/Response Select A Folder To Create A Mount Point In حدد مجلد لإنشاء نقطة تحميل Ùيه Select A File To Be Used As A Keyfile حدد Ù…Ù„ÙØ§ لاستخدامه ÙƒÙ…Ù„Ù Ù…ÙØªØ§Ø­ Cancel ألغ ERROR! خطأ! Internal wallet is not configured لم يتم تهيئة خزنة داخلية Atleast one required field is empty حقل واحد ÙØ§Ø±Øº على الأقل Failed to unlock a cryfs volume. Wrong password entered ÙØ´Ù„ ÙÙŠ ÙØªØ­ مجلد cryfs. أدخلت كلمة سر غير صحيحة Failed to unlock an encfs volume. Wrong password entered ÙØ´Ù„ ÙÙŠ ÙØªØ­ مجلد encfs. أدخلت كلمة سر غير صحيحة Failed to unlock a gocryptfs volume. Wrong password entered ÙØ´Ù„ ÙÙŠ ÙØªØ­ مجلد gocryfs. أدخلت كلمة سر غير صحيحة Failed to unlock an ecryptfs volume. Wrong password entered ÙØ´Ù„ ÙÙŠ ÙØªØ­ مجلد ecrytfs. أدخلت كلمة سر غير صحيحة A Space Character Is Not Allowed In Paths When Using Ecryptfs Backend And Polkit Failed to unlock a securefs volume. Wrong password entered ÙØ´Ù„ ÙÙŠ ÙØªØ­ مجلد securefs. أدخلت كلمة سر غير صحيحة Failed to unlock a cryfs volume. cryfs executable could not be found ÙØ´Ù„ ÙÙŠ ÙØªØ­ مجلد cryfs. لم يعثر على مل٠cryfs التنÙيذي Failed to unlock a securefs volume. securefs executable could not be found ÙØ´Ù„ ÙÙŠ ÙØªØ­ مجلد securefs. لم يعثر على مل٠securefs التنÙيذي Failed to unlock a gocryptfs volume. gocryptfs executable could not be found ÙØ´Ù„ ÙÙŠ ÙØªØ­ مجلد gocryptfs. لم يعثر على مل٠gocryptfs التنÙيذي Failed to unlock an encfs volume. encfs executable could not be found ÙØ´Ù„ ÙÙŠ ÙØªØ­ مجلد encfs. لم يعثر على مل٠encfs التنÙيذي Failed to unlock an ecryptfs volume. ecryptfs-simple executable could not be found ÙØ´Ù„ ÙÙŠ ÙØªØ­ مجلد encryptfs. لم يعثر على مل٠encryptfs التنÙيذي Failed to create mount point ÙØ´Ù„ ÙÙŠ إنشاء نقطة تحميل Failed to unlock the volume. Not supported volume encountered ÙØ´Ù„ ÙÙŠ ÙØªØ­ المجلد. المجلد غير مدعوم This backend requires root's privileges and an attempt to acquire them has failed. zuluMount Can Not Unlock This Volume Because Its FileSystem Has To Manually Be Converted To The Version Of Cryfs That Is Currently In Use. Run Cryfs With This Volume To Manually Update This Volume's FileSystem. Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? ÙØ´Ù„ ÙÙŠ تحميل نظام Ù…Ù„ÙØ§Øª ntfs أو exfat باستخدام ntfs-3g. هل حزمة ntfs/exfat مثبتة؟ There seem to be an open volume accociated with given address يبدو أن مجلدا Ù…ÙØªÙˆØ­Ø§ ÙÙŠ العوان المعطى No file or device exist on given path لا يوجد مل٠أو قرص بالمسار المعطى Volume could not be opened with the presented key المجلد لم يمكن ÙØªØ­Ù‡ Ø¨Ø§Ù„Ù…ÙØªØ§Ø­ المعطى Insufficient privilege to mount the device with given options صلاحيات غير كاÙية لتحميل القرص بالخيارات المعطاة Insufficient privilege to open device in read write mode or device does not exist صلاحيات غير كاÙية Ù„ÙØªØ­ القرص للقراءة Ùقط أو أن القرص غير موجود Only root user can perform this operation Ùقط المستخدم بصلاحيات المدير يستطيع تنÙيذ هذه العملية -O and -m options can not be used together هذان الخياران لا يمكن استخدامهما معا: -O Ùˆ -m Could not create mount point, invalid path or path already taken لم يمكن إنشاء نقطة تحميل. مسار خاطئ أو قد تم تعيينه من قبل Shared mount point path aleady taken نقطة التحميل.المشتركة مسارها تم تعيينه من قبل There seem to be an opened mapper associated with the device المخطط المقترن بالقرص يبدو Ù…ÙØªÙˆØ­Ø§ Could not get a passphrase from the module لم يمكن استرجاع كلمة السر من البرنامج Could not get passphrase in silent mode لم يمكن استرجاع كلمة السر ÙÙŠ النمط الصامت Insufficient memory to hold passphrase ذاكرة غير كاÙية Ù„Ø­ÙØ¸ كلمة السر One or more required argument(s) for this operation is missing معطى أو أكثر مطلوب لكنه لم ÙŠÙˆÙØ± Invalid path to key file مسار غير صحيح Ù„Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Could not get enought memory to hold the key file ذاكرة غير كاÙية Ù„Ø­ÙØ¸ Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ Insufficient privilege to open key file for reading صلاحيات غير كاÙية Ù„ÙØªØ­ Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ للقراءة Could not get a passphrase through a local socket لم يمكن الحصول على كلمة السر من Ø§Ù„Ù…Ù†ÙØ° المحلي Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered ÙØ´Ù„ ÙÙŠ تحميل نظام Ø§Ù„Ù…Ù„ÙØ§Øª أو نقطة تحميل غير مدعومة أو نظام تشغيل غير مدعوم Could not create a lock on /etc/mtab لم يمكن إنشاء Ù‚ÙÙ„ للمسار /etc/mtab Insufficient privilege to open a system volume. Consult menu->help->permission for more informaion صلاحيات غير كاÙية Ù„ÙØªØ­ مجلد النظام. للمزيد من المعلومات، راجع قائمة المساعدة ثم اللأذونات A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature قرص غير مدعوم أو قرص Ù…Ùقود أو أذونات مرÙوضة. الأسباب المحتملة لهذا الخطأ: 1- مسار القرص غير صحيح 2- القرص عليه توقيع LVM or MDRAID Plug in name field is empty حقل اسم Ø§Ù„Ø¥Ø¶Ø§ÙØ© ÙØ§Ø±Øº Keyfile field is empty حقل Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ ÙØ§Ø±Øº "/" character is not allowed in the mount name field هذا الرمز "/" غير مقبول ÙÙŠ حقل اسم التحميل Failed To Locate Or Run Yubikey's "ykchalresp" Program. ERROR: خطأ: Plugin name اسم Ø§Ù„Ø¥Ø¶Ø§ÙØ© Keyfile path مسار Ù…Ù„Ù Ø§Ù„Ù…ÙØªØ§Ø­ mountPartition select mount point path أدخل مسار نقطة التحميل Mount Name اسم التحميل &Mount حمل Use La&bel استخدم الملصق التعريÙÙŠ &Cancel ألغ Mount &Read Only حمل للقراءة Ùقط &Share Mount Point شارك نقطة التحميل &Options خيارات Enter Below The Offset Location Of The Volume About To Be Opened Enter The Password Below To A Volume At The Above Offset Set Cancel ألغ TextLabel النص &OK Set File System Options حدد خيارات نظام Ø§Ù„Ù…Ù„ÙØ§Øª Could not resolve path to device or device could not be opened in read write mode لم يمكن Ù…Ø¹Ø±ÙØ© المسار للقرص أو القرص لم يمكن ÙØªØ­Ù‡ للقراءة والكتابة Insuffienct privileges to mount the volume with given mount options صلاحيات غير كاÙية لتحميل المجلد بالخيارات المعطاة Device already mounted القرص محمل من قبل Insuffienct privilege to manage a system volume. necessary privileges can be acquired by: 1. Adding an entry for the volume in fstab with "user" mount option . Add yourself to "zulumount" group صلاحيات غير كاÙية للتحكم ÙÙŠ مجلد النظام. الأذونات اللازمة يمكن تحقيقها عن طريق: 1- Ø¥Ø¶Ø§ÙØ© سجل المجلد ÙÙŠ مل٠fstab بخيار تحميل المستخدم 2- أض٠حسابك ÙÙŠ مجموعة زلو ماونت "/etc/fstab" entry for this volume requires it to be mounted read only سجل المجلد ÙÙŠ "/etc/fstab" يتطلب أن يكون التحميل للقراءة Ùقط "/etc/fstab" entry for this volume is malformed سجل المجلد ÙÙŠ "/etc/fstab" غير مصاغ بشكل سليم "/etc/fstab" entry for this volume does not allow you to mount it سجل المجلد ÙÙŠ "/etc/fstab" لا يسمح لك بتحميل المجلد Could not create mount point path,path already taken لم يمكن إنشاء نقطة التحميل أو أنه سبق أخذها Shared mount point path aleady taken نقطة التحميل المشتركة سبق أخذها Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered ÙØ´Ù„ ÙÙŠ تحميل نقطة النظام أو خيار التحميل غير مدعوم أو نظام Ø§Ù„Ù…Ù„ÙØ§Øª غير مدعوم Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? ÙØ´Ù„ ÙÙŠ تحميل نظام Ù…Ù„ÙØ§Øª ntfs أو exfat باستخدام ntfs-3g. هل حزمة ntfs/exfat مثبتة؟ Mount failed,no or unrecognized file system ÙØ´Ù„ التحميل أو نظام Ø§Ù„Ù…Ù„ÙØ§Øª غير معرو٠Mount failed,could not get a lock on /etc/mtab~ ÙØ´Ù„ التحميل أو لم يمكن Ù‚ÙÙ„ /etc/mtab~ Failed to mount the partition ÙØ´Ù„ ÙÙŠ تحميل القسم ERROR خطأ "/" character is not allowed in the mount name field هذا الرمز "/" غير مقبول ÙÙŠ حقل اسم التحميل ERROR: خطأ: Select Path To Mount Point Folder اختر مسار مجلد نقطة التحميل oneinstance Previous instance seem to have crashed,trying to clean up before starting النسخة السابقة يبدو أنها انهارت. حاول التنظي٠قبل البدء There seem to be another instance running,exiting this one يبدو أنه توجد نسخة أخرى قيد التشغيل. اخرج من هذه النسخة utility::veraCryptWarning Elapsed time: 0 seconds الوقت المستغرق: 0 ثوان Elapsed time: %0 minutes الوقت المستغرق: 0% دقيقة Elapsed time: %0 seconds الوقت المستغرق: 0% ثانية Please be patient as unlocking a VeraCrypt volume may take a very long time. يرجى الانتظار لأن ÙØªØ­ مجلد Ùيرا كربت يستغرق وقتا طويلا zuluMount zuluMount زولو ماونت Volume Path مسار المجلد Mount Point Path مسار نقطة التحميل File System نظام Ø§Ù„Ù…Ù„ÙØ§Øª Label ملصق Size حجم %Used %مستخدم &Favorites &Ø§Ù„ØªÙØ¶ÙŠÙ„ات Men&u قائمة &Mount File حمل مل٠Mount F&older تحميل المجلد &Refresh تحديث Automount Volumes تحميل تلقائي للمجلدات Auto Open Mount Point Ø§ÙØªØ­ نقطة التحميل تلقائيا Unmount All نزل الجميع Favorites Ø§Ù„ØªÙØ¶ÙŠÙ„ات Hide Volume From View أخ٠المجلد من المعاينة Unhide Volume From View ألغ Ø¥Ø®ÙØ§Ø¡ المجلد من المعاينة Select Language اختر اللغة Select Icons اختر الأيقونات About حول Quit خروج Show/Hide أظهر/أخ٠LABEL="%1" ملصق="1%" LABEL="%1" %2 ملصق="1%" 2% Total Blocks %4 مجموع البلكات 4% Used Space: %5 المساحة المستخدمة 5% Free Space: %6 المساحة الشاغرة 6% Total Space: %7 المساحة الكلية 7% Used %: %8 المستخدم 8% Properties خصائص Mount حمل Unmount نزل Unmount + Power Down نزل ÙˆØ£Ø·ÙØ¦ Select An Encrypted Volume Directory اختر دليلا للمجلد Ø§Ù„Ù…Ø´ÙØ± Failed to unmount volume ÙØ´Ù„ ÙÙŠ تنزيل المجلد Open Folder Ø§ÙØªØ­ المجلد Open Private Folder Ø§ÙØªØ­ مجلدا خاصا Open Shared Folder Ø§ÙØªØ­ مجلدا مشتركا Close Menu أغلق القائمة Warning تحذير Could not open mount point because "%1" tool does not appear to be working correctly لم يمكن ÙØªØ­ نقطة التحميل لأن الأداة "1%" لا تبدو تعمل بشكل سليم ERROR خطأ Do Not Minimize To Tray Clear Dead Mount Points zuluMount Failed To Connect To zuluPolkit. Please Report This Serious Bug. Cryptsetup library could not be found and zuluCrypt will most likely not work as expected. Please recompile zuluCrypt to force it to re-discover the new library Failed To Read Volume Properties ÙØ´Ù„ ÙÙŠ قراءة خصائص المجلد INFORMATION معلومات Block Size: %1 حجم البلوك: 1% Used Blocks: %2 البلوكات المستخدمة: 2% Free Blocks: %3 البلوكات الشاغرة: 3% Could not get volume properties. volume is not open or was opened by a different user لم يمكن الحصول على خصائص المجلد Volume Properties خصائص المجلد Permission to access the volume was denied or the volume is not supported (LVM/MDRAID signatures found) الأذونات لا تسمح بالدخول على المجلد أو المجلد غير مدعوم (لا يوجد توقيعLVM/MDRAID) Select An Image File To Mount اختر مل٠صورة للتحميل ERROR! خطأ! Volume is not open or was opened by a different user المجلد غير Ù…ÙØªÙˆØ­ أو Ù…ÙØªÙˆØ­ من قبل مستخدم آخر One or more files in the volume are in use. مل٠أو أكثر ÙÙŠ المجلد قيد الاستخدام حاليا Volume does not have an entry in /etc/mtab المجلد ليس له سجل ÙÙŠ /etc/mtab Could not get a lock on /etc/mtab~ لم يمكن الحصول على Ù‚ÙÙ„ على /etc/mtab~ Volume is unmounted but could not close mapper,advice to close it manually المجلد غير منزل لكن لا يمكن إغلاق المخطط. أغلق القرص يدويا Could not resolve full path of device لم يمكن Ù…Ø¹Ø±ÙØ© المسار الكامل للقرص Shared mount point appear to be busy نقطة التحميل المشتركة تبدو مشغولة Shared mount point appear to belong to a different user or multiple mount points detected نقطة التحميل المشتركة تتبع لمستخدم آخر أو Ø§ÙƒØªØ´ÙØª عدة نقاط تحميل Shared mount point appear to be in an ambiguous state,advice to unmount manually نقطة التحميل ÙÙŠ حالة غامضة. نزل القرص يدويا Multiple mount points for the volume detected Ø§ÙƒØªØ´ÙØª عدة نقاط تحميل للقرص Device does not appear to be mounted القرص لا يبدو محملا Only root user of members of group "zulumount" can unmount this volume Ùقط مستخدم مدير من مجموعة زولو كربت يمكنه تنزيل المجلد Shared mount point appear to be busy نقطة التحميل المشتركة تبدو مشغولة Shared mount point appear to belong to a different user نقطة التحميل المشتركة تبدو تتبع مستخدما آخر Device does not exist القرص غير موجود Failed to unmount,the mount point and/or one or more files are in use ÙØ´Ù„ ÙÙŠ تنزيل المجلد. مل٠أو أكثر قيد الاستخدام Failed to unmount,could not get a lock on /etc/mtab~ ÙØ´Ù„ ÙÙŠ التنزيل. لم يمكن الحصول على Ù‚ÙÙ„ على /etc/mtab~ Failed to unmount the partition ÙØ´Ù„ ÙÙŠ تنزيل القسم Failed to unmount,multiple mount points for the volume detected ÙØ´Ù„ ÙÙŠ التنزيل. Ø§ÙƒØªØ´ÙØª عدة نقاط تحميل للمجلد Close failed, could not find any partition with the presented UUID ÙØ´Ù„ ÙÙŠ الإغلاق. لم يمكن العثور على قسم Ø¨Ù†ÙØ³ رقم UUID ERROR: خطأ: Reading partition properties took longer than expected and operation was terminated,click refresh to try again قراءة خصائص القسم أخذ وقتا أكثر من المتوقع وعليه تم إنهاء العملية. اضغط تحديث للمحاولة مرة أخرى zuluCrypt-6.2.0/translations/zuluMount/de_DE.qm000066400000000000000000001236401425361753700216250ustar00rootroot00000000000000<¸dÊÍ!¿`¡½Ý§de_DEB Ó°+O1+[\QÉM~¹Ä&­¿Ãƒ[èˆÑŒŽt¡—¯6`ZE¥Á¡¬ô«ÀeÉ´¦ÞjÕ*É´wR+f¾*lG–ÄxJJgz JwBJwB&ìJwBeýJwB€bJ  vRx¼‡éR}ÕTSÀÕˆ"TlTˆOWñÕ*÷Zz è^Ü„*^Ü„bÑaŒE‚)bƒÉZ;jyeGjsf:ŒtZŠí|ŠEˆ¬Ä~Øž#)nžÎÎÛ¤Œé!Ǧó %*ÅÃ…W½ð¬Ã€ø”ÉÓ¦s ÞZ´Lq1ëdDXîå5DcÛ>nJš2NRÊœ%M±ÍÐuN ï'×7;»Im’|Ú“ ŒÃå4qŸÃD‰!´lTbW¸r{y˜ài¿( hš©B-BšN‚ÅR"S†UJj–te‚¯ŒªÞck¤ë”žL½("µ)%ÐDSu¡ÓÏó‘¿ ÷>zã’i|æ çÉ’Z&<žX™Q‘yOS0ùœ·xg€'$€d¥B–Ê…˜I¼0Y˜I¼c0¢at©¤F‹¡§tA5ó§tA€‘¯ƒW«¾ïˆPíÕ³"‡¤ðD‚›?ô,usç&Ìr:_y B=ïS_?ÅÂ1hF)ƒF^OŠåw¿P-e”\ÆDûa¤ÂO’bõP—bõmïl¨¤, s½þSÔ~­ôC™ÔŽ2œôÄyÛÍœ LÕf)/Âá³cšèý?´8ý¨Í…ÞgÚIÔDN- 8™ÈB"é#`ZcYËfÊwK {ãb”›Èž'æ nÂe£¶U—b¥ýSV°¬³îލ¬Ï•ÌÌÖ£Ž2Ñô^ô‰5’ ä_6X§~\X§~ÉX§~‡)\ÙÄk•¨N¿€T8­€Tfk¯J‰NK·—†¶ÅÉ´pɶ%ÔɶŠQËòúmÚâê ë—˜{ì>RO½Î &ßQÖ1¤E>QüÃH X•wrÊ\aòŒAn•d?É™ø½o&»våTW½Ž(x½¬nž…ØÌi“Á ™P) •~U( q™5y— ‡>óxæ ¶æ Œ£ ÖžÉa ç””ƒ‹ øV øq úMR‡h ì:— C#| ¿þi' !XrZ #x:' #xgê ,ßÞ˜ WãÔ`< \ t‘( l “p” wE€6% wE€f1 wE€€Ã ‘ô;_ ˜Iœ&k ˜Iœ*3 ˜Iœb ¦wþ… Ìùêú Ò‘Ãä âá0 “b+H YTB “T=‚ ¶¥’‹ä Á¬2Û × ®™# ú 4Fs L™ƒ tÄ%’ Tl˜ì VLº ¯yµM µ‰”› µÚ”3² ·¨Ô º|Òˆ„ »~h ¾'Ž6Z îÈò• ômõ-< š lt}üFÔ—ÛiŸÕþ "System-Volumes" sind Volumes, die entweder von udev als solche identifiziert werden, wenn udev aktiviert ist oder einen Eintrag in "/etc/fstab", "/etc/c/crypttab" oder "/etc/zuluCrypt/system_volumes.list" haben. Wenn Sie es vorziehen, dass ein Volume nicht als System-Volume betrachtet wird, starten Sie das Werkzeug vom root-Konto aus und gehen Sie dann zu "Menü -> Optionen -> Nicht-System-Partitionen verwalten" und fügen Sie das Volume der Liste hinzu, und das Volume wird nicht mehr als "System" betrachtet. Alternativ können Sie sich in die Gruppe "zulucrypt" und "zulumount" eintragen und alle Einschränkungen werden aufgehoben. "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. DialogMsg &Nein&No DialogMsg&OK&Ok DialogMsg&Ja&Yes DialogMsg DialogDialog DialogMsgFDiesen Dialog nicht erneut anzeigenDo not show this dialog again DialogMsgINFORMATION INFORMATION DialogMsg(Unzureichende Rechte für den Zugriff auf ein Systemgerät im Lese-/Schreibmodus, nur der Benutzer root und Mitglieder der Gruppe zulucrypt dürfen dasƒInsufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that DialogMsgüUnzureichende Rechte für den Zugriff auf ein Systemgerät, nur der Benutzer root und Mitglieder der Gruppe zulucrypt dürfen dasjInsufficient privilege to access a system device, only root user or members of group zulucrypt can do that DialogMsg UUID:UUID: DialogMsg4Sie scheinen nicht genügend Rechte für den Zugriff auf die verschlüsselte Datei im %1 zu haben. Überprüfen Sie die Dateirechte und probieren Sie es erneutwYou do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again DialogMsgAktive Slots active slots DialogMsgAktive Slots: active slots: DialogMsgChiffrecipher DialogMsgChiffre:cipher: DialogMsg Gerätdevice DialogMsg Gerät:device: DialogMsgDateisystem: file system: DialogMsgFreier Platz: free space: DialogMsgFSfs DialogMsgSchlüssellängekey size DialogMsgSchlüsselgröße:keysize: DialogMsgSchleifeloop DialogMsgSchleife:loop: DialogMsg Modusmode DialogMsg Modus:mode: DialogMsg Offsetoffset DialogMsgOffset:offset: DialogMsg Größesize DialogMsgTexttext DialogMsgGesamter Platz: total space: DialogMsgTyptype DialogMsgTyp:type: DialogMsgungenutztunused DialogMsg belegtused DialogMsggenutzt %used % DialogMsgBelegter Platz: used space: DialogMsgBelegt%:used%: DialogMsgÆ Optionen: d Pfad zu einem Volume, das automatisch aufgeschlossen/eingehängt werden soll m Werkzeug zum Öffnen eines Standard-Dateimanagers (Standard-Werkzeug ist xdg-open) e Starten der Anwendung ohne Anzeige der GUI Í options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI QObjectdDie Ordner "%1" und "%2" müssen beschreibbar sein.'"%1" and "%2" Folders Must Be Writable.QObjectÐDie ausführbare Datei "gpg" konnte nicht in "/usr/local/bin", "/usr/bin" und "/usr/sbin" gefunden werdenNCould not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin"QObject FEHLERERRORQObjectjDie ausführbare Datei %1 konnte nicht gefunden werdenFailed To Find %1 ExecutableQObjectfVolume-Eigenschaften konnten nicht abgerufen werdenFailed To Get Volume PropertiesQObjectÄDie Hilfsanwendung konnte nicht gestartet werden. "org.zulucrypt.zulupolkit.policy" polkit-Datei ist falsch konfiguriert, ausführbare Datei zuluPolkit konnte nicht gefunden werden oder pkexec konnte zuluPolkit nicht starten.´Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit.QObjectrDie ausführbare Datei pkexec konnte nicht gefunden werden"Failed to locate pkexec executableQObjectINFORMATION INFORMATIONQObjectbWenn die Option aktiviert ist, wird in "%1" ein primärer privater Einhängepunkt erstellt und ein sekundärer öffentlich zugänglicher "Spiegel"-Einhängepunkt wird in "%2" erstelltŸIf the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2"QObjectListe ist leer List Is EmptyQObject&Favoriten verwaltenManage FavoritesQObjectAlle einhängen Mount AllQObjectÜber zuluCryptabout zuluCryptQObjectgpg-Erweiterung. Diese Erweiterung stellt einen Schlüssel wieder her, der in einer gpg-Datei mit einem symmetrischen Schlüssel gesperrt istQgpg plugin. This plugin retrives a key locked in a gpg file with a symmetric keyQObject*hmac-Erweiterung. Diese Erweiterung erzeugt einen Schlüssel mit Hilfe des folgenden Formulars: key = hmac(sha256, Passphrase, Schlüsseldateiinhalt)ohmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents)QObject(keykeyfile-Erweiterung. Diese Erweiterung erzeugt einen Schlüssel mit Hilfe des folgenden Formulars: Schlüssel = Passphrase + Schlüsseldateiinhaltjkeykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contentsQObject8öffentlicher Einhängepunkt: public mount point: QObject„zuluCrypt: Der Verbindungsaufbau mit zuluPolkit ist fehlgeschlagen9zuluCrypt: Failed To Establish Connection With zuluPolkitQObjectAbbre&chen&CancelVeraCryptPIMDialogFe&stlegen&SetVeraCryptPIMDialog FEHLERERRORVeraCryptPIMDialogpDer Wert konnte nicht nur in Ziffern umgewandelt werden +Failed to convert the value to digits only VeraCryptPIMDialogžLegen Sie unten die magische Zahl für den dynamischen Modus von VeraCrypt fest..Set VeraCrypt dynamic mode magic number below.VeraCryptPIMDialogTextmarkierung TextLabelVeraCryptPIMDialog$VeraCrypt PIM-WertVeraCrypt PIM valueVeraCryptPIMDialog^Das Zeichen "/" ist im Namensfeld nicht erlaubt4"/" character is not allowed in the mount name field keyDialogAbbre&chen&Cancel keyDialog&Öffnen&Open keyDialog*Einhängepunkt &teilen&Share Mount Point keyDialog"&VeraCrypt-Volume&VeraCrypt Volume keyDialogzDie Optionen -O und -m können nicht zusammen verwendet werden*-O and -m options can not be used together keyDialogÄEin Leerzeichen in Pfaden ist nicht erlaubt, wenn ein Ecryptfs Backend und Polkit verwendet werdenPA Space Character Is Not Allowed In Paths When Using Ecryptfs Backend And Polkit keyDialog°Ein nicht unterstütztes Gerät wurde gefunden, das Gerät fehlt oder Sie haben keine Berechtigung. Mögliche Gründe für diesen Fehler sind: 1. Der Gerätepfad ist ungültig. 2. Das Gerät hat eine LVM oder MD-RAID Signatur¸A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature keyDialogVMindestens ein erforderliches Feld ist leer#Atleast one required field is empty keyDialogAbbrechenCancel keyDialog”Aktivieren Sie dieses Kontrollkästchen, um das Passwort sichtbar zu machen'Check This Box To Make Password Visible keyDialogVKonnte keine Sperre für /etc/mtab erstellen$Could not create a lock on /etc/mtab keyDialog°Es konnte kein Einhängepunkt erstellt werden, ungültiger Pfad oder bereits belegter Pfad@Could not create mount point, invalid path or path already taken keyDialog\Konnte keine Passphrase von dem Modul erhalten*Could not get a passphrase from the module keyDialogpKonnte keine Passphrase über den lokalen Socket erhalten1Could not get a passphrase through a local socket keyDialog„Konnte nicht genug Speicher zum Halten der Schlüsseldatei bekommen1Could not get enought memory to hold the key file keyDialogjKonnte die Passphrase nicht im stillen Modus bekommen'Could not get passphrase in silent mode keyDialogFEHLER!ERROR! keyDialogFEHLER: ERROR:  keyDialog‚Geben Sie unten die Offset-Position des zu öffnenden Volumes ein.AEnter Below The Offset Location Of The Volume About To Be Opened. keyDialogŽGeben Sie unten die kommagetrennten Dateisystemoptionen des Volumes ein8Enter Comma Separated Volume's File System Options Below keyDialogTEinhängepunkt konnte nicht erstellt werdenFailed to create mount point keyDialogøKonnte kein Dateisystem einhängen: ungültige/nicht unterstützte Einhängeoption oder nicht unterstütztes Dateisystem entdecktdFailed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered keyDialogÂKonnte das NTFS/EXFAT-Dateisystem mit ntfs-3g nicht einhängen, ist das ntfs-3g-Paket installiert?XFailed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? keyDialogšcryfs-Volume konnte nicht aufgeschlossen werden. Falsches Passwort eingegeben7Failed to unlock a cryfs volume. Wrong password entered keyDialogÒcryfs-Volume konnte nicht aufgeschlossen werden. Die ausführbare Datei cryfs konnte nicht gefunden werdenDFailed to unlock a cryfs volume. cryfs executable could not be found keyDialog¢gocryptfs-Volume konnte nicht aufgeschlossen werden. Falsches Passwort eingegeben;Failed to unlock a gocryptfs volume. Wrong password entered keyDialogâgocryptfs-Volume konnte nicht aufgeschlossen werden. Die ausführbare Datei gocryptfs konnte nicht gefunden werdenLFailed to unlock a gocryptfs volume. gocryptfs executable could not be found keyDialog securefs-Volume konnte nicht aufgeschlossen werden. Falsches Passwort eingegeben:Failed to unlock a securefs volume. Wrong password entered keyDialogÞsecurefs-Volume konnte nicht aufgeschlossen werden. Die ausführbare Datei securefs konnte nicht gefunden werdenJFailed to unlock a securefs volume. securefs executable could not be found keyDialog ecryptfs-Volume konnte nicht aufgeschlossen werden. Falsches Passwort eingegeben;Failed to unlock an ecryptfs volume. Wrong password entered keyDialogÞecryptfs-Volume konnte nicht aufgeschlossen werden. Die ausführbare Datei ecryptfs konnte nicht gefunden werdenRFailed to unlock an ecryptfs volume. ecryptfs-simple executable could not be found keyDialogšencfs-Volume konnte nicht aufgeschlossen werden. Falsches Passwort eingegeben8Failed to unlock an encfs volume. Wrong password entered keyDialogÒencfs-Volume konnte nicht aufgeschlossen werden. Die ausführbare Datei encfs konnte nicht gefunden werdenEFailed to unlock an encfs volume. encfs executable could not be found keyDialogœVolume konnte nicht aufgeschlossen werden. Nicht unterstütztes Volume gefunden=Failed to unlock the volume. Not supported volume encountered keyDialogrNicht genügend Speicherplatz zum Speichern der Passphrase&Insufficient memory to hold passphrase keyDialog”Unzureichende Rechte zum Einhängen des Geräts mit den angegebenen Optionen=Insufficient privilege to mount the device with given options keyDialogâUnzureichende Rechte zum Öffnen eines System-Volumes. Siehe Menü->Hilfe->Berechtigung für weitere Informationen dInsufficient privilege to open a system volume. Consult menu->help->permission for more informaion  keyDialog¾Unzureichende Rechte zum Öffnen des Geräts im Schreib-/Lesemodus oder das Gerät existiert nichtQInsufficient privilege to open device in read write mode or device does not exist keyDialog€Unzureichende Rechte zum Öffnen der Schlüsseldatei für das Lesen3Insufficient privilege to open key file for reading keyDialogTInterne Brieftasche ist nicht konfiguriert!Internal wallet is not configured keyDialogDUngültiger Pfad zur SchlüsseldateiInvalid path to key file keyDialogSchlüsselKey keyDialog0Schlüssel+Schlüsseldatei Key+KeyFile keyDialogSchlüsseldateiKeyFile keyDialog@Das Feld Schlüsseldatei ist leerKeyfile field is empty keyDialog.Pfad zur Schlüsseldatei Keyfile path keyDialogBEin LUKS-Volume in "%1" einhängenMount A LUKS volume in "%1" keyDialogXEin verschlüsseltes Volume in "%1" einhängen!Mount An Encrypted Volume In "%1" keyDialog8Im Nu&r-Lese-Modus einhängenMount In &Read Only Mode keyDialog.Name des Einhängepunkts Mount Name keyDialognEs existiert keine Datei oder Gerät am angegebenen Pfad%No file or device exist on given path keyDialogO&ptionenO&ptions keyDialog˜Ein oder mehrere für diese Operation erforderlichen Argument(e) fehlt/fehlen>One or more required argument(s) for this operation is missing keyDialogNNur root kann diese Operation ausführen)Only root user can perform this operation keyDialog<Feld Erweiterungsname ist leerPlug in name field is empty keyDialogErweiterungPlugin keyDialog Erweiterungsname Plugin name keyDialogŽWählen Sie eine Datei aus, die als Schlüsseldatei verwendet werden soll%Select A File To Be Used As A Keyfile keyDialog”Wählen Sie einen Ordner aus, in dem ein Einhängepunkt erstellt werden soll*Select A Folder To Create A Mount Point In keyDialogjDer gemeinsame Einhängepunktpfad ist bereits vergeben$Shared mount point path aleady taken keyDialog²Es scheint ein geöffnetes Volumen zu geben, das mit der angegebenen Adresse verknüpft ist=There seem to be an open volume accociated with given address keyDialog‚Es scheint ein geöffneter Mapper mit dem Gerät assoziiert zu seinEinhängepfad automatisch öffnenAuto Open Mount Point zuluMount:Volumes automatisch einhängenAutomount Volumes zuluMountBlockgröße: %1Block Size: %1 zuluMountMenü schließen Close Menu zuluMount¨Schließen fehlgeschlagen, es wurde keine Partition mit der angegebenen UUID gefundenBClose failed, could not find any partition with the presented UUID zuluMountVKonnte keine Sperre auf /etc/mtab~ erhalten"Could not get a lock on /etc/mtab~ zuluMountúVolume-Eigenschaften konnten nicht ermittelt werden. Volume ist nicht geöffnet oder wurde von einem anderen Benutzer geöffnetUCould not get volume properties. volume is not open or was opened by a different user zuluMountÚDer Einhängepunkt konnte nicht geöffnet werden, weil das Werkzeug "%1" nicht richtig zu funktionieren scheintTCould not open mount point because "%1" tool does not appear to be working correctly zuluMountbDer Pfad zum Gerät konnte nicht aufgelöst werden &Could not resolve full path of device  zuluMountTDas Gerät scheint nicht eingehängt zu sein$Device does not appear to be mounted zuluMount2Das Gerät existiert nichtDevice does not exist zuluMountZNicht in das Benachrichtigungsfeld minimierenDo Not Minimize To Tray zuluMount FEHLERERROR zuluMountFEHLER!ERROR! zuluMountFEHLER: ERROR:  zuluMountbVolume-Eigenschaften konnten nicht gelesen werden Failed To Read Volume Properties zuluMountTAushängen der Partition ist fehlgeschlagenFailed to unmount the partition zuluMountPAushängen des Volumes ist fehlgeschlagenFailed to unmount volume zuluMountŠAushängen fehlgeschlagen, konnte keine Sperre auf /etc/mtab~ erhalten4Failed to unmount,could not get a lock on /etc/mtab~ zuluMountœAushängen fehlgeschlagen, für das Volume wurden mehrere Einhängepunkte erkannt?Failed to unmount,multiple mount points for the volume detected zuluMount¾Aushängen fehlgeschlagen, der Einhängepunkt und/oder eine oder mehrere Dateien werden verwendetEFailed to unmount,the mount point and/or one or more files are in use zuluMountFavoriten Favorites zuluMountDateisystem File System zuluMount Freie Blöcke: %3Free Blocks: %3 zuluMount Freier Platz: %6Free Space: %6 zuluMount@Volume in der Ansicht ausblendenHide Volume From View zuluMountINFORMATION INFORMATION zuluMountLABEL="%1" LABEL="%1" zuluMountLABEL="%1" %2 LABEL="%1" %2 zuluMountBezeichnungLabel zuluMount Men&üMen&u zuluMountEinhängenMount zuluMount"&Ordner einhängen Mount F&older zuluMount"EinhängepunktpfadMount Point Path zuluMounthFür das Volume wurden mehrere Einhängepunkte erkannt-Multiple mount points for the volume detected zuluMountjEine oder mehrere Dateien im Volume werden verwendet.+One or more files in the volume are in use. zuluMount¶Nur der Benutzer root oder Mitglieder der Gruppe "zulumount" können dieses Volume aushängenFOnly root user of members of group "zulumount" can unmount this volume zuluMountOrdner öffnen Open Folder zuluMount,Privaten Ordner öffnenOpen Private Folder zuluMount2Gemeinsamen Ordner öffnenOpen Shared Folder zuluMount Die Berechtigung zum Zugriff auf das Volume wurde verweigert oder das Volume wird nicht unterstützt (LVM/MD-RAID-Signaturen gefunden)gPermission to access the volume was denied or the volume is not supported (LVM/MDRAID signatures found) zuluMountEigenschaften Properties zuluMountSchließenQuit zuluMount:Das Lesen der Partitionseigenschaften dauerte länger als erwartet und der Vorgang wurde abgebrochen, klicken Sie auf Aktualisieren, um es erneut zu versuchennReading partition properties took longer than expected and operation was terminated,click refresh to try again zuluMountxWählen Sie ein Verzeichnis für das verschlüsselte Volume aus$Select An Encrypted Volume Directory zuluMount\Wählen Sie eine Abbild-Datei zum Einhängen ausSelect An Image File To Mount zuluMount"Symbole auswählen Select Icons zuluMount"Sprache auswählenSelect Language zuluMountpDer gemeinsame Einhängepunkt scheint ausgelastet zu sein$Shared mount point appear to be busy zuluMountrDer gemeinsame Einhängepunkt scheint ausgelastet zu sein %Shared mount point appear to be busy  zuluMountðDer gemeinsame Einhängepunkt scheint in einem ungewöhnlichen Zustand zu sein. Es wird empfohlen, ihn manuell auszuhängenPShared mount point appear to be in an ambiguous state,advice to unmount manually zuluMountŒDer gemeinsame Einhängepunkt scheint einem anderen Benutzer zu gehören7Shared mount point appear to belong to a different user zuluMountêDer gemeinsame Einhängepunkt scheint einem anderen Benutzer zu gehören oder es wurden mehrere Einhängepunkte erkannt ZShared mount point appear to belong to a different user or multiple mount points detected  zuluMount&Anzeigen/Ausblenden Show/Hide zuluMount GrößeSize zuluMount"Gesamte Blöcke %4Total Blocks %4 zuluMount$Gesamter Platz: %7Total Space: %7 zuluMount<Volume in der Ansicht anzeigenUnhide Volume From View zuluMountAushängenUnmount zuluMount.Aushängen + AusschaltenUnmount + Power Down zuluMountAlle aushängen Unmount All zuluMountBelegt %: %8 Used %: %8 zuluMount$Belegte Blöcke: %2Used Blocks: %2 zuluMount$Belegter Platz: %5Used Space: %5 zuluMountVolume-Pfad Volume Path zuluMount(Volume-EigenschaftenVolume Properties zuluMountNVolume hat keinen Eintrag in /etc/mstab*Volume does not have an entry in /etc/mtab zuluMountVolume ist nicht geöffnet oder wurde von einem anderen Benutzer geöffnet4Volume is not open or was opened by a different user zuluMountúDas Volume ist nicht eingehängt, aber der Mapper konnte nicht geschlossen werden. Es wird empfohlen, ihn manuell zu schließenJVolume is unmounted but could not close mapper,advice to close it manually zuluMountWarnungWarning zuluMountzuluMount zuluMount zuluMountèDie Verbindung zwischen zuluMount und zuluPolkit ist fehlgeschlagen. Bitte melden Sie diesen schwerwiegenden Fehler.JzuluMount Failed To Connect To zuluPolkit. Please Report This Serious Bug. zuluMountˆzuluCrypt-6.2.0/translations/zuluMount/de_DE.ts000066400000000000000000002134501425361753700216350ustar00rootroot00000000000000 DialogMsg Dialog Dialog &Ok &OK &Yes &Ja &No &Nein text Text type Typ cipher Chiffre key size Schlüssellänge device Gerät loop Schleife offset Offset size Größe mode Modus fs FS used belegt unused ungenutzt used % genutzt % active slots Aktive Slots "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. "System-Volumes" sind Volumes, die entweder von udev als solche identifiziert werden, wenn udev aktiviert ist oder einen Eintrag in "/etc/fstab", "/etc/c/crypttab" oder "/etc/zuluCrypt/system_volumes.list" haben. Wenn Sie es vorziehen, dass ein Volume nicht als System-Volume betrachtet wird, starten Sie das Werkzeug vom root-Konto aus und gehen Sie dann zu "Menü -> Optionen -> Nicht-System-Partitionen verwalten" und fügen Sie das Volume der Liste hinzu, und das Volume wird nicht mehr als "System" betrachtet. Alternativ können Sie sich in die Gruppe "zulucrypt" und "zulumount" eintragen und alle Einschränkungen werden aufgehoben. INFORMATION INFORMATION Insufficient privilege to access a system device, only root user or members of group zulucrypt can do that Unzureichende Rechte für den Zugriff auf ein Systemgerät, nur der Benutzer root und Mitglieder der Gruppe zulucrypt dürfen das Insufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that Unzureichende Rechte für den Zugriff auf ein Systemgerät im Lese-/Schreibmodus, nur der Benutzer root und Mitglieder der Gruppe zulucrypt dürfen das You do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again Sie scheinen nicht genügend Rechte für den Zugriff auf die verschlüsselte Datei im %1 zu haben. Überprüfen Sie die Dateirechte und probieren Sie es erneut type: Typ: cipher: Chiffre: keysize: Schlüsselgröße: offset: Offset: device: Gerät: loop: Schleife: mode: Modus: active slots: Aktive Slots: file system: Dateisystem: total space: Gesamter Platz: used space: Belegter Platz: free space: Freier Platz: used%: Belegt%: UUID: UUID: Do not show this dialog again Diesen Dialog nicht erneut anzeigen QObject zuluCrypt: Failed To Establish Connection With zuluPolkit zuluCrypt: Der Verbindungsaufbau mit zuluPolkit ist fehlgeschlagen options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI Optionen: d Pfad zu einem Volume, das automatisch aufgeschlossen/eingehängt werden soll m Werkzeug zum Öffnen eines Standard-Dateimanagers (Standard-Werkzeug ist xdg-open) e Starten der Anwendung ohne Anzeige der GUI If the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2" Wenn die Option aktiviert ist, wird in "%1" ein primärer privater Einhängepunkt erstellt und ein sekundärer öffentlich zugänglicher "Spiegel"-Einhängepunkt wird in "%2" erstellt public mount point: öffentlicher Einhängepunkt: Manage Favorites Favoriten verwalten Mount All Alle einhängen about zuluCrypt Über zuluCrypt hmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents) hmac-Erweiterung. Diese Erweiterung erzeugt einen Schlüssel mit Hilfe des folgenden Formulars: key = hmac(sha256, Passphrase, Schlüsseldateiinhalt) keykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contents keykeyfile-Erweiterung. Diese Erweiterung erzeugt einen Schlüssel mit Hilfe des folgenden Formulars: Schlüssel = Passphrase + Schlüsseldateiinhalt gpg plugin. This plugin retrives a key locked in a gpg file with a symmetric key gpg-Erweiterung. Diese Erweiterung stellt einen Schlüssel wieder her, der in einer gpg-Datei mit einem symmetrischen Schlüssel gesperrt ist Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit. Die Hilfsanwendung konnte nicht gestartet werden. "org.zulucrypt.zulupolkit.policy" polkit-Datei ist falsch konfiguriert, ausführbare Datei zuluPolkit konnte nicht gefunden werden oder pkexec konnte zuluPolkit nicht starten. ERROR FEHLER Failed to locate pkexec executable Die ausführbare Datei pkexec konnte nicht gefunden werden "%1" and "%2" Folders Must Be Writable. Die Ordner "%1" und "%2" müssen beschreibbar sein. Could not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin" Die ausführbare Datei "gpg" konnte nicht in "/usr/local/bin", "/usr/bin" und "/usr/sbin" gefunden werden List Is Empty Liste ist leer Failed To Find %1 Executable Die ausführbare Datei %1 konnte nicht gefunden werden INFORMATION INFORMATION Failed To Get Volume Properties Volume-Eigenschaften konnten nicht abgerufen werden VeraCryptPIMDialog VeraCrypt PIM value VeraCrypt PIM-Wert &Set Fe&stlegen &Cancel Abbre&chen TextLabel Textmarkierung Set VeraCrypt dynamic mode magic number below. Legen Sie unten die magische Zahl für den dynamischen Modus von VeraCrypt fest. ERROR FEHLER Failed to convert the value to digits only Der Wert konnte nicht nur in Ziffern umgewandelt werden keyDialog unlock and mount a luks volume Ein LUKS-Volume aufschließen und einhängen &Open &Öffnen &Cancel Abbre&chen Key Schlüssel Mount Name Name des Einhängepunkts Mount In &Read Only Mode Im Nu&r-Lese-Modus einhängen &Share Mount Point Einhängepunkt &teilen O&ptions O&ptionen &VeraCrypt Volume &VeraCrypt-Volume VeraCrypt System Volume VeraCrypt PIM Value &OK Enter Below The Offset Location Of The Volume About To Be Opened. Geben Sie unten die Offset-Position des zu öffnenden Volumes ein. Enter Comma Separated Volume's File System Options Below Geben Sie unten die kommagetrennten Dateisystemoptionen des Volumes ein Set Mount A LUKS volume in "%1" Ein LUKS-Volume in "%1" einhängen Mount An Encrypted Volume In "%1" Ein verschlüsseltes Volume in "%1" einhängen Check This Box To Make Password Visible Aktivieren Sie dieses Kontrollkästchen, um das Passwort sichtbar zu machen KeyFile Schlüsseldatei Key+KeyFile Schlüssel+Schlüsseldatei Plugin Erweiterung TrueCrypt/VeraCrypt Keys TrueCrypt/VeraCrypt-Schlüssel YubiKey Challenge/Response Select A Folder To Create A Mount Point In Wählen Sie einen Ordner aus, in dem ein Einhängepunkt erstellt werden soll Select A File To Be Used As A Keyfile Wählen Sie eine Datei aus, die als Schlüsseldatei verwendet werden soll Cancel Abbrechen ERROR! FEHLER! Internal wallet is not configured Interne Brieftasche ist nicht konfiguriert Atleast one required field is empty Mindestens ein erforderliches Feld ist leer Failed to unlock a cryfs volume. Wrong password entered cryfs-Volume konnte nicht aufgeschlossen werden. Falsches Passwort eingegeben Failed to unlock an encfs volume. Wrong password entered encfs-Volume konnte nicht aufgeschlossen werden. Falsches Passwort eingegeben Failed to unlock a gocryptfs volume. Wrong password entered gocryptfs-Volume konnte nicht aufgeschlossen werden. Falsches Passwort eingegeben Failed to unlock an ecryptfs volume. Wrong password entered ecryptfs-Volume konnte nicht aufgeschlossen werden. Falsches Passwort eingegeben A Space Character Is Not Allowed In Paths When Using Ecryptfs Backend And Polkit Ein Leerzeichen in Pfaden ist nicht erlaubt, wenn ein Ecryptfs Backend und Polkit verwendet werden Failed to unlock a securefs volume. Wrong password entered securefs-Volume konnte nicht aufgeschlossen werden. Falsches Passwort eingegeben Failed to unlock a cryfs volume. cryfs executable could not be found cryfs-Volume konnte nicht aufgeschlossen werden. Die ausführbare Datei cryfs konnte nicht gefunden werden Failed to unlock a securefs volume. securefs executable could not be found securefs-Volume konnte nicht aufgeschlossen werden. Die ausführbare Datei securefs konnte nicht gefunden werden Failed to unlock a gocryptfs volume. gocryptfs executable could not be found gocryptfs-Volume konnte nicht aufgeschlossen werden. Die ausführbare Datei gocryptfs konnte nicht gefunden werden Failed to unlock an encfs volume. encfs executable could not be found encfs-Volume konnte nicht aufgeschlossen werden. Die ausführbare Datei encfs konnte nicht gefunden werden Failed to unlock an ecryptfs volume. ecryptfs-simple executable could not be found ecryptfs-Volume konnte nicht aufgeschlossen werden. Die ausführbare Datei ecryptfs konnte nicht gefunden werden Failed to create mount point Einhängepunkt konnte nicht erstellt werden Failed to unlock the volume. Not supported volume encountered Volume konnte nicht aufgeschlossen werden. Nicht unterstütztes Volume gefunden This backend requires root's privileges and an attempt to acquire them has failed. Dieses Backend benötigt die Rechte von root und ein Versuch, sie zu erwerben, ist fehlgeschlagen. zuluMount Can Not Unlock This Volume Because Its FileSystem Has To Manually Be Converted To The Version Of Cryfs That Is Currently In Use. Run Cryfs With This Volume To Manually Update This Volume's FileSystem. zuluMount kann dieses Volume nicht entsperren, da sein Dateisystem manuell in die Version des derzeit verwendeten Cryfs konvertiert werden muss. Führen Sie Cryfs mit diesem Volume aus, um das Dateisystem dieses Volumes manuell zu aktualisieren. Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? Konnte das NTFS/EXFAT-Dateisystem mit ntfs-3g nicht einhängen, ist das ntfs-3g-Paket installiert? There seem to be an open volume accociated with given address Es scheint ein geöffnetes Volumen zu geben, das mit der angegebenen Adresse verknüpft ist No file or device exist on given path Es existiert keine Datei oder Gerät am angegebenen Pfad Volume could not be opened with the presented key Das Volume konnte nicht mit dem eingegebenen Schlüssel geöffnet werden Insufficient privilege to mount the device with given options Unzureichende Rechte zum Einhängen des Geräts mit den angegebenen Optionen Insufficient privilege to open device in read write mode or device does not exist Unzureichende Rechte zum Öffnen des Geräts im Schreib-/Lesemodus oder das Gerät existiert nicht Only root user can perform this operation Nur root kann diese Operation ausführen -O and -m options can not be used together Die Optionen -O und -m können nicht zusammen verwendet werden Could not create mount point, invalid path or path already taken Es konnte kein Einhängepunkt erstellt werden, ungültiger Pfad oder bereits belegter Pfad Shared mount point path aleady taken Der gemeinsame Einhängepunktpfad ist bereits vergeben There seem to be an opened mapper associated with the device Es scheint ein geöffneter Mapper mit dem Gerät assoziiert zu sein Could not get a passphrase from the module Konnte keine Passphrase von dem Modul erhalten Could not get passphrase in silent mode Konnte die Passphrase nicht im stillen Modus bekommen Insufficient memory to hold passphrase Nicht genügend Speicherplatz zum Speichern der Passphrase One or more required argument(s) for this operation is missing Ein oder mehrere für diese Operation erforderlichen Argument(e) fehlt/fehlen Invalid path to key file Ungültiger Pfad zur Schlüsseldatei Could not get enought memory to hold the key file Konnte nicht genug Speicher zum Halten der Schlüsseldatei bekommen Insufficient privilege to open key file for reading Unzureichende Rechte zum Öffnen der Schlüsseldatei für das Lesen Could not get a passphrase through a local socket Konnte keine Passphrase über den lokalen Socket erhalten Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered Konnte kein Dateisystem einhängen: ungültige/nicht unterstützte Einhängeoption oder nicht unterstütztes Dateisystem entdeckt Could not create a lock on /etc/mtab Konnte keine Sperre für /etc/mtab erstellen Insufficient privilege to open a system volume. Consult menu->help->permission for more informaion Unzureichende Rechte zum Öffnen eines System-Volumes. Siehe Menü->Hilfe->Berechtigung für weitere Informationen A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature Ein nicht unterstütztes Gerät wurde gefunden, das Gerät fehlt oder Sie haben keine Berechtigung. Mögliche Gründe für diesen Fehler sind: 1. Der Gerätepfad ist ungültig. 2. Das Gerät hat eine LVM oder MD-RAID Signatur Plug in name field is empty Feld Erweiterungsname ist leer Keyfile field is empty Das Feld Schlüsseldatei ist leer Failed To Locate Or Run Yubikey's "ykchalresp" Program. ERROR: FEHLER: Plugin name Erweiterungsname Keyfile path Pfad zur Schlüsseldatei "/" character is not allowed in the mount name field Das Zeichen "/" ist im Namensfeld nicht erlaubt mountPartition select mount point path Einhängepunktpfad auswählen Mount Name Name des Einhängepunkts &Mount &Einhängen Use La&bel &Bezeichnung verwenden &Cancel Abbre&chen Mount &Read Only Nu&r lesend einhängen &Share Mount Point Einhängepunkt &teilen &Options &Optionen Enter Below The Offset Location Of The Volume About To Be Opened Enter The Password Below To A Volume At The Above Offset Set Cancel Abbrechen TextLabel Textmarkierung &OK Set File System Options Dateisystemoptionen festlegen Could not resolve path to device or device could not be opened in read write mode Pfad zum Gerät konnte nicht aufgelöst werden oder das Gerät konnte nicht im Lese-/Schreibmodus geöffnet werden Insuffienct privileges to mount the volume with given mount options Unzureichende Rechte zum Einhängen des Volumes mit den angegeben Einhängeoptionen Unzureichende Rechte zum Einhängen des Geräts mit den angegebenen Optionen Device already mounted Gerät bereits eingehängt Insuffienct privilege to manage a system volume. necessary privileges can be acquired by: 1. Adding an entry for the volume in fstab with "user" mount option . Add yourself to "zulumount" group Unzureichende Rechte zur Verwaltung eines System-Volumes. Notwendige Berechtigungen können erworben werden durch: 1. Hinzufügen eines Eintrags für das Volume in fstab mit der Einhängeoption "user" . Fügen Sie sich selbst zur Gruppe "zulumount" hinzu "/etc/fstab" entry for this volume requires it to be mounted read only Der Eintrag "/etc/fstab" für dieses Volume erfordert, dass es nur lesend eingehängt wird "/etc/fstab" entry for this volume is malformed Der Eintrag "/etc/fstab" für dieses Volume ist fehlerhaft "/etc/fstab" entry for this volume does not allow you to mount it Der Eintrag "/etc/fstab" für dieses Volume erlaubt es Ihnen nicht, es einzuhängen Could not create mount point path,path already taken Es konnte kein Einhängepunkt erstellt werden, Pfad bereits belegt Shared mount point path aleady taken Der gemeinsame Einhängepunktpfad ist bereits vergeben Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered Konnte kein Dateisystem einhängen: ungültige/nicht unterstützte Einhängeoption oder nicht unterstütztes Dateisystem entdeckt Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? Konnte das NTFS/EXFAT-Dateisystem mit ntfs-3g nicht einhängen, ist das ntfs-3g-Paket installiert? Mount failed,no or unrecognized file system Einhängen fehlgeschlagen, kein oder nicht erkanntes Dateisystem Mount failed,could not get a lock on /etc/mtab~ Einhängen fehlgeschlagen, konnte keine Sperre auf /etc/mtab~ erhalten Failed to mount the partition Die Partition konnte nicht eingehängt werden ERROR FEHLER "/" character is not allowed in the mount name field Das Zeichen "/" ist im Namensfeld nicht erlaubt ERROR: FEHLER: Select Path To Mount Point Folder Wählen Sie den Pfad zum Einhängepunktordner aus oneinstance Previous instance seem to have crashed,trying to clean up before starting Die vorherige Instanz scheint abgestürzt zu sein, versuche sie vor dem Start zu bereinigen There seem to be another instance running,exiting this one Es scheint bereits eine Instanz zu laufen, breche ab utility::veraCryptWarning Elapsed time: 0 seconds Vergangene Zeit: 0 Sekunden Elapsed time: %0 minutes Vergangene Zeit: %0 Minuten Elapsed time: %0 seconds Vergangene Zeit: %0Sekunden Please be patient as unlocking a VeraCrypt volume may take a very long time. Bitte haben Sie Geduld, da das Aufschließen eines VeraCrypt-Volumes sehr lange dauern kann. zuluMount zuluMount zuluMount Volume Path Volume-Pfad Mount Point Path Einhängepunktpfad File System Dateisystem Label Bezeichnung Size Größe %Used %Belegt Mount F&older &Ordner einhängen &Mount File Datei &einhängen &Refresh Aktualisie&ren &Favorites &Favoriten Men&u Men&ü Automount Volumes Volumes automatisch einhängen Auto Open Mount Point Einhängepfad automatisch öffnen Unmount All Alle aushängen Favorites Favoriten Hide Volume From View Volume in der Ansicht ausblenden Unhide Volume From View Volume in der Ansicht anzeigen Select Language Sprache auswählen Select Icons Symbole auswählen About Über Quit Schließen Show/Hide Anzeigen/Ausblenden LABEL="%1" LABEL="%1" LABEL="%1" %2 LABEL="%1" %2 ERROR FEHLER Do Not Minimize To Tray Nicht in das Benachrichtigungsfeld minimieren Clear Dead Mount Points zuluMount Failed To Connect To zuluPolkit. Please Report This Serious Bug. Die Verbindung zwischen zuluMount und zuluPolkit ist fehlgeschlagen. Bitte melden Sie diesen schwerwiegenden Fehler. Cryptsetup library could not be found and zuluCrypt will most likely not work as expected. Please recompile zuluCrypt to force it to re-discover the new library Failed To Read Volume Properties Volume-Eigenschaften konnten nicht gelesen werden INFORMATION INFORMATION Block Size: %1 Blockgröße: %1 Used Blocks: %2 Belegte Blöcke: %2 Free Blocks: %3 Freie Blöcke: %3 Total Blocks %4 Gesamte Blöcke %4 Used Space: %5 Belegter Platz: %5 Free Space: %6 Freier Platz: %6 Total Space: %7 Gesamter Platz: %7 Used %: %8 Belegt %: %8 Properties Eigenschaften Mount Einhängen Open Folder Ordner öffnen Open Private Folder Privaten Ordner öffnen Open Shared Folder Gemeinsamen Ordner öffnen Unmount Aushängen Unmount + Power Down Aushängen + Ausschalten Close Menu Menü schließen Warning Warnung Could not open mount point because "%1" tool does not appear to be working correctly Der Einhängepunkt konnte nicht geöffnet werden, weil das Werkzeug "%1" nicht richtig zu funktionieren scheint Could not get volume properties. volume is not open or was opened by a different user Volume-Eigenschaften konnten nicht ermittelt werden. Volume ist nicht geöffnet oder wurde von einem anderen Benutzer geöffnet Volume Properties Volume-Eigenschaften Permission to access the volume was denied or the volume is not supported (LVM/MDRAID signatures found) Die Berechtigung zum Zugriff auf das Volume wurde verweigert oder das Volume wird nicht unterstützt (LVM/MD-RAID-Signaturen gefunden) Select An Image File To Mount Wählen Sie eine Abbild-Datei zum Einhängen aus Select An Encrypted Volume Directory Wählen Sie ein Verzeichnis für das verschlüsselte Volume aus ERROR! FEHLER! Volume is not open or was opened by a different user Volume ist nicht geöffnet oder wurde von einem anderen Benutzer geöffnet One or more files in the volume are in use. Eine oder mehrere Dateien im Volume werden verwendet. Volume does not have an entry in /etc/mtab Volume hat keinen Eintrag in /etc/mstab Could not get a lock on /etc/mtab~ Konnte keine Sperre auf /etc/mtab~ erhalten Volume is unmounted but could not close mapper,advice to close it manually Das Volume ist nicht eingehängt, aber der Mapper konnte nicht geschlossen werden. Es wird empfohlen, ihn manuell zu schließen Could not resolve full path of device Der Pfad zum Gerät konnte nicht aufgelöst werden Shared mount point appear to be busy Der gemeinsame Einhängepunkt scheint ausgelastet zu sein Shared mount point appear to belong to a different user or multiple mount points detected Der gemeinsame Einhängepunkt scheint einem anderen Benutzer zu gehören oder es wurden mehrere Einhängepunkte erkannt Shared mount point appear to be in an ambiguous state,advice to unmount manually Der gemeinsame Einhängepunkt scheint in einem ungewöhnlichen Zustand zu sein. Es wird empfohlen, ihn manuell auszuhängen Multiple mount points for the volume detected Für das Volume wurden mehrere Einhängepunkte erkannt Device does not appear to be mounted Das Gerät scheint nicht eingehängt zu sein Only root user of members of group "zulumount" can unmount this volume Nur der Benutzer root oder Mitglieder der Gruppe "zulumount" können dieses Volume aushängen Shared mount point appear to be busy Der gemeinsame Einhängepunkt scheint ausgelastet zu sein Shared mount point appear to belong to a different user Der gemeinsame Einhängepunkt scheint einem anderen Benutzer zu gehören Device does not exist Das Gerät existiert nicht Failed to unmount,the mount point and/or one or more files are in use Aushängen fehlgeschlagen, der Einhängepunkt und/oder eine oder mehrere Dateien werden verwendet Failed to unmount,could not get a lock on /etc/mtab~ Aushängen fehlgeschlagen, konnte keine Sperre auf /etc/mtab~ erhalten Failed to unmount the partition Aushängen der Partition ist fehlgeschlagen Failed to unmount,multiple mount points for the volume detected Aushängen fehlgeschlagen, für das Volume wurden mehrere Einhängepunkte erkannt Close failed, could not find any partition with the presented UUID Schließen fehlgeschlagen, es wurde keine Partition mit der angegebenen UUID gefunden Failed to unmount volume Aushängen des Volumes ist fehlgeschlagen ERROR: FEHLER: Reading partition properties took longer than expected and operation was terminated,click refresh to try again Das Lesen der Partitionseigenschaften dauerte länger als erwartet und der Vorgang wurde abgebrochen, klicken Sie auf Aktualisieren, um es erneut zu versuchen zuluCrypt-6.2.0/translations/zuluMount/en_US.qm000066400000000000000000000000201425361753700216600ustar00rootroot00000000000000<¸dÊÍ!¿`¡½ÝzuluCrypt-6.2.0/translations/zuluMount/en_US.ts000066400000000000000000001726411425361753700217140ustar00rootroot00000000000000 DialogMsg Dialog &Ok &Yes &No text type cipher key size device loop offset size mode fs used unused used % active slots "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. INFORMATION Insufficient privilege to access a system device, only root user or members of group zulucrypt can do that Insufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that You do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again type: cipher: keysize: offset: device: loop: mode: active slots: file system: total space: used space: free space: used%: UUID: Do not show this dialog again QObject zuluCrypt: Failed To Establish Connection With zuluPolkit options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI If the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2" public mount point: Manage Favorites Mount All about zuluCrypt hmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents) keykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contents gpg plugin. This plugin retrives a key locked in a gpg file with a symmetric key Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit. ERROR Failed to locate pkexec executable "%1" and "%2" Folders Must Be Writable. Could not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin" List Is Empty Failed To Find %1 Executable INFORMATION Failed To Get Volume Properties VeraCryptPIMDialog VeraCrypt PIM value &Set &Cancel TextLabel Set VeraCrypt dynamic mode magic number below. ERROR Failed to convert the value to digits only keyDialog unlock and mount a luks volume &Open &Cancel Key Mount Name Mount In &Read Only Mode &Share Mount Point O&ptions &VeraCrypt Volume VeraCrypt System Volume VeraCrypt PIM Value &OK Enter Below The Offset Location Of The Volume About To Be Opened. Enter Comma Separated Volume's File System Options Below Set Mount A LUKS volume in "%1" Mount An Encrypted Volume In "%1" Check This Box To Make Password Visible KeyFile Key+KeyFile Plugin TrueCrypt/VeraCrypt Keys YubiKey Challenge/Response Select A Folder To Create A Mount Point In Select A File To Be Used As A Keyfile Cancel ERROR! Internal wallet is not configured Atleast one required field is empty Failed to unlock a cryfs volume. Wrong password entered Failed to unlock an encfs volume. Wrong password entered Failed to unlock a gocryptfs volume. Wrong password entered Failed to unlock an ecryptfs volume. Wrong password entered A Space Character Is Not Allowed In Paths When Using Ecryptfs Backend And Polkit Failed to unlock a securefs volume. Wrong password entered Failed to unlock a cryfs volume. cryfs executable could not be found Failed to unlock a securefs volume. securefs executable could not be found Failed to unlock a gocryptfs volume. gocryptfs executable could not be found Failed to unlock an encfs volume. encfs executable could not be found Failed to unlock an ecryptfs volume. ecryptfs-simple executable could not be found Failed to create mount point Failed to unlock the volume. Not supported volume encountered This backend requires root's privileges and an attempt to acquire them has failed. zuluMount Can Not Unlock This Volume Because Its FileSystem Has To Manually Be Converted To The Version Of Cryfs That Is Currently In Use. Run Cryfs With This Volume To Manually Update This Volume's FileSystem. Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? There seem to be an open volume accociated with given address No file or device exist on given path Volume could not be opened with the presented key Insufficient privilege to mount the device with given options Insufficient privilege to open device in read write mode or device does not exist Only root user can perform this operation -O and -m options can not be used together Could not create mount point, invalid path or path already taken Shared mount point path aleady taken There seem to be an opened mapper associated with the device Could not get a passphrase from the module Could not get passphrase in silent mode Insufficient memory to hold passphrase One or more required argument(s) for this operation is missing Invalid path to key file Could not get enought memory to hold the key file Insufficient privilege to open key file for reading Could not get a passphrase through a local socket Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered Could not create a lock on /etc/mtab Insufficient privilege to open a system volume. Consult menu->help->permission for more informaion A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature Plug in name field is empty Keyfile field is empty "/" character is not allowed in the mount name field Failed To Locate Or Run Yubikey's "ykchalresp" Program. ERROR: Plugin name Keyfile path mountPartition select mount point path Mount Name &Mount Use La&bel &Cancel Mount &Read Only &Share Mount Point &Options Enter Below The Offset Location Of The Volume About To Be Opened Enter The Password Below To A Volume At The Above Offset Set Cancel TextLabel &OK Set File System Options Could not resolve path to device or device could not be opened in read write mode Insuffienct privileges to mount the volume with given mount options Device already mounted Insuffienct privilege to manage a system volume. necessary privileges can be acquired by: 1. Adding an entry for the volume in fstab with "user" mount option . Add yourself to "zulumount" group "/etc/fstab" entry for this volume requires it to be mounted read only "/etc/fstab" entry for this volume is malformed "/etc/fstab" entry for this volume does not allow you to mount it Could not create mount point path,path already taken Shared mount point path aleady taken Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? Mount failed,no or unrecognized file system Mount failed,could not get a lock on /etc/mtab~ Failed to mount the partition ERROR "/" character is not allowed in the mount name field ERROR: Select Path To Mount Point Folder oneinstance Previous instance seem to have crashed,trying to clean up before starting There seem to be another instance running,exiting this one utility::veraCryptWarning Elapsed time: 0 seconds Elapsed time: %0 minutes Elapsed time: %0 seconds Please be patient as unlocking a VeraCrypt volume may take a very long time. zuluMount zuluMount Volume Path Mount Point Path File System Label Size %Used &Favorites Men&u &Mount File Mount F&older &Refresh Automount Volumes Auto Open Mount Point Unmount All Favorites Hide Volume From View Unhide Volume From View Select Language Select Icons About Quit Show/Hide LABEL="%1" LABEL="%1" %2 zuluMount Failed To Connect To zuluPolkit. Please Report This Serious Bug. Total Blocks %4 Used Space: %5 Free Space: %6 Total Space: %7 Used %: %8 Properties Mount Unmount Unmount + Power Down Select An Encrypted Volume Directory Failed to unmount volume Open Folder Open Private Folder Open Shared Folder Close Menu Warning Could not open mount point because "%1" tool does not appear to be working correctly ERROR Do Not Minimize To Tray Clear Dead Mount Points Cryptsetup library could not be found and zuluCrypt will most likely not work as expected. Please recompile zuluCrypt to force it to re-discover the new library Failed To Read Volume Properties INFORMATION Block Size: %1 Used Blocks: %2 Free Blocks: %3 Could not get volume properties. volume is not open or was opened by a different user Volume Properties Permission to access the volume was denied or the volume is not supported (LVM/MDRAID signatures found) Select An Image File To Mount ERROR! Volume is not open or was opened by a different user One or more files in the volume are in use. Volume does not have an entry in /etc/mtab Could not get a lock on /etc/mtab~ Volume is unmounted but could not close mapper,advice to close it manually Could not resolve full path of device Shared mount point appear to be busy Shared mount point appear to belong to a different user or multiple mount points detected Shared mount point appear to be in an ambiguous state,advice to unmount manually Multiple mount points for the volume detected Device does not appear to be mounted Only root user of members of group "zulumount" can unmount this volume Shared mount point appear to be busy Shared mount point appear to belong to a different user Device does not exist Failed to unmount,the mount point and/or one or more files are in use Failed to unmount,could not get a lock on /etc/mtab~ Failed to unmount the partition Failed to unmount,multiple mount points for the volume detected Close failed, could not find any partition with the presented UUID ERROR: Reading partition properties took longer than expected and operation was terminated,click refresh to try again zuluCrypt-6.2.0/translations/zuluMount/fr_FR.qm000066400000000000000000001250351425361753700216630ustar00rootroot00000000000000<¸dÊÍ!¿`¡½Ý§fr_FRBÓ¼+;)+;aK+OË+[òQÉKÖYÄSúYÄp¥¹Ä%C¿Ã[苸Œ‘W¡šJ6`nE¥Á¡k¬ô™Àe É´ŽÞjÅ*É´xä+f¾)-G–ÄyØJgzJwB%JwB%~JwBdøJwBƒ¥J  v«Rx¼ŠÒR}ÕR4SÀÕ‹TlT‹4WñÕ)ÐZz Ä^Ü„)^^Ü„a²aŒE…RbƒÉXÆjyeExsf:tZŠã|Š3ˆ¬Ä‚#ž#)“AžÎΉ¤Œé å¦ó #ÎÅÃ…Užð¬Ã„;”Ƀ(¦s ´Z´J×1ëcXîå4cÛ>néš2NPÔœ%KýÍÐuLJï'×5ú»In=|Ú•­ŒÃå3<ŸÃDŒ´lTa¸r}ž˜àjˆ( h.B-BœN‚Å»R"S‰UJj˜¥te…ÀŒªÞbV¤ë” §½("„µ'—ÐDSv6ÓÏó”RâµX ÷>}’i~ñ çÉ•$/ÅXa&<žVn3Ü3{QQ‘zýS0ùŸFxg€%¶€d¥R–Ês˜I¼/\˜I¼b¢auH¤FÂŽª§tA4À§tAƒÔ¯ƒWC¾ïˆOÕ³"Š…ðD‚Îô,utT&ÌrZ:_y²=ïQ‡?ÅÂ0=F'ùF]"OŠåyOP-d‘\ÆD]a¤ÂMÖbõN¿bõn l¨¤*és½þR~­ôA¾™ÔŽ0ÍœôÄ|Íœ 4Õf).¿á³cwý?´7Ïý¨Íˆ±gÚGÔBØ- 8œKB"é‰`ZcW¢fÊwJ{ãaw›Èž&~ nÂI£¶Uš¥ýSTɬ³î‘‡¬Ï•¸ÌÖ£‘Ñô^ô‰5”¬ä]ÿX§~ X§~EX§~Š\ÙÄk•¨M€T8Y€Tg¯J‰L‹·—‰™ÅÉ´`ɶ%¾ɶŠ;ËòúyÚâêôë—›ì>RM_½Î ñ&ßOð1¤C°QüÃFX•ws;\aòTn•d>ù™ ހ˙ø½o­»våRw½Ž(yœ½¬n àØÌi–X ™NY •~S< q™5{Ô w3YwÕ ‡>óz ¶æ ¼ ÖžÉ_Á ç””†ˆ øT) øqe úMRŠA üX…Y ì:m C"d ¿þj !Xr­ #x9Ï #xh ,ßÞ„Ñ WãÔ^û \ t“Ë l “pÙ wE€4ò wE€e, wE€„ ‘ô;C ˜Iœ% ˜Iœ(Ñ ˜Iœ`Ú ¦wþ] Ìùêô Ò‘ÃÊ âá/Ž “b*! YT@Ý “T= ¶¥’Žõ Á¬2 Ìߤf; × ®›° Ýæ~6Ü ú 4D£ Lœ tÄ$0 Tl›{ VL" ¯yµKT µ‰”M µÚ”2u ·¨à º|Ò‹c »~Ô ¾'Ž5' îÈò—´ ômõ,' š& lt< 2„z =ìNŒË iFCˆ| j'd?Ù k¦Cy y…µ1Ç {COº ‰P p Úz' æÃ‡šÉ.%œÞŽõœœYé§W3m?· rpaÄÄDHµÆù„ &ËâtefÞN€àcu¾®žV%¢žn/œ6‰MP™´‚«’"|'C’"|r ¨%‡m·c¾ZkðV4=ïüFÔšxi¡ê˜ "Les volumes système" sont des volumes ayant été identifiés par udev, si udev est activé, ou bien qui ont une entrée dans "/etc/fstab","/etc/crypttab" ou "/etc/zuluCrypt/system_volumes.list". Si vous préférez qu'un volume ne soit pas considéré comme un volume système, démarrez le logiciel depuis le compte root, puis aller à "menu-> options-> gérer des partitions non-système" et ajouter le volume à la liste, celui-ci cessera d'être considéré comme «système». Autrement, vous pouvez vous ajouter aussi au groupe "zulucrypt" et "zulumount" et toutes les restrictions vont disparaître. "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. DialogMsg&No&No DialogMsg&Ok&Ok DialogMsg&Oui&Yes DialogMsg"Boîte de dialogueDialog DialogMsgHNe plus montrer ce message désormaisDo not show this dialog again DialogMsgINFORMATIONS INFORMATION DialogMsg8Privilèges insuffisants pour accéder à un périphérique en mode lecture/écriture, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le faireƒInsufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that DialogMsgPrivilèges insuffisants pour accéder à un périphérique système, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le fairejInsufficient privilege to access a system device, only root user or members of group zulucrypt can do that DialogMsg UUID:UUID: DialogMsg.Vous ne semblez pas avoir les autorisations nécessaires pour accéder au fichier chiffré en mode %1, vérifiez les droits du fichier et essayez à nouveauwYou do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again DialogMsg&emplacements actifs active slots DialogMsgslots actifs: active slots: DialogMsgÿÿÿÿcipher DialogMsg&clé de chiffrement:cipher: DialogMsgpériphériquedevice DialogMsgdevice:device: DialogMsg(système de fichiers: file system: DialogMsgespace libre: free space: DialogMsgfsfs DialogMsg taille de la clékey size DialogMsg"taille de la clé:keysize: DialogMsgÿÿÿÿloop DialogMsgboucle:loop: DialogMsgÿÿÿÿmode DialogMsg mode:mode: DialogMsgÿÿÿÿoffset DialogMsgdécalage:offset: DialogMsg taillesize DialogMsg textetext DialogMsgespace total: total space: DialogMsgtypetype DialogMsg type:type: DialogMsg libreunused DialogMsgutiliséused DialogMsgutilisé %used % DialogMsgespace utilisé: used space: DialogMsg% utilisé:used%: DialogMsgú Options: -d localisation du chemin d'un volume pour être auto déverrouillé / monté -m à utiliser pour ouvrir un gestionnaire de fichiers par défaut (l'outil par défaut est xdg-open) -e démarre l'application sans afficher l'interface graphique Í options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI QObject€"%1" et "%2" doivent être des répertoires autorisés en écriture.'"%1" and "%2" Folders Must Be Writable.QObject¢Ne trouve pas de "gpg" executable dans "/usr/local/bin","/usr/bin" ou "/usr/sbin"NCould not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin"QObject ERREURERRORQObject@Échoue à trouver l'exécutable %1Failed To Find %1 ExecutableQObjectXÉchec à l'obtention des propriétés de volumeFailed To Get Volume PropertiesQObjectŽÉchec du lancement de l'application Helper. "org.zulucrypt.zulupolkit.policy" fichier polkit mal configuré, le zuluPolkit exécutable ne peut être trouvé ou bien pkexec échoue à démarrer zuluPolkit.´Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit.QObjectLÉchoue à localiser l'exécutable pkexec"Failed to locate pkexec executableQObjectINFORMATIONS INFORMATIONQObjectJSi l'option est cochée, un point de montage privé primaire sera créé dans "%1" et un «miroir» secondaire du point de montage accessible au public sera créé dans "%2"ŸIf the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2"QObject"La liste est vide List Is EmptyQObject"Gérer les favorisManage FavoritesQObjectMonter tout Mount AllQObject*A propos de zuluCryptabout zuluCryptQObjectÆgpg plugin. Ce plugin récupère une clé de verrouillage dans un fichier gpg avec une clé symétriqueQgpg plugin. This plugin retrives a key locked in a gpg file with a symmetric keyQObjectôhmac plugin. Ce plugin génère une clé en utilisant la formule ci-dessous: key = hmac(sha256,passphrase,keyfile contents)ohmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents)QObjectäkeykeyfile plugin. Ce plugin génère une clé à l'aide de la formule suivante: key = passphrase + keyfile contentsjkeykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contentsQObject2point de montage public: public mount point: QObject€zuluCrypt: Échec de l'établissement de connexion avec zuluPolkit9zuluCrypt: Failed To Establish Connection With zuluPolkitQObject&Annuler&CancelVeraCryptPIMDialog&Définir&SetVeraCryptPIMDialog ERREURERRORVeraCryptPIMDialogvEchec de la conversion de la valeur en chiffres uniquement +Failed to convert the value to digits only VeraCryptPIMDialogpActiver le dynamic mode magic number Veracrypt ci-après..Set VeraCrypt dynamic mode magic number below.VeraCryptPIMDialog$Etiquette de texte TextLabelVeraCryptPIMDialog(Valeur PIM VeraCryptVeraCrypt PIM valueVeraCryptPIMDialog†Le caractère "/" n'est pas autorisé dans le champ du nom de montage4"/" character is not allowed in the mount name field keyDialog&Annuler&Cancel keyDialog&OK&OK keyDialog&Ouvrir&Open keyDialogB&Share (Partage) Point de montage&Share Mount Point keyDialog"Volume &VeraCrypt&VeraCrypt Volume keyDialog€Les options -O et -m ne peuvent pas être utilisées conjointement*-O and -m options can not be used together keyDialogÐLe caractère d'espace n'est pas autorisé dans les chemins quand Ecryptfs Backend et Polkit sont utilisésPA Space Character Is Not Allowed In Paths When Using Ecryptfs Backend And Polkit keyDialogÂUn périphérique est non supporté ou manquant ou permission refusée Les raisons possibles pour corriger l'erreur sont les suivantes: 1. Chemin du périphérique invalide. 2. le périphérique possède un LVM ou une signature MDRAID¸A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature keyDialog\Au moins un des champs qui est requis est vide#Atleast one required field is empty keyDialogAnnulerCancel keyDialogjCocher cette case pour rendre le mot de passe visible'Check This Box To Make Password Visible keyDialogNNe peut pas créer un lock sur /etc/mtab$Could not create a lock on /etc/mtab keyDialogœImpossible de créer le point de montage, chemin non valide ou chemin déjà pris@Could not create mount point, invalid path or path already taken keyDialogfNe peut pas obtenir une passphrase depuis ce module*Could not get a passphrase from the module keyDialogxNe peut pas obtenir une passphrase à travers un socket local1Could not get a passphrase through a local socket keyDialog†Ne peut pas avoir assez de mémoire pour manipuler le fichier de clé1Could not get enought memory to hold the key file keyDialogjNe peut pas obtenir une passphrase en mode silencieux'Could not get passphrase in silent mode keyDialogERREUR!ERROR! keyDialogERREUR: ERROR:  keyDialogtEntrer ci après l'offset d'emplacement du volume à ouvrir.AEnter Below The Offset Location Of The Volume About To Be Opened. keyDialogŒEntrer un fichier d'options système de volume en séparation à virgules8Enter Comma Separated Volume's File System Options Below keyDialogžEchec de la localisation ou de l'exécution du programme Yubikey's "ykchalresp".7Failed To Locate Or Run Yubikey's "ykchalresp" Program. keyDialogPEchec de la création du point de montageFailed to create mount point keyDialogôEchec du montage du système de fichier : option de montage invalide/non supportée ou bien système de fichiers non supportédFailed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered keyDialogþImpossible de monter le système de fichiers ntfs / exfat en utilisant ntfs-3g, est ce que le paquet ntfs-3g/exfat est installé?XFailed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? keyDialog‚Echec de l'ouverture du volume cryfs Mot de passe entré incorrect7Failed to unlock a cryfs volume. Wrong password entered keyDialogEchec de l'ouverture du volume cryfs. L'exécutable cryfs est introuvableDFailed to unlock a cryfs volume. cryfs executable could not be found keyDialogŠEchec de l'ouverture du volume gocryptfs Mot de passe entré incorrect;Failed to unlock a gocryptfs volume. Wrong password entered keyDialog Echec de l'ouverture du volume gocryptfs. L'exécutable gocryptfs est introuvableLFailed to unlock a gocryptfs volume. gocryptfs executable could not be found keyDialogˆEchec de l'ouverture du volume securefs Mot de passe entré incorrect:Failed to unlock a securefs volume. Wrong password entered keyDialogœEchec de l'ouverture du volume securefs. L'exécutable securefs est introuvableJFailed to unlock a securefs volume. securefs executable could not be found keyDialogˆEchec de l'ouverture du volume ecryptfs Mot de passe entré incorrect;Failed to unlock an ecryptfs volume. Wrong password entered keyDialogªEchec de l'ouverture du volume ecryptfs. L'exécutable ecryptfs-simple est introuvableRFailed to unlock an ecryptfs volume. ecryptfs-simple executable could not be found keyDialog‚Echec de l'ouverture du volume encfs Mot de passe entré incorrect8Failed to unlock an encfs volume. Wrong password entered keyDialogEchec de l'ouverture du volume encfs. L'exécutable encfs est introuvableEFailed to unlock an encfs volume. encfs executable could not be found keyDialogzEchec de l'ouverture du volume. Volume non supporté rencontré=Failed to unlock the volume. Not supported volume encountered keyDialogbMémoire insuffisante pour manipuler la passphrase&Insufficient memory to hold passphrase keyDialog˜Privilèges insuffisants pour monter le périphérique avec des options données=Insufficient privilege to mount the device with given options keyDialog"Privilèges insuffisants pour opérer sur un volume système. Consultez le menu ->Aide-> Zulucrypt.pdf - Permissions pour davantage d'informations dInsufficient privilege to open a system volume. Consult menu->help->permission for more informaion  keyDialogâPrivilèges insuffisants pour ouvrir le périphérique en mode lecture-écriture ou bien le périphérique n'existe pasQInsufficient privilege to open device in read write mode or device does not exist keyDialog€Privilège insuffisant pour ouvrir le fichier clé pour la lecture3Insufficient privilege to open key file for reading keyDialog>Trousseau Interne non configuré!Internal wallet is not configured keyDialogLChemin invalide vers le fichier de cléInvalid path to key file keyDialogCléKey keyDialog$Clé+fichier de clé Key+KeyFile keyDialogFichier de cléKeyFile keyDialogFLe champ de fichier de clé est videKeyfile field is empty keyDialog0Chemin du fichier de clé Keyfile path keyDialog>Monter un volume LUKS dans "%1"Mount A LUKS volume in "%1" keyDialogDMonter un volume chiffré dans "%1"!Mount An Encrypted Volume In "%1" keyDialog0Monter en &Lecture SeuleMount In &Read Only Mode keyDialogNom du montage Mount Name keyDialogtAucun fichier ou périphérique existant sur le chemin donné%No file or device exist on given path keyDialogO&ptionsO&ptions keyDialogˆUn ou plusieurs argument(s) requis pour cette opération est manquant>One or more required argument(s) for this operation is missing keyDialoglSeul l'utilisateur root peut effectuer cette opération)Only root user can perform this operation keyDialogDLe champ de nom de plugin est videPlug in name field is empty keyDialog PluginPlugin keyDialogNom de plugin Plugin name keyDialog‚Sélectionner un fichier pour être utilisé comme un fichier de clé%Select A File To Be Used As A Keyfile keyDialogvSélectionner un répertoire pour y créer un point de montage*Select A Folder To Create A Mount Point In keyDialogDéfinirSet keyDialog^Chemin de point de montage du partage déjà pris$Shared mount point path aleady taken keyDialogzIl semble y avoir un volume ouvert associé à l'adresse donnée=There seem to be an open volume accociated with given address keyDialogvIl semble y avoir un mappeur ouvert associé au périphériqueMontage automatique des volumesAutomount Volumes zuluMount(Taille des blocs: %1Block Size: %1 zuluMountNEffacer les points de montage obsolètesClear Dead Mount Points zuluMountFermer le Menu Close Menu zuluMount˜Echec de la fermeture, ne trouve aucune partition avec l'UUID correspondanteBClose failed, could not find any partition with the presented UUID zuluMountNNe peut pas créer un lock sur /etc/mtab"Could not get a lock on /etc/mtab~ zuluMountàNe peut pas obtenir les propriétés du volume Le volume n'est pas ouvert ou a été ouvert par un autre utilisateurUCould not get volume properties. volume is not open or was opened by a different user zuluMountºImpossible d'ouvrir le point de montage parce que "%1" ne semble pas fonctionner correctementTCould not open mount point because "%1" tool does not appear to be working correctly zuluMountjNe trouve pas le chemin complet vers le périphérique &Could not resolve full path of device  zuluMountàLa bibliothèque Cryptsetup n'a pas été trouvée et ZuluCrypt risque évidemment de ne pas fonctionner comme prévu.ZCryptsetup library could not be found and zuluCrypt will most likely not work as expected. zuluMountFLe périphérique ne semble pas monté$Device does not appear to be mounted zuluMountJLe périphérique ne semble pas existerDevice does not exist zuluMountHNe pas minimiser en barre des tâchesDo Not Minimize To Tray zuluMount ERREURERROR zuluMountERREUR!ERROR! zuluMountERREUR: ERROR:  zuluMountXEchec de la lecture des propriétés du volume Failed To Read Volume Properties zuluMountDEchec du démontage de la partitionFailed to unmount the partition zuluMount8Echec du démontage du volumeFailed to unmount volume zuluMountvEchec du démontage, ne peut pas créer un lock sur /etc/mtab4Failed to unmount,could not get a lock on /etc/mtab~ zuluMountˆEchec du démontage, des points de montage multiples ont été détectés?Failed to unmount,multiple mount points for the volume detected zuluMount¬Echec du démontage, le point de montage et/ou des fichiers sont en cours d'utilisationEFailed to unmount,the mount point and/or one or more files are in use zuluMountFavoris Favorites zuluMount&Système de Fichiers File System zuluMount Blocs Libres: %3Free Blocks: %3 zuluMount Espace Libre: %6Free Space: %6 zuluMount4Cacher le volume de la vueHide Volume From View zuluMountINFORMATIONS INFORMATION zuluMountEtiquette="%1" LABEL="%1" zuluMount"Etiquette="%1" %2 LABEL="%1" %2 zuluMountEtiquetteLabel zuluMount Men&uMen&u zuluMount MonterMount zuluMount*Monter un &Répertoire Mount F&older zuluMount4Chemin du point de montageMount Point Path zuluMountfPlusieurs points de montage détectés pour le volume-Multiple mount points for the volume detected zuluMountˆUn ou plusieurs fichiers dans le volume sont en cours d'utilisation.+One or more files in the volume are in use. zuluMountªSeul l'utilisateur root ou les membres du groupe zulucrypt peuvent demonter ce volumeFOnly root user of members of group "zulumount" can unmount this volume zuluMount"Ouvrir Répertoire Open Folder zuluMount.Ouvrir Répertoire PrivéOpen Private Folder zuluMount8Ouvrir un répertoire partagéOpen Shared Folder zuluMountÚLa permission d'accéder au volume a été refusée ou le volume n'est pas supporté (LVM/MDRAID signatures found)gPermission to access the volume was denied or the volume is not supported (LVM/MDRAID signatures found) zuluMountPropriétés Properties zuluMountQuitterQuit zuluMount.La lecture des propriétés de la partition prend plus de temps que prévu et l'opération a été terminée, cliquez sur actualiser/rafraîchir pour réessayernReading partition properties took longer than expected and operation was terminated,click refresh to try again zuluMountHSélectionner un répertoire de volume$Select An Encrypted Volume Directory zuluMountLSélectionner un fichier image à MonterSelect An Image File To Mount zuluMount0Choisir le type d'icônes Select Icons zuluMount,Sélectionner la langueSelect Language zuluMountfChemin de point de montage du partage semble occupé$Shared mount point appear to be busy zuluMounthChemin de point de montage du partage semble occupé %Shared mount point appear to be busy  zuluMountîChemin de point de montage du partage semble être dans un état incohérent, il est conseillé de le démonter manuellementPShared mount point appear to be in an ambiguous state,advice to unmount manually zuluMountœChemin de point de montage du partage semble appartenir à un autre utilisateur7Shared mount point appear to belong to a different user zuluMountæChemin de point de montage du partage semble appartenir à un autre utilisateur ou bien points de montage multiples ZShared mount point appear to belong to a different user or multiple mount points detected  zuluMount Afficher/Masquer Show/Hide zuluMount TailleSize zuluMount$Total des Blocs %4Total Blocks %4 zuluMount Espace Total: %7Total Space: %7 zuluMount0Montrer le volume en vueUnhide Volume From View zuluMountDémonterUnmount zuluMount&Démonter + ÉteindreUnmount + Power Down zuluMountDémonter tout Unmount All zuluMountUtilisé %: %8 Used %: %8 zuluMount$Blocs utilisés: %2Used Blocks: %2 zuluMount$Espace Utilisé: %5Used Space: %5 zuluMount Chemin du volume Volume Path zuluMount(Propriétés du VolumeVolume Properties zuluMountXLe volume n'a pas d'entrée dans le /etc/mtab*Volume does not have an entry in /etc/mtab zuluMount†Le volume n'est pas ouvert ou a été ouvert par un autre utilisateur4Volume is not open or was opened by a different user zuluMountÂLe volume est démonté mais le mappeur n'est pas fermé, il est conseillé de le fermer manuellementJVolume is unmounted but could not close mapper,advice to close it manually zuluMountAttentionWarning zuluMountzuluMount zuluMount zuluMount¢zuluMount a échoué à se connecter à zuluPolkit. Merci de reporter ce bug sérieux.JzuluMount Failed To Connect To zuluPolkit. Please Report This Serious Bug. zuluMountˆzuluCrypt-6.2.0/translations/zuluMount/fr_FR.ts000066400000000000000000002131701425361753700216720ustar00rootroot00000000000000 DialogMsg Dialog Boîte de dialogue &Ok &Ok &Yes &Oui &No &No text texte type type cipher key size taille de la clé device périphérique loop offset size taille mode fs fs used utilisé unused libre used % utilisé % active slots emplacements actifs "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt/system_volumes.list". If you prefer for a volume not to be considered a system volume,start the toolfrom root account and then go to "menu->options->manage non system partitions" and add the volume to the list and the volume will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and "zulumount" and all restrictions will go away. "Les volumes système" sont des volumes ayant été identifiés par udev, si udev est activé, ou bien qui ont une entrée dans "/etc/fstab","/etc/crypttab" ou "/etc/zuluCrypt/system_volumes.list". Si vous préférez qu'un volume ne soit pas considéré comme un volume système, démarrez le logiciel depuis le compte root, puis aller à "menu-> options-> gérer des partitions non-système" et ajouter le volume à la liste, celui-ci cessera d'être considéré comme «système». Autrement, vous pouvez vous ajouter aussi au groupe "zulucrypt" et "zulumount" et toutes les restrictions vont disparaître. INFORMATION INFORMATIONS Insufficient privilege to access a system device, only root user or members of group zulucrypt can do that Privilèges insuffisants pour accéder à un périphérique système, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le faire Insufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that Privilèges insuffisants pour accéder à un périphérique en mode lecture/écriture, seul l'utilisateur root ou les membres du groupe zulucrypt peuvent le faire You do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again Vous ne semblez pas avoir les autorisations nécessaires pour accéder au fichier chiffré en mode %1, vérifiez les droits du fichier et essayez à nouveau type: type: cipher: clé de chiffrement: keysize: taille de la clé: offset: décalage: device: device: loop: boucle: mode: mode: active slots: slots actifs: file system: système de fichiers: total space: espace total: used space: espace utilisé: free space: espace libre: used%: % utilisé: UUID: UUID: Do not show this dialog again Ne plus montrer ce message désormais QObject zuluCrypt: Failed To Establish Connection With zuluPolkit zuluCrypt: Échec de l'établissement de connexion avec zuluPolkit options: -d path to where a volume to be auto unlocked/mounted is located -m tool to use to open a default file manager(default tool is xdg-open) -e start the application without showing the GUI Options: -d localisation du chemin d'un volume pour être auto déverrouillé / monté -m à utiliser pour ouvrir un gestionnaire de fichiers par défaut (l'outil par défaut est xdg-open) -e démarre l'application sans afficher l'interface graphique If the option is checked,a primary private mount point will be created in "%1" and a secondary publicly accessible "mirror" mount point will be created in "%2" Si l'option est cochée, un point de montage privé primaire sera créé dans "%1" et un «miroir» secondaire du point de montage accessible au public sera créé dans "%2" public mount point: point de montage public: Manage Favorites Gérer les favoris Mount All Monter tout about zuluCrypt A propos de zuluCrypt hmac plugin. This plugin generates a key using below formular: key = hmac(sha256,passphrase,keyfile contents) hmac plugin. Ce plugin génère une clé en utilisant la formule ci-dessous: key = hmac(sha256,passphrase,keyfile contents) keykeyfile plugin. This plugin generates a key using below formular: key = passphrase + keyfile contents keykeyfile plugin. Ce plugin génère une clé à l'aide de la formule suivante: key = passphrase + keyfile contents gpg plugin. This plugin retrives a key locked in a gpg file with a symmetric key gpg plugin. Ce plugin récupère une clé de verrouillage dans un fichier gpg avec une clé symétrique Failed To Start Helper Application. "org.zulucrypt.zulupolkit.policy" polkit file is misconfigured, zuluPolkit executable could not be found or pkexec failed to start zuluPolkit. Échec du lancement de l'application Helper. "org.zulucrypt.zulupolkit.policy" fichier polkit mal configuré, le zuluPolkit exécutable ne peut être trouvé ou bien pkexec échoue à démarrer zuluPolkit. ERROR ERREUR Failed to locate pkexec executable Échoue à localiser l'exécutable pkexec "%1" and "%2" Folders Must Be Writable. "%1" et "%2" doivent être des répertoires autorisés en écriture. Could not find "gpg" executable in "/usr/local/bin","/usr/bin" and "/usr/sbin" Ne trouve pas de "gpg" executable dans "/usr/local/bin","/usr/bin" ou "/usr/sbin" List Is Empty La liste est vide Failed To Find %1 Executable Échoue à trouver l'exécutable %1 INFORMATION INFORMATIONS Failed To Get Volume Properties Échec à l'obtention des propriétés de volume VeraCryptPIMDialog VeraCrypt PIM value Valeur PIM VeraCrypt &Set &Définir &Cancel &Annuler TextLabel Etiquette de texte Set VeraCrypt dynamic mode magic number below. Activer le dynamic mode magic number Veracrypt ci-après. ERROR ERREUR Failed to convert the value to digits only Echec de la conversion de la valeur en chiffres uniquement keyDialog unlock and mount a luks volume Déchiffrer et monter un volume LUKS &Open &Ouvrir &Cancel &Annuler Key Clé Mount Name Nom du montage Mount In &Read Only Mode Monter en &Lecture Seule &Share Mount Point &Share (Partage) Point de montage O&ptions O&ptions &VeraCrypt Volume Volume &VeraCrypt VeraCrypt System Volume Volume Système VeraCrypt VeraCrypt PIM Value VeraCrypt PIM Valeur &OK &OK Enter Below The Offset Location Of The Volume About To Be Opened. Entrer ci après l'offset d'emplacement du volume à ouvrir. Enter Comma Separated Volume's File System Options Below Entrer un fichier d'options système de volume en séparation à virgules Set Définir Mount A LUKS volume in "%1" Monter un volume LUKS dans "%1" Mount An Encrypted Volume In "%1" Monter un volume chiffré dans "%1" Check This Box To Make Password Visible Cocher cette case pour rendre le mot de passe visible KeyFile Fichier de clé Key+KeyFile Clé+fichier de clé Plugin Plugin TrueCrypt/VeraCrypt Keys Clés TrueCrypt/VeraCrypt YubiKey Challenge/Response YubiKey Challenge/Réponse Select A Folder To Create A Mount Point In Sélectionner un répertoire pour y créer un point de montage Select A File To Be Used As A Keyfile Sélectionner un fichier pour être utilisé comme un fichier de clé Cancel Annuler ERROR! ERREUR! Internal wallet is not configured Trousseau Interne non configuré Atleast one required field is empty Au moins un des champs qui est requis est vide Failed to unlock a cryfs volume. Wrong password entered Echec de l'ouverture du volume cryfs Mot de passe entré incorrect Failed to unlock an encfs volume. Wrong password entered Echec de l'ouverture du volume encfs Mot de passe entré incorrect Failed to unlock a gocryptfs volume. Wrong password entered Echec de l'ouverture du volume gocryptfs Mot de passe entré incorrect Failed to unlock an ecryptfs volume. Wrong password entered Echec de l'ouverture du volume ecryptfs Mot de passe entré incorrect A Space Character Is Not Allowed In Paths When Using Ecryptfs Backend And Polkit Le caractère d'espace n'est pas autorisé dans les chemins quand Ecryptfs Backend et Polkit sont utilisés Failed to unlock a securefs volume. Wrong password entered Echec de l'ouverture du volume securefs Mot de passe entré incorrect Failed to unlock a cryfs volume. cryfs executable could not be found Echec de l'ouverture du volume cryfs. L'exécutable cryfs est introuvable Failed to unlock a securefs volume. securefs executable could not be found Echec de l'ouverture du volume securefs. L'exécutable securefs est introuvable Failed to unlock a gocryptfs volume. gocryptfs executable could not be found Echec de l'ouverture du volume gocryptfs. L'exécutable gocryptfs est introuvable Failed to unlock an encfs volume. encfs executable could not be found Echec de l'ouverture du volume encfs. L'exécutable encfs est introuvable Failed to unlock an ecryptfs volume. ecryptfs-simple executable could not be found Echec de l'ouverture du volume ecryptfs. L'exécutable ecryptfs-simple est introuvable Failed to create mount point Echec de la création du point de montage Failed to unlock the volume. Not supported volume encountered Echec de l'ouverture du volume. Volume non supporté rencontré This backend requires root's privileges and an attempt to acquire them has failed. Ce processus nécessite les privilèges root et leur tentative d'obtention a malheureusement échoué. zuluMount Can Not Unlock This Volume Because Its FileSystem Has To Manually Be Converted To The Version Of Cryfs That Is Currently In Use. Run Cryfs With This Volume To Manually Update This Volume's FileSystem. zuluMount ne peut débloquer ce volume car son système de fichier doit être converti dans la version de Cryfs actuellement utilisée. Exécutez Cryfs avec ce volume pour manuellement mettre à jour le système de fichier du volume. Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? Impossible de monter le système de fichiers ntfs / exfat en utilisant ntfs-3g, est ce que le paquet ntfs-3g/exfat est installé? There seem to be an open volume accociated with given address Il semble y avoir un volume ouvert associé à l'adresse donnée No file or device exist on given path Aucun fichier ou périphérique existant sur le chemin donné Volume could not be opened with the presented key Le volume n'a pas pu être ouvert avec la clé proposée Insufficient privilege to mount the device with given options Privilèges insuffisants pour monter le périphérique avec des options données Insufficient privilege to open device in read write mode or device does not exist Privilèges insuffisants pour ouvrir le périphérique en mode lecture-écriture ou bien le périphérique n'existe pas Only root user can perform this operation Seul l'utilisateur root peut effectuer cette opération -O and -m options can not be used together Les options -O et -m ne peuvent pas être utilisées conjointement Could not create mount point, invalid path or path already taken Impossible de créer le point de montage, chemin non valide ou chemin déjà pris Shared mount point path aleady taken Chemin de point de montage du partage déjà pris There seem to be an opened mapper associated with the device Il semble y avoir un mappeur ouvert associé au périphérique Could not get a passphrase from the module Ne peut pas obtenir une passphrase depuis ce module Could not get passphrase in silent mode Ne peut pas obtenir une passphrase en mode silencieux Insufficient memory to hold passphrase Mémoire insuffisante pour manipuler la passphrase One or more required argument(s) for this operation is missing Un ou plusieurs argument(s) requis pour cette opération est manquant Invalid path to key file Chemin invalide vers le fichier de clé Could not get enought memory to hold the key file Ne peut pas avoir assez de mémoire pour manipuler le fichier de clé Insufficient privilege to open key file for reading Privilège insuffisant pour ouvrir le fichier clé pour la lecture Could not get a passphrase through a local socket Ne peut pas obtenir une passphrase à travers un socket local Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered Echec du montage du système de fichier : option de montage invalide/non supportée ou bien système de fichiers non supporté Could not create a lock on /etc/mtab Ne peut pas créer un lock sur /etc/mtab Insufficient privilege to open a system volume. Consult menu->help->permission for more informaion Privilèges insuffisants pour opérer sur un volume système. Consultez le menu ->Aide-> Zulucrypt.pdf - Permissions pour davantage d'informations A non supported device encountered,device is missing or permission denied Possible reasons for getting the error are: 1.Device path is invalid. 2.The device has LVM or MDRAID signature Un périphérique est non supporté ou manquant ou permission refusée Les raisons possibles pour corriger l'erreur sont les suivantes: 1. Chemin du périphérique invalide. 2. le périphérique possède un LVM ou une signature MDRAID Plug in name field is empty Le champ de nom de plugin est vide Keyfile field is empty Le champ de fichier de clé est vide "/" character is not allowed in the mount name field Le caractère "/" n'est pas autorisé dans le champ du nom de montage Failed To Locate Or Run Yubikey's "ykchalresp" Program. Echec de la localisation ou de l'exécution du programme Yubikey's "ykchalresp". ERROR: ERREUR: Plugin name Nom de plugin Keyfile path Chemin du fichier de clé mountPartition select mount point path Sélectionner le chemin du point de montage Mount Name Nom du montage &Mount &Monter Use La&bel Utiliser &Etiquette &Cancel &Annuler Mount &Read Only Monter en &Lecture Seule &Share Mount Point &Partage du point de montage &Options &Options Enter Below The Offset Location Of The Volume About To Be Opened Entrer ci après l'offset d'emplacement du volume à ouvrir Enter The Password Below To A Volume At The Above Offset Entrer ci après le mot de passe du volume au dessus de l'offset Set Définir Cancel Annuler TextLabel Etiquette de texte &OK &OK Set File System Options Régler les options du système de fichiers Could not resolve path to device or device could not be opened in read write mode Ne trouve pas le chemin d'emplacement du périphérique ou alors le périphérique ne peut pas être ouvert en mode lecture/écriture Insuffienct privileges to mount the volume with given mount options Privilèges insuffisants pour monter le périphérique avec des options données Device already mounted Périphérique déjà monté Insuffienct privilege to manage a system volume. necessary privileges can be acquired by: 1. Adding an entry for the volume in fstab with "user" mount option . Add yourself to "zulumount" group Privilèges insuffisants pour gérer un volume système. Les droits nécessaires peuvent être obtenus par : - ajout d'unee entrée pour le volume dans le fstab avec l'option de montage "user" - ajout de l'utilisateur au groupe "zulumount" "/etc/fstab" entry for this volume requires it to be mounted read only Une entrée dans "/etc/fstab" est requise pour ce volume pour être monté en lecture seule "/etc/fstab" entry for this volume is malformed Une entrée dans "/etc/fstab" est incorrecte pour ce volume "/etc/fstab" entry for this volume does not allow you to mount it Une entrée dans "/etc/fstab" pour ce volume ne vous autorise pas à le monter Could not create mount point path,path already taken Impossible de créer le point de montage, chemin déjà pris Shared mount point path aleady taken Chemin de point de montage du partage déjà pris Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered Echec du montage du système de fichier : option de montage invalide/non supportée ou bien système de fichiers non supporté Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed? Impossible de monter le système de fichiers ntfs / exfat en utilisant ntfs-3g, est ce que le paquet ntfs-3g/exfat est installé? Mount failed,no or unrecognized file system Echec du montage ou système de fichiers non reconnu Mount failed,could not get a lock on /etc/mtab~ Echec du montage, ne peut pas créer un lock sur /etc/mtab Failed to mount the partition Echec du montage de la partition ERROR ERREUR "/" character is not allowed in the mount name field Le caractère "/" n'est pas autorisé dans le champ du nom de montage ERROR: ERREUR: Select Path To Mount Point Folder oneinstance Previous instance seem to have crashed,trying to clean up before starting L'instance précédente semble avoir crashé, tentative de réinitialisation avant démarrage There seem to be another instance running,exiting this one Il semble y avoir une autre instance en cours d'exécution, sortie de celle-ci utility::veraCryptWarning Elapsed time: 0 seconds Temps écoulé: 0 secondes Elapsed time: %0 minutes Temps écoulé: %0 minutes Elapsed time: %0 seconds Temps écoulé: %0 secondes Please be patient as unlocking a VeraCrypt volume may take a very long time. Soyez patient car le déchiffrement d'un volume VeraCrypt peut durer un certain temps. zuluMount zuluMount zuluMount Volume Path Chemin du volume Mount Point Path Chemin du point de montage File System Système de Fichiers Label Etiquette Size Taille %Used %Utilisé &Favorites &Favoris Men&u Men&u &Mount File &Monter un Fichier Mount F&older Monter un &Répertoire &Refresh &Rafraîchir Automount Volumes Montage automatique des volumes Auto Open Mount Point Ouverture automatique du point de montage Unmount All Démonter tout Favorites Favoris Hide Volume From View Cacher le volume de la vue Unhide Volume From View Montrer le volume en vue Select Language Sélectionner la langue Select Icons Choisir le type d'icônes About À propos Quit Quitter LABEL="%1" Etiquette="%1" LABEL="%1" %2 Etiquette="%1" %2 zuluMount Failed To Connect To zuluPolkit. Please Report This Serious Bug. zuluMount a échoué à se connecter à zuluPolkit. Merci de reporter ce bug sérieux. Total Blocks %4 Total des Blocs %4 Used Space: %5 Espace Utilisé: %5 Free Space: %6 Espace Libre: %6 Total Space: %7 Espace Total: %7 Used %: %8 Utilisé %: %8 Properties Propriétés Mount Monter Unmount Démonter Unmount + Power Down Démonter + Éteindre Open Folder Ouvrir Répertoire Open Private Folder Ouvrir Répertoire Privé Open Shared Folder Ouvrir un répertoire partagé Close Menu Fermer le Menu Warning Attention Could not open mount point because "%1" tool does not appear to be working correctly Impossible d'ouvrir le point de montage parce que "%1" ne semble pas fonctionner correctement Select An Encrypted Volume Directory Sélectionner un répertoire de volume ERROR ERREUR Do Not Minimize To Tray Ne pas minimiser en barre des tâches Clear Dead Mount Points Effacer les points de montage obsolètes Show/Hide Afficher/Masquer Cryptsetup library could not be found and zuluCrypt will most likely not work as expected. La bibliothèque Cryptsetup n'a pas été trouvée et ZuluCrypt risque évidemment de ne pas fonctionner comme prévu. Please recompile zuluCrypt to force it to re-discover the new library Merci de recompiler zuluCrypt pour le forcer à redécouvrir la nouvelle bibliothèque Failed To Read Volume Properties Echec de la lecture des propriétés du volume INFORMATION INFORMATIONS Block Size: %1 Taille des blocs: %1 Used Blocks: %2 Blocs utilisés: %2 Free Blocks: %3 Blocs Libres: %3 Could not get volume properties. volume is not open or was opened by a different user Ne peut pas obtenir les propriétés du volume Le volume n'est pas ouvert ou a été ouvert par un autre utilisateur Volume Properties Propriétés du Volume Permission to access the volume was denied or the volume is not supported (LVM/MDRAID signatures found) La permission d'accéder au volume a été refusée ou le volume n'est pas supporté (LVM/MDRAID signatures found) Select An Image File To Mount Sélectionner un fichier image à Monter ERROR! ERREUR! Volume is not open or was opened by a different user Le volume n'est pas ouvert ou a été ouvert par un autre utilisateur One or more files in the volume are in use. Un ou plusieurs fichiers dans le volume sont en cours d'utilisation. Volume does not have an entry in /etc/mtab Le volume n'a pas d'entrée dans le /etc/mtab Could not get a lock on /etc/mtab~ Ne peut pas créer un lock sur /etc/mtab Volume is unmounted but could not close mapper,advice to close it manually Le volume est démonté mais le mappeur n'est pas fermé, il est conseillé de le fermer manuellement Could not resolve full path of device Ne trouve pas le chemin complet vers le périphérique Shared mount point appear to be busy Chemin de point de montage du partage semble occupé Shared mount point appear to belong to a different user or multiple mount points detected Chemin de point de montage du partage semble appartenir à un autre utilisateur ou bien points de montage multiples Shared mount point appear to be in an ambiguous state,advice to unmount manually Chemin de point de montage du partage semble être dans un état incohérent, il est conseillé de le démonter manuellement Multiple mount points for the volume detected Plusieurs points de montage détectés pour le volume Device does not appear to be mounted Le périphérique ne semble pas monté Only root user of members of group "zulumount" can unmount this volume Seul l'utilisateur root ou les membres du groupe zulucrypt peuvent demonter ce volume Shared mount point appear to be busy Chemin de point de montage du partage semble occupé Shared mount point appear to belong to a different user Chemin de point de montage du partage semble appartenir à un autre utilisateur Device does not exist Le périphérique ne semble pas exister Failed to unmount,the mount point and/or one or more files are in use Echec du démontage, le point de montage et/ou des fichiers sont en cours d'utilisation Failed to unmount,could not get a lock on /etc/mtab~ Echec du démontage, ne peut pas créer un lock sur /etc/mtab Failed to unmount the partition Echec du démontage de la partition Failed to unmount,multiple mount points for the volume detected Echec du démontage, des points de montage multiples ont été détectés Close failed, could not find any partition with the presented UUID Echec de la fermeture, ne trouve aucune partition avec l'UUID correspondante Failed to unmount volume Echec du démontage du volume ERROR: ERREUR: Reading partition properties took longer than expected and operation was terminated,click refresh to try again La lecture des propriétés de la partition prend plus de temps que prévu et l'opération a été terminée, cliquez sur actualiser/rafraîchir pour réessayer zuluCrypt-6.2.0/translations/zuluMount/messages.pot000066400000000000000000000155101425361753700226550ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-11-25 17:44-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: ../../zuluMount-cli/main.c:331 msgid "ERROR: unrecognized argument encountered" msgstr "" #: ../../zuluMount-cli/main.c:340 msgid "" "options:\n" "-m -- mount a volume : arguments: -d volume_path -z mount_point -e mode(rw/" "ro)\n" " -- additional arguments for crypto_LUKS,crypto_PLAIN,crypto_TCRYPT " "volumes, -p passphrase/-f keyfile\n" "-z -- mount point component to append to \"/run/media/private/$USER/\"\n" "-Y -- file system options\n" msgstr "" #: ../../zuluMount-cli/main.c:347 msgid "" "-u -- unmount a volume: arguments: -d volume_path\n" "-s -- print properties of a volume: arguments: -d partition_path\n" "-M -- this option will create a mount point in \"/run/media/private/$USER\" " "and a publicly accessible \"mirror\" in \"/run/media/public/'\n" msgstr "" #: ../../zuluMount-cli/main.c:352 msgid "" "-l -- print expanded list of all volumes\n" "-L -- must be used with -d,print properties of a volume specified by d " "option\n" "-P -- print a list of all volumes\n" "-D -- get a device node address from its mapper path( mapper paths are " "usually located in /dev/mapper ). Required argument: -d\n" msgstr "" #: ../../zuluMount-cli/main.c:358 msgid "" "-A -- print a list of all volumes\n" "-S -- print a list of system volumes\n" "-N -- print a list of non system volumes\n" "-E -- print a list of mounted volumes\n" msgstr "" #: ../../zuluMount-cli/main.c:364 msgid "" "examples:\n" "mount a volume : zuluMount-cli -m -d /dev/sdc1\n" "unmount a volume: zuluMount-cli -u -d /dev/sdc1\n" "mount and encrypted volume with a key \"xyz\" : zuluMount-cli -m -d /dev/" "sdc2 -p xyz\n" msgstr "" #: ../../zuluMount-cli/main.c:377 #, c-format msgid "unexpected exiting because you have run out of memory\n" msgstr "" #: ../../zuluMount-cli/main.c:387 msgid "" "ERROR: a non supported device encountered,device is missing or permission " "denied\n" "Possible reasons for getting the error are:\n" "1.Device path is invalid.\n" "2.The device has LVM or MDRAID signature\n" msgstr "" #: ../../zuluMount-cli/main.c:405 #, c-format msgid "ERROR: devices in /dev/shm path is not suppored\n" msgstr "" #: ../../zuluMount-cli/main.c:406 #, c-format msgid "ERROR: given path is a directory\n" msgstr "" #: ../../zuluMount-cli/main.c:407 #, c-format msgid "ERROR: a file can have only one hard link\n" msgstr "" #: ../../zuluMount-cli/main.c:408 #, c-format msgid "ERROR: insufficient privilges to access the device\n" msgstr "" #: ../../zuluMount-cli/main.c:533 msgid "ERROR: action not specified" msgstr "" #: ../../zuluMount-cli/main.c:557 msgid "ERROR: device argument missing" msgstr "" #: ../../zuluMount-cli/main.c:576 #, c-format msgid "could not resolve UUID\n" msgstr "" #: ../../zuluMount-cli/main.c:586 #, c-format msgid "could not resolve LABEL\n" msgstr "" #: ../../zuluMount-cli/mount.c:199 msgid "" "ERROR: insuffienct privilege to manage a system volume.\n" "necessary privileges can be acquired by:\n" "1. adding an entry for the volume in fstab with \"user\" mount option\n" "2. add yourself to \"zulumount\" group" msgstr "" #: ../../zuluMount-cli/mount.c:212 ../../zuluMount-cli/mount.c:234 msgid "" "ERROR: could not resolve path to device or device could not be opened in " "read write mode" msgstr "" #: ../../zuluMount-cli/mount.c:241 msgid "" "ERROR: insuffienct privileges to mount the volume with given mount options" msgstr "" #: ../../zuluMount-cli/mount.c:247 msgid "ERROR: device already mounted" msgstr "" #: ../../zuluMount-cli/mount.c:255 msgid "" "ERROR: \"/etc/fstab\" entry for this volume requires it to be mounted read " "only" msgstr "" #: ../../zuluMount-cli/mount.c:256 msgid "ERROR: \"/etc/fstab\" entry for this volume is malformed" msgstr "" #: ../../zuluMount-cli/mount.c:257 msgid "" "ERROR: \"/etc/fstab\" entry for this volume does not allow you to mount it" msgstr "" #: ../../zuluMount-cli/mount.c:266 msgid "ERROR: could not create mount point path,path already taken" msgstr "" #: ../../zuluMount-cli/mount.c:279 msgid "ERROR: shared mount point path aleady taken" msgstr "" #: ../../zuluMount-cli/mount.c:300 #, c-format msgid "" "SUCCESS: mount complete successfully\n" "volume mounted at: %s\n" msgstr "" #: ../../zuluMount-cli/mount.c:307 msgid "" "ERROR: failed to mount a filesystem:invalid/unsupported mount option or " "unsupported file system encountered" msgstr "" #: ../../zuluMount-cli/mount.c:308 msgid "" "ERROR: failed to mount ntfs file system using ntfs-3g,is ntfs-3g package " "installed?" msgstr "" #: ../../zuluMount-cli/mount.c:309 msgid "ERROR: mount failed,no or unrecognized file system" msgstr "" #: ../../zuluMount-cli/mount.c:310 msgid "ERROR: mount failed,could not get a lock on /etc/mtab~" msgstr "" #: ../../zuluMount-cli/mount.c:311 msgid "ERROR: failed to mount the partition" msgstr "" #: ../../zuluMount-cli/umount.c:35 #, c-format msgid "" "ERROR: you can not umount volumes out of \"%s\" since you are not root and " "do not belong to group \"zulumount\"\n" msgstr "" #: ../../zuluMount-cli/umount.c:51 ../../zuluMount-cli/umount.c:60 #: ../../zuluMount-cli/umount.c:69 msgid "ERROR: device does not appear to be mounted" msgstr "" #: ../../zuluMount-cli/umount.c:98 msgid "ERROR: shared mount point appear to be busy" msgstr "" #: ../../zuluMount-cli/umount.c:99 msgid "ERROR: shared mount point appear to belong to a different user" msgstr "" #: ../../zuluMount-cli/umount.c:100 msgid "" "ERROR: shared mount point appear to be in an ambiguous state,advice to " "unmount manually" msgstr "" #: ../../zuluMount-cli/umount.c:124 msgid "SUCCESS: umount complete successfully" msgstr "" #: ../../zuluMount-cli/umount.c:127 msgid "ERROR: device does not exist" msgstr "" #: ../../zuluMount-cli/umount.c:128 msgid "" "ERROR: failed to unmount,the mount point and/or one or more files are in use" msgstr "" #: ../../zuluMount-cli/umount.c:129 msgid "ERROR: failed to unmount,could not get a lock on /etc/mtab~" msgstr "" #: ../../zuluMount-cli/umount.c:130 msgid "ERROR: failed to unmount the partition" msgstr "" #: ../../zuluMount-cli/volume_status.c:645 #, c-format msgid "" "ERROR: could not get volume properties,volume is not open or was opened by a " "different user\n" msgstr "" #: ../../zuluMount-cli/volume_status.c:664 #, c-format msgid "" "ERROR: could not get volume properties,volume is not open or was opened by a " "different user" msgstr "" zuluCrypt-6.2.0/udev_support_README000066400000000000000000000025171425361753700172610ustar00rootroot00000000000000 udev is a runtime dependency but it is configured at build time to remove a necessity to manage yet another configuration option. udev support is off by default because udev has a bad habit of identifying some clearly external volumes as internal[1]. [1]https://wiki.archlinux.org/index.php/udev#Mark_internal_SATA_ports_as_eSATA If udev support is off,volumes with entries only in /etc/fstab and /etc/crypttab will be considered as system volumes.Section 6 of the FAQ has more information on additional ways to make volumes be considered as system. if udev support is on,udev will be consulted before a decision is being when if a volume is to be considered system or not.Section 7 of the FAQ has more information on how to remove a volume of a list of system volumes. I recommend disabling udev support if you are building zuluCrypt for your own use and you have all your internal volumes mentioned either in fstab or crypttab. I recommend enabling udev support if you are packaging for distribution or if you dont use /etc/fstab or /etc/crypttab as a central place to manage system volumes. To build with udev support add "-DUDEVSUPPORT=true" to cmake option list. Example build steps to build with udev support cd $SRC mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/usr/ -DUDEVSUPPORT=true -DCMAKE_BUILD_TYPE=RELEASE . .. make make install zuluCrypt-6.2.0/version000066400000000000000000000000061425361753700151610ustar00rootroot000000000000005.4.0 zuluCrypt-6.2.0/zuluCrypt-cli.1000066400000000000000000000171061425361753700164320ustar00rootroot00000000000000 .TH zuluCrypt-cli 1 .br .SH NAME zuluCrypt-cli - command line interface frontend to cryptsetup and tcplay .SH SYNOPSIS meaning of symbols: .br <> = required option .br [] = optional argument .br * = default option .br | = alternatives for the same option .br {} = not allowed option .br zuluCrypt-cli --test .br zuluCrypt-cli -o [e] .br zuluCrypt-cli -O {m} [e] .br zuluCrypt-cli -q .br zuluCrypt-cli -i .br zuluCrypt-cli -c [ktzg] .br zuluCrypt-cli -r <-d> .br zuluCrypt-cli -a < >| .br zuluCrypt-cli -b .br zuluCrypt-cli -w d argument must be something like: UUID=\"2468d6a7-9a71-4312-8bd9-662f982fade5\" ( or without quotes ) .br zuluCrypt-cli -P d device must be mapper path at /dev/mapper/ .br zuluCrypt-cli -X .br zuluCrypt-cli -J .br zuluCrypt-cli -R .br zuluCrypt-cli -B .br zuluCrypt-cli -A .br zuluCrypt-cli -S .br zuluCrypt-cli -N .br .br examples: .br create volume: zuluCrypt-cli -c -d /dev/sdc1 -z ext4 -t luks -p xxx .br open volume : zuluCrypt-cli -o -d /dev/sdc1 -m sdc1 -e ro -p xxx .br open volume through sudo/pkexec : zuluCrypt-cli -o -d /dev/sdc1 -m sdc1 -e ro -p xxx -K $USER_ID .br close volume ; zuluCrypt-cli -q -d /dev/sdc1 .br remove key ; zuluCrypt-cli -r -d /dev/sdc1 -p xxx .br add key : zuluCrypt-cli -a -d /dev/sdc1 -y xxx -l yyy .br get device path from mapper : zuluCrypt-cli -P -d /dev/mapper/zuluCrypt-sdc1 .br check if partition with UUID is present : zuluCrypt-cli -w -d UUID=\"d2d210b8-0b1f-419f-9172-9d509ea9af0c\" .br .SH DESCRIPTION zuluCrypt is a front end to cryptsetup. It aims to simplify using cryptsetup volumes by creating a simple to use command line interface and a Qt based GUI front end to the command line. The command line program is called "zuluCrypt-cli", the Qt based GUI is called "zuluCrypt-gui". The cli part of the program is an suid program to allow management of the volumes without setting up sudo with appropriate permissions first or requiring root's password. The GUI part of the program calls the cli part for its operations. This tool will create volumes only in non system partitions. System partition is a partition with an active entry in /etc/fstab and /etc/crypttab .br .SH USAGE usage: zuluCrypt-cli .br operation list: .br -c create an encrypted volume .br -o open and encrypted volume .br -O open an encrypted volume but do not mount it( -m therefore not needed ) .br -K if zuluCrypt-cli or zuluMount-cli is invoked with sudo/pkexec to unlock a volume, use this option to tell zuluCrypt to work on behalf of what user. If this option is not set them the unlocked volume will incorrectly belong to root user instead of the user who run zuluCrypt-cli/zuluMount-cli. .br -q close an opened encrypted volume .br -r remove a key from luks volume .br -a add a key to luks volume .br -i check if a device contain a luks volume .br -s check if a device is opened and print its properties if it is .br -b show status of each slot of luks volume."0"=empty,"1"=occupied,"2"=invalid slot,"3"=last occupied .br -A print the list of all partitions on the system .br -N print a list of non system partitions on the system( partitions with no active entries in /etc/fstab and /etc/crypttab .br -T print a detailed list of mounted partitions.Must be used with -A or -S or -N .br -Z print a detailed list of unmounted partitions.Must be used with -A or -S or -N .br -S print a list of system partitions on the system( partitions with active entries in /etc/fstab and /etc/crypttab .br -w check if UUID matches UUID of any partition .br -P get device path from mapper( located at /dev/mapper ) .br -L print a list of all opened volumes and their mount point.The list is not formatted .br -X open a device pointed by argument -d and write random data to it hiding data previously written to device .br -W check if a device is a truecrypt device or not,required argument are -p or -f .br -U print UUID of a given device,required argument: -d .br -H compare a header on a luks device to a backup header,required arg: -d and -f .br -M create a publicly accessible "mirror" of the mount point in "/run/media/public/" from the original created in "/run/media/private/$USER/" .br -J create a plain mapper owned by the user who run the command on a device pointed by argument -d .br -B create a luks or truecrypt header backup .br -R restore a luks or truecrypt header on a device from backup .br .br .B NOTE .br A system partition is defined as a partition with an active entry in /etc/fstab and/or /etc/crypttab. .br An active entry is an entry that is not commented out. .br .br options that goes with above operations: .br -G module name to use to get a passphrase to open a volume .br -e mode for opening volumes(ro*/rw) when used with -o/-O. .br -e mode for managing a truecrypt header when used with -B/-R.Options can be "fde" for volumes that use whole disk .br encryption,"sys" for a windows system volume.The volume is assumed to be a normal one when the option is not set. .br -k do not ask for confirmation when doing dangerous operations .br -d path to a file or partition with encrypted volume .br -m path component to be added to mount point prefix(/run/media/private/$USER or /home/$USER) .br -z file system type installed(ext2,ext3,ext4* etc) or or luks/tcrypt header backup path .br -t type of volume (vera,plain/luks*). "vera" is a necessary argument when opening a VeraCrypt volume .br -g options to be used when creating a volume. .br default for luks are: "/dev/urandom.aes.xts-plain64.256.sha1" .br default for tcrypt are: "/dev/urandom.aes.xts-plain64.256.ripemd160" possible combination for tcrypt: "/dev/urandom.serpent:twofish:aes.xts-plain64.256.whirlpool" .br -h get passphrase interactively .br -p passphrase .br -f path to keyfile .br -F path to normal truecrypt multiple keyfiles.Multiple keyfiles are added by setting the option multiple times. .br -V path to hidden truecrypt multiple keyfiles.Multiple keyfiles are added by setting the option multiple times. .br -y passphrase already in the volume(required by -a if -u is absent and -h is also absent) .br -u path to keyfile with passphrase already in the volume(required by -a if -y is absent and -h is also absent) .br -l passphrase to be added(required by -a if -n is absent and -h is also absent) .br -n path to keyfile with a passphrase to be added (required by -a if -l is absent and -h is also absent) .br .SH COPYRIGHT Copyright (c) 2011-2020 .br name : Francis Banyikwa .br email: mhogomchungu@gmail.com .br .br 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, see . .br .SH LAST EDIT Last change: Tue 09 Jun 2020 01:21:51 PM EAT zuluCrypt-6.2.0/zuluCrypt-cli/000077500000000000000000000000001425361753700163435ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluCrypt-cli/CMakeLists.txt000066400000000000000000000236751425361753700211200ustar00rootroot00000000000000 cmake_minimum_required(VERSION 3.0.2) file(WRITE ${PROJECT_BINARY_DIR}/bin_path.h "\n#define ZULUCRYPTzuluCrypt \"${CMAKE_INSTALL_FULL_BINDIR}/zuluCrypt-cli\"\n") file(APPEND ${PROJECT_BINARY_DIR}/bin_path.h "\n#define zuluPolkitPath \"${CMAKE_INSTALL_FULL_BINDIR}/zuluPolkit\"\n") file(APPEND ${PROJECT_BINARY_DIR}/bin_path.h "\n#define zuluMountPath \"${CMAKE_INSTALL_FULL_BINDIR}/zuluMount-cli\"\n") file(APPEND ${PROJECT_BINARY_DIR}/bin_path.h "\n#define ZULUCRYPTplugInPath \"${PLUGINPATH}/zuluCrypt-testKey\"\n") add_definitions( -I${PROJECT_BINARY_DIR} ) SET( BIN bin/close_volume.c bin/add_key.c bin/volume_info.c bin/open_volume.c bin/volumes.c bin/security.c bin/check_invalid_key.c bin/create_volumes.c bin/remove_key.c bin/write_device_with_junk.c bin/save_and_restore_volume_header.c bin/crypt_file.c bin/check_opened_mapper.c bin/get_opts.c bin/help.c bin/mount_flags.c bin/file_encryption.c bin/clear_dead_mappers.c bin/bind.c bin/create_mount_point.c bin/path_access.c bin/test.c ../zuluMount-cli/volume_status.c ) SET( BINMount ../zuluMount-cli/volume_status.c ../zuluMount-cli/main.c ../zuluMount-cli/mount.c ../zuluMount-cli/umount.c ../zuluMount-cli/crypto_mount.c ../zuluMount-cli/crypto_umount.c ) SET( LIB lib/bitlocker.c lib/mountinfo.c lib/create_mapper_name.c lib/is_path_valid.c lib/version.c lib/close_volume.c lib/add_key.c lib/remove_key.c lib/empty_slots.c lib/status.c lib/create_luks.c lib/is_luks.c lib/create_volume.c lib/close_mapper.c lib/open_luks.c lib/open_plain.c lib/open_volume.c lib/mount_volume.c lib/unmount_volume.c lib/user_home_path.c lib/create_loop_device.c lib/blkid_evaluate_tag.c lib/open_tcrypt.c lib/volume_type.c lib/mount_fs_options.c lib/real_path.c lib/file_path_security.c lib/create_tcrypt.c lib/parse_fstab.c lib/resolve_paths.c ) add_library( Socket STATIC utility/socket/socket.c ) #add_library( String STATIC string/String.c string/StringManage.c ) add_library( String STATIC utility/string/String.c ) add_library( StringList STATIC utility/string/StringList.c ) add_library( Process STATIC utility/process/process.c ) TARGET_LINK_LIBRARIES( Process -pthread ) add_library( zuluCrypt-exe SHARED ${BIN} ) #add_library( zuluCrypt-exe-static STATIC ${BIN} ) add_library( zuluCrypt SHARED ${LIB} ) #add_library( zuluCrypt-static STATIC ${LIB} ) add_library( zuluCryptPluginManager SHARED pluginManager/zuluCryptPluginManager.c ) #add_library( zuluCryptPluginManager-static STATIC pluginManager/zuluCryptPluginManager.c ) TARGET_LINK_LIBRARIES( zuluCryptPluginManager Socket Process String ) #TARGET_LINK_LIBRARIES( zuluCryptPluginManager-static Socket Process String ) set_target_properties( zuluCryptPluginManager PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) #set_target_properties( zuluCryptPluginManager-static PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIC -pthread -pedantic " ) set_target_properties( zuluCryptPluginManager PROPERTIES SOVERSION ${LIB_PLUGIN_VERSION} ) set_target_properties( Socket PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) set_target_properties( String PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) set_target_properties( StringList PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) set_target_properties( Process PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) set_target_properties( zuluCrypt-exe PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) set_target_properties( zuluCrypt PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) #set_target_properties( zuluCrypt-exe-static PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) #set_target_properties( zuluCrypt-static PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pthread -pedantic " ) set_target_properties( zuluCrypt PROPERTIES SOVERSION ${LIB_VERSION} ) set_target_properties( zuluCrypt-exe PROPERTIES SOVERSION ${LIB_VERSION} ) if( STATIC_ZULUPLAY ) TARGET_LINK_LIBRARIES( zuluCrypt String StringList Process tcplay-static ${cryptsetup_lib} ${blkid} ${uuid_lib} ${devmapper_lib} -lgcrypt ) else() TARGET_LINK_LIBRARIES( zuluCrypt String StringList Process ${cryptsetup_lib} ${blkid} ${uuid_lib} ${devmapper_lib} -lgcrypt -lzuluplay ) endif() set_target_properties( zuluCrypt PROPERTIES LINK_FLAGS "-pie -Wl,-z,relro -Wl,-z,now" ) TARGET_LINK_LIBRARIES( zuluCrypt-exe zuluCrypt zuluCryptPluginManager ) set_target_properties( zuluCrypt-exe PROPERTIES LINK_FLAGS "-pie -Wl,-z,relro -Wl,-z,now" ) #TARGET_LINK_LIBRARIES( zuluCrypt-static String StringList Process ) #TARGET_LINK_LIBRARIES( zuluCrypt-exe-static zuluCrypt-static zuluCryptPluginManager-static ) TARGET_LINK_LIBRARIES( zuluCrypt-exe zuluCrypt ) add_executable( zuluMount-cli ../zuluMount-cli ${BINMount} ) set_target_properties( zuluMount-cli PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIE -pthread -pedantic " ) set_target_properties( zuluMount-cli PROPERTIES LINK_FLAGS "-pie -Wl,-z,relro -Wl,-z,now" ) TARGET_LINK_LIBRARIES( zuluMount-cli zuluCrypt-exe zuluCrypt ) add_executable( zuluCrypt-cli bin/main.c ) set_target_properties( zuluCrypt-cli PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIE -pthread -pedantic " ) set_target_properties( zuluCrypt-cli PROPERTIES LINK_FLAGS "-pie -Wl,-z,relro -Wl,-z,now" ) TARGET_LINK_LIBRARIES( zuluCrypt-cli zuluCrypt-exe zuluCrypt ) set_target_properties( zuluCrypt-cli PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( zuluMount-cli PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) #zuluCryptKeyServer not used #add_executable( zuluCryptKeyServer ../plugins/network_key/server.c ) #set_target_properties( zuluCryptKeyServer PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic " ) #TARGET_LINK_LIBRARIES( zuluCryptKeyServer lxqtwallet crypt_buffer ) if( NOT NOSECRETSUPPORT ) pkg_check_modules( LIBSECRET libsecret-1 ) if( LIBSECRET_FOUND ) add_definitions( ${LIBSECRET_CFLAGS} ) add_executable( keyring ../plugins/keyring/keyring.c ) set_target_properties( keyring PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIE -pthread -pedantic" ) set_target_properties( keyring PROPERTIES LINK_FLAGS "-pie" ) TARGET_LINK_LIBRARIES( keyring zuluCryptPluginManager ${keyring_library} ${blkid} ${LIBSECRET_LIBRARIES} ) set_target_properties( keyring PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) install( TARGETS keyring RUNTIME DESTINATION "${PLUGINPATH}" ) endif() endif() if( USE_POLKIT ) install(TARGETS zuluCrypt-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) install(TARGETS zuluMount-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) else() install(TARGETS zuluCrypt-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE SETUID ) install(TARGETS zuluMount-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE SETUID ) endif() add_executable( zuluCrypt-testKey ../plugins/test/zuluCrypt-testKey.c ) set_target_properties( zuluCrypt-testKey PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIE -pthread -pedantic " ) set_target_properties( zuluCrypt-testKey PROPERTIES LINK_FLAGS "-pie" ) TARGET_LINK_LIBRARIES( zuluCrypt-testKey zuluCryptPluginManager ${blkid} ) set_target_properties( zuluCrypt-testKey PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) #set_target_properties( zuluCrypt-test PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) file( WRITE ${PROJECT_BINARY_DIR}/libzuluCrypt.pc "prefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${CMAKE_INSTALL_PREFIX} libdir=${CMAKE_INSTALL_FULL_LIBDIR} includedir=${CMAKE_INSTALL_FULL_INCLUDEDIR} Name: libzuluCrypt Description: a zuluCrypt library,a front end to cryptsetup Version: ${LIB_VERSION} Libs: -L${CMAKE_INSTALL_FULL_LIBDIR} -lcryptsetup -lzuluCrypt -lzuluCrypt-exe -lzuluCryptPluginManager -lblkid -lmount ${TCPLAY_LIB} -L${TCPLAY_LIBDIR} -L${BLKID_LIBDIR} -L${CRYPTSETUP_LIBDIR} Cflags: -I${CMAKE_INSTALL_FULL_INCLUDEDIR} \n") #install(TARGETS zuluCrypt-test RUNTIME DESTINATION bin #PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE #) install( TARGETS zuluCrypt-testKey RUNTIME DESTINATION "${PLUGINPATH}" ) install(TARGETS zuluCryptPluginManager LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) #install(TARGETS zuluCryptPluginManager-static ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install(TARGETS zuluCrypt LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install(TARGETS zuluCrypt-exe LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) #install(TARGETS zuluCrypt-exe-static ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) #install(TARGETS zuluCrypt-static ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install(FILES lib/libzuluCrypt.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/zuluCrypt ) install(FILES bin/libzuluCrypt-exe.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/zuluCrypt ) install(FILES pluginManager/libzuluCryptPluginManager.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/zuluCrypt ) install(FILES ${PROJECT_BINARY_DIR}/libzuluCrypt.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig/ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) zuluCrypt-6.2.0/zuluCrypt-cli/bin/000077500000000000000000000000001425361753700171135ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluCrypt-cli/bin/add_key.c000066400000000000000000000303741425361753700206660ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include #include typedef struct{ const char * device ; const char * existing_key ; size_t existing_key_size ; size_t existing_key_is_keyfile ; const char * new_key ; size_t new_key_size ; size_t new_key_is_keyfile ; const char * type ; }tcrypt_opts ; /* * Its not possible to add more keys to a volume with no empty slots or to a non luks volume * * This function checks if a volume is luks and if it has atleast one empty slot. */ static int _zuluCryptCheckEmptySlots( const char * device ) { int r = 0 ; char * c ; char * d ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptVolumeIsLuks() is defined in ../lib/is_luks.c */ if( zuluCryptVolumeIsLuks( device ) ){ /* * zuluCryptEmptySlots() is defined in ../lib/empty_slots.c */ c = zuluCryptEmptySlots( device ) ; if( c == NULL ){ /* * we shouldnt get here */ r = 1 ; }else{ d = c - 1 ; while( *++d ){ if( *d == '0' ){ r = 2 ; break ; } } StringFree( c ) ; } }else{ /* * volume is not a LUKS volume,assuming its a TrueCrypt volume */ r = 2 ; } zuluCryptSecurityDropElevatedPrivileges() ; return r ; } static int _replace_truecrypt_key( const tcrypt_opts * opts ) { info_t info ; string_t st = StringVoid ; string_t xt = StringVoid ; int r ; stringList_t stl ; memset( &info,'\0',sizeof( info_t ) ) ; stl = veraCryptVolumePIMValue( &info,opts->type ) ; info.device = opts->device ; /* * zuluCryptCreateKeyFile() is defined in ../lib/open_tcrypt.c */ if( opts->existing_key_is_keyfile ){ info.header_key_source = "keyfiles" ; st = zuluCryptCreateKeyFile( opts->existing_key,opts->existing_key_size,"add-tcrypt-1" ) ; info.header_key = StringContent( st ) ; }else{ info.header_key_source = "passphrase" ; info.header_key = opts->existing_key ; } if( opts->new_key_is_keyfile ){ info.header_new_key_source = "new_keyfiles" ; st = zuluCryptCreateKeyFile( opts->new_key,opts->new_key_size,"add-tcrypt-2" ) ; info.header_new_key = StringContent( st ) ; }else{ info.header_new_key_source = "new_passphrase" ; info.header_new_key = opts->new_key ; } info.rng = "/dev/urandom" ; /* * zuluCryptModifyTcryptHeader() is defined in ../lib/create_tcrypt.c */ r = zuluCryptModifyTcryptHeader( &info ) ; /* * zuluCryptDeleteFile_1() is defined in ../lib/file_path_security.c */ if( st != StringVoid ){ zuluCryptDeleteFile_1( st ) ; StringDelete( &st ) ; } if( xt != StringVoid ){ zuluCryptDeleteFile_1( xt ) ; StringDelete( &xt ) ; } StringListDelete( &stl ) ; if( r == 0 ){ return 0 ; }else{ return 1 ; } } static int zuluExit( int st,stringList_t stl ) { zuluCryptSecurityUnlockMemory( stl ) ; /* * this function is defined in ../string/StringList.c */ StringListClearDelete( &stl ) ; switch( st ){ case 0 : printf( gettext( "SUCCESS: key added successfully\n" ) ) ; break ; case 1 : printf( gettext( "ERROR: Presented key does not match any key in the volume\n" ) ) ; break ; case 2 : printf( gettext( "ERROR: Could not open luks volume\n" ) ) ; break ; case 3 : printf( gettext( "ERROR: Volume is not a luks volume\n" ) ); break ; case 4 : printf( gettext( "ERROR: Insufficient privilege to open a system device,\n\ only root user or members of group \"zulucrypt\" can do that\n" ) ) ; break ; case 5 : printf( gettext( "ERROR: Could not open volume in write mode\n" ) ) ; break ; case 6 : printf( gettext( "ERROR: All key slots are occupied, can not add any more keys\n" ) ) ; break ; case 7 : printf( gettext( "ERROR: Can not get passphrase in silent mode\n" ) ) ; break ; case 8 : printf( gettext( "ERROR: Insufficient memory to hold passphrase\n" ) ) ; break ; case 9 : printf( gettext( "ERROR: New passphrases do not match\n" ) ) ; break ; case 10 : printf( gettext( "ERROR: One or more required argument(s) for this operation is missing\n" ));break ; case 11 : printf( gettext( "ERROR: One or both keyfile(s) does not exist\n" ) ) ; break ; case 12 : printf( gettext( "ERROR: Insufficient privilege to open key file for reading\n" ) ) ; break ; case 13 : printf( gettext( "ERROR: Couldnt get enought memory to hold the key file\n" ) ) ; break ; case 14 : printf( gettext( "ERROR: Could not get a key from a socket\n" ) ) ; break ; case 15 : printf( gettext( "ERROR: Could not get elevated privilege,check binary permissions\n" ) ) ; break ; case 16 : printf( gettext( "ERROR: Key slot already occupied\n" ) ) ; break ; case 17 : printf( gettext( "ERROR: Failed to find empty key slot or key slot out of range\n" ) ) ; break ; default : printf( gettext( "ERROR: Unrecognized error with status number %d encountered\n" ),st ) ; } return st ; } static int zuluGetKeys( string_t * key1,string_t * key2,string_t * key3 ) { int st ; /* * ZULUCRYPT_KEY_MAX_SIZE is set in ../constants.h */ printf( gettext( "Enter an existing passphrase: " ) ) ; st = StringSilentlyGetFromTerminal_1( key1,ZULUCRYPT_KEY_MAX_SIZE ) ; if( st != 0 ){ return st ; } printf( gettext( "\nEnter the new passphrase: " ) ) ; st = StringSilentlyGetFromTerminal_1( key2,ZULUCRYPT_KEY_MAX_SIZE ) ; if( st != 0 ){ StringClearDelete( key1 ) ; return st ; } printf( gettext( "\nRe enter the new passphrase: " ) ) ; st = StringSilentlyGetFromTerminal_1( key3,ZULUCRYPT_KEY_MAX_SIZE ) ; if( st != 0 ){ StringClearDelete( key1 ) ; StringClearDelete( key2 ) ; return st ; } printf( "\n" ) ; return 0 ; } /* * get_pass_from_file function is defined at get_pass_from_file.c * */ int zuluCryptEXEAddKey( const struct_opts * opts,uid_t uid ) { const char * device = opts->device ; const char * keyType1 = opts->existing_key_source ; const char * existingKey = opts->existing_key ; const char * keyType2 = opts->new_key_source ; const char * newKey = opts->new_key ; const char * luksOptions = opts->rng ; int slot_number ; char * m ; /* * Below is a form of memory management.All strings are collected in a stringlist object to easily delete them * when the function returns.This allows for the function to have multiple exit points without risks of leaking * memory from manually examining each exit point to make sure all strings are deleted or go with multiple goto * code deleting blocks to take into account different exit points. */ stringList_t stl ; string_t * stringArray = StringListArray( &stl,6 ) ; string_t * presentKey = &stringArray[ 0 ] ; string_t * newKey_1 = &stringArray[ 1 ] ; string_t * newKey_2 = &stringArray[ 2 ] ; string_t * ek = &stringArray[ 3 ] ; string_t * nk = &stringArray[ 4 ] ; string_t * slots = &stringArray[ 5 ] ; const char * key1 = NULL ; const char * key2 = NULL ; size_t len1 = 0 ; size_t len2 = 0 ; size_t len3 ; ssize_t slot ; int status = 0 ; int socket_path ; tcrypt_opts tcrypt ; memset( &tcrypt,'\0',sizeof( tcrypt_opts ) ) ; /* * zuluCryptPartitionIsSystemPartition() is defined in ./partitions.c */ if( zuluCryptPartitionIsSystemPartition( device,uid ) ){ if( zuluCryptExeOriginalUserIsNotRoot() ){ if( !zuluCryptUserIsAMemberOfAGroup( uid,"zulucrypt" ) ){ return zuluExit( 4,stl ) ; } } } /* * zuluCryptSecurityDeviceIsWritable() is defined in path_access.c */ status = zuluCryptCanOpenPathForWriting( device,uid ) ; /* * 1-permissions denied * 2-invalid path * 3-shenanigans * 4-common error */ switch( status ){ case 0 : break ; case 1 : return zuluExit( 5,stl ) ; case 2 : return zuluExit( 5,stl ) ; case 3 : return zuluExit( 5,stl ) ; case 4 : return zuluExit( 5,stl ) ; default: return zuluExit( 5,stl ) ; } switch( _zuluCryptCheckEmptySlots( device ) ){ case 0 : return zuluExit( 6,stl ) ; case 1 : return zuluExit( 2,stl ) ; case 2 : /* no complains,continue */ ; } if( keyType1 == NULL && keyType2 == NULL ){ switch( zuluGetKeys( presentKey,newKey_1,newKey_2 ) ){ case 1 : return zuluExit( 7,stl ) ; case 2 : return zuluExit( 8,stl ) ; } if( StringsAreEqual_1( *newKey_1,*newKey_2 ) ){ key1 = StringContent( *presentKey ) ; len1 = StringLength ( *presentKey ) ; key2 = StringContent( *newKey_1 ) ; len2 = StringLength ( *newKey_1 ) ; }else{ return zuluExit( 9,stl ) ; } }else{ if( newKey == NULL || existingKey == NULL ){ return zuluExit( 10,stl ) ; } if( StringsAreEqual( keyType1,"-f" ) ){ /* * this function is defined at "path_access.c" */ switch( zuluCryptGetPassFromFile( &socket_path,existingKey,uid,ek ) ){ case 1 : return zuluExit( 11,stl ) ; case 4 : return zuluExit( 12,stl ) ; case 2 : return zuluExit( 13,stl ) ; case 5 : return zuluExit( 14,stl ) ; } key1 = StringContent( *ek ) ; len1 = StringLength( *ek ) ; if( !socket_path ){ tcrypt.existing_key_is_keyfile = 1 ; } } if( StringsAreEqual( keyType2,"-f" ) ){ /* * this function is defined at "path_access.c" */ switch( zuluCryptGetPassFromFile( &socket_path,newKey,uid,nk ) ){ case 1 : return zuluExit( 11,stl ) ; case 4 : return zuluExit( 12,stl ) ; case 2 : return zuluExit( 13,stl ) ; case 5 : return zuluExit( 14,stl ) ; } key2 = StringContent( *nk ) ; len2 = StringLength( *nk ) ; if( !socket_path ){ tcrypt.new_key_is_keyfile = 1 ; } } if( StringsAreEqual( keyType1,"-f" ) && StringsAreEqual( keyType2,"-f" ) ){ }else if( StringsAreEqual( keyType1,"-p" ) && StringsAreEqual( keyType2,"-p" ) ){ key1 = existingKey ; len1 = StringSize( existingKey ) ; key2 = newKey ; len2 = StringSize( newKey ) ; }else if( StringsAreEqual( keyType1,"-p" ) && StringsAreEqual( keyType2,"-f" ) ){ key1 = existingKey ; len1 = StringSize( existingKey ) ; }else if( StringsAreEqual( keyType1,"-f" ) && StringsAreEqual( keyType2,"-p" ) ){ key2 = newKey ; len2 = StringSize( newKey ) ; }else{ return zuluExit( 10,stl ) ; } } zuluCryptSecurityLockMemory( stl ) ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptVolumeIsLuks() is defined in ../lib/is_luks.c */ if( zuluCryptVolumeIsLuks( device ) ){ m = zuluCryptEmptySlots( device ) ; *slots = StringInherit( &m ) ; len3 = StringLength( *slots ) ; if( StringsAreEqual( luksOptions,"/dev/urandom" ) ){ luksOptions = "-1.-1.argon2id.-1.-1.-1" ; } if( StringEndsWith_1( luksOptions,"-1" ) ){ status = zuluCryptAddKey_0( device,key1,len1,key2,len2,luksOptions ) ; }else{ slot = StringLastIndexOfChar_1( luksOptions,'.' ) + 1 ; slot_number = (int)StringConvertToInt( luksOptions + slot ) ; if( len3 > 0 && ( size_t )slot_number < len3 ){ if( StringContent( *slots )[ slot_number ] == '0' ){ /* * zuluCryptAddKey() is defined in ../lib/add_key.c */ status = zuluCryptAddKey_0( device,key1,len1,key2,len2,luksOptions ) ; }else{ return zuluExit( 16,stl ) ; } }else{ return zuluExit( 17,stl ) ; } } }else{ tcrypt.device = device ; tcrypt.existing_key = key1 ; tcrypt.existing_key_size = len1 ; tcrypt.new_key = key2 ; tcrypt.new_key_size = len2 ; tcrypt.type = opts->type ; status = _replace_truecrypt_key( &tcrypt ) ; } zuluCryptSecurityDropElevatedPrivileges() ; return zuluExit( status,stl ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/bash_special_chars.h000066400000000000000000000020451425361753700230620ustar00rootroot00000000000000 /* * * Copyright (c) 2012 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ /* * cryptsetup 1.4.1 and previous have a bug and its triggered when the mapper has one or more bash * special characters, this functions substitute bash special characters for an underscore to * work around the bug. */ #define BASH_SPECIAL_CHARS "#;\"',\\`:!*?&$@(){}[]><|%~^ \n" zuluCrypt-6.2.0/zuluCrypt-cli/bin/bind.c000066400000000000000000000162471425361753700202050ustar00rootroot00000000000000/* * * Copyright (c) 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include "../lib/includes.h" /* * default value of "SHARE_MOUNT_PREFIX" is "/run/media/public" */ #include "share_mount_prefix_path.h" #include #include static void _chmod( const char * x,mode_t y ) { if( chmod( x,y ) ){} } static int _zuluCryptBindUnmountVolume( stringList_t stx,const char * device,uid_t uid ) { stringList_t stl ; string_t xt ; string_t st ; string_t zt ; ssize_t index = -1 ; const char * f ; const char * g ; char * h = NULL ; int r = 1 ; int k ; /* * zuluCryptUserIsAMemberOfAGroup() is defined in security.c */ /* * root user is a member of all groups and hence is allowed */ int allowedUser = zuluCryptUserIsAMemberOfAGroup( uid,"zulumount" ) ; zuluCryptSecurityGainElevatedPrivileges() ; if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_2() is defined in ../lib/create_loop_device.c */ st = zuluCryptLoopDeviceAddress_2( device ) ; /* * Add a space at the end of the device name to make sure we check the full device name to avoid possible collisions * that may exist if one device is named "/home/abc" and another "/home/abcdef" */ zt = StringListHasStartSequence_1( stx,StringAppend( st," " ) ) ; StringRemoveRight( st,1 ) ; device = h = StringDeleteHandle( &st ) ; }else{ /* * Add a space at the end of the device name to make sure we check the full device name to avoid possible collisions * that may exist if one device is named "/dev/sdc1" and another "/dev/sdc12" */ st = String( device ) ; zt = StringListHasStartSequence_1( stx,StringAppend( st," " ) ) ; StringDelete( &st ) ; } if( zt == StringVoid ){ /* * The volume does not appear to be mounted */ r = 1 ; }else{ stl = StringListStringSplit( zt,' ' ) ; xt = StringListCopyStringAtSecondPlace( stl ) ; StringListDelete( &stl ) ; st = StringCopy( xt ) ; /* * zuluCryptDecodeMountEntry() is defined in ../lib/mount_volume.c * g will contain something like "/run/media/private/$USER/sdc1" */ g = zuluCryptDecodeMountEntry( st ) ; if( allowedUser ){ /* * a privileged user is attempting to unmount a shared mount point,allow them */ k = 1 ; }else{ /* * a non privileged user is attempting to unmount a shared mount point,allow them only if * they are the one that created it */ /* * zuluCryptMountPointPrefixMatch() is defined in create_mount_point.c */ k = zuluCryptMountPointPrefixMatch( g,uid,NULL ) ; } StringDelete( &st ) ; if( k != 1 ){ /* * One none privileged user is attempting to unmount a bind mount from another use,disallow it */ r = 4 ; }else{ index = StringLastIndexOfChar( xt,'/' ) + 1 ; StringRemoveLeft( xt,(size_t)index ) ; StringPrepend( xt,SHARE_MOUNT_PREFIX "/" ) ; /* * f will now contain something like "/run/media/public/sdc1" * space character is added before checking to avoid possible collisions * as explained in above comments */ f = StringAppend( xt," " ) ; zt = StringListHasSequence_1( stx,f ) ; f = StringRemoveRight( xt,1 ) ; if( zt == StringVoid ){ /* * volume is not shared */ }else{ /* * volume is shared,try to unmount it * a volume is assumed to be shared if its device path in mountinfo has two mount points,one * in /run/media/private/$USER and the other in /run/media/public/ */ if( StringStartsWith( zt,device ) ){ f = zuluCryptDecodeMountEntry( xt ) ; /* * good,the device associated with the shared mount is the same as that of the * private mount,try to unmount it. */ r = 3 ; for( k = 0 ; k < 3 ; k++ ){ /* * try to unmount 3 times before giving up */ if( umount( f ) == 0 ){ rmdir( f ) ; r = 0 ; break ; }else{ sleep( 1 ) ; } } }else{ /* * i dont see how we will get here,we shouldnt */ r = 0 ; } } } StringDelete( &xt ) ; } StringFree( h ) ; zuluCryptSecurityDropElevatedPrivileges() ; return r ; } int zuluCryptBindUnmountVolume( stringList_t stx,const char * device,uid_t uid ) { stringList_t stl ; int r ; if( stx == StringListVoid ){ /* * zuluCryptGetMoutedList() is defined in ../lib/mountinfo.c */ stl = zuluCryptGetMoutedList() ; r = _zuluCryptBindUnmountVolume( stl,device,uid ) ; StringListDelete( &stl ) ; return r ; }else{ return _zuluCryptBindUnmountVolume( stx,device,uid ) ; } } int zuluCryptBindSharedMountPointPathTaken( string_t path ) { struct stat str ; ssize_t index = StringLastIndexOfChar( path,'/' ) ; string_t st = String( SHARE_MOUNT_PREFIX ) ; const char * e = StringAppend( st,StringContent( path ) + index ) ; int r = stat( e,&str ) ; StringDelete( &st ) ; return r == 0 ; } int zuluCryptBindMountVolume( const char * device,string_t z_path,unsigned long flags ) { struct stat st ; string_t path ; string_t tmp ; ssize_t index = StringLastIndexOfChar( z_path,'/' ) ; const char * o_path = StringContent( z_path ) ; const char * m_path ; const char * e ; int xt ; stringList_t stl ; if( index == -1 ){ return 1 ; } if( device ){} zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptGetMoutedList() is defined in ../lib/process_mountinfo.c */ stl = zuluCryptGetMoutedList() ; path = String( SHARE_MOUNT_PREFIX "/" ) ; m_path = StringAppend( path,o_path + index + 1 ) ; /* * zuluCryptCreateMountPath() is defined in create_mount_point.c */ zuluCryptCreateMountPath( SHARE_MOUNT_PREFIX ) ; if( stat( m_path,&st ) == 0 ){ _chmod( m_path,st.st_mode | S_IXOTH | S_IROTH ) ; /* * bind mount point exists,this will happen if the mount point is already taken or a mount point folder * was not autodeleted for some reason */ tmp = StringCopy( path ) ; e = StringAppend( tmp," " ) ; if( StringListHasSequence( stl,e ) != -1 ){ /* * An attempt is made to bind mount on a path already bind mounted path,dont attempt to mount */ xt = 1 ; }else{ /* * the mount point folder is there for some reason but is not being used. */ xt = mount( o_path,m_path,"",flags|MS_BIND,"" ) ; } StringDelete( &tmp ) ; }else{ zuluCryptCreateMountPath( m_path ) ; xt = mount( o_path,m_path,"",flags|MS_BIND,"" ) ; if( xt != 0 ){ rmdir( m_path ) ; } } StringListDelete( &stl ) ; StringDelete( &path ) ; zuluCryptSecurityDropElevatedPrivileges() ; return xt ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/check_invalid_key.c000066400000000000000000000025611425361753700227160ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include void zuluCryptCheckInvalidKey( const char * device ) { char * d ; const char * c ; int e = 0 ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptEmptySlots() is defined in ../lib/empty_slots.c */ d = zuluCryptEmptySlots( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( d == NULL ){ /* * we got here because the volume is either not luks based or the path is invalid */ }else{ c = d - 1 ; while( *++c ){ if( *c == '2' ){ fprintf( stderr,"WARNING: key slot number: %d is corrupted\n",e ) ; } e++ ; } StringFree( d ) ; } } zuluCrypt-6.2.0/zuluCrypt-cli/bin/check_opened_mapper.c000066400000000000000000000025301425361753700232320ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include int zuluCryptCheckOpenedMapper( const char * mapper ) { const char * c = mapper ; char * d ; int st = 0 ; struct dirent * entry ; DIR * dir = opendir( crypt_get_dir() ) ; if( dir == NULL ){ return 2 ; } while( *++c != '-' ) {} while( *++c != '-' ) {} while( ( entry = readdir( dir ) ) != NULL ){ d = strstr( entry->d_name,"zuluCrypt-" ) ; if( d != NULL ){ while( *++d != '-' ) {} while( *++d != '-' ) {} if( StringsAreEqual( c,d ) ){ st = 1 ; break ; } } } closedir( dir ) ; return st ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/clear_dead_mappers.c000066400000000000000000000134741425361753700230620ustar00rootroot00000000000000 /* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include "mount_prefix_path.h" #include #include #include #include #include #include #include #include static void _remove_mapper( const char * path,stringList_t stl,uid_t uid ) { char * m_point = NULL ; /* * zuluCryptBindUnmountVolume() is defined in ./bind.c */ int r = zuluCryptBindUnmountVolume( stl,path,uid ) ; if( r == 3 || r == 4 ){ /* * shared mount is busy or belong to another user */ return ; } /* * zuluCryptCloseVolume() is defined in ../lib/close_volume.c */ r = zuluCryptCloseVolume( path,&m_point ) ; if( r == 0 && m_point != NULL ){ remove( m_point ) ; StringFree( m_point ) ; } } static void _zuluCryptDeleteDeadMountPoints( stringList_t stl,const char * m ) { struct dirent * entry ; const char * e ; string_t st ; string_t xt ; const char * bl = zuluCryptBitLockerFolderPrefix() ; DIR * dir = opendir( m ) ; if( dir == NULL ){ return ; } while( ( entry = readdir( dir ) ) != NULL ){ e = entry->d_name ; if( !StringAtLeastOneMatch_1( e,".","..",bl,NULL ) ){ st = String( e ) ; zuluCryptEncodeMountEntry( st ) ; StringMultiplePrepend( st,"/",m,NULL ) ; e = StringAppend( st," " ) ; if( StringListHasSequence( stl,e ) < 0 ){ xt = String_1( m,"/",entry->d_name,NULL ) ; if( rmdir( StringContent( xt ) ) != 0 ){ /* * Failed to delete an unmounted folder for some reason */ } StringDelete( &xt ) ; } StringDelete( &st ) ; } } } static void _unmount_dead_mount_points( uid_t uid ) { stringList_t stl = zuluCryptPartitions( ZULUCRYPTallPartitions,uid ) ; stringList_t stx = zuluCryptGetAListOfMountedVolumes() ; StringListIterator it ; StringListIterator end ; string_t st ; char * mout_point = NULL ; char * m_point = NULL ; const char * device ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ st = *it ; it++ ; StringListRemoveIfPresent_1( stx,st ) ; } StringListGetIterators( stx,&it,&end ) ; while( it != end ){ st = *it ; it++ ; if( StringStartsWith( st,"/dev/" ) ){ device = StringContent( st ) ; mout_point = zuluCryptGetMountPointFromPath( device ) ; printf( "unmounting : %s\n",device ) ; if( zuluCryptUnmountVolume( device,&m_point ) == 0 ){ if( m_point ){ rmdir( m_point ) ; printf( "unmounted : %s:%s\n",device,m_point ) ; } }else{ perror( "failed" ) ; } } } StringFree( mout_point ) ; StringFree( m_point ) ; } void zuluCryptDeleteDeadMountPoints( uid_t uid,stringList_t stl ) { string_t st = zuluCryptGetUserName( uid ) ; _zuluCryptDeleteDeadMountPoints( stl,StringPrepend( st,"/run/media/private/" ) ) ; _zuluCryptDeleteDeadMountPoints( stl,"/run/media/public" ) ; _unmount_dead_mount_points( uid ) ; StringDelete( &st ) ; } void zuluCryptClearDeadMappers( uid_t uid,int s ) { struct crypt_device * cd ; const char * dir_path = crypt_get_dir() ; DIR * dir = opendir( dir_path ) ; struct dirent * entry ; const char * m ; const char * e ; char * r ; size_t len ; size_t len1 ; stringList_t stl ; string_t p ; string_t z ; if( dir == NULL ){ return ; } /* * zuluCryptGetMoutedList_1() is defined in ../lib/process_mountinfo.c */ stl = zuluCryptGetMoutedList_1() ; z = String_1( dir_path,"/",NULL ) ; len1 = StringLength( z ) ; p = String( "zuluCrypt-" ) ; m = StringAppendInt( p,uid ) ; len = StringLength( p ) ; /* * zuluCryptSecurityGainElevatedPrivileges() is defined in security.c */ zuluCryptSecurityGainElevatedPrivileges() ; while( ( entry = readdir( dir ) ) != NULL ){ if( StringPrefixMatch( entry->d_name,m,len ) ){ e = StringAppendAt( z,len1,entry->d_name ) ; /* * zuluCryptTrueCryptOrVeraCryptVolume() is defined in ../lib/status.c */ if( zuluCryptVolumeManagedByTcplay( e ) ){ /* * zuluCryptVolumeDeviceName() is defined in ../lib/status.c */ r = zuluCryptVolumeDeviceName( e ) ; if( *( r + 0 ) != '/' ){ /* * tcplay seems to report device name as something like "8:33" * when a mapper exists but its underlying device is gone and we exploit * this behavior by checking if path starts with "/" and we assume the * device is gone if it isnt. */ _remove_mapper( e,stl,uid ) ; } StringFree( r ) ; }else{ if( crypt_init_by_name( &cd,e ) == 0 ){ if( crypt_get_device_name( cd ) == NULL ){ /* * we will get here if none LUKS mapper is active but the underlying device is gone */ _remove_mapper( e,stl,uid ) ; } crypt_free( cd ) ; }else{ /* * we will get here if the LUKS mapper is active but the underlying device is gone */ _remove_mapper( e,stl,uid ) ; } } } } if( s ){ zuluCryptDeleteDeadMountPoints( uid,stl ) ; } /* * zuluCryptSecurityDropElevatedPrivileges() is defined in security.c */ zuluCryptSecurityDropElevatedPrivileges() ; StringListDelete( &stl ) ; StringMultipleDelete( &p,&z,NULL ) ; closedir( dir ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/close_volume.c000066400000000000000000000104761425361753700217630ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include #include #include static int zuluExit( int st,string_t p ) { StringDelete( &p ) ; switch( st ) { case 0 : printf( gettext( "SUCCESS: volume closed successfully \n" ) ) ; break ; case 1 : printf( gettext( "ERROR: Close failed, volume is not open or was opened by a different user\n" ) ) ; break ; case 2 : printf( gettext( "ERROR: Close failed, the mount point and/or one or more files are in use\n" ) ) ; break ; case 3 : printf( gettext( "ERROR: Close failed, volume does not have an entry in /etc/mtab\n" ) ) ; break ; case 4 : printf( gettext( "ERROR: Close failed, could not get a lock on /etc/mtab~\n" ) ) ; break ; case 5 : printf( gettext( "ERROR: Close failed, volume is unmounted but could not close mapper,advice to close it manually\n") ); break ; case 6 : printf( gettext( "ERROR: Close failed, could not resolve full path of device\n") ) ; break ; case 7 : printf( gettext( "ERROR: Close failed, shared mount point appear to be busy\n" ) ) ; break ; case 8 : printf( gettext( "ERROR: Close failed, shared mount point appear to belong to a different user or multiple mount points detected\n" ) ) ; break ; case 9 : printf( gettext( "ERROR: Close failed, shared mount point appear to be in an ambiguous state,advice to unmount manually\n" ) ) ; break ; case 10: printf( gettext( "ERROR: Close failed, multiple mount points for the volume detected\n" ) ) ; break ; default: printf( gettext( "ERROR: Unrecognized error with status number %d encountered\n" ),st ); } return st ; } int zuluCryptEXECloseVolume( const char * dev,const char * mapping_name,uid_t uid ) { int st ; int i ; string_t p = StringVoid ; char * m_point = NULL ; struct stat xt ; const char * mapper ; zuluCryptSecurityGainElevatedPrivileges() ; if( zuluCryptDeviceHasAgivenFileSystem( dev,zuluCryptBitLockerType() ) && zuluCryptDeviceManagedByDislocker( dev,uid ) ){ p = zuluCryptBitLockerFullMapperPath( uid,dev ) ; mapper = StringContent( p ) ; i = stat( mapper,&xt ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( i != 0 ){ return zuluExit( 1,p ) ; } }else{ zuluCryptSecurityDropElevatedPrivileges() ; /* * ZULUCRYPTlongMapperPath is set in ../constants.h * zuluCryptCreateMapperName() defined in ../lib/create_mapper_name.c */ p = zuluCryptCreateMapperName( dev,mapping_name,uid,ZULUCRYPTlongMapperPath ) ; mapper = StringContent( p ) ; if( stat( mapper,&xt ) != 0 ){ return zuluExit( 1,p ) ; } } /* * zuluCryptBindUnmountVolume() is defined in ./bind.c */ switch( zuluCryptBindUnmountVolume( StringListVoid,mapper,uid ) ){ case 3 : return zuluExit( 7,p ) ; case 4 : return zuluExit( 8,p ) ; case 5 : return zuluExit( 9,p ) ; default: ; } zuluCryptSecurityGainElevatedPrivileges() ; if( zuluCryptIsDislockerMapperPath( StringContent( p ) ) ){ if( zuluCryptReuseMountPoint() ){ st = zuluCryptBitLockerlock( p,NULL ) ; }else{ st = zuluCryptBitLockerlock( p,&m_point ) ; } }else{ if( zuluCryptReuseMountPoint() ){ st = zuluCryptCloseVolume( mapper,NULL ) ; }else{ st = zuluCryptCloseVolume( mapper,&m_point ) ; } } if( st == 0 && m_point != NULL ){ for( i = 0 ; i < 2 ; i++ ){ if( rmdir( m_point ) == 0 ){ break ; }else{ sleep( 1 ) ; } } } StringFree( m_point ) ; zuluCryptSecurityDropElevatedPrivileges() ; return zuluExit( st,p ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/create_mount_point.c000066400000000000000000000204211425361753700231540ustar00rootroot00000000000000/* * * Copyright (c) 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include "mount_prefix_path.h" #include "reuse_mount_point.h" #include #include static void _chown( const char * x,uid_t y,gid_t z ) { struct passwd * usr ; if( z == ( gid_t ) -1 ){ usr = getpwuid( y ) ; if( usr != NULL ){ z = usr->pw_gid ; } } if( chown( x,y,z ) ){} } static void _chmod( const char * x,mode_t y ) { if( chmod( x,y ) ){} } static void _mkdir( const char * x,mode_t y ) { if( mkdir( x,y ) ){} } static void _stat( const char * x,struct stat * y ) { if( stat( x,y ) ){} } int zuluCryptReuseMountPoint( void ) { return REUSE_MOUNT_POINT ; } static string_t _create_path_0( const char * m_point,uid_t uid,string_t path ) { struct stat st ; if( zuluCryptReuseMountPoint() ){ if( stat( m_point,&st ) == 0 ){ if( S_ISDIR( st.st_mode ) ){ /* * zuluCryptMountPointIsActive() is defined in ../lib/mountinfo.c */ if( zuluCryptMountPointIsActive( m_point ) ){ StringDelete( &path ) ; }else{ _chown( m_point,uid,( gid_t )-1 ) ; } }else{ StringDelete( &path ) ; } }else{ if( mkdir( m_point,S_IRWXU ) == 0 ){ _chown( m_point,uid,( gid_t )-1 ) ; }else{ StringDelete( &path ) ; } } }else{ if( mkdir( m_point,S_IRWXU ) == 0 ){ _chown( m_point,uid,( gid_t )-1 ) ; }else{ StringDelete( &path ) ; } } return path ; } static string_t _create_path( uid_t uid,string_t path,int need_privileges ) { string_t st = StringVoid ; const char * m_point = StringContent( path ) ; if( m_point != NULL ){ if( need_privileges ){ zuluCryptSecurityGainElevatedPrivileges() ; st = _create_path_0( m_point,uid,path ) ; zuluCryptSecurityDropElevatedPrivileges() ; }else{ st = _create_path_0( m_point,uid,path ) ; } } return st ; } static string_t _create_mount_point_1( const char * device,uid_t uid,string_t path,int need_privileges ) { string_t st ; char * loop_path = NULL ; if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../lib/create_loop_device.c */ device = loop_path = zuluCryptLoopDeviceAddress_1( device ) ; } StringMultipleAppend( path,device + StringLastIndexOfChar_1( device,'/' ) + 1,NULL ) ; st = _create_path( uid,path,need_privileges ) ; StringFree( loop_path ) ; return st ; } static string_t _create_home_default_mount_point( const char * device,uid_t uid,string_t path ) { return _create_mount_point_1( device,uid,path,0 ) ; } static string_t _create_default_mount_point( const char * device,uid_t uid,string_t path ) { return _create_mount_point_1( device,uid,path,1 ) ; } static string_t _create_mount_point_0( const char * label,uid_t uid,string_t path,int need_privileges ) { const char * q = strrchr( label,'/' ) ; const char * e ; if( q == NULL ){ StringAppend( path,label ) ; }else{ if( *( q + 1 ) == '\0' ){ /* * -m option was given with a path that ends with "/",backtrack until you find the second "/" * from the right and use it as the last "/". */ e = q - 1 ; if( e < label ){ /* * -m option was given with a single "/". */ StringDelete( &path ) ; return StringVoid ; } while( 1 ){ if( e == label ){ StringAppend( path,e + 1 ) ; StringRemoveRight( path,1 ) ; break ; }else if( *e == '/' ){ StringAppend( path,e + 1 ) ; StringRemoveRight( path,1 ) ; break ; }else{ e-- ; } } }else{ StringAppend( path,q + 1 ) ; } } return _create_path( uid,path,need_privileges ) ; } static string_t _create_home_custom_mount_point( const char * label,uid_t uid,string_t path ) { return _create_mount_point_0( label,uid,path,0 ) ; } static string_t _create_custom_mount_point( const char * label,uid_t uid,string_t path ) { return _create_mount_point_0( label,uid,path,1 ) ; } static string_t create_home_mount_point( const char * device,const char * label,uid_t uid ) { /* * zuluCryptGetUserHomePath() is defined in ../lib/user_home_path.c */ string_t path = zuluCryptGetUserHomePath( uid ) ; if( label == NULL ){ return _create_home_default_mount_point( device,uid,path ) ; }else{ return _create_home_custom_mount_point( label,uid,path ) ; } } static int mount_point_prefix_match_0( const char * m_path,uid_t uid,string_t * m_point,int home_prefix ) { int st ; /* * zuluCryptGetUserName() is defined in ../lib/user_home_path.c */ string_t uname ; /* * below constant are set in ../constants.h */ const char * str ; if( home_prefix ){ uname = zuluCryptGetUserHomePath( uid ) ; str = StringContent( uname ) ; }else{ uname = zuluCryptGetUserName( uid ) ; StringPrepend( uname,"/run/media/private/" ) ; str = StringAppendChar( uname,'/' ) ; } st = StringPrefixEqual( m_path,str ) ; if( m_point ){ *m_point = uname ; }else{ StringDelete( &uname ) ; } return st ; } static int home_mount_point_prefix_match( const char * m_path,uid_t uid,string_t * m_point ) { return mount_point_prefix_match_0( m_path,uid,m_point,1 ) ; } static int mount_point_prefix_match( const char * m_path,uid_t uid,string_t * m_point ) { return mount_point_prefix_match_0( m_path,uid,m_point,0 ) ; } static void _zuluCryptCreateMountPath( const char * path ) { struct stat st ; _mkdir( path,S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH | S_IROTH ) ; _stat( path,&st ) ; _chown( path,0,0 ) ; _chmod( path,st.st_mode | S_IXOTH | S_IROTH ) ; } void zuluCryptCreateMountPath( const char * path ) { string_t p = String( path ) ; StringIterator it ; StringIterator end ; char * e ; char * f ; StringGetIterators( p,&it,&end ) ; if( end ){} f = it + 1 ; while( 1 ){ e = strchr( f,'/' ) ; if( e == NULL ){ _zuluCryptCreateMountPath( it ) ; break ; }else{ *e = '\0' ; _zuluCryptCreateMountPath( it ) ; *e = '/' ; f = e + 1 ; } } StringDelete( &p ) ; } static string_t create_mount_point( const char * device,const char * label,uid_t uid ) { string_t path = zuluCryptGetUserName( uid ) ; const char * e = StringPrepend( path,"/run/media/private/" ) ; zuluCryptSecurityGainElevatedPrivileges() ; zuluCryptCreateMountPath( e ) ; _chmod( e,S_IREAD | S_IXUSR ) ; _chown( e,uid,( gid_t )-1 ) ; zuluCryptSecurityDropElevatedPrivileges() ; StringAppendChar( path,'/' ) ; if( label == NULL ){ return _create_default_mount_point( device,uid,path ) ; }else{ return _create_custom_mount_point( label,uid,path ) ; } } static int home_mount_prefix( void ) { return USE_HOME_PATH_AS_MOUNT_PREFIX ; } void zuluCryptCreateMountPointPrefix( uid_t uid ) { string_t st = zuluCryptGetUserName( uid ) ; const char * e = StringPrepend( st,"/run/media/private/" ) ; zuluCryptCreateMountPath( e ) ; StringDelete( &st ) ; } string_t zuluCryptCreateMountPoint( const char * device,const char * label,const char * m_opts,uid_t uid ) { if( home_mount_prefix() ){ return create_home_mount_point( device,label,uid ) ; }else{ if( StringHasComponent( m_opts,"mount-prefix=home" ) ){ if( zuluCryptUserIsAMemberOfAGroup( uid,"zulumount" ) ){ return create_home_mount_point( device,label,uid ) ; }else{ return StringVoid ; } }else{ return create_mount_point( device,label,uid ) ; } } } int zuluCryptMountPointPrefixMatch( const char * m_path,uid_t uid,string_t * m_point ) { if( home_mount_prefix() ){ return home_mount_point_prefix_match( m_path,uid,m_point ) ; }else{ if( mount_point_prefix_match( m_path,uid,m_point ) ){ return 1 ; }else{ return home_mount_point_prefix_match( m_path,uid,m_point ) ; } } } zuluCrypt-6.2.0/zuluCrypt-cli/bin/create_volumes.c000066400000000000000000000347701425361753700223070ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include #include static int zuluExit( int st,stringList_t stl ) { /* * this function is defined in ../string/StringList.c */ StringListClearDelete( &stl ) ; switch ( st ){ case 0 : printf( gettext( "SUCCESS: volume created successfully\n" ) ) ; break ; case 1 : printf( gettext( "ERROR: Presented file system is not supported,see documentation for more information\n" ) ) ;break ; case 2 : printf( gettext( "ERROR: Insufficient privilege to open a system device in read/write mode,\n\ only root user or members of group zulucrypt-system can do that\n" ) ) ; break ; case 3 : printf( gettext( "ERROR: Could not create an encrypted volume\n" ) ) ; break ; case 4 : printf( gettext( "ERROR: Could not open volume for writing\n" ) ) ; break ; case 5 : printf( gettext( "ERROR: There seem to be an opened mapper associated with the device\n" ) ); break ; case 6 : printf( gettext( "ERROR: Can not create a volume on a mounted device\n" ) ) ; break ; case 7 : printf( gettext( "ERROR: Container file must be bigger than 3MB\n" ) ) ; break ; case 8 : printf( "ERROR: %s not found \n",ZULUCRYPTmkfs ) ; break ; case 9 : printf( gettext( "ERROR: Insufficient memory to hold your response\n" ) ) ; break ; case 10: printf( gettext( "INFO: Operation terminated per user request\n" ) ) ; break ; case 11: printf( gettext( "ERROR: Could not get passphrase in silent mode\n" ) ) ; break ; case 12: printf( gettext( "ERROR: Insufficient memory to hold the passphrase\n" ) ) ; break ; case 13: printf( gettext( "ERROR: Passphrases do not match\n" ) ) ; break ; case 14: printf( gettext( "ERROR: Invalid path to key file\n" ) ) ; break ; case 15: printf( gettext( "ERROR: Could not get a key from a key file\n" ) ) ; break ; case 16: printf( gettext( "ERROR: Couldnt get enought memory to hold the key file\n" ) ) ; break ; case 17: printf( gettext( "ERROR: Could not get a key from a socket\n" ) ) ; break ; case 18: printf( gettext( "ERROR: One or more required argument(s) for this operation is missing\n" )); break ; case 19: printf( gettext( "ERROR: Can not get passphrase in silent mode\n" ) ) ; break ; case 20: printf( gettext( "ERROR: Insufficient memory to hold passphrase\n" ) ) ; break ; case 21: printf( gettext( "ERROR: Passphrases do not match\n" ) ) ; break ; case 22: printf( gettext( "ERROR: Failed to create a volume\n" ) ) ; break ; case 23: printf( gettext( "ERROR: Wrong argument detected for tcrypt volume\n" ) ) ; break ; default: printf( gettext( "ERROR: Unrecognized error with status number %d encountered\n" ),st ) ; } return st ; } static int zuluExit_1( const char * type,stringList_t stl ) { printf( gettext( "SUCCESS: Volume created successfully\n" ) ) ; if( StringAtLeastOneMatch_1( type,"luks","luks1","luks2","tcrypt","truecrypt","veracrypt","vera","vcrypt",NULL ) ){ printf( gettext( "\nCreating a backup of the \"%s\" volume header is strongly adviced.\n" ),type ) ; printf( gettext( "Please read documentation on why this is important\n\n" ) ) ; } StringListClearDelete( &stl ) ; return 0 ; } int zuluCryptEXECreateVolume( const struct_opts * opts,const char * mapping_name,uid_t uid ) { int ask_confirmation = opts->ask_confirmation ; const char * device = opts->device ; const char * fs = opts->fs ; const char * type = opts->type ; const char * key_source = opts->key_source ; const char * pass = opts->key ; const char * rng = opts->rng ; const char * const * tcrypt_keyfiles = opts->tcrypt_multiple_keyfiles ; /* * Below is a form of memory management.All strings are collected in a stringlist object to easily delete them * when the function returns.This allows for the function to have multiple exit points without risks of leaking * memory from manually examining each exit point to make sure all strings are deleted or go with multiple goto * code deleting blocks to take into account different exit points. */ stringList_t stl ; string_t * stringArray = StringListArray( &stl,6 ) ; string_t * pass_1 = &stringArray[ 0 ] ; string_t * pass_2 = &stringArray[ 1 ] ; string_t * confirm = &stringArray[ 2 ] ; string_t * mapper = &stringArray[ 3 ] ; string_t * pass_3 = &stringArray[ 4 ] ; string_t * pass_4 = &stringArray[ 5 ] ; stringList_t stz = StringListVoid ; stringList_t stk = StringListVoid ; string_t p = StringVoid ; const char * volkey = "" ; size_t volkeysize = 0 ; const char * volkey_h = "" ; size_t volkeysize_h = 0 ; int tcrypt_source = TCRYPT_PASSPHRASE ; int tcrypt_source_h = TCRYPT_PASSPHRASE ; int socket_path = 0 ; int st ; int j ; int k ; int truecrypt_volume = 0 ; int veracrypt_volume = 0 ; u_int64_t hidden_volume_size = 0 ; u_int64_t size ; create_tcrypt_t tcrypt ; const char * tcrypt_hidden_volume_size = opts->tcrypt_hidden_volume_size ; const char * tcrypt_hidden_volume_key = opts->tcrypt_hidden_volume_key ; const char * tcrypt_hidden_volume_key_file = opts->existing_key ; const char * const * tcrypt_hidden_volume_keyFiles = opts->tcrypt_hidden_volume_multiple_keyfiles ; /* * zulucryptFileSystemIsNotSupported() is defined in ../lib/mount_fs_options.c */ if( !zulucryptFileSystemIsSupported( fs ) ){ return zuluExit( 1,stl ) ; } /* * zuluCryptPartitionIsSystemPartition() is defined in ./volumess.c */ if( zuluCryptPartitionIsSystemPartition( device,uid ) ){ if( zuluCryptExeOriginalUserIsNotRoot() ){ if( !zuluCryptUserIsAMemberOfAGroup( uid,"zulucrypt" ) ){ return zuluExit( 2,stl ) ; } } } /* * zuluCryptSecurityDeviceIsWritable() is defined in path_access.c */ st = zuluCryptCanOpenPathForWriting( device,uid ) ; /* * 1-permissions denied * 2-invalid path * 3-shenanigans * 4-common error */ switch( st ){ case 0 : break ; case 1 : return zuluExit( 4,stl ) ; case 2 : return zuluExit( 4,stl ) ; case 3 : return zuluExit( 4,stl ) ; case 4 : return zuluExit( 4,stl ) ; default: return zuluExit( 4,stl ) ; } /* * ZULUCRYPTlongMapperPath is set in ../constants.h * zuluCryptCreateMapperName() is defined at ../lib/create_mapper_name.c */ *mapper = zuluCryptCreateMapperName( device,mapping_name,uid,ZULUCRYPTlongMapperPath ) ; j = zuluCryptCheckOpenedMapper( StringContent( *mapper ) ) ; /* * defined in ../lib/mountinfo.c */ k = zuluCryptPartitionIsMounted( device ) ; if( j == 1 ){ return zuluExit( 5,stl ) ; } if( k == 1 ){ return zuluExit( 6,stl ) ; } if( StringPrefixEqual( device,"/dev/loop" ) ){ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptGetVolumeSize() is defined in volumes.c */ size = zuluCryptGetVolumeSize( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( size < 3145728 ){ return zuluExit( 7,stl ) ; } } /* * ZULUCRYPTmkfs is defined at "../constants.h" * File systems are created not through file systems APIs but through mkfs.xxx executables started using exec call. */ if( zuluCryptPathIsNotValid( ZULUCRYPTmkfs ) ){ return zuluExit( 8,stl ) ; } if( ask_confirmation ){ printf( gettext( "\nThis operation will destroy all data in a device at: \"%s\"\n" ),device ) ; printf( gettext( "Are you sure you want to proceed?\n" ) ) ; printf( gettext( "Type \"YES\" and press enter if you want to process: " ) ) ; *confirm = StringGetFromTerminal_1( 3 ) ; if( *confirm == StringVoid ){ return zuluExit( 9,stl ) ; }else{ if( StringsAreNotEqual_2( *confirm,gettext( "YES" ) ) ){ return zuluExit( 10,stl ) ; } } } truecrypt_volume = StringAtLeastOneMatch_1( type,"tcrypt","truecrypt",NULL ) ; veracrypt_volume = StringAtLeastOneMatch_1( type,"vcrypt","veracrypt","vera",NULL ) ; if( key_source == NULL ){ printf( gettext( "Enter passphrase: " ) ) ; /* * ZULUCRYPT_KEY_MAX_SIZE is set in ../constants.h */ switch( StringSilentlyGetFromTerminal_1( pass_1,ZULUCRYPT_KEY_MAX_SIZE ) ){ case 1 : return zuluExit( 11,stl ) ; case 2 : return zuluExit( 12,stl ) ; } printf( gettext( "\nRe enter passphrase: " ) ) ; switch( StringSilentlyGetFromTerminal_1( pass_2,ZULUCRYPT_KEY_MAX_SIZE ) ){ case 1 : return zuluExit( 11,stl ) ; case 2 : return zuluExit( 12,stl ) ; } printf( "\n" ) ; if( !StringsAreEqual_1( *pass_1,*pass_2 ) ){ return zuluExit( 13,stl ) ; } tcrypt_source = TCRYPT_PASSPHRASE ; }else{ if( StringsAreEqual( key_source,"-p" ) ){ *pass_1 = String( pass ) ; tcrypt_source = TCRYPT_PASSPHRASE ; }else if( StringsAreEqual( key_source,"-f" ) ){ /* * function is defined at "path_access.c" */ switch( zuluCryptGetPassFromFile( &socket_path,pass,uid,pass_1 ) ){ case 1 : return zuluExit( 14,stl ) ; case 4 : return zuluExit( 15,stl ) ; case 2 : return zuluExit( 16,stl ) ; case 5 : return zuluExit( 17,stl ) ; } if( *pass_1 == StringVoid ){ return zuluExit( 17,stl ) ; } if( socket_path ){ tcrypt_source = TCRYPT_PASSPHRASE ; }else{ tcrypt_source = TCRYPT_KEYFILE ; } }else{ return zuluExit( 18,stl ) ; } } if( tcrypt_hidden_volume_size != NULL ){ if( !( truecrypt_volume || veracrypt_volume ) ){ return zuluExit( 23,stl ) ; }else{ hidden_volume_size = StringConvertToInt( tcrypt_hidden_volume_size ) ; if( tcrypt_hidden_volume_key_file != NULL ){ /* * function is defined in "path_access.c" */ switch( zuluCryptGetPassFromFile( &socket_path,tcrypt_hidden_volume_key_file,uid,pass_3 ) ){ case 1 : return zuluExit( 14,stl ) ; case 4 : return zuluExit( 15,stl ) ; case 2 : return zuluExit( 16,stl ) ; case 5 : return zuluExit( 17,stl ) ; } if( socket_path ){ tcrypt_source_h = TCRYPT_PASSPHRASE ; }else{ tcrypt_source_h = TCRYPT_KEYFILE ; } }else if( tcrypt_hidden_volume_key == NULL ){ printf( gettext( "Enter tcrypt hidden passphrase: " ) ) ; /* * ZULUCRYPT_KEY_MAX_SIZE is set in ../constants.h */ switch( StringSilentlyGetFromTerminal_1( pass_3,ZULUCRYPT_KEY_MAX_SIZE ) ){ case 1 : return zuluExit( 19,stl ) ; case 2 : return zuluExit( 20,stl ) ; } printf( gettext( "\nRe enter tcrypt hidden passphrase: " ) ) ; switch( StringSilentlyGetFromTerminal_1( pass_4,ZULUCRYPT_KEY_MAX_SIZE ) ){ case 1 : return zuluExit( 19,stl ) ; case 2 : return zuluExit( 20,stl ) ; } printf( "\n" ) ; if( !StringsAreEqual_1( *pass_3,*pass_4 ) ){ return zuluExit( 21,stl ) ; } tcrypt_source_h = TCRYPT_PASSPHRASE ; }else if( tcrypt_hidden_volume_key != NULL ){ *pass_3 = String( tcrypt_hidden_volume_key ) ; tcrypt_source_h = TCRYPT_PASSPHRASE ; }else{ return zuluExit( 18,stl ) ; } volkey_h = StringContent( *pass_3 ) ; volkeysize_h = StringLength( *pass_3 ) ; } } volkey = StringContent( *pass_1 ) ; volkeysize = StringLength( *pass_1 ) ; if( truecrypt_volume || veracrypt_volume ){ memset( &tcrypt,'\0',sizeof( create_tcrypt_t ) ) ; tcrypt.device = device ; tcrypt.fs = fs ; tcrypt.fs_h = fs ; tcrypt.encryption_options = rng ; tcrypt.hidden_volume_size = hidden_volume_size ; tcrypt.veraCrypt_volume = veracrypt_volume ; if( tcrypt_keyfiles[ 0 ] != NULL ){ /* * zuluCryptCreateKeyFiles() is defined in create_volume.c */ stz = zuluCryptCreateKeyFiles( tcrypt_keyfiles,0 ) ; } if( tcrypt_source == TCRYPT_KEYFILE ){ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptCreateKeyFile() is defined in ../lib/open_tcrypt.c */ p = zuluCryptCreateKeyFile( volkey,volkeysize,"create-key-" ) ; zuluCryptSecurityDropElevatedPrivileges() ; StringListAppendString_1( &stz,&p ) ; tcrypt.passphrase = "" ; tcrypt.passphrase_size = 0 ; }else{ tcrypt.passphrase = volkey ; tcrypt.passphrase_size = volkeysize ; } tcrypt.keyfiles = StringListStringArray( stz ) ; tcrypt.keyfiles_number = (int)StringListSize( stz ) ; if( tcrypt.hidden_volume_size > 0 ){ if( tcrypt_hidden_volume_keyFiles[ 0 ] != NULL ){ /* * zuluCryptCreateKeyFiles() is defined in open_volume.c */ stk = zuluCryptCreateKeyFiles( tcrypt_hidden_volume_keyFiles,1000 ) ; } if( tcrypt_source_h == TCRYPT_KEYFILE ){ zuluCryptSecurityGainElevatedPrivileges() ; p = zuluCryptCreateKeyFile( volkey_h,volkeysize_h,"create-key_h-" ) ; zuluCryptSecurityDropElevatedPrivileges() ; StringListAppendString_1( &stk,&p ) ; tcrypt.passphrase_h = "" ; tcrypt.passphrase_h_size = 0 ; }else{ tcrypt.passphrase_h = volkey_h ; tcrypt.passphrase_h_size = volkeysize_h ; } tcrypt.keyfiles_h = StringListStringArray( stk ) ; tcrypt.keyfiles_h_number = StringListSize( stk ) ; } zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptCreateTCryptVolume() is defined in ../lib/create_tcrypt.c */ st = zuluCryptCreateTCryptVolume( &tcrypt ) ; zuluCryptSecurityDropElevatedPrivileges() ; /* * zuluCryptDeleteKeyFiles() is defined in open_volume.c */ zuluCryptDeleteKeyFiles( stz ) ; zuluCryptDeleteKeyFiles( stk ) ; StringFree( tcrypt.keyfiles_h ) ; StringFree( tcrypt.keyfiles ) ; StringListMultipleDelete( &stz,&stk,NULL ) ; }else{ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptCreateVolume() is defined in ../lib/create_volume.c */ if( StringsAreEqual( type,"plain" ) && StringsAreEqual( key_source,"-f" ) && !socket_path ){ st = zuluCryptCreateVolume( device,fs,"plain.keyfile",volkey,volkeysize,rng ) ; }else{ st = zuluCryptCreateVolume( device,fs,type,volkey,volkeysize,rng ) ; } zuluCryptSecurityDropElevatedPrivileges() ; } if( st == 0 ){ return zuluExit_1( type,stl ) ; }else{ return zuluExit( 22,stl ) ; } } zuluCrypt-6.2.0/zuluCrypt-cli/bin/crypt_file.c000066400000000000000000000131251425361753700214210ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include #include #include #include #define DECRYPT 1 #define ENCRYPT 0 #define _ignore_result( x ) if( x ){;} static int zuluExit( int st ) { switch( st ){ case 0 : printf( gettext( "SUCCESS: Encrypted file created successfully\n" ) ) ; break ; case 1 : printf( gettext( "SUCCESS: Decrypted file created successfully\n" ) ) ; break ; case 2 : printf( gettext( "ERROR: Could not open key file for reading\n" ) ) ; break ; case 3 : printf( gettext( "ERROR: Missing key source\n" ) ) ; break ; case 4 : printf( gettext( "ERROR: Could not open encryption routines\n" ) ) ; break ; case 5 : printf( gettext( "ERROR: File or folder already exist at destination address\n" ) ) ; break ; case 6 : printf( gettext( "ERROR: Invalid path to source\n" ) ) ; break ; case 7 : printf( gettext( "ERROR: Could not resolve path to destination file\n" ) ) ; break ; case 8 : printf( gettext( "ERROR: Passphrases do not match\n" ) ) ; break ; case 9 : printf( gettext( "ERROR: Destination path is missing\n" ) ) ; break ; case 10: printf( gettext( "ERROR: Insufficient privilege to create destination file\n" ) ) ; break ; case 11: printf( gettext( "ERROR: Presented key did not match the encryption key\n" ) ) ; break ; case 12: printf( gettext( "ERROR: Can not get passphrase in silent mode\n" ) ) ; break ; case 13: printf( gettext( "ERROR: Insufficient memory to hold passphrase\n" ) ) ; break ; case 14: printf( gettext( "ERROR: Source path is missing\n" ) ) ; break ; case 15: printf( gettext( "ERROR: Insufficient privilege to open source file for reading\n" ) ) ; break ; case 16: printf( gettext( "INFORMATION: Functionality currently disabled\n" ) ) ; break ; } return st ; } static int crypt_opt( const struct_opts * opts,uid_t uid,int opt ) { string_t q = StringVoid ; string_t p = StringVoid ; int st ; const char * source = opts->device ; const char * dest = opts->m_opts ; const char * passphrase = opts->key ; const char * type = opts->key_source ; return zuluExit( 16 ) ; if( dest == NULL ){ return zuluExit( 9 ) ; } if( source == NULL ){ return zuluExit( 14 ) ; } /* * zuluCryptPathStartsWith() is defined in real_path.c */ if( zuluCryptPathStartsWith( dest,"/dev/" ) ){ return zuluExit( 10 ) ; } if( zuluCryptPathStartsWith( source,"/dev/" ) ){ return zuluExit( 15 ) ; } /* * zuluCryptPathIsValid() is defined in ../lib/is_path_valid.c */ if( zuluCryptPathIsValid( dest ) ){ return zuluExit( 5 ) ; } /* * zuluCryptPathIsNotValid() is defined in ../lib/is_path_valid.c */ if( zuluCryptPathIsNotValid( source ) ){ return zuluExit( 6 ) ; } /* * below two functions are defined in path_access.c */ if( zuluCryptCanOpenPathForWriting( dest,uid ) == 1 ){ return zuluExit( 10 ) ; } if( zuluCryptCanOpenPathForReading( source,uid ) == 1 ){ return zuluExit( 15 ) ; } if( type == NULL ){ printf( gettext( "Enter passphrase: " ) ) ; /* * ZULUCRYPT_KEY_MAX_SIZE is set in ../constants.h */ switch( StringSilentlyGetFromTerminal_1( &p,ZULUCRYPT_KEY_MAX_SIZE ) ){ case 1 : return zuluExit( 12 ) ; case 2 : return zuluExit( 13 ) ; } printf( gettext( "\nRe enter passphrase: " ) ) ; switch( StringSilentlyGetFromTerminal_1( &q,ZULUCRYPT_KEY_MAX_SIZE ) ){ case 1 : StringClearDelete( &p ) ; return zuluExit( 12 ) ; case 2 : StringClearDelete( &p ) ; return zuluExit( 13 ) ; } printf( "\n" ) ; if( !StringsAreEqual_1( p,q ) ){ StringClearDelete( &p ) ; StringClearDelete( &q ) ; return zuluExit( 8 ) ; }else{ StringDelete( &q ) ; } }else{ if( type == NULL ){ return zuluExit( 9 ) ; } if( StringsAreEqual( type,"-p" ) ){ p = String( passphrase ) ; }else if( StringsAreEqual( type,"-f" ) ){ p = StringGetFromFile( passphrase ) ; if( p == NULL ){ return zuluExit( 2 ) ; } }else{ return zuluExit( 3 ) ; } } if( opt == ENCRYPT ){ /* * zuluCryptEncryptFile() is defined in ./crypt_file.c */ st = zuluCryptEncryptFile( source,dest,StringContent( p ),StringLength( p ) ) ; }else{ /* * zuluCryptDecryptFile() is defined in ./crypt_file.c */ st = zuluCryptDecryptFile( source,dest,StringContent( p ),StringLength( p ) ) ; } StringClearDelete( &p ) ; switch( st ){ case 1 : return zuluExit( 4 ) ; case 2 : return zuluExit( 11 ) ; } _ignore_result( chmod( dest,S_IRUSR | S_IWUSR ) ) _ignore_result( chown( dest,uid,uid ) ) if( opt == 1 ){ return zuluExit( 1 ) ; }else{ return zuluExit( 0 ) ; } } int zuluCryptExeFileDecrypt( const struct_opts * opts,uid_t uid ) { return crypt_opt( opts,uid,DECRYPT ) ; } int zuluCryptExeFileEncrypt( const struct_opts * opts,uid_t uid ) { return crypt_opt( opts,uid,ENCRYPT ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/file_encryption.c000066400000000000000000000173021425361753700224530ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../bin/includes.h" #include #include #include #include #include #include #include #include #include #include #define SIZE 512 static void _write( int x,const void * y,size_t z ) { if( write( x,y,z ) ){} } static void _read( int x,void * y,size_t z ) { if( read( x,y,z ) ){} } /* * routines for encrypting and decrypting stand alone files. * * Basic idea of the operation: * * basic concept: * * to create an encrypted file: * * create a "shell" file, attach a mapper to it and then copy the content of plain text file * to the shell file through the mapper to create a cypher text file. * * to create a decrypted file: * * create a container file, attach a mapper to the container file and copy contents ofthe file to be encrypted to the container file through * the mapper . * * The container file has a simple format. * 1. The file will be a multiple of 512,if the plain text file has a file size that is not a multiple of 512,then * encrypted file will be padded to the next file size of 512 mupltiple. * * 2. The encrypted file will have an addition size of 512 bytes added to the beginning of the encrypted file.This is the header * of the encrypted file. * * 100 bytes of data are read from "/dev/urandom" and added at offset 100 and offset 200.These two 100 bytes data chunks will bo * compared to check if the decryption key is the same as encrypting key.The offsett should math if thhe keys are the same. * * The first 100 bytes will contain the size of the load and the format should be a format atoll() can correctly undestand. ie * the size must be a null terminated string of digits representing the size of the load. * * * If for example, a 100 bytes file is to be encrypted,the encrypted file will have a file size of 1024 bytes. First, the 100 bytes * will be padded to 512 and then 512 bytes will be added to store the size of the plain text file,useful when decrypting the file. * */ static string_t crypt_mapper( const char * path,const char * key,u_int64_t key_len ) { string_t p ; char * mpath = realpath( path,NULL ) ; if( mpath == NULL ){ return StringVoid ; } /* * ZULUCRYPTshortMapperPath is set in ../constants.h * zuluCryptCreateMapperName() is defined at ../lib/create_mapper_name.c */ p = zuluCryptCreateMapperName( mpath,strrchr( mpath,'/' ) + 1,0,ZULUCRYPTshortMapperPath ) ; if( zuluCryptOpenPlain( mpath,StringContent( p ),"rw",key,key_len ) != 0 ){ StringDelete( &p ) ; }else{ StringMultiplePrepend( p,"/",crypt_get_dir(),NULL ) ; } StringFree( mpath ) ; return p ; } static int zuluExit( int st,int f_in,int f_out,string_t p ) { if( f_out != -1 ){ close( f_out ) ; } close( f_in ) ; zuluCryptCloseMapper( StringContent( p ) ) ; StringDelete( &p ) ; return st ; } /* * function responsible for creating a decrypted file */ int zuluCryptDecryptFile( const char * source,const char * dest,const char * key,u_int64_t key_len ) { struct stat st ; char buffer[ SIZE ] ; u_int64_t size ; u_int64_t len ; u_int64_t i ; int f_in ; int f_out = -1 ; int test ; /* * attach a mapper to the file containing encrypted data */ string_t p = crypt_mapper( source,key,key_len ) ; if( p == StringVoid ){ return 1 ; } f_in = open( StringContent( p ),O_RDONLY ) ; /* * 100 bytes from offset 100 and 100 bytes from offset 200 are supposed to be te same if * the right key is used. */ _read( f_in,buffer,SIZE ) ; if( memcmp( buffer + 100,buffer + 200,100 ) != 0 ){ return zuluExit( 2,f_in,f_out,p ) ; } /* * get the size of encrypted data */ size = (size_t)atoll( buffer ) ; /* * Make sure the size of the encrypted file is with in expected range. * It being out of range means either a wrong encrypted key was used or the encrypted file is corrupted. * * Because the padding can be up to 511 bytes and the header takes 512 bytes, the encrypted file will be * larger and the different will be >= 512 and < 1024. */ stat( source,&st ) ; test = (int)st.st_size - (int)size ; if( test < SIZE || test >= ( SIZE * 2 ) ){ return zuluExit( 2,f_in,f_out,p ) ; } f_out = open( dest,O_WRONLY | O_CREAT,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ; if( size <= SIZE ){ _read( f_in,buffer,size ) ; _write( f_out,buffer,size ) ; }else{ len = size / SIZE ; for( i = 0 ; i < len ; i++ ){ _read( f_in,buffer,SIZE ) ; _write( f_out,buffer,SIZE ) ; } len = size - ( i * SIZE ) ; _read( f_in,buffer,len ) ; _write( f_out,buffer,len ) ; } return zuluExit( 0,f_in,f_out,p ) ; } /* * function responsible for creating an encrypted file */ int zuluCryptEncryptFile( const char * source,const char * dest,const char * key,u_int64_t key_len ) { string_t p ; string_t q ; char buffer[ SIZE ] ; char r = '\0' ; int f_in ; int f_out ; u_int64_t size ; u_int64_t size_1 ; const char * mapper ; struct stat st ; stat( source,&st ) ; size = (size_t)st.st_size ; /* * make sure the encrypted file is a multiple of 512, important because data will be read/written in chunks of 512 bytes. */ while( size % SIZE != 0 ){ size++ ; } /* * add 512 bytes to encrypted file, the exta space will be used to store the content size of the data to be encrypted. */ size += SIZE ; memset( buffer,0,SIZE ) ; f_out = open( dest,O_WRONLY | O_CREAT,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ; size_1 = 0 ; /* * create a file to be used to store encrypted data. */ while( 1 ){ _write( f_out,buffer,SIZE ); size_1 += SIZE ; if( size_1 == size ){ break ; } } close( f_out ) ; /* * attach a mapper to the file that will contain encrypted data */ p = crypt_mapper( dest,key,key_len ) ; if( p == StringVoid ){ remove( dest ) ; return 1 ; } mapper = StringContent( p ) ; f_out = open( mapper,O_WRONLY ) ; q = StringIntToString( (u_int64_t)st.st_size ) ; /* * write the size of plain text file to the encrypted file. This information is important when decrypting the data * because it tells us how much padding was applied if any. * */ _write( f_out,StringContent( q ),StringLength( q ) ) ; _write( f_out,&r,1 ) ; /* * write the same 100 byte random data in two locations to be used to check the decrypting key during decryption. * */ f_in = open( "/dev/urandom",O_RDONLY ) ; _read( f_in,buffer,100 ) ; close( f_in ) ; lseek( f_out,100,SEEK_SET ) ; _write( f_out,buffer,100 ) ; _write( f_out,buffer,100 ) ; /* * set the beginning of the payload,The cypher text will start at byte 512. */ lseek( f_out,SIZE,SEEK_SET ) ; f_in = open( source,O_RDONLY ) ; /* * Copy over plain text data to the "shell" file through the mapper, creating an encrypted file. */ while( read( f_in,buffer,SIZE ) > 0 ){ _write( f_out,buffer,SIZE ) ; } close( f_in ) ; close( f_out ) ; zuluCryptCloseMapper( mapper ) ; StringMultipleDelete( &q,&p,NULL ) ; return 0 ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/get_opts.c000066400000000000000000000127431425361753700211120ustar00rootroot00000000000000/* * * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include void zuluCryptEXEGetOptsSetDefault( struct_opts * stopts ) { static char random[] = "/dev/urandom" ; static char type[] = "luks" ; memset( stopts,'\0',sizeof( struct_opts ) ) ; stopts->fs = "ext4" ; stopts->rng = random ; stopts->type = type ; stopts->open_mount = 1 ; stopts->ask_confirmation = 1 ; stopts->luks_slot_number = -1 ; if( zuluCryptPathIsValid( "/etc/zuluCrypt/dislocker" ) ){ stopts->use_cryptsetup_for_bitlocker = 0 ; }else{ stopts->use_cryptsetup_for_bitlocker = 1 ; } } void zuluCryptEXEGetOpts( int argc,char * argv[],struct_opts * stopts ) { int c ; int k = 0 ; int n = 0 ; int switch_b = 0 ; zuluCryptEXEGetOptsSetDefault( stopts ) ; while ( ( c = getopt( argc,argv,"MHZCUWTJLORBXASNPkhocsarqwibEDs:m:d:p:f:e:Y:i:z:g:y:u:l:n:j:t:G:F:V:K:" ) ) != -1 ) { switch( c ){ case( 'H' ) : stopts->action = 'H' ; break ; case( 'C' ) : stopts->action = 'C' ; break ; case( 'U' ) : stopts->action = 'U' ; break ; case( 'W' ) : stopts->action = 'W' ; break ; case( 'E' ) : stopts->action = 'E' ; break ; case( 'D' ) : stopts->action = 'D' ; break ; case( 'X' ) : stopts->action = 'X' ; break ; case( 'J' ) : stopts->action = 'J' ; break ; case( 'L' ) : stopts->action = 'L' ; break ; case( 'o' ) : stopts->action = 'o' ; break ; case( 'c' ) : stopts->action = 'c' ; break ; case( 's' ) : stopts->action = 's' ; break ; case( 'a' ) : stopts->action = 'a' ; break ; case( 'r' ) : stopts->action = 'r' ; break ; case( 'q' ) : stopts->action = 'q' ; break ; case( 'w' ) : stopts->action = 'w' ; break ; case( 'i' ) : stopts->action = 'i' ; break ; case( 'P' ) : stopts->action = 'P' ; break ; case( 'b' ) : { switch_b++ ; if( switch_b == 1 ){ stopts->action = 'b' ; }else{ stopts->action = '2' ; } break ; } case( 'O' ) : stopts->action = 'O' ; stopts->open_mount = 0 ; break ; case( 'T' ) : stopts->print_partition_type = 1 ; break; case( 'M' ) : stopts->share = 1 ; break ; case( 'Z' ) : stopts->print_partition_type = 2 ; break; case( 'B' ) : stopts->action = 'B' ; stopts->key_source = optarg ; break ; case( 'G' ) : stopts->plugin_path = optarg ; break ; case( 'R' ) : stopts->action = 'R' ; stopts->key_source = optarg ; break ; case( 'k' ) : stopts->ask_confirmation = 0 ; break ; /* * ZULUCRYPTallPartitions,ZULUCRYPTsystemPartitions and ZULUCRYPTnonSystemPartitions * are set in ../constants.h */ case( 'A' ) : stopts->partition_number = ZULUCRYPTallPartitions ; stopts->action = 'A' ; break ; case( 'S' ) : stopts->partition_number = ZULUCRYPTsystemPartitions ; stopts->action = 'S' ; break ; case( 'N' ) : stopts->partition_number = ZULUCRYPTnonSystemPartitions ; stopts->action = 'N' ; break ; case( 't' ) : stopts->type = optarg ; break ; case( 'K' ) : stopts->uid = optarg ; break ; case( 'm' ) : stopts->mount_point = optarg ; break ; case( 'd' ) : stopts->device = optarg ; break ; case( 'p' ) : stopts->key_source = "-p" ; stopts->key = optarg ; break ; case( 'F' ) : if( k < TRUECRYPT_MAX_KEYFILES ){ /* * TRUECRYPT_MAX_KEYFILES is set at libzuluCrypt-exe.h */ stopts->tcrypt_multiple_keyfiles[ k ] = optarg ; k++ ; } break ; case( 'f' ) : stopts->key_source = "-f" ; stopts->key = optarg ; break ; case( 'e' ) : stopts->m_opts = optarg ; stopts->tcrypt_hidden_volume_size = optarg ; break ; case( 'Y' ) : stopts->fs_opts = optarg ; break ; case( 'z' ) : stopts->fs = optarg ; stopts->back_up_file_path = optarg ; stopts->luks_external_header = optarg ; break ; case( 'g' ) : stopts->rng = optarg ; stopts->luks_slot_number = ( int )StringConvertToInt( optarg ) ; break ; case( 'y' ) : stopts->existing_key_source = "-p" ; stopts->existing_key = optarg ; break ; case( 'u' ) : stopts->existing_key_source = "-f" ; stopts->existing_key = optarg ; break ; case( 'V' ) : if( n < TRUECRYPT_MAX_KEYFILES ){ /* * TRUECRYPT_MAX_KEYFILES is set at libzuluCrypt-exe.h */ stopts->tcrypt_hidden_volume_multiple_keyfiles[ n ] = optarg ; n++ ; } break ; case( 'l' ) : stopts->new_key_source = "-p" ; stopts->new_key = optarg ; stopts->tcrypt_hidden_volume_key = optarg ; break ; case( 'n' ) : stopts->new_key_source = "-f" ; stopts->new_key = optarg ; break ; default: printf( "run zuluCrypt-cli --help for help\n" ) ; } } } zuluCrypt-6.2.0/zuluCrypt-cli/bin/help.c000066400000000000000000000157221425361753700202160ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include /* * The string is broken up to remove a compiler warning that says: * warning: string length ‘XXX’ is greater than the length ‘509’ ISO C90 compilers are required to support */ void zuluCryptEXEHelp( void ) { const char * help1 ; const char * help2 ; const char * help3 ; const char * help4 ; const char * help5 ; const char * help6 ; const char * help7 ; const char * help8 ; const char * help9 ; const char * help10; const char * help11; const char * help12; const char * help13; help1 = gettext( "\ usage: zuluCrypt-cli < operation > < options specific to the operation >\n\ meaning of symbols:\n\ <> = required option\n\ [] = optional argument\n\ * = default option\n\ | = alternatives for the same option\n\ {} = not allowed option\n\ \n\ zuluCrypt-cli -E \n\ zuluCrypt-cli -D \n\ zuluCrypt-cli -o [-e] \n\ zuluCrypt-cli -O {-m} [-e] \n" ) ; help2 = gettext( "\ zuluCrypt-cli -q \n\ zuluCrypt-cli -i \n\ zuluCrypt-cli -c [ktzg]\n\ zuluCrypt-cli -r \n\ zuluCrypt-cli -a < >|\n\ zuluCrypt-cli -b \n\ zuluCrypt-cli -w d argument must be something like: UUID=\"2468d6a7-9a71-4312-8bd9-662f982fade5\" ( or without quotes )\n\ zuluCrypt-cli -P d device must be mapper path at /dev/mapper/\n\ zuluCrypt-cli -X \n\ zuluCrypt-cli -J \n" ) ; help3 = gettext( "\ zuluCrypt-cli -R \n\ zuluCrypt-cli -B \n\ zuluCrypt-cli -A\n\ zuluCrypt-cli -S\n\ zuluCrypt-cli -N\n\ examples:\n\ create volume: zuluCrypt-cli -c -d /dev/sdc1 -z ext4 -t luks -p xxx\n\ open volume : zuluCrypt-cli -o -d /dev/sdc1 -m sdc1 -e ro -p xxx\n\ close volume ; zuluCrypt-cli -q -d /dev/sdc1\n\ remove key ; zuluCrypt-cli -r -d /dev/sdc1 -p xxx\n\ add key : zuluCrypt-cli -a -d /dev/sdc1 -y xxx -l yyy\n" ) ; help4 = gettext( "\ get device path from mapper : zuluCrypt-cli -P -d /dev/mapper/zuluCrypt-sdc1\n\ check if partition with UUID is present : zuluCrypt-cli -w -d UUID=\"d2d210b8-0b1f-419f-9172-9d509ea9af0c\"\n\ operation list\n\n\ --test run a test program\n\ -c create an encrypted volume\n\ -o open and encrypted volume\n\ -O open an encrypted volume but do not mount it( -m therefore not needed )\n\ -q close an opened encrypted volume\n\ -r remove a key from luks volume\n" ) ; help5 = gettext( "\ -i check if a device contain a luks volume\n\ -s check if a device is opened and print its properties if it is\n\ -b show status of each slot of luks volume.\"0\"=empty,\"1\"=occupied,\"2\"=invalid slot,\"3\"=last occupied\n\ -A print the list of all partitions on the system\n\ -N print a list of non system partitions on the system( partitions with no active entries in /etc/fstab and /etc/crypttab\n" ) ; help6 = gettext( "\ -T print a detailed list of mounted partitions.Must be used with -A or -S or -N\n\ -Z print a detailed list of unmounted partitions.Must be used with -A or -S or -N\n\ -S print a list of system partitions on the system( partitions with active entries in /etc/fstab and /etc/crypttab\n\ -w check if UUID matches UUID of any partition\n\ -P get device path from mapper( located at /dev/mapper )\n" ) ; help7 = gettext( "\ -L print a list of all opened volumes and their mount point.The list is not formatted\n\ -X open a device pointed by argument -d and write random data to it hiding data previously written to device\n\ -W check if a device is a truecrypt device or not,required argument are -p or -f\n\ -U print UUID of a given device,required argument: -d\n\ -H compare a header on a luks device to a backup header,required arg: -d and -f\n" ) ; help8 = gettext( "\ -M create a publicly accessible \"mirror\" of the mount point in \"/run/media/public/\" from the original\n\ created in \"/run/media/private/$USER/\"\n\ -a add a key to luks volume\n\ -F path to truecrypt multiple keyfiles.Keyfiles are separated by \":\" character\n" ) ; help9 = gettext( "\ -J create a plain mapper owned by the user who run the command on a device pointed by argument -d\n\ -B create a luks or truecrypt header backup\n\ -R restore a luks or truecrypt header on a device from backup\n\ \n\ options that goes with above operations:\n\ -G module name to use to get a passphrase to open a volume\n " ) ; help10 = gettext( "\ -k do not ask for confirmation when doing dangerous operations\n\ -d path to a file or partition with encrypted volume\n\ -m path component to be added to mount point prefix(/run/media/private/$USER)\n\ -z file system type installed(ext2,ext3,ext4* etc)\n\ -t type of volume (plain/luks*/tcrypt/vcrypt)\n\ -g options to use when creating a volume,see man page for more info\n\ -h get passphrase interactively\n\ -p passphrase \n" ) ; help11 = gettext( "\ -f path to keyfile or luks header backup\n\ -y passphrase already in the volume(required by -a if -u is absent and -h is also absent)\n\ -n path to keyfile with a passphrase to be added (required by -a if -l is absent and -h is also absent)\n" ); help12 = gettext( "\ -u path to keyfile with passphrase already in the volume(required by -a if -y is absent and -h is also absent)\n\ truecrypt hidden volume passphrase from keyfile when used with -c\n\ -l passphrase to be added(required by -a if -n is absent and -h is also absent)\n\ truecrypt hidden volume passphrase when used with -c\n" ) ; help13 = gettext( "\ -e mode for opening volumes(ro*/rw) when used with -o/-O. path to destination file when used with -E/-D\n\ -e mode for managing a truecrypt header when used with -B/-R.Options can be \"fde\" for volumes that use whole disk\n\ encryption,\"sys\" for a windows system volume.The volume is assumed to be a normal one when the option is not set\n" ) ; printf( "%s%s%s%s%s%s%s%s%s%s%s%s%s\n",help1,help2,help3,help4,help5,help6,help7,help8,help9,help10,help11,help12,help13 ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/includes.h000066400000000000000000000172001425361753700210720ustar00rootroot00000000000000 /* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ZULUCRYPT_BIN #define ZULUCRYPT_BIN #define STRING_MEMORY_HACK 1 #include "../utility/string/String.h" #include "../utility/string/StringList.h" #include "../constants.h" #include "../lib/libzuluCrypt.h" #include "../utility/socket/socket.h" #include "../utility/process/process.h" #include "libzuluCrypt-exe.h" #include "security.h" #include "locale_path.h" #include "../lib/includes.h" typedef struct{ int iteration_count ; string_t type ; }tvcrypt ; /* * these two defines are used in save_and_restore_volume_header.c */ #define VOLUME_HEADER_RESTORE 1 #define VOLUME_HEADER_SAVE 0 /* * These functions are here and not in libzuluCrypt-exe.h because they use string_t and the type is not supposed to be * seen in public API */ /* * global_variable_user_uid global variable is defined in security.c */ extern uid_t global_variable_user_uid ; /* * zuluCryptTrueCryptVeraCryptVolumeInfo() is defined in open_volume.c */ void zuluCryptTrueCryptVeraCryptVolumeInfo( const char * type,tvcrypt * e ) ; /* * this function is defined in security.c */ int zuluCryptSecurityConvertUID( uid_t uid,const char * u_id ) ; /* * this function is defined in volumes.c */ int zuluCryptVolumeIsInSystemVolumeList( const char * device ) ; /* * this function is defined in path_access.c */ void zuluCryptPrepareSocketPath( uid_t uid ) ; /* * this function is defined in open_volume.c */ stringList_t zuluCryptCreateKeyFiles( const char * const * list,int s ) ; /* * this function is defined in save_and_restore_volume_header.c */ stringList_t veraCryptVolumePIMValue( info_t * s,const char * type ) ; /* * this function is defined in open_volume.c */ void zuluCryptDeleteKeyFiles( stringList_t stl ) ; /* * this function is defined in module_system.c * It gets a passphrase from a .so file as a plugin. */ string_t GetKeyFromModule( const char * path,uid_t ) ; /* * this function is defined in get_key_from_socket.c */ void zuluCryptGetKeyFromSocket( const char * path,string_t *,uid_t uid ) ; /* * this function returns "$HOME/" and is defined in ../pluginManager/zuluCryptPluginManager.c */ string_t zuluCryptGetUserHomePath( uid_t ) ; /* * this function is defined in volumes.c */ int zuluCryptPartitionIsSystemPartition( const char * dev,uid_t uid ) ; /* * this function is defined in is_luks.c */ int zuluCryptVolumeIsNotLuks( const char * dev ) ; /* * this function is defined in volumes.c */ int zuluCryptPrintDeviceProperties( int type ) ; /* * this function is defined in volumes.c */ const char * zuluCryptVolumeType( blkid_probe blkid,const char * device ) ; /* * this function is defined in security.c */ int zuluCryptSecurityCheckPartitionPermissions( uid_t uid ) ; /* * this function is defined in volumes.c */ char * zuluCryptDeviceFromLabel( const char * label ) ; /* * this function is defined in security.c */ int zuluCryptSecurityPathIsValid( const char * path,uid_t uid ) ; /* * this function is defined in get_opts.c */ void zuluCryptEXEGetOptsSetDefault( struct_opts * stopts ) ; /* * this function is defined in mount_flags.c */ int zuluCryptMountFlagsAreNotCorrect( const char * mode,uid_t uid,unsigned long * flags ) ; /* * this function is defined in security.c */ int zuluCryptSecurityGainElevatedPrivileges( void ) ; /* * this function is defined in security.c */ int zuluCryptSecurityDropElevatedPrivileges( void ) ; /* * this function is defined in security.c */ string_t zuluCryptSecurityGetFileSystemFromDevice( const char * path ) ; /* * this function is defined in real_path.c */ int zuluCryptPathStartsWith( const char * path,const char * start ) ; /* * this function is defined in real_path.c */ int zuluCryptPathDoesNotStartsWith( const char * path,const char * start ) ; /* * this function is defined in mount_fs_options.c */ int zulucryptFileSystemIsNotSupported( const char * fs ) ; /* * this function is defined in ../lib/real_path.c */ char * zuluCryptRealPath( const char * path ) ; /* * this function is defined in clear_dead_mapper.c */ void zuluCryptClearDeadMappers( uid_t uid,int ) ; /* * this function is defined in clear_dead_mapper.c */ void zuluCryptDeleteDeadMountPoints( uid_t,stringList_t ) ; /* * this function is defined in save_and_restore_luks_header.c */ int zuluCryptHeaderMatchBackUpHeader( const char * device,const char * header_backup,uid_t uid ) ; /* * this function is defined in bind.c */ int zuluCryptBindUnmountVolume( stringList_t mountinfo,const char * device,uid_t uid ) ; /* * this function is defined in bind.c */ int zuluCryptBindMountVolume( const char * device,string_t,unsigned long flags ) ; /* * this function is defined in bind.c */ int zuluCryptBindSharedMountPointPathTaken( string_t path ) ; /* * this function is defined in ../pluginManager/zuluCryptPluginManager.c */ string_t zuluCryptPluginManagerGetKeyFromModule( const char * device, const char * name, const char * uuid, uid_t uid, const struct_opts * opts, const char * run_path, int * r ) ; /* * this function is defined in volumes.c */ stringList_t zuluCryptGetPartitionFromCrypttab( void ) ; /* * this function is defined in volumes.c */ stringList_t zuluCryptGetPartitionFromConfigFile( const char * path ) ; /* * this function is defined in volumes.c */ stringList_t zuluCryptPartitionList( void ) ; /* * this function is defined in create_mount_point.c */ string_t zuluCryptCreateMountPoint( const char * device,const char * m_point,const char * m_opts,uid_t uid ) ; /* * this function is defined in create_mount_point.c */ void zuluCryptCreateMountPointPrefix( uid_t uid ) ; /* * zuluCryptCreateMountPath() is defined in create_mount_point.c */ void zuluCryptCreateMountPath( const char * path ) ; /* * this function is defined in create_mount_point.c */ int zuluCryptMountPointPrefixMatch( const char * path,uid_t uid,string_t * m_point ) ; /* * this function is defined in path_access.c */ int zuluCryptGetPassFromFile( int * socket_path,const char * path,uid_t uid,string_t * st ) ; /* * this function is defined in path_access.c */ char * zuluCryptUUIDFromPath( const char * device ) ; /* * this function is defined in path_access.c */ char * zuluCryptEvaluateDeviceTags( const char * tag,const char * path ) ; /* * zuluCryptRunTest() is defined in test.c */ int zuluCryptRunTest( void ) ; /* * zuluCryptDeviceIsSupported() is defined in volumes.c */ int zuluCryptDeviceIsSupported( const char * device,uid_t uid ) ; /* * zuluCryptPartitions() is defined in volumes.c */ stringList_t zuluCryptPartitions( int option,uid_t uid ) ; /* * zuluCryptGetVolumeSize() is defined in volumes.c */ u_int64_t zuluCryptGetVolumeSize( const char * device ) ; /* * zuluCryptGetAListOfAllPartitions() is defined in volumes.c */ stringList_t zuluCryptGetAListOfAllVolumes( void ) ; /* * zuluCryptReuseMountPoint() is defined in create_mount_point.c */ int zuluCryptReuseMountPoint( void ) ; #endif zuluCrypt-6.2.0/zuluCrypt-cli/bin/libzuluCrypt-exe.h000066400000000000000000000143031425361753700225540ustar00rootroot00000000000000 /* * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ZULUCRYPTEXE #define ZULUCRYPTEXE #ifdef __cplusplus extern "C" { #endif #include #define TRUECRYPT_MAX_KEYFILES 16 /* * this structure holds command line arguments. * * It is instantiated in main.c * */ typedef struct struct_opts_1{ const char * plugin_path ; const char * device ; const char * mount_point ; const char * m_opts ; const char * fs_opts ; const char * key_source ; const char * key ; const char * fs ; const char * type ; const char * rng ; const char * existing_key_source ; const char * existing_key ; const char * new_key ; const char * new_key_source ; const char * argv ; const char * tcrypt_hidden_volume_size ; const char * tcrypt_hidden_volume_key ; const char * tcrypt_hidden_volume_multiple_keyfiles[ TRUECRYPT_MAX_KEYFILES + 1 ] ; const char * tcrypt_multiple_keyfiles[ TRUECRYPT_MAX_KEYFILES + 1 ] ; const char * back_up_file_path ; const char * offset ; const char * uid ; const char * luks_external_header ; const char ** env ; char action ; int luks_slot_number ; int partition_number ; int ask_confirmation ; int open_mount ; int mount_point_option ; int print_partition_type ; int share ; int use_cryptsetup_for_bitlocker ; }struct_opts; /* * this function is defined in security.c */ void zuluCryptExeSetOriginalUID( uid_t s ) ; /* * this function is defined in security.c */ int zuluCryptExeOriginalUserIsNotRoot() ; /* * get command line arguments and in struct_opts structure to be used in various calls * */ void zuluCryptEXEGetOpts( int argc,char * argv[],struct_opts * ) ; /* * this function is responsibe for creating and restoring luks header. * * the function is defined in save_and_restore_luks_header.c */ int zuluCryptEXESaveAndRestoreVolumeHeader( const struct_opts * opts,uid_t uid,int option ) ; /* * this function is responsibe for printing information about an opened volume. * It is defined in volume_info.c */ int zuluCryptEXEVolumeInfo( const char * mapper,const char * device,uid_t ) ; /* * this function is responsibe for closing an opened volume. * It is defined in close_volume.c */ int zuluCryptEXECloseVolume( const char * device,const char * mapping_name,uid_t ) ; /* * this function is responsibe for opening volumes. * It is defined in open_volume.c * */ int zuluCryptEXEOpenVolume( const struct_opts *,const char * mapping_name,uid_t uid ) ; /* * this function is responsibe for creating volumes. * It is defined in create_volume.c */ int zuluCryptEXECreateVolume( const struct_opts *,const char * mapping_name,uid_t uid ) ; /* * this function is responsibe for adding keys to luks volumes. * It is defined in add_key.c */ int zuluCryptEXEAddKey( const struct_opts *,uid_t ) ; /* * this function is responsibe for removing keys from luks files. * It is defined in remove_key.c */ int zuluCryptEXERemoveKey( const struct_opts *,uid_t ) ; /* * this function is responsibe for checking if a path exist or not. * It is defined in ../lib/is_path_valid.c */ int zuluCryptIsPathValid( const char * path ) ; /* * this function checks if a user who started the tool has writing access to a file or device they want this tool to * write to. * It is defined in path_access.c */ int zuluCryptCanOpenPathForWriting( const char * path,uid_t uid ) ; /* * this function checks if a user who started the tool has reading access to a file or device they want this tool to * read from. * It is defined in path_access.c */ int zuluCryptCanOpenPathForReading( const char * path,uid_t uid ) ; /* * check if the volume has atleast one corrupted key slot */ void zuluCryptCheckInvalidKey( const char * device ) ; /* * this function checks if a device is a system partition or not. * * the function is defined in partitions.c * */ int zuluCryptCheckIfPartitionIsSystemPartition( const char * device ) ; /* * defined in crypt_file.c */ int zuluCryptExeFileEncrypt( const struct_opts *,uid_t uid ) ; /* * defined in crypt_file.c */ int zuluCryptExeFileDecrypt( const struct_opts *,uid_t uid ) ; /* * defined in check_opened_mapper.c * * the function checks to see if the argument mapper has an entry in crypt_get_dir(). * * the function is used to prevent performing operations like creating a volume on devices with mapper open. */ int zuluCryptCheckOpenedMapper( const char * mapper ) ; /* * check if a device with a path "path" as an entry in /etc/mtab. * * defined in process_mountinfo.c */ int zuluCryptCheckIfMounted( const char * path ) ; /* * function defined at write_device_with_junk.c */ int zuluCryptEXEWriteDeviceWithJunk( const struct_opts * opts,const char * mapping_name,uid_t uid ) ; /* * function defined at write_device_with_junk.c */ int zuluCryptEXEOpenPlainAsMe(const struct_opts * opts,const char * mapping_name,uid_t uid ) ; /* * defined in lib/status.c * remember to free() the return value when done with it * */ char * zuluCryptVolumeDeviceName( const char * ) ; /* * defined at help.c * */ void zuluCryptEXEHelp( void ) ; /* * defined at partitions.c */ int zuluCryptCheckSystemTools( void ) ; /* * defined in partitions.c * remember to free() the return value when done with it * */ char * zuluCryptDeviceFromUUID( const char * uuid ) ; /* * defined in partitions.c */ int zuluCryptPrintPartitions( int option,int info,uid_t uid ) ; /* * defined at process_mountinfo.c * remember to free() a returned pointer when done with it. */ char * zuluCryptGetMountPointFromPath( const char * path ) ; #ifdef __cplusplus } #endif #endif zuluCrypt-6.2.0/zuluCrypt-cli/bin/main.c000066400000000000000000000457541425361753700202220ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include "../lib/libzuluCrypt.h" #include #include #include #include #include #include #include #include #include static void _seteuid( uid_t uid ) { if( seteuid( uid ) ){;} } static void _setuid( uid_t uid ) { if( setuid( uid ) ){;} } static int zuluCryptEXEGetDevice( const char * device ) { /* * zuluCryptVolumeDeviceName() is defined in ../lib/status.c */ char * c = NULL ; int st = 1 ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptVolumeDeviceName() is defined in ../lib/status.c */ c = zuluCryptVolumeDeviceName( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( c == NULL ){ printf( gettext( "ERROR: Could not get device address from mapper address\n" ) ) ; st = 1 ; }else{ printf( "%s\n",c ) ; StringFree( c ) ; st = 0 ; } return st ; } static int zuluCryptEXECheckIfLuks( const char * device ) { int status ; char * e ; zuluCryptSecurityGainElevatedPrivileges() ; /* * this zuluCryptVolumeIsLuks() is defined in ../lib/is_luks.c */ status = zuluCryptVolumeIsLuks( device ) ; /* * zuluCryptUUIDFromPath_1() is defined in ../lib/blkid_evaluate_tag.c */ e = zuluCryptUUIDFromPath_1( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( status ){ printf( gettext( "Device is a luks volume\n" ) ) ; if( e ){ printf( "%s %s\n",gettext( "Its UUID is:" ),e ) ; } }else{ printf( gettext( "Device is not a luks volume\n" ) ) ; } StringFree( e ) ; return status ; } static int zuluCryptEXECheckIfTcrypt( struct_opts * clargs,uid_t uid ) { string_t st_key = StringVoid ; const char * device = clargs->device ; const char * key = clargs->key ; const char * source = clargs->key_source ; size_t key_len ; int st = 1 ; if( key == NULL ){ printf( gettext( "ERROR: Key argument is missing\n" ) ) ; return 1 ; } if( source == NULL ){ printf( gettext( "ERROR: Key source argument is missing\n" ) ) ; return 1 ; } if( StringsAreEqual( source,"-p" ) ){ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptGetVolumeType() is defined in ../lib/volume_type.c */ if( zuluCryptGetVolumeType( device,key,strlen( key ) ) == 2 ){ printf( gettext( "\"%s\" is a tcrypt device\n" ),device ) ; st = 0 ; } zuluCryptSecurityDropElevatedPrivileges() ; }else if( StringsAreEqual( source,"-f" ) ){ /* * zuluCryptGetPassFromFile() is defined in path_access.c */ if( zuluCryptGetPassFromFile( NULL,key,uid,&st_key ) == 0 ){ key = StringContent( st_key ) ; key_len = StringLength( st_key ) ; zuluCryptSecurityGainElevatedPrivileges() ; if( zuluCryptGetVolumeType( device,key,key_len ) == 2 ){ printf( gettext( "\"%s\" is a tcrypt device\n" ),device ) ; st = 0 ; }else{ printf( gettext( "\"%s\" is a not tcrypt device\n" ),device ) ; st = 1 ; } StringDelete( &st_key ) ; zuluCryptSecurityDropElevatedPrivileges() ; }else{ printf( gettext( "\"%s\" is not a tcrypt device\n"),device ) ; st = 1 ; } }else{ /* * shouldnt get here */ printf( gettext( "\"%s\" is not a tcrypt device\n" ),device ) ; st = 1 ; } return st ; } static int zuluCryptEXECheckEmptySlots( const char * device ) { int status ; char * c ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptEmptySlots() is defined in ../lib/empty_slots.c */ c = zuluCryptEmptySlots( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( c == NULL ){ printf( gettext( "Device \"%s\" is not a luks device\n" ),device ) ; status = 2 ; }else{ printf( "%s\n",c ) ; status = 0 ; free( c ) ; } return status ; } static int zuluCryptEXEPrintSlotStatus( const char * device ) { int status ; char * c ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptEmptySlots() is defined in ../lib/empty_slots.c */ c = zuluCryptSlotsStatus( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( c == NULL ){ printf( gettext( "Device \"%s\" is not a luks device\n" ),device ) ; status = 2 ; }else{ printf( "%s",c ) ; status = 0 ; free( c ) ; } return status ; } static int zuluCryptEXECheckUUID( const char * device ) { printf( "%s\n",device ) ; return 0 ; } static int zuluCryptEXEHeaderMatchBackUpHeader( const char * device,const char * header_backup,uid_t uid ) { /* * zuluCryptPartitionIsSystemPartition() is defined in partitions.c */ int r = zuluCryptPartitionIsSystemPartition( device,uid ) ; if( r == 1 ){ if( uid != 0 || !zuluCryptUserIsAMemberOfAGroup( uid,"zulucrypt" ) ){ printf( gettext( "ERROR: Insufficient privilges to operate on a system device\n" ) ) ; return 1 ; } } /* * zuluCryptHeaderMatchBackUpHeader() is defined in save_and_restore_luks_header.c */ r = zuluCryptHeaderMatchBackUpHeader( device,header_backup,uid ) ; if( r ){ printf( gettext( "Header backup match the one on the device\n" ) ) ; return 0 ; }else{ printf( gettext( "Header backup does not match the one on the device\n" ) ) ; return 1 ; } } static int zuluCryptEXE( struct_opts * clargs,const char * mapping_name,uid_t uid ) { switch( clargs->action ){ case 'H' : return zuluCryptEXEHeaderMatchBackUpHeader( clargs->device,clargs->key,uid ) ; case 'W' : return zuluCryptEXECheckIfTcrypt( clargs,uid ) ; case 'B' : return zuluCryptEXESaveAndRestoreVolumeHeader( clargs,uid,VOLUME_HEADER_SAVE ) ; case 'R' : return zuluCryptEXESaveAndRestoreVolumeHeader( clargs,uid,VOLUME_HEADER_RESTORE ) ; case 'J' : return zuluCryptEXEOpenPlainAsMe( clargs,mapping_name,uid ) ; /* function is defined in write_device_with_junk.c */ case 'X' : return zuluCryptEXEWriteDeviceWithJunk( clargs,mapping_name,uid ) ; case 'w' : return zuluCryptEXECheckUUID( clargs->device ) ; case 'b' : return zuluCryptEXECheckEmptySlots( clargs->device ) ; case '2' : return zuluCryptEXEPrintSlotStatus( clargs->device ) ; case 'i' : return zuluCryptEXECheckIfLuks( clargs->device ) ; case 'P' : return zuluCryptEXEGetDevice( clargs->device ) ; case 's' : return zuluCryptEXEVolumeInfo( mapping_name,clargs->device,uid ) ; case 'q' : return zuluCryptEXECloseVolume( clargs->device,mapping_name,uid ) ; case 'o' : return zuluCryptEXEOpenVolume( clargs,mapping_name,uid ) ; case 'O' : return zuluCryptEXEOpenVolume( clargs,mapping_name,uid ) ; case 'c' : return zuluCryptEXECreateVolume( clargs,mapping_name,uid ) ; case 'a' : return zuluCryptEXEAddKey( clargs,uid ) ; case 'r' : return zuluCryptEXERemoveKey( clargs,uid ); case 'E' : return zuluCryptExeFileEncrypt( clargs,uid ) ; case 'D' : return zuluCryptExeFileDecrypt( clargs,uid ) ; } printf( gettext( "ERROR!!!!!!!!!!: cli option missed!\n" ) ) ; return 200 ; /* shouldnt get here */ } static int zuluExit( int st,stringList_t stl,stringList_t stx,const char ** env,const char * msg ) { zuluCryptSecurityUnlockMemory( stl ) ; StringListClearDelete( &stl ) ; StringListDelete( &stx ) ; if( env != NULL ){ StringFree( env ) ; } if( msg != NULL ){ printf( "%s\n",msg ) ; } return st ; } static void ExitOnMemoryExaustion( void ) { printf( gettext( "Unexpected exiting because you have run out of memory\n" ) ) ; exit( 1 ) ; } static int _print_uuid_from_path( const char * device ) { /* * zuluCryptSecurityUUIDFromPath() is defined in path_access.c */ char * e = zuluCryptUUIDFromPath( device ) ; if( e == NULL ){ puts( "UUID=\"Nil\"" ) ; return 1 ; }else{ printf( "UUID=\"%s\"\n",e ) ; StringFree( e ) ; return 0 ; } } static void _privilegeEvelationError( const char * msg ) { perror( msg ) ; exit( 255 ) ; } static void _forceTerminateOnSeriousError( int sig ) { if( sig ){;} puts( "SIGSEGV caught,exiting" ) ; exit( 255 ) ; } static int _clear_dead_mappers( uid_t uid ) { /* * zuluCryptClearDeadMappers() is defined in ../zuluCrypt-cli/bin/clear_dead_mappers.c */ zuluCryptClearDeadMappers( uid,0 ) ; return 0 ; } static int _printOpenedVolumes( uid_t uid ) { /* * zuluCryptOpenedVolumesList() is defined in ../lib/process_mountinfo.c */ stringList_t stl ; zuluCryptSecurityGainElevatedPrivileges() ; stl = zuluCryptOpenedVolumesList( uid ) ; zuluCryptSecurityDropElevatedPrivileges() ; StringListPrintList( stl ) ; StringListDelete( &stl ) ; return 0 ; } int main( int argc,char * argv[] ) { int fd1 = -1 ; int fd = -1; const char * device ; const char * mapping_name ; char * ac ; char * ac_1 ; char * dev ; char action ; int st ; const char ** env = NULL ; ssize_t i ; string_t q = StringVoid ; stringList_t stl = StringListVoid ; stringList_t stx = StringListVoid ; struct_opts clargs ; uid_t uid = getuid() ; gid_t gid = uid ; struct sigaction sa ; memset( &sa,'\0',sizeof( struct sigaction ) ) ; sa.sa_handler = _forceTerminateOnSeriousError ; sigaction( SIGSEGV,&sa,NULL ) ; if( argc == 1 ){ zuluCryptEXEHelp(); return 1; } if( argc == 2 ){ ac = argv[ 1 ] ; if( StringAtLeastOneMatch_1( ac,"-h","--help","-help",NULL ) ){ zuluCryptEXEHelp(); return 0 ; } if( StringAtLeastOneMatch_1( ac,"-v","-version","--version",NULL ) ){ printf( "%s\n",zuluCryptVersion() ); return 0 ; } if( StringsAreEqual( ac,"--clear-dead-mount-points" ) ){ zuluCryptClearDeadMappers( uid,1 ) ; return 0 ; } } zuluCryptExeSetOriginalUID( uid ) ; /* * zuluCryptDisableMetadataLocking() is defined in ../lib/create_luks.c */ zuluCryptDisableMetadataLocking() ; if( argc >= 2 && StringsAreEqual( argv[ 1 ],"--test" ) ){ /* * zuluCryptRunTest() is defined in test.c */ return zuluCryptRunTest() ; } /* * setgroups() requires seteuid(0) ; */ _seteuid( 0 ) ; if( setgroups( 1,&gid ) != 0 ){ _privilegeEvelationError( gettext( "ERROR: setgroups() failed" ) ) ; } if( setegid( uid ) != 0 ){ _privilegeEvelationError( gettext( "ERROR: setegid() failed" ) ) ; } setlocale( LC_ALL,"" ); bindtextdomain( "zuluCrypt-cli",TRANSLATION_PATH ) ; textdomain( "zuluCrypt-cli" ) ; memset( &clargs,'\0',sizeof( struct_opts ) ) ; /* * zuluCryptEXEGetOpts() is defined in ./get_opts.c */ zuluCryptEXEGetOpts( argc,argv,&clargs ) ; /* * zuluCryptSecurityConvertUID() is defined in security.c */ st = zuluCryptSecurityConvertUID( uid,clargs.uid ) ; if( st == -1 ){ printf( gettext( "User is not root\n" ) ) ; return 114 ; }else{ uid = (uid_t)st ; } /* * Run with higher priority to speed things up */ setpriority( PRIO_PROCESS,0,-15 ) ; _setuid( 0 ) ; _seteuid( uid ) ; /* * zuluCryptSetUserUIDForPrivilegeManagement() is defined in ./security.c */ zuluCryptSetUserUIDForPrivilegeManagement( uid ) ; /* * zuluCryptSecuritySetPrivilegeElevationErrorFunction() is defined in ./security.c * _privilegeEvelationError() function will be called when functions that elevate or drop privilges fail */ zuluCryptSecuritySetPrivilegeElevationErrorFunction( _privilegeEvelationError ) ; StringExitOnMemoryExaustion( ExitOnMemoryExaustion ) ; StringListExitOnMemoryExaustion( ExitOnMemoryExaustion ) ; ProcessExitOnMemoryExaustion( ExitOnMemoryExaustion ) ; SocketExitOnMemoryExaustion( ExitOnMemoryExaustion ) ; /* * zuluCryptSecurityDropElevatedPrivileges() is defined in ./security.c */ zuluCryptSecurityDropElevatedPrivileges() ; /* * this object is used as a form of memory management.It collects all string objects to make them easily deletable * at the end of the function and allows a function to have easily managebale multiple exit points. */ stl = StringListInit() ; /* * zuluCryptSecuritySanitizeTheEnvironment() is defined in ./security.c */ zuluCryptSecuritySanitizeTheEnvironment( uid,&stx ) ; /* * clargs.env contains a copy of the inherited environment because the above function clears it because we dont need it. * The copy will ultimately be passed to a plugin architecture system just in case a plugin needs it. * * The plugin system is managed by code in ../pluginManager/zuluCryptPluginManager.c * */ clargs.env = env = StringListStringArray( stx ) ; q = StringListAssignString( stl,String( "" ) ) ; if( argc > 0 ){ while( *argv ){ StringMultipleAppend( q,*argv," ",NULL ) ; argv++ ; } StringSubChar( q,StringLength( q ) - 1,'\0' ) ; } clargs.argv = StringListContentAtFirstPlace( stl ) ; /* * Hide "sensitive" command line arguments from ps comamnd and related tools. * Best way to pass keys to zuluCrypt-cli is to use libzuluCryptPluginManager API */ #define hide( z ) strncpy( ( char * )z,"x",StringLength( q ) ) if( clargs.key != NULL ){ q = StringListAssignString( stl,String( clargs.key ) ) ; hide( clargs.key ) ; clargs.key = StringContent( q ) ; } if( clargs.new_key != NULL ){ q = StringListAssignString( stl,String( clargs.new_key ) ) ; hide( clargs.new_key ) ; clargs.new_key = StringContent( q ) ; clargs.tcrypt_hidden_volume_key = clargs.new_key ; } if( clargs.existing_key != NULL ){ q = StringListAssignString( stl,String( clargs.existing_key ) ) ; hide( clargs.existing_key ) ; clargs.existing_key = StringContent( q ) ; } if( clargs.device != NULL ){ q = StringListAssignString( stl,String( clargs.device ) ) ; hide( clargs.device ) ; clargs.device = StringContent( q ) ; } if( clargs.type != NULL ){ q = StringListAssignString( stl,String( clargs.type ) ) ; hide( clargs.type ) ; clargs.type = StringContent( q ) ; } if( clargs.rng != NULL ){ q = StringListAssignString( stl,String( clargs.rng ) ) ; hide( clargs.rng ) ; clargs.rng = StringContent( q ) ; } for( i = 0 ; clargs.tcrypt_multiple_keyfiles[ i ] != NULL ; i++ ){ q = StringListAssignString( stl,String( clargs.tcrypt_multiple_keyfiles[ i ] ) ) ; hide( clargs.tcrypt_multiple_keyfiles[ i ] ) ; clargs.tcrypt_multiple_keyfiles[ i ] = StringContent( q ) ; } for( i = 0 ; clargs.tcrypt_hidden_volume_multiple_keyfiles[ i ] != NULL ; i++ ){ q = StringListAssignString( stl,String( clargs.tcrypt_hidden_volume_multiple_keyfiles[ i ] ) ) ; hide( clargs.tcrypt_hidden_volume_multiple_keyfiles[ i ] ) ; clargs.tcrypt_hidden_volume_multiple_keyfiles[ i ] = StringContent( q ) ; } zuluCryptSecurityLockMemory( stl ) ; action = clargs.action ; device = clargs.device ; if( action == 'C' ){ return zuluExit( _clear_dead_mappers( uid ),stl,stx,env,NULL ) ; }else{ _clear_dead_mappers( uid ) ; } /* * below tests are here because they do not use -d option * * zuluCryptPrintPartitions() function is defined in volumes.c * zuluCryptSecurityCheckPartitionPermissions() is defined in security.c */ switch( action ){ case 'A': case 'N': case 'S': st = zuluCryptPrintPartitions( clargs.partition_number,clargs.print_partition_type,uid ) ; return zuluExit( st,stl,stx,env,NULL ) ; case 'L': st = _printOpenedVolumes( uid ) ; return zuluExit( st,stl,stx,env,NULL ) ; } if( action == '\0' ){ return zuluExit( 130,stl,stx,env,gettext( "ERROR: \"action\" argument is missing" ) ) ; } if( device == NULL ){ return zuluExit( 120,stl,stx,env,gettext( "ERROR: Required option( device path ) is missing for this operation" ) ) ; } if( action == 'U' ){ st = _print_uuid_from_path( device ) ; return zuluExit( st,stl,stx,env,NULL ) ; } if( StringPrefixEqual( device,"UUID=" ) ){ q = String( device ) ; StringRemoveString( q,"\"" ) ; StringSubChar( q,4,'-' ) ; mapping_name = StringContent( q ) ; /* * zuluCryptEvaluateDeviceTags() is defined in path_access.c */ ac = zuluCryptEvaluateDeviceTags( "UUID",mapping_name + 5 ) ; if( ac != NULL ) { clargs.device = ac ; st = zuluCryptEXE( &clargs,mapping_name,uid ) ; StringFree( ac ) ; StringDelete( &q ) ; return zuluExit( st,stl,stx,env,NULL ) ; }else{ StringDelete( &q ) ; return zuluExit( 110,stl,stx,env,gettext( "ERROR: Could not find any partition with the presented UUID" ) ) ; } }else{ /* * this function is defined in ../zuluCrypt-lib/file_path_security.c */ switch( zuluCryptGetDeviceFileProperties( device,&fd,&fd1,&dev,uid ) ){ case 0 : break ; case 1 : return zuluExit( 111,stl,stx,env,gettext( "ERROR: Devices in /dev/shm/ path is not suppored" ) ) ; case 2 : return zuluExit( 112,stl,stx,env,gettext( "ERROR: Given path is a directory" ) ) ; case 3 : return zuluExit( 113,stl,stx,env,gettext( "ERROR: A file can have only one hard link" ) ) ; case 4 : return zuluExit( 113,stl,stx,env,gettext( "ERROR: Insufficient privilges to access the device" ) ) ; default: return zuluExit( 113,stl,stx,env,gettext( "ERROR: A non supported device encountered,device is missing or permission denied\n\ Possible reasons for getting the error are:\n1.Device path is invalid.\n2.The device has LVM or MDRAID signature" ) ) ; } if( dev == NULL ){ if( fd1 != -1 ){ close( fd1 ) ; } if( fd != -1 ){ close( fd ) ; } return zuluExit( 114,stl,stx,env,gettext( "ERROR: Could not resolve path to device" ) ) ; }else{ q = String( "/dev/mapper/zuluCrypt-" ) ; StringAppendInt( q,uid ) ; StringAppend( q,"-" ) ; st = StringPrefixMatch( dev,StringContent( q ),StringLength( q ) ) ; StringDelete( &q ) ; if( st && clargs.action == 'P' ){ return zuluCryptEXEGetDevice( clargs.device ) ; } /* * zuluCryptDeviceIsSupported() is defined in partitions.c */ if( zuluCryptDeviceIsSupported( dev,uid ) ){ clargs.device = dev ; if( StringPrefixEqual( dev,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../zuluCrypt-cli/create_loop_device.c */ ac_1 = zuluCryptLoopDeviceAddress_1( dev ) ; i = StringLastIndexOfChar_1( ac_1,'/' ) ; if( i != -1 ){ mapping_name = ac_1 + i + 1 ; }else{ mapping_name = dev ; } st = zuluCryptEXE( &clargs,mapping_name,uid ) ; StringFree( ac_1 ) ; }else{ i = StringLastIndexOfChar_1( dev,'/' ) ; if( i != -1 ){ mapping_name = dev + i + 1 ; }else{ mapping_name = dev ; } st = zuluCryptEXE( &clargs,mapping_name,uid ) ; } }else{ st = 113 ; puts( gettext( "ERROR: A non supported device encountered,device is missing or permission denied\n\ Possible reasons for getting the error are:\n1.Device path is invalid.\n2.The device has LVM or MDRAID signature" ) ) ; } StringFree( dev ) ; if( fd1 != -1 ){ close( fd1 ) ; } if( fd != -1 ){ close( fd ) ; } return zuluExit( st,stl,stx,env,NULL ) ; } } } zuluCrypt-6.2.0/zuluCrypt-cli/bin/mount_flags.c000066400000000000000000000077031425361753700216040ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include #include "includes.h" #define MOUNT_WITH_NOEXEC_BY_DEFAULT 0 static int _user_has_no_access( uid_t uid ) { if( uid == 0 ){ return 0 ; }else{ /* * zuluCryptUserIsAMemberOfAGroup() is defined in security.c */ return !zuluCryptUserIsAMemberOfAGroup( uid,"zulumount" ) ; } } int zuluCryptMountFlagsAreNotCorrect( const char * mode,uid_t uid,unsigned long * flags ) { unsigned long flg = 0 ; if( mode == NULL ){ flg |= MS_NODEV | MS_NOSUID | MS_NOEXEC | MS_RELATIME ; *flags = flg ; return 0 ; } if( StringHasComponent( mode,"ro" ) ){ flg |= MS_RDONLY ; } if( StringHasComponent( mode,"dev" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } }else{ flg |= MS_NODEV ; } #if MOUNT_WITH_NOEXEC_BY_DEFAULT if( zuluCryptUserIsAMemberOfAGroup( uid,"zulumount-exec" ) ){ /* * user is a member of a group,mount volume with exec option by default */ if( StringHasComponent( mode,"noexec" ) ){ /* * user with access wish to mount a volume without it */ flg |= MS_NOEXEC ; } }else{ if( StringHasComponent( mode,"exec" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } }else{ flg |= MS_NOEXEC ; } } #else if( StringHasComponent( mode,"noexec" ) ){ /* * user with access wish to mount a volume without it */ flg |= MS_NOEXEC ; } #endif if( StringHasComponent( mode,"suid" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } }else{ flg |= MS_NOSUID ; } if( StringHasComponent( mode,"bind" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } flg |= MS_BIND ; } if( StringHasComponent( mode,"mandlock" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } flg |= MS_MANDLOCK ; } if( StringHasComponent( mode,"move" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } flg |= MS_MOVE ; } if( StringHasComponent( mode,"noatime" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } flg |= MS_NOATIME ; } if( StringHasComponent( mode,"strictatime" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } flg |= MS_STRICTATIME ; } if( flg & MS_NOATIME ){ /* * MS_NOATIME flag is set by user,use it instead of MS_RELATIME */ }else if( flg & MS_STRICTATIME ){ /* * MS_STRICTATIME flag is set by user,use it instead of MS_RELATIME */ }else{ /* * MS_NOATIME flag not set,autoset MS_RELATIME flag as the default flag */ flg |= MS_RELATIME ; } #if 0 /* * done check for this one since its a default option set above */ if( StringHasComponent( mode,"relatime" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } flg |= MS_RELATIME ; } #endif if( StringHasComponent( mode,"nodiratime" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } flg |= MS_NODIRATIME ; } if( StringHasComponent( mode,"remount" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } flg |= MS_REMOUNT ; } if( StringHasComponent( mode,"silent" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } flg |= MS_SILENT ; } if( StringHasComponent( mode,"synchronous" ) ){ if( _user_has_no_access( uid ) ){ return 1 ; } flg |= MS_SYNCHRONOUS ; } *flags = flg ; return 0 ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/open_volume.c000066400000000000000000000462251425361753700216200ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include #include #include #include #include stringList_t zuluCryptCreateKeyFiles( const char * const * list,int s ) { #define buffer_size 32 char buffer[ buffer_size ] ; const char * e ; int i ; stringList_t stz = StringListVoid ; string_t xt ; string_t zt ; for( i = 0 ; list[ i ] != NULL ; i++ ){ e = *( list + i ) ; zuluCryptSecurityDropElevatedPrivileges() ; /* * TrueCrypt only uses the first 1MB of keyfile. */ if( StringGetFromFile_3( &xt,e,0,1048576 ) == 0 ){ zuluCryptSecurityGainElevatedPrivileges() ; e = StringIntToString_1( buffer,buffer_size,(u_int64_t)i + (u_int64_t)s ) ; /* * zuluCryptCreateKeyFile_1() is defined in ../lib/open_tcrypt.c */ zt = zuluCryptCreateKeyFile_1( xt,e ) ; StringDelete( &xt ) ; StringListAppendString_1( &stz,&zt ) ; } } zuluCryptSecurityDropElevatedPrivileges() ; return stz ; } void zuluCryptDeleteKeyFiles( stringList_t stl ) { StringListIterator it ; StringListIterator end ; StringListGetIterators( stl,&it,&end ) ; zuluCryptSecurityGainElevatedPrivileges() ; while( it != end ){ /* * zuluCryptDeleteFile_1() is defined in ../lib/file_path_security.c */ zuluCryptDeleteFile_1( *it ) ; it++ ; } zuluCryptSecurityDropElevatedPrivileges() ; } static char * _device_path( const char * device ) { char * path ; if( StringPrefixEqual( device,"/dev/loop" ) ){ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptLoopDeviceAddress_1() is defined in ../zuluCrypt-cli/create_loop_device.c */ path = zuluCryptLoopDeviceAddress_1( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( path == NULL ){ return StringCopy_2( device ) ; }else{ return path ; } }else{ return StringCopy_2( device ) ; } } static void _printResult( const char * device,const char * m_point ) { char * e ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptGetVolumeTypeFromMapperPath() is defined in ../lib/status.c */ e = zuluCryptGetVolumeTypeFromMapperPath( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( StringHasComponent( e,"LUKS" ) ){ printf( gettext( "SUCCESS: %s volume opened successfully\n" ),"luks" ) ; }else if( StringHasComponent( e,"PLAIN" ) ){ printf( gettext( "SUCCESS: %s volume opened successfully\n" ),"plain" ) ; }else if( StringHasComponent( e,"TCRYPT" ) ){ printf( gettext( "SUCCESS: %s volume opened successfully\n" ),"tcrypt" ) ; }else if( StringHasComponent( e,"VCRYPT" ) ){ printf( gettext( "SUCCESS: %s volume opened successfully\n" ),"vcrypt" ) ; }else if( StringHasComponent( e,"BITLK" ) ){ printf( gettext( "SUCCESS: %s volume opened successfully\n" ),"bitlocker" ) ; }else{ printf( gettext( "SUCCESS: volume opened successfully\n" ) ) ; } StringFree( e ) ; if( m_point != NULL ){ printf( gettext( "volume mounted at: %s\n" ),m_point ) ; } } static int zuluExit( int st,const char * device,const char * m_point,stringList_t * stl ) { switch( st ){ case 0 : _printResult( device,m_point ) ; break ; case 1 : printf( gettext( "ERROR: Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed?\n" ) ) ;break ; case 2 : printf( gettext( "ERROR: There seem to be an open volume accociated with given address\n" ) ) ; break ; case 3 : printf( gettext( "ERROR: No file or device exist on given path\n" ) ) ; break ; case 4 : printf( gettext( "ERROR: Volume could not be opened with the presented key\n" ) ) ; break ; case 5 : printf( gettext( "ERROR: Insufficient privilege to mount the device with given options\n" ) ) ; break ; case 6 : printf( gettext( "ERROR: Insufficient privilege to open device in read write mode or device does not exist\n" ) ) ; break ; case 7 : printf( gettext( "ERROR: Only root user can perform this operation\n" ) ) ; break ; case 8 : printf( gettext( "ERROR: -O and -m options can not be used together\n" ) ) ; break ; case 9 : printf( gettext( "ERROR: Could not create mount point, invalid path or path already taken\n" ) ) ; break ; case 10: printf( gettext( "ERROR: Shared mount point path aleady taken\n" ) ) ; break ; case 11: printf( gettext( "ERROR: There seem to be an opened mapper associated with the device\n" ) ) ; break ; case 12: printf( gettext( "ERROR: Could not get a passphrase from the module\n" ) ) ; break ; case 13: printf( gettext( "ERROR: Could not get passphrase in silent mode\n" ) ); break ; case 14: printf( gettext( "ERROR: Insufficient memory to hold passphrase\n" ) ) ; break ; case 15: printf( gettext( "ERROR: One or more required argument(s) for this operation is missing\n" ) ) ; break ; case 16: printf( gettext( "ERROR: Invalid path to key file\n" ) ) ; break ; case 17: printf( gettext( "ERROR: Could not get enought memory to hold the key file\n" ) ) ; break ; case 18: printf( gettext( "ERROR: Insufficient privilege to open key file for reading\n" ) ); break ; case 19: printf( gettext( "ERROR: Could not get a passphrase through a local socket\n" ) ); break ; case 20: printf( gettext( "ERROR: Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered\n" ) );break ; case 21: printf( gettext( "ERROR: Could not create a lock on /etc/mtab\n" ) ) ; break ; case 22: printf( gettext( "ERROR: Insufficient privilege to open a system volume\n" ) ) ; break ; default: printf( gettext( "ERROR: Unrecognized error with status number %d encountered\n" ),st ) ; } zuluCryptSecurityUnlockMemory( *stl ) ; StringListClearDelete( stl ) ; return st ; } /* * open_volume function below can be devided into two, the first part is before the mount point folder is created and the * other part is after. This function is called after the mount point is created to see if it the mount point folder * should be removed first before calling the above function.The above function is called directly when "open_volume" * function is to be exited before the mount point is created. * */ static int zuluExit_1( int st,const struct_opts * opts,const char * device,const char * m_point,stringList_t * stl ) { if( opts->open_mount && st != 0 ){ zuluCryptSecurityGainElevatedPrivileges() ; rmdir( m_point ) ; zuluCryptSecurityDropElevatedPrivileges() ; } return zuluExit( st,device,m_point,stl ) ; } static int _open_volume( const open_struct_t * volume ) { int r ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptOpenVolume_2() is defined in ../lib/open_volume.c */ r = zuluCryptOpenVolume_2( volume ) ; zuluCryptSecurityDropElevatedPrivileges() ; return r ; } void zuluCryptTrueCryptVeraCryptVolumeInfo( const char * type,tvcrypt * e ) { stringList_t stl = StringListSplit( type,'.' ) ; size_t p = StringListSize( stl ) ; const char * q ; memset( e,'\0',sizeof( tvcrypt ) ) ; if( p > 0 ){ e->type = StringListCopyStringAtFirstPlace( stl ) ; if( p > 1 ){ q = StringListContentAtSecondPlace( stl ) ; e->iteration_count = ( int )StringConvertToInt( q ) ; } } StringListDelete( &stl ) ; } int zuluCryptEXEOpenVolume( const struct_opts * opts,const char * mapping_name,uid_t uid ) { int share = opts->share ; int open_mount = opts->open_mount ; const char * device = opts->device ; const char * mount_point = opts->mount_point ; const char * m_opts = opts->m_opts ; const char * source = opts->key_source ; const char * pass = opts->key ; const char * plugin_path = opts->plugin_path ; const char * fs_opts = opts->fs_opts ; const char * const * tcrypt_keyfiles = opts->tcrypt_multiple_keyfiles ; /* * Below is a form of memory management.All strings are collected in a stringlist object to easily delete them * when the function returns.This allows for the function to have multiple exit points without risks of leaking * memory from manually examining each exit point to make sure all strings are deleted or go with multiple goto * code deleting blocks to take into account different exit points. */ stringList_t stl = StringListVoid ; string_t * stringArray = StringListArray( &stl,8 ) ; string_t * passphrase = &stringArray[ 0 ] ; string_t * m_name = &stringArray[ 1 ] ; string_t * data = &stringArray[ 2 ] ; string_t * m_point = &stringArray[ 3 ] ; string_t * mapper = &stringArray[ 4 ] ; string_t * mapper_path = &stringArray[ 5 ] ; string_t * offset = &stringArray[ 6 ] ; string_t * bitlk = &stringArray[ 7 ] ; const char * key = NULL ; const char * mapper_name ; const char * path_mapper ; size_t key_len = 0 ; int st = 0 ; int bitlockerVolume ; stringList_t stz ; tvcrypt v_info ; unsigned long m_flags ; int tcrypt_keyfile = 0 ; const char * uuid ; char * device_path ; /* * open_struct_t is declared in ../lib/include.h */ open_struct_t volume ; struct stat statstr ; #if 0 /* * zuluCryptVolumeIsInSystemVolumeList() is defined in volumes.c */ if( zuluCryptVolumeIsInSystemVolumeList( device ) ){ /* * check permissions only if volume is explicity mentioned as system. * This is an exception to avoid some udev bad behaviors on udev enabled build */ if( !zuluCryptUserIsAMemberOfAGroup( uid,"zulucrypt" ) ){ return zuluExit( 22,device,mount_point,stl ) ; } } #endif if( m_opts == NULL ){ m_opts = "rw" ; } /* * zuluCryptMountFlagsAreNotCorrect() is defined in ./mount_flags.c */ if( zuluCryptMountFlagsAreNotCorrect( m_opts,uid,&m_flags ) ){ return zuluExit( 5,device,mount_point,&stl ) ; } if( StringHasComponent( m_opts,"rw" ) ){ /* * zuluCryptSecurityDeviceIsWritable() is defined in path_access.c */ st = zuluCryptCanOpenPathForWriting( device,uid ) ; }else{ /* * zuluCryptSecurityDeviceIsReadable() is defined in path_access.c */ st = zuluCryptCanOpenPathForReading( device,uid ) ; } /* * 1-permissions denied * 2-invalid path * 3-shenanigans * 4-common error */ switch( st ){ case 0 : break ; case 1 : return zuluExit( 6,device,mount_point,&stl ) ; case 2 : return zuluExit( 6,device,mount_point,&stl ) ; case 3 : return zuluExit( 6,device,mount_point,&stl ) ; case 4 : return zuluExit( 6,device,mount_point,&stl ) ; default: return zuluExit( 6,device,mount_point,&stl ) ; } if( open_mount ){ /* * zuluCryptCreateMountPoint() is defined in create_mount_point.c */ *m_point = zuluCryptCreateMountPoint( device,mount_point,m_opts,uid ) ; mount_point = StringContent( *m_point ) ; if( mount_point == NULL ){ return zuluExit( 9,device,mount_point,&stl ) ; } }else{ if( uid != 0 ){ return zuluExit( 7,device,mount_point,&stl ) ; } if( mount_point != NULL ){ return zuluExit( 8,device,mount_point,&stl ) ; } } if( share ){ /* * zuluCryptBindSharedMountPointPathTaken() is defined in bind.c */ if( zuluCryptBindSharedMountPointPathTaken( *m_point ) ){ return zuluExit_1( 10,opts,device,mount_point,&stl ) ; } } zuluCryptSecurityGainElevatedPrivileges() ; bitlockerVolume = zuluCryptDeviceHasAgivenFileSystem( device,zuluCryptBitLockerType() ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( bitlockerVolume && zuluCryptUseDislockerBitLocker( opts->use_cryptsetup_for_bitlocker ) ){ *mapper_path = zuluCryptBitLockerMapperPath( uid ) ; zuluCryptSecurityGainElevatedPrivileges() ; *m_name = zuluCryptBitLockerMapperName( device ) ; mapper_name = StringContent( *m_name ) ; path_mapper = StringContent( *mapper_path ) ; zuluCryptCreateMountPointPrefix( uid ) ; zuluCryptSecurityDropElevatedPrivileges() ; }else{ /* * zuluCryptCreateMapperName() is defined in ../lib/create_mapper_name.c */ *m_name = zuluCryptCreateMapperName( device,mapping_name,uid,ZULUCRYPTshortMapperPath ) ; *mapper = StringCopy( *m_name ) ; mapper_name = StringContent( *m_name ) ; *mapper_path = String( zuluCryptMapperPrefix() ) ; path_mapper = StringMultipleAppend( *mapper_path,"/",mapper_name,NULL ) ; if( stat( path_mapper,&statstr ) == 0 ){ return zuluExit_1( 11,opts,device,mount_point,&stl ) ; } } if( plugin_path != NULL ){ /* * zuluCryptPrepareSocketPath() is defined in path_access.c */ zuluCryptPrepareSocketPath( uid ) ; /* * zuluCryptUUIDFromPath() is defined in path_access.c */ uuid = zuluCryptUUIDFromPath( device ) ; device_path = _device_path( device ) ; /* * zuluCryptPluginManagerGetKeyFromModule is defined in ../pluginManager/zuluCryptPluginManager.c */ *passphrase = zuluCryptPluginManagerGetKeyFromModule( device_path, plugin_path, uuid, uid, opts, zuluCryptRunTimePath(), &st ) ; StringFree( device_path ) ; StringFree( uuid ) ; if( st != 0 || *passphrase == StringVoid ){ return zuluExit_1( 12,opts,device,mount_point,&stl ) ; } key_len = StringLength( *passphrase ) ; key = StringContent( *passphrase ) ; zuluCryptSecurityLockMemory_1( *passphrase ) ; }else if( source == NULL && tcrypt_keyfiles[ 0 ] == NULL ){ printf( gettext( "Enter passphrase: " ) ) ; /* * ZULUCRYPT_KEY_MAX_SIZE is set in ../constants.h */ switch( StringSilentlyGetFromTerminal_1( passphrase,ZULUCRYPT_KEY_MAX_SIZE ) ){ case 1 : return zuluExit_1( 13,opts,device,mount_point,&stl ) ; case 2 : return zuluExit_1( 14,opts,device,mount_point,&stl ) ; } printf( "\n" ) ; key = StringContent( *passphrase ) ; key_len = StringLength( *passphrase ) ; zuluCryptSecurityLockMemory_1( *passphrase ) ; }else{ if( source == NULL || pass == NULL ){ if( tcrypt_keyfiles == NULL ){ return zuluExit_1( 15,opts,device,mount_point,&stl ) ; } } if( StringsAreEqual( source,"-p" ) ){ key = pass ; key_len = StringSize( pass ) ; }else if( StringsAreEqual( source,"-f" ) ){ if( StringHasNoComponent( pass,zuluCryptRunTimePath() ) ){ tcrypt_keyfile = 1 ; } /* * function is defined at "path_access.c" */ switch( zuluCryptGetPassFromFile( NULL,pass,uid,data ) ){ case 1 : return zuluExit_1( 16,opts,device,mount_point,&stl ) ; case 2 : return zuluExit_1( 17,opts,device,mount_point,&stl ) ; case 4 : return zuluExit_1( 18,opts,device,mount_point,&stl ) ; case 5 : return zuluExit_1( 19,opts,device,mount_point,&stl ) ; } if( *data == StringVoid ){ return zuluExit_1( 12,opts,device,mount_point,&stl ) ; } key = StringContent( *data ) ; key_len = StringLength( *data ) ; zuluCryptSecurityLockMemory_1( *data ) ; } } memset( &volume,'\0',sizeof( open_struct_t ) ) ; if( key != NULL ){ volume.key = key ; volume.key_len = key_len ; }else{ volume.key = "" ; volume.key_len = 0 ; } volume.device = device ; volume.mapper_name = mapper_name ; volume.mapper_path = path_mapper ; volume.m_point = mount_point ; volume.fs_opts = fs_opts ; volume.uid = uid ; volume.m_opts = m_opts ; volume.m_flags = m_flags ; volume.bitlocker_volume = bitlockerVolume ; volume.luks_detached_header = opts->luks_external_header ; volume.use_cryptsetup_for_bitlocker = opts->use_cryptsetup_for_bitlocker ; /* * zuluCryptTrueCryptVeraCryptVolumeInfo() is defined in this source file. */ zuluCryptTrueCryptVeraCryptVolumeInfo( opts->type,&v_info ) ; volume.iteration_count = v_info.iteration_count ; if( StringAtLeastOneMatch( v_info.type,"tcrypt","truecrypt",NULL ) ){ volume.trueCrypt_volume = 1 ; }else if( StringAtLeastOneMatch( v_info.type,"vcrypt","veracrypt","vera",NULL ) ){ volume.veraCrypt_volume = 1 ; }else if( StringAtLeastOneMatch( v_info.type,"vcrypt-sys","veracrypt-sys","vera-sys",NULL ) ){ volume.veraCrypt_volume = 1 ; volume.system_volume = 1 ; }else if( StringAtLeastOneMatch( v_info.type,"vcrypt-hbk","veracrypt-hbk","vera-hbk",NULL ) ){ volume.veraCrypt_volume = 1 ; volume.use_backup_header = 1 ; }else if( StringAtLeastOneMatch( v_info.type,"vcrypt-sys-hbk","veracrypt-sys-hbk","vera-sys-hbk",NULL ) ){ volume.veraCrypt_volume = 1 ; volume.system_volume = 1 ; volume.use_backup_header = 1 ; } if( !volume.veraCrypt_volume && !volume.trueCrypt_volume ){ if( opts->offset != NULL ){ *offset = String( "/dev/urandom.aes.cbc-essiv:sha256.256.ripemd160." ) ; volume.plain_dm_properties = StringAppend( *offset,opts->offset ) ; }else{ if( StringsAreEqual( opts->type,"plain" ) ){ volume.plain_dm_properties = "aes.cbc-essiv:sha256.256.sha256.0" ; }else if( StringsAreNotEqual( opts->type,"luks" ) ){ volume.plain_dm_properties = opts->type ; } } } StringDelete( &v_info.type ) ; if( plugin_path != NULL ){ plugin_path = plugin_path + StringLastIndexOfChar_1( plugin_path,'/' ) + 1 ; } if( tcrypt_keyfile ){ volume.key_source = TCRYPT_KEYFILE ; } if( tcrypt_keyfiles[ 0 ] != NULL ){ /* * Here, we take a list of keyfiles supplied by the user and then copy them to a safe * location at "/run/zuluCrypt" and then we pass these safe copies to cryptsetup. * * The idea is not to let cryptsetup, a privileged process handle user managed files. */ stz = zuluCryptCreateKeyFiles( tcrypt_keyfiles,0 ) ; volume.tcrypt_keyfiles_count = StringListSize( stz ) ; volume.tcrypt_keyfiles = StringListStringArray( stz ) ; st = _open_volume( &volume ) ; zuluCryptDeleteKeyFiles( stz ) ; StringFree( volume.tcrypt_keyfiles ) ; StringListDelete( &stz ) ; }else{ st = _open_volume( &volume ) ; } /* * below two return values comes from ../lib/mount_volume.c */ if( st == -1 ){ st = 20 ; } if( st == 12 ){ st = 21 ; } if( st == 8 || st == 3 ){ st = 3 ; } if( volume.bitlocker_volume ){ if( zuluCryptUseCryptsetupBitLocker( opts->use_cryptsetup_for_bitlocker ) ){ device = StringMultiplePrepend( *mapper,"/",zuluCryptMapperPrefix(),NULL ) ; }else{ *bitlk = zuluCryptBitLockerFullMapperPath( uid,device ) ; device = StringContent( *bitlk ) ; } }else{ device = StringMultiplePrepend( *mapper,"/",zuluCryptMapperPrefix(),NULL ) ; } if( st == 0 && share ){ /* * user wish to share the mount point bind the mount point to a publicly accessed path at /run/media/public/ */ /* * zuluCryptBindMountVolume() is defined in ../zuluCrypt-cli/bin/bind.c */ zuluCryptBindMountVolume( device,*m_point,m_flags ) ; } /* * zuluCryptCheckInvalidKey() is defined in check_invalid_key.c */ zuluCryptCheckInvalidKey( opts->device ) ; return zuluExit_1( st,opts,device,mount_point,&stl ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/partitions.c000066400000000000000000000000641425361753700214530ustar00rootroot00000000000000 contents of this source file are now in volumes.c zuluCrypt-6.2.0/zuluCrypt-cli/bin/path_access.c000066400000000000000000000110101425361753700215250ustar00rootroot00000000000000/* * * Copyright (c) 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include "../constants.h" #include "../lib/includes.h" #include "includes.h" #include #include static int has_device_access( const char * path,int c ) { int f ; if( c == ZULUCRYPTread ){ f = open( path,O_RDONLY ) ; }else{ f = open( path,O_WRONLY ) ; } if( f == -1 ){ switch( errno ){ case EACCES : return 1 ; /* permission denied */ case ENOENT : return 2 ; /* invalid path*/ default : return 4 ; /* common error */ } }else{ close( f ) ; return 0 ; } } /* * 1-permissions denied * 2-invalid path * 3-shenanigans * 4-common error */ static int path_is_accessible( const char * path,uid_t uid,int action ) { int st ; char * e ; if( uid ){} if( StringPrefixEqual( path,"/dev/shm/" ) ){ return 4 ; } if( StringPrefixEqual( path,"/dev/" ) ){ if( StringPrefixEqual( path,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../zuluCrypt-cli/create_loop_device.c */ e = zuluCryptLoopDeviceAddress_1( path ) ; if( e != NULL ){ st = has_device_access( e,action ) ; StringFree( e ) ; }else{ return 4 ; } }else{ zuluCryptSecurityGainElevatedPrivileges() ; st = has_device_access( path,action ) ; zuluCryptSecurityDropElevatedPrivileges() ; } return st ; }else{ zuluCryptSecurityDropElevatedPrivileges() ; return has_device_access( path,action ) ; } } int zuluCryptCanOpenPathForReading( const char * path,uid_t uid ) { return path_is_accessible( path,uid,ZULUCRYPTread ) ; } int zuluCryptCanOpenPathForWriting( const char * path,uid_t uid ) { return path_is_accessible( path,uid,ZULUCRYPTwrite ) ; } void zuluCryptPrepareSocketPath( uid_t uid ) { if( uid ){} } /* * return values: * 5 - couldnt get key from the socket * 4 -permission denied * 1 invalid path * 2 insufficient memory to open file * 0 success */ int zuluCryptGetPassFromFile( int * socket_path,const char * path,uid_t uid,string_t * st ) { string_t p = String( zuluCryptRunTimePath() ) ; const char * z = StringContent( p ) ; size_t s = StringLength( p ) ; int m = StringPrefixMatch( path,z,s ) ; StringDelete( &p ) ; if( socket_path ){ *socket_path = m ; } if( m ){ /* * zuluCryptPrepareSocketPath() is defined in path_access.c */ zuluCryptPrepareSocketPath( uid ) ; zuluCryptSecurityDropElevatedPrivileges() ; /* * path that starts with $/tmp/zuluCrypt-$UID is treated not as a path to key file but as path * to a local socket to get a passphrase */ /* * zuluCryptGetKeyFromSocket() is defined in ../pluginManager/zuluCryptPluginManager.c */ zuluCryptGetKeyFromSocket( path,st,uid ) ; return 0 ; }else{ zuluCryptSecurityDropElevatedPrivileges() ; /* * 8192000 bytes is the default cryptsetup maximum keyfile size */ m = StringGetFromFileMemoryLocked( st,path,0,8192000 ) ; switch( m ){ case 0 : return 0 ; case 1 : return 4 ; case 2 : return 2 ; } /* * not supposed to get here */ return -1 ; } } char * zuluCryptEvaluateDeviceTags( const char * tag,const char * path ) { char * r ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptDeviceFromUUID() is defined in ../lib/blkid_evaluate_tag.c * zuluCryptDeviceFromLabel() is defined in ../lib/blkid_evaluate_tag.c */ if( StringsAreEqual( tag,"UUID" ) ){ r = zuluCryptDeviceFromUUID( path ) ; }else{ r = zuluCryptDeviceFromLabel( path ) ; } zuluCryptSecurityDropElevatedPrivileges() ; return r ; } char * zuluCryptUUIDFromPath( const char * device ) { char * c ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptUUIDFromPath_1() is defined in ../lib/blkid_evaluate_tag.c */ c = zuluCryptUUIDFromPath_1( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; return c ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/remove_key.c000066400000000000000000000146261425361753700214350ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include static int _zuluCryptExECheckEmptySlots( const char * device ) { int status = 0 ; char * c ; char * d ; zuluCryptSecurityGainElevatedPrivileges() ; c = zuluCryptEmptySlots( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( c == NULL ){ return 1 ; } d = c - 1 ; while( *++d ){ if( *d == '3' ){ status = 3 ; break ; } } StringFree( c ) ; return status ; } static int zuluExit( int st,stringList_t stl ) { zuluCryptSecurityUnlockMemory( stl ) ; /* * this function is defined in ../string/StringList.c */ StringListClearDelete( &stl ) ; switch ( st ){ case 0 : printf( gettext( "SUCCESS: Key removed successfully\n" ) ) ; break ; case 2 : printf( gettext( "ERROR: There is no key in the volume that match the presented key\n" ) ) ; break ; case 3 : printf( gettext( "ERROR: Could not open the volume\n" ) ) ; break ; case 4 : printf( gettext( "ERROR: Insufficient privilege to open a system device,\ only root user or members of group zulucrypt can do that\n" ) ) ; break ; case 5 : printf( gettext( "ERROR: Could not open the volume in write mode\n" ) ) ; break ; case 6 : printf( gettext( "ERROR: Insufficient memory to hold your response\n" ) ) ; break ; case 7 : printf( gettext( "INFO: Operation terminated per user request\n" ) ) ; break ; case 8 : printf( gettext( "ERROR: Can not get passphrase in silent mode\n" ) ) ; break ; case 9 : printf( gettext( "ERROR: Insufficient memory to hold passphrase\n" ) ) ; break ; case 10: printf( gettext( "ERROR: One or more required argument(s) for this operation is missing\n" ) );break ; case 11: printf( gettext( "ERROR: Keyfile does not exist\n" ) ) ; break ; case 12: printf( gettext( "ERROR: Could not get enough memory to open the key file\n" ) ) ; break ; case 13: printf( gettext( "ERROR: Insufficient privilege to open key file for reading\n" ) ) ; break ; case 14: printf( gettext( "ERROR: Could not get a key from a socket\n" ) ) ; break ; default: printf( gettext( "ERROR: Unrecognized error with status number %d encountered\n" ),st ); } return st ; } static int zuluExit_1( int st,const char * device,stringList_t stl ) { printf( gettext( "ERROR: Device \"%s\" is not a luks device\n" ),device ) ; StringListClearDelete( &stl ) ; return st ; } int zuluCryptEXERemoveKey( const struct_opts * opts,uid_t uid ) { int ask_confirmation = opts->ask_confirmation ; const char * device = opts->device ; const char * keyType = opts->key_source ; const char * keytoremove = opts->key ; int key_slot = opts->luks_slot_number ; stringList_t stl = StringListInit() ; string_t * pass = StringListAssign( stl ) ; string_t * confirm = StringListAssign( stl ) ; int status = 0 ; const char * key ; size_t key_size ; /* * zuluCryptPartitionIsSystemPartition() is defined in ./partitions.c */ if( zuluCryptPartitionIsSystemPartition( device,uid ) ){ if( zuluCryptExeOriginalUserIsNotRoot() ){ if( !zuluCryptUserIsAMemberOfAGroup( uid,"zulucrypt" ) ){ return zuluExit( 4,stl ) ; } } } /* * zuluCryptCanOpenPathForWriting is defined in path_access.c */ status = zuluCryptCanOpenPathForWriting( device,uid ) ; /* * 1-permissions denied * 2-invalid path * 3-shenanigans * 4-common error */ switch( status ){ case 0 : break ; case 1 : return zuluExit( 5,stl ) ; case 2 : return zuluExit( 5,stl ) ; case 3 : return zuluExit( 5,stl ) ; case 4 : return zuluExit( 5,stl ) ; default: return zuluExit( 5,stl ) ; } if( _zuluCryptExECheckEmptySlots( device ) == 3 ){ if( ask_confirmation ){ printf( gettext( "WARNING: There is only one key in the volume and all data in it will be lost if you continue.\n" ) ) ; printf( gettext( "Do you still want to continue? Type \"YES\" if you do: " ) ) ; *confirm = StringGetFromTerminal_1( 3 ) ; if( *confirm == StringVoid ){ return zuluExit( 6,stl ) ; } if( !StringsAreEqual_2( *confirm,gettext( "YES" ) ) ){ return zuluExit( 7,stl ) ; } } } if( keyType == NULL ){ printf( gettext( "Enter a key to be removed: " ) ) ; /* * ZULUCRYPT_KEY_MAX_SIZE is set in ../constants.h */ switch( StringSilentlyGetFromTerminal_1( pass,ZULUCRYPT_KEY_MAX_SIZE ) ){ case 1 : return zuluExit( 8,stl ) ; case 2 : return zuluExit( 9,stl ) ; } printf( "\n" ) ; key = StringContent( *pass ) ; key_size = StringLength( *pass ) ; zuluCryptSecurityLockMemory_1( *pass ) ; }else{ if( keyType == NULL || keytoremove == NULL ){ return zuluExit( 10,stl ) ; } if( StringsAreEqual( keyType,"-f" ) ){ /* * zuluCryptGetPassFromFile() is defined at path_access.c" */ switch( zuluCryptGetPassFromFile( NULL,keytoremove,uid,pass ) ){ case 1 : return zuluExit( 11,stl ) ; case 2 : return zuluExit( 12,stl ) ; case 4 : return zuluExit( 13,stl ) ; case 5 : return zuluExit( 14,stl ) ; } key = StringContent( *pass ) ; key_size = StringLength( *pass ) ; zuluCryptSecurityLockMemory_1( *pass ) ; }else if( StringsAreEqual( keyType, "-p" ) ){ key = keytoremove ; key_size = StringSize( keytoremove ) ; }else{ return zuluExit( 10,stl ) ; } } zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptRemoveKey() is defined in ../lib/remove_key.c */ status = zuluCryptRemoveKey_0( device,key,key_size,key_slot ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( status == 1 ){ status = zuluExit_1( status,device,stl ) ; }else{ status = zuluExit( status,stl ) ; } /* * zuluCryptCheckInvalidKey() is defined in check_invalid_key.c */ zuluCryptCheckInvalidKey( opts->device ) ; return status ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/save_and_restore_volume_header.c000066400000000000000000000446011425361753700255060ustar00rootroot00000000000000 /* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include #include #include #include #include #include #include #include #include "zuluplay_api.h" #define SIZE 512 #define ignore_result( x ) if( x ){;} static int zuluExit( int st,const char * dev ) { switch( st ){ case 0 : printf( gettext( "SUCCESS: Header saved successfully\n" ) ) ; break ; case 1 : printf( gettext( "SUCCESS: Header restored successfully\n" ) ) ; break ; case 2 : printf( gettext( "ERROR: Presented device is not a LUKS device\n" ) ) ; break ; case 3 : printf( gettext( "ERROR: Failed to perform requested operation\n" ) ) ; break ; case 4 : printf( gettext( "ERROR: Failed to perform requested operation\n" ) ) ; break ; case 5 : printf( gettext( "INFO: Operation terminater per user request\n" ) ) ; break ; case 6 : printf( gettext( "ERROR: Path to be used to create a back up file is occupied or permission denied\n" ) ); break ; case 7 : printf( gettext( "ERROR: Failed to perform requested operation\n" ) ) ; break ; case 8 : printf( gettext( "ERROR: Insufficient privilege to open backup header file for reading\n" ) ) ; break ; case 9 : printf( gettext( "ERROR: Invalid path to back up header file\n" ) ) ; break ; case 10: printf( gettext( "ERROR: Insufficient privilege to create a backup header in a destination folder\n" )); break ; case 11: printf( gettext( "ERROR: Invalid path to device\n" ) ) ; break ; case 12: printf( gettext( "ERROR: Argument for path to a backup header file is missing\n" ) ) ; break ; case 13: printf( gettext( "ERROR: Argument for path to a backup header file is missing\n" ) ) ; break ; case 14: printf( gettext( "ERROR: Only root and \"zulucrypt\" group members can restore and back up luks headers on system devices\n" ) ); break ; case 15: printf( gettext( "ERROR: Insufficient privilege to open device for writing\n" ) ) ; break ; case 16: printf( gettext( "ERROR: Could not resolve path to device\n" ) ) ; break ; case 17: printf( gettext( "ERROR: Backup file does not appear to contain luks header\n" ) ) ; break ; case 18: printf( gettext( "ERROR: Insufficient privilege to open device for reading\n" ) ) ; break ; case 19: printf( gettext( "ERROR: Insufficient memory to hold your responce\n" ) ) ; break ; case 20: printf( gettext( "ERROR: Wrong password entered or volume is not a truecrypt volume\n" ) ) ; break ; case 21: printf( gettext( "ERROR: Wrong password entered or volume is not a veracrypt volume\n" ) ) ; break ; } StringFree( dev ) ; if( st == 1 ){ return 0 ; }else{ return st ; } } /* * This place is a bit involving and an explanation seem to be the least i can do. * * We do not want cryptsetup and tcplay to access file paths a normal can modify for security * reasons and hence we copy user provided files to "/run/zuluCrypt" folder and then * pass these copied files to cryptsetup or tcplay.This happens when we are restoring * header files. * * When we are taking header backups,we let these tools create the header backups in * "/run/zuluCrypt" and then we copied these created header files from "/run/zuluCrypt" * to where the normal user expect them to be. * * normal user should zero access to "/run/zuluCrypt" path. */ /* * Below function creates a secured folder path,ie a folder path a normal user has no access to */ static string_t _create_work_directory( void ) { /* * ZULUCRYPTtempFolder and ZULUCRYPtmountMiniPath are set in ../constants.h */ const char * temp_path = "/run/zuluCrypt/" ; struct stat xt ; mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH | S_IROTH ; zuluCryptSecurityGainElevatedPrivileges() ; #define path_does_not_exist( x ) stat( x,&xt ) != 0 if( path_does_not_exist( "/run" ) ){ mkdir( "/run",mode ) ; ignore_result( chown( "/run",0,0 ) ) } if( path_does_not_exist( temp_path ) ){ mkdir( temp_path,S_IRWXU ) ; ignore_result( chown( temp_path,0,0 ) ) } zuluCryptSecurityDropElevatedPrivileges() ; return String( temp_path ) ; } /* * Below function copies a file owned and managed by a user to a secured location so that it can be accessed securely. */ static int _secure_file_path( const char ** path,const char * source ) { int fd_source ; int fd_temp ; char buffer[ SIZE ] ; size_t len ; const char * temp_path ; struct stat ststr ; string_t st_path = _create_work_directory() ; StringAppend( st_path,"0-" ) ; temp_path = StringAppendInt( st_path,(u_int64_t)syscall( SYS_gettid ) ) ; zuluCryptSecurityDropElevatedPrivileges() ; fd_source = open( source,O_RDONLY ) ; if( fd_source == -1 ){ StringDelete( &st_path ) ; return 0 ; } fstat( fd_source,&ststr ) ; if( ststr.st_size >= ZULUCRYPT_LUKS2_MAX_HEADER_SIZE ){ /* * Lets assume a header can not be larger that ZULUCRYPT_LUKS2_MAX_HEADER_SIZE. */ StringDelete( &st_path ) ; return 0 ; } zuluCryptSecurityGainElevatedPrivileges() ; fd_temp = open( temp_path,O_WRONLY | O_CREAT,S_IRUSR | S_IWUSR | S_IRGRP |S_IROTH ) ; if( fd_temp == -1 ){ close( fd_source ) ; StringDelete( &st_path ) ; return 0 ; } while( 1 ){ len = (size_t)read( fd_source,buffer,SIZE ) ; if( len < SIZE ){ ignore_result( write( fd_temp,buffer,len ) ) break ; }else{ ignore_result( write( fd_temp,buffer,len ) ) } } close( fd_source ) ; close( fd_temp ) ; zuluCryptSecurityDropElevatedPrivileges() ; *path = StringDeleteHandle( &st_path ) ; return 1 ; } /* * this function return a secured file path to be used to create a file at the path */ static const char * _secure_file_path_1( void ) { string_t st_path = _create_work_directory() ; StringAppend( st_path,"1-" ) ; StringAppendInt( st_path,(size_t)syscall( SYS_gettid ) ) ; return StringDeleteHandle( &st_path ) ; } /* * Below function copies a secured file from secured location to a user owned and managed location. * The source file will be deleted when the copy is done. */ static int _secure_copy_file( const char * source,const char * dest,uid_t uid ) { int st = 4 ; int fd_source ; int fd_dest ; size_t len ; char buffer[ SIZE ] ; zuluCryptSecurityDropElevatedPrivileges() ; fd_dest = open( dest,O_WRONLY | O_CREAT,S_IRUSR | S_IWUSR | S_IRGRP |S_IROTH ) ; if( fd_dest == -1 ){ zuluCryptSecurityGainElevatedPrivileges() ; zuluCryptDeleteFile( source ) ; zuluCryptSecurityDropElevatedPrivileges() ; return 6 ; } zuluCryptSecurityGainElevatedPrivileges() ; fd_source = open( source,O_RDONLY ) ; if( fd_source != -1 ){ while( 1 ){ len = (size_t)read( fd_source,buffer,SIZE ) ; if( len < SIZE ){ ignore_result( write( fd_dest,buffer,len ) ) break ; }else{ ignore_result( write( fd_dest,buffer,len ) ) } } ignore_result( chmod( dest,S_IRUSR ) ) ignore_result( chown( dest,uid,uid ) ) st = 0 ; } /* * zuluCryptDeleteFile() is defined in ../lib/file_path_security.c */ zuluCryptDeleteFile( source ) ; zuluCryptSecurityDropElevatedPrivileges() ; return st ; } static int _save_luks_header( const struct_opts * opts,const char * temp_path,const char * path,uid_t uid ) { struct crypt_device * cd ; int st ; if( crypt_init( &cd,opts->device ) != 0 ){ st = 3 ; }else{ st = crypt_header_backup( cd,NULL,temp_path ) ; crypt_free( cd ) ; if( st == 0 ){ st = _secure_copy_file( temp_path,path,uid ) ; }else{ st = 4 ; } } return st ; } static int zuluExit_1( int r,string_t st,string_t xt ) { StringMultipleDelete( &xt,&st,NULL ) ; return r ; } static string_t _get_password( int * r ) { string_t st = StringVoid ; *r = 1 ; printf( gettext( "Enter passphrase in the volume: " ) ) ; /* * ZULUCRYPT_KEY_MAX_SIZE is set in ../constants.h */ StringSilentlyGetFromTerminal_1( &st,ZULUCRYPT_KEY_MAX_SIZE ) ; return st ; } static string_t _get_password_0( int * r ) { string_t st = StringVoid ; *r = 1 ; printf( gettext( "Enter passphrase in the header file: " ) ) ; /* * ZULUCRYPT_KEY_MAX_SIZE is set in ../constants.h */ StringSilentlyGetFromTerminal_1( &st,ZULUCRYPT_KEY_MAX_SIZE ) ; return st ; } static int _modify_tcrypt( info_t * info,const struct_opts * opts ) { int k = 4 ; int r ; int socket_path ; string_t st = StringVoid ; string_t xt = StringVoid ; if( StringsAreEqual( opts->key_source,"-p" ) ){ info->header_key = opts->key ; info->header_key_source = "passphrase" ; info->header_new_key_source = "new_passphrase" ; }else if( opts->key == NULL && StringsAreNotEqual( opts->key_source,"-f" ) ){ st = info->getKey( &r ) ; if( r ){ info->key = StringContent( st ) ; info->header_key = info->key ; info->header_key_source = "passphrase" ; info->header_new_key_source = "new_passphrase" ; }else{ return zuluExit_1( k,st,xt ) ; } }else{ /* * function is defined at "path_access.c" */ zuluCryptGetPassFromFile( &socket_path,opts->key,info->uid,&st ) ; zuluCryptSecurityGainElevatedPrivileges() ; if( st == StringVoid ){ return zuluExit_1( k,st,xt ) ; }else{ if( socket_path ){ info->key = StringContent( st ) ; info->header_key = info->key ; info->header_key_source = "passphrase" ; info->header_new_key_source = "new_passphrase" ; }else{ /* * zuluCryptCreateKeyFile_1 is defined in ../lib/open_tcrypt.c */ xt = zuluCryptCreateKeyFile_1( st,"tcrypt-bk-" ) ; if( xt == StringVoid ){ return zuluExit_1( k,st,xt ) ; }else{ info->key = StringContent( xt ) ; info->header_key = info->key ; info->header_key_source = "keyfiles" ; info->header_new_key_source = "new_keyfiles" ; } } } } info->header_new_key = info->header_key ; /* * zuluCryptModifyTcryptHeader() is defined in ../lib/create_tcrypt.c */ k = zuluCryptModifyTcryptHeader( info ) ; if( xt != StringVoid ){ /* * zuluCryptDeleteFile_1() is defined in ../lib/file_path_security.c */ zuluCryptDeleteFile_1( xt ) ; } return zuluExit_1( k,st,xt ) ; } stringList_t veraCryptVolumePIMValue( info_t * s,const char * type ) { stringList_t stl = StringListSplit( type,'.' ) ; const char * e = StringListContentAtFirstPlace( stl ) ; const char * f = StringListContentAtSecondPlace( stl ) ; s->veraCrypt_volume = StringsAreEqual( e,"vcrypt" ) ; s->iteration_count = ( int ) StringConvertToInt( f ) ; return stl ; } static int _save_truecrypt_header( const struct_opts * opts,const char * temp_path,const char * path,uid_t uid ) { int r ; stringList_t stl ; /* * info_t structure is declared in ../lib/include.h */ info_t info ; memset( &info,'\0',sizeof( info_t ) ) ; info.device = opts->device ; info.header_source = "save_header_to_file" ; info.getKey = _get_password ; info.tmp_path = temp_path ; info.uid = uid ; info.rng = opts->rng ; info.opt = opts->m_opts ; stl = veraCryptVolumePIMValue( &info,opts->type ) ; r = _modify_tcrypt( &info,opts ) ; StringListDelete( &stl ) ; if( opts->key == NULL && StringsAreNotEqual( opts->key_source,"-f" ) ){ printf( "\n" ) ; } if( r == TC_OK ){ return _secure_copy_file( temp_path,path,uid ) ; }else{ if( StringPrefixEqual( opts->type,"vcrypt" ) ){ return 21 ; }else{ return 20 ; } } } static int _restore_truecrypt_header( const struct_opts * opts,const char * temp_path,uid_t uid ) { stringList_t stl ; int r ; /* * info_t structure is declared in ../lib/include.h */ info_t info ; memset( &info,'\0',sizeof( info_t ) ) ; info.device = opts->device ; info.header_source = "header_from_file" ; info.getKey = _get_password_0 ; info.tmp_path = temp_path ; info.uid = uid ; info.rng = opts->rng ; info.opt = opts->m_opts ; stl = veraCryptVolumePIMValue( &info,opts->type ) ; r = _modify_tcrypt( &info,opts ) ; StringListDelete( &stl ) ; if( opts->key == NULL && StringsAreNotEqual( opts->key_source,"-f" ) ){ printf( "\n" ) ; } if( r == TC_OK ){ return 1 ; }else{ if( StringPrefixEqual( opts->type,"vcrypt" ) ){ return 21 ; }else{ return 20 ; } } } static int _save_header( const struct_opts * opts,const char * path,uid_t uid ) { int st = 4 ; const char * temp_path = _secure_file_path_1() ; zuluCryptSecurityGainElevatedPrivileges() ; if( zuluCryptVolumeIsLuks( opts->device ) ){ st = _save_luks_header( opts,temp_path,path,uid ) ; }else{ st = _save_truecrypt_header( opts,temp_path,path,uid ) ; } zuluCryptSecurityDropElevatedPrivileges() ; StringFree( temp_path ) ; return st ; } static int _restore_luks_header( const struct_opts * opts,const char * temp_path ) { int st ; struct crypt_device * cd ; if( crypt_init( &cd,opts->device ) != 0 ){ st = 7 ; }else{ if( crypt_header_restore( cd,NULL,temp_path ) == 0 ){ st = 1 ; }else{ st = 7 ; } crypt_free( cd ) ; } return st ; } static int _restore_header( const struct_opts * opts,const char * dev,const char * path,int ask_confirmation,uid_t uid ) { const char * temp_path = NULL ; int k ; int st = 7; string_t confirm ; const char * warn = gettext( "\ Are you sure you want to replace a header on device \"%s\" with a backup copy at \"%s\"?\n\ Type \"YES\" and press Enter to continue: " ) ; if( uid ){} if( ask_confirmation ){ zuluCryptSecurityDropElevatedPrivileges() ; printf( warn,dev,path ) ; confirm = StringGetFromTerminal_1( 3 ) ; if( confirm != StringVoid ){ k = StringsAreEqual_2( confirm,gettext( "YES" ) ); StringDelete( &confirm ) ; if( k == 0 ){ return 5 ; } }else{ return 19 ; } } if( _secure_file_path( &temp_path,path ) ){ zuluCryptSecurityGainElevatedPrivileges() ; if( zuluCryptVolumeIsLuks( temp_path ) ){ /* * temp_path will point to a header back up file and it is assumed that a user * want to restore a header to a luks volume since the backup header has luks signature */ st = _restore_luks_header( opts,temp_path ) ; }else{ /* * the header back up has no luks signature and hence it is assumed that a request is * made to restore a truecrypt header backup */ st = _restore_truecrypt_header( opts,temp_path,uid ) ; } zuluCryptDeleteFile( temp_path ) ; StringFree( temp_path ) ; zuluCryptSecurityDropElevatedPrivileges() ; return st ; }else{ return 7 ; } } int zuluCryptEXESaveAndRestoreVolumeHeader( const struct_opts * opts,uid_t uid,int option ) { const char * device = opts->device ; const char * path = opts->back_up_file_path ; int st ; int k ; const char * dev = NULL ; const char * dev_1 = NULL ; if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../lib/create_loop_device.c */ dev = zuluCryptLoopDeviceAddress_1( device ) ; dev_1 = dev ; /* * zuluCryptPartitionIsSystemPartition() is defined in partitions.c */ k = zuluCryptPartitionIsSystemPartition( dev,uid ) ; }else{ dev_1 = device ; /* * zuluCryptPartitionIsSystemPartition() is defined in partitions.c */ k = zuluCryptPartitionIsSystemPartition( device,uid ) ; } if( k == 1 ){ if( zuluCryptExeOriginalUserIsNotRoot() ){ if( uid != 0 && !zuluCryptUserIsAMemberOfAGroup( uid,"zulucrypt" ) ){ return zuluExit( 14,dev ) ; } } } if( path == NULL ){ if( option == VOLUME_HEADER_RESTORE ){ return zuluExit( 12,dev ) ; }else{ return zuluExit( 13,dev ) ; } } if( option == VOLUME_HEADER_RESTORE ){ st = _restore_header( opts,dev_1,path,opts->ask_confirmation,uid ) ; }else{ st = _save_header( opts,path,uid ) ; } return zuluExit( st,dev ) ; } static int _files_are_equal( const char * file1,const char * file2 ) { struct stat st1 ; struct stat st2 ; int fd1; int fd2; int r = 1 ; void * map1 ; void * map2 ; fd1 = open( file1,O_RDONLY ) ; if( fd1 == -1 ){ return 0 ; } fd2 = open( file2,O_RDONLY ) ; if( fd2 == -1 ){ close( fd1 ) ; return 0 ; } fstat( fd1,&st1 ) ; fstat( fd2,&st2 ) ; /* * headers are less than 10MB,anything larger is automatically an error */ if( st1.st_size < ZULUCRYPT_LUKS2_MAX_HEADER_SIZE && st2.st_size < ZULUCRYPT_LUKS2_MAX_HEADER_SIZE ){ map1 = mmap( 0,st1.st_size,PROT_READ,MAP_PRIVATE,fd1,0 ) ; if( map1 != MAP_FAILED ){ map2 = mmap( 0,st2.st_size,PROT_READ,MAP_PRIVATE,fd2,0 ) ; if( map2 != MAP_FAILED ){ if( st1.st_size > st2.st_size ){ r = memcmp( map1,map2,st1.st_size ) ; }else{ r = memcmp( map1,map2,st2.st_size ) ; } munmap( map2,st2.st_size ) ; } munmap( map1,st1.st_size ) ; } }else{ return 0 ; } close( fd1 ) ; close( fd2 ) ; return r == 0 ; } static int _save_tmp_header( const char * device,const char * backup ) { struct crypt_device * cd ; int st = 1 ; if( crypt_init( &cd,device ) == 0 ){ st = crypt_header_backup( cd,NULL,backup ) ; crypt_free( cd ) ; } return st == 0 ; } int zuluCryptHeaderMatchBackUpHeader( const char * device,const char * header_backup,uid_t uid ) { const char * header_path = NULL; const char * device_header = NULL; int st = 0 ; if( uid ){;} if( device == NULL || header_backup == NULL ){ return 0 ; } _secure_file_path( &header_path,header_backup ) ; if( header_path == NULL ){ return 0 ; } device_header = _secure_file_path_1() ; if( device_header == NULL ){ StringFree( header_path ) ; return 0 ; } zuluCryptSecurityGainElevatedPrivileges() ; if( _save_tmp_header( device,device_header ) ){ st = _files_are_equal( header_path,device_header ) ; } zuluCryptDeleteFile( header_path ) ; zuluCryptDeleteFile( device_header ) ; zuluCryptSecurityDropElevatedPrivileges() ; StringFree( header_path ) ; StringFree( device_header ) ; return st ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/security.c000066400000000000000000000131201425361753700211230ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include #include "../constants.h" #include #include #include #include #include #include /* * This source file makes sure the user who started the tool( usually non root user ) has permission * to perform operations they want on paths they presented. * * This feature allows tradition unix permissions to be set on a paths to control non user access to volumes */ /* * zuluCryptUserIsAMemberOfAGroup() was moved to ../lib/mount_fs_options.c */ #define ZULUDEBUG 0 static uid_t _original_UID ; static const char * _run_time_path ; /* * set the function to be called when an attempt to evelate or downgrade privileges fail. */ static void ( *zuluCryptSecurityPrivilegeElevationError )( const char * ) = NULL ; const char * zuluCryptRunTimePath() { return _run_time_path ; } void zuluCryptExeSetOriginalUID( uid_t s ) { _original_UID = s ; } int zuluCryptExeOriginalUserIsNotRoot() { return _original_UID != 0 ; } int zuluCryptSecurityGainElevatedPrivileges( void ) { /* * printf( "GAINING:uid=%d:euid=%d\n",getuid(),geteuid() ) ; */ if( seteuid( 0 ) == 0 ){ return 1 ; }else{ if( zuluCryptSecurityPrivilegeElevationError ){ zuluCryptSecurityPrivilegeElevationError( "WARNING: failed to seteuid root" ) ; } } return 0 ; } int zuluCryptSecurityConvertUID( uid_t uid,const char * u_id ) { extern char ** environ ; const char * sudo_uid = NULL ; char ** e = environ ; const char * s ; for( ; *e != NULL ; e++ ){ s = *e ; if( StringPrefixMatch( s,"SUDO_UID=",9 ) ){ sudo_uid = s + 9 ; break ; } } if( u_id != NULL ){ if( uid == 0 ){ return (int)StringConvertToInt( u_id ) ; }else{ return -1 ; } }else if( sudo_uid != NULL ){ if( uid == 0 ){ return (int)StringConvertToInt( sudo_uid ) ; }else{ return -1 ; } }else{ return (int)uid ; } } uid_t global_variable_user_uid ; void zuluCryptSetUserUIDForPrivilegeManagement( uid_t uid ) { global_variable_user_uid = uid ; } void zuluCryptSecuritySetPrivilegeElevationErrorFunction( void ( *f ) ( const char * ) ) { zuluCryptSecurityPrivilegeElevationError = f ; } int zuluCryptSecurityDropElevatedPrivileges( void ) { /* printf( "DROPPING:uid=%d:euid=%d\n",getuid(),geteuid() ) ; */ if( seteuid( global_variable_user_uid ) != 0 ){ if( zuluCryptSecurityPrivilegeElevationError ){ zuluCryptSecurityPrivilegeElevationError( "ERROR: seteuid() failed" ) ; } } return 1 ; } void zuluCryptSecuritySanitizeTheEnvironment( uid_t uid,stringList_t * stx ) { extern char ** environ ; const char ** env = ( const char ** ) environ ; ssize_t index ; string_t xt ; stringList_t stl = StringListVoid ; string_t st ; StringListIterator it ; StringListIterator end ; /* * First,we make a copy of the enviromental varibales * Second,we clear the enviromental variable because we dont want it * Third,we return a copy of the enviromental variable because we want to pass it along * the plugins */ while( *env ){ stl = StringListAppend( stl,*env ) ; env++ ; } StringListGetIterators( stl,&it,&end ) ; while( it != end ){ st = *it ; it++ ; index = StringIndexOfChar( st,0,'=' ) ; if( index >= 0 ){ unsetenv( StringSubChar( st,(size_t)index,'\0' ) ) ; StringSubChar( st,(size_t)index,'=' ) ; } } xt = String( "/tmp/zuluCrypt-" ) ; StringAppendInt( xt,uid ) ; StringListAppendString_1( &stl,&xt ) ; _run_time_path = StringListContentAtLast( stl ) ; *stx = stl ; } int zuluCryptSecurityUserOwnTheFile( const char * device,uid_t uid ) { if( device && uid ){} return 0 ; } void zuluCryptSecurityLockMemory_1( string_t st ) { if( st != StringVoid ){ mlock( StringContent( st ),StringLength( st ) ) ; } } void zuluCryptSecurityUnlockMemory_1( string_t st ) { void * e ; size_t f ; if( st != StringVoid ){ e = ( void * )StringContent( st ) ; f = StringLength( st ) ; memset( e,'\0',f ) ; munlock( e,f ) ; } } void zuluCryptSecurityLockMemory( stringList_t stl ) { StringListIterator it ; StringListIterator end ; string_t st ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ st = *it ; it++ ; mlock( StringContent( st ),StringLength( st ) ) ; } } void zuluCryptSecurityUnlockMemory( stringList_t stl ) { StringListIterator it ; StringListIterator end ; string_t st ; void * e ; size_t f ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ st = *it ; it++ ; if( st != StringVoid ){ e = ( void * )StringContent( st ) ; f = StringLength( st ) ; memset( e,'\0',f ) ; munlock( e,f ) ; } } } void zuluCryptSecurityPrintPermissions( void ) { puts( "----------------------" ) ; printf( "uid:%d\neuid:%d\n",(int)getuid(),(int)geteuid() ) ; puts( "----------------------" ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/security.h000066400000000000000000000030501425361753700211310ustar00rootroot00000000000000 /* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ZULUCRYPTSECURITY #define ZULUCRYPTSECURITY #ifdef __cplusplus extern "C" { #endif #include "includes.h" /* * All these functions are defined in security.c */ void zuluCryptSecuritySetPrivilegeElevationErrorFunction( void ( * ) ( const char * ) ) ; void zuluCryptSecuritySanitizeTheEnvironment( uid_t uid,stringList_t * ) ; int zuluCryptSecurityUserOwnTheFile( const char * device,uid_t uid ) ; void zuluCryptSecurityPrintPermissions( void ) ; void zuluCryptSetUserUIDForPrivilegeManagement( uid_t ) ; void zuluCryptSecurityLockMemory( stringList_t stl ) ; void zuluCryptSecurityUnlockMemory( stringList_t stl ) ; void zuluCryptSecurityLockMemory_1( string_t st ) ; void zuluCryptSecurityUnlockMemory_1( string_t st ) ; const char * zuluCryptRunTimePath() ; #ifdef __cplusplus } #endif #endif zuluCrypt-6.2.0/zuluCrypt-cli/bin/test.c000066400000000000000000000276451425361753700202540ustar00rootroot00000000000000 /* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include #include #include #include #include #include #include #include "../pluginManager/libzuluCryptPluginManager.h" #include "../utility/process/process.h" #include "bin_path.h" #include "plugin_path.h" static void _write( int x,const void * y,size_t z ) { if( write( x,y,z ) ){} } static void _close( int x ) { if( close( x ) ){} } static void _fchmod( int x,mode_t y ) { if( fchmod( x,y ) ){} } static const char * luksTestVolume = "/tmp/zuluCrypt-luksTestVolume" ; static const char * plainTestVolume = "/tmp/zuluCrypt-plainTestVolume" ; static const char * tcryptTestVolume = "/tmp/zuluCrypt-tcryptTestVolume" ; static const char * vcryptTestVolume = "/tmp/zuluCrypt-vcryptTestVolume" ; static const char * headerBackUp = "/tmp/zuluCrypt-HeaderBackUp" ; static const char * mount_point = "zuluCrypt-MountPoint" ; static const char * key = "xyz" ; static const char * key1 = "xxx" ; static const char * zuluCryptExe = ZULUCRYPTzuluCrypt ; static const char * pluginPath = ZULUCRYPTplugInPath; static const char * keyfile = "/tmp/zuluCrypt-KeyFile" ; static const char * keyfile1 = "/tmp/zuluCrypt-KeyFile1" ; static void _print( const char * msg ) { printf( "%s",msg ) ; fflush( stdout ) ; } static void _printLine( void ) { sleep( 1 ) ; _print( "\n" ) ; } static void EXIT( int st,char * msg ) { unlink( keyfile ) ; unlink( keyfile1 ) ; unlink( luksTestVolume ) ; unlink( plainTestVolume ) ; unlink( tcryptTestVolume ) ; unlink( vcryptTestVolume ) ; unlink( headerBackUp ) ; rmdir( mount_point ) ; if( msg ){ puts( msg ) ; free( msg ) ; } exit( st ) ; } static void createKeyFiles_0( const char * keyfile ) { int f = open( keyfile,O_WRONLY|O_TRUNC|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH ) ; ssize_t e ; puts( "creating a keyfile" ) ; if( f < 0 ){ perror( "failed to create a keyfile: " ) ; EXIT( 1,NULL ) ; }else{ _fchmod( f,S_IRWXU ) ; e = write( f,key,strlen( key ) ) ; _close( f ) ; if( e != 3 ){ perror( "failed to create a keyfile: " ) ; EXIT( 1,NULL ) ; } } } static void createKeyFiles( void ) { createKeyFiles_0( keyfile ) ; createKeyFiles_0( keyfile1 ) ; } static void createTestImages_0( const char * path ) { int i ; int f ; int opt = O_WRONLY|O_TRUNC|O_CREAT ; char buffer[ 1024 ] = { '\0' } ; int size = 10 * 1024 ; f = open( path,opt,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH ) ; puts( "creating a testing image file" ) ; if( f < 0 ){ perror( "failed to create testing images: " ) ; EXIT( 1,NULL ) ; }else{ _fchmod( f,S_IRWXU ) ; for( i = 0 ; i < size ; i++ ){ _write( f,buffer,1024 ) ; } close( f ) ; } } static void createTestImages( void ) { createTestImages_0( plainTestVolume ) ; createTestImages_0( luksTestVolume ) ; createTestImages_0( tcryptTestVolume ) ; createTestImages_0( vcryptTestVolume ) ; } static void _ProcessPrint( process_t p,void ( *print )( const char * ) ) { char * e = NULL ; ProcessGetOutPut( p,&e,ProcessStdOut ) ; if( ProcessWaitUntilFinished( &p ) != 0 ){ puts( "FAILED" ) ; EXIT( 1,e ) ; }else{ if( e ){ if( print ){ print( e ) ; }else{ puts( "PASSED" ) ; } free( e ) ; } } } static void _ProcessGetResult( process_t p ) { _ProcessPrint( p,NULL ) ; } static void _ProcessGetResultANDPrint( process_t p ) { _ProcessPrint( p,_print ) ; } static void createHeaderBackup( const char * device,const char * msg ) { process_t p ; _print( msg ) ; p = Process( zuluCryptExe,"-B","-d",device,"-z",headerBackUp,NULL ) ; ProcessStart( p ) ; _ProcessGetResult( p ) ; } static void restoreHeaderBackup( const char * device,const char * msg ) { process_t p ; _print( msg ) ; p = Process( zuluCryptExe,"-R","-k","-d",device,"-z",headerBackUp,NULL ) ; ProcessStart( p ) ; _ProcessGetResult( p ) ; } static void createVolume( const char * device,const char * msg,const char * keysource,const char * type,const char * arg1,const char * arg2 ) { process_t p ; _print( msg ) ; p = Process( zuluCryptExe,NULL ) ; if( strcmp( keysource,"-p" ) == 0 ){ ProcessSetArgumentList( p,"-c","-k","-d",device,"-t",type,keysource,key,arg1,arg2,NULL ) ; }else{ ProcessSetArgumentList( p,"-c","-k","-d",device,"-t",type,keysource,keyfile,arg1,arg2,NULL ) ; } ProcessStart( p ) ; _ProcessGetResult( p ) ; } static void closeVolume( const char * device,const char * msg ) { process_t p ; _print( msg ) ; p = Process( zuluCryptExe,"-q","-d",device,NULL ) ; ProcessStart( p ) ; _ProcessGetResult( p ) ; } static void openVolume( const char * device,const char * msg,const char * keysource,const char * arg1,const char * arg2 ) { process_t p ; _print( msg ) ; p = Process( zuluCryptExe,NULL ) ; if( strcmp( keysource,"-p" ) == 0 ){ ProcessSetArgumentList( p,"-o","-d",device,"-m",mount_point,keysource,key,arg1,arg2,NULL ) ; }else{ ProcessSetArgumentList( p,"-o","-d",device,"-m",mount_point,keysource,keyfile,arg1,arg2,NULL ) ; } ProcessStart( p ) ; _ProcessGetResult( p ) ; } static void checkKeySlotsInUse( const char * device ) { process_t p ; _print( "check key slots in use: " ) ; p = Process( zuluCryptExe,"-b","-d",device,NULL ) ; ProcessStart( p ) ; _ProcessGetResultANDPrint( p ) ; } static void addKeysToLuks( const char * device ) { process_t p ; _print( "add a key to a luks volume using a key and a key: " ) ; p = Process( zuluCryptExe,"-a","-d",device,"-y",key,"-l",key1,NULL ) ; ProcessStart( p ) ; _ProcessGetResult( p ) ; _print( "add key to luks volume using keyfile and keyfile: " ) ; p = Process( zuluCryptExe,"-a","-d",device,"-u",keyfile,"-n",keyfile1,NULL ) ; ProcessStart( p ) ; _ProcessGetResult( p ) ; _print( "add key to luks volume using passphrase and keyfile: " ) ; p = Process( zuluCryptExe,"-a","-d",device,"-y",key,"-n",keyfile,NULL ) ; ProcessStart( p ) ; _ProcessGetResult( p ) ; _print( "add key to luks volume using keyfile and passphrase: " ) ; p = Process( zuluCryptExe,"-a","-d",device,"-u",keyfile1,"-l",key1,NULL ) ; ProcessStart( p ) ; _ProcessGetResult( p ) ; } static void removeKeysFromLuksVolume( const char * device ) { process_t p ; _print( "remove a key from a luks volume using a key: " ) ; p = Process( zuluCryptExe,"-r","-d",device,"-p",key,NULL ) ; ProcessStart( p ) ; _ProcessGetResult( p ) ; _print( "remove a key from a luks volume using a keyfile: " ) ; p = Process( zuluCryptExe,"-r","-d",device,"-f",keyfile,NULL ) ; ProcessStart( p ) ; _ProcessGetResult( p ) ; } static void checkForOpenedMappers( void ) { char * d ; int st = 1 ; struct dirent * entry ; DIR * dir = opendir( crypt_get_dir() ) ; printf( "check if there are no opened mappers: " ) ; if( dir == NULL ){ printf( "failed to complete the test\n" ) ; EXIT( 1,NULL ) ; } while( ( entry = readdir( dir ) ) != NULL ){ d = strstr( entry->d_name,"zuluCrypt-" ) ; if( d != NULL ){ if( st ){ printf( "FAILED\n" ) ; st = 0 ; } st = 0 ; printf( "found opened mapper: /dev/mapper/%s\n",entry->d_name ) ; } } closedir( dir ) ; if( st ){ printf( "PASSED\n" ) ; } } static void openVolumeWithPlugIn( const char * device,const char * msg ) { process_t p ; _print( msg ) ; p = Process( zuluCryptExe,"-o","-d",device,"-m",mount_point,"-G",pluginPath,NULL ) ; ProcessStart( p ) ; _ProcessGetResult( p ) ; } static void checkIfDeviceIsLuks( const char * device ) { int st ; process_t p = Process( zuluCryptExe,"-i","-d",device,NULL ) ; ProcessStart( p ) ; st = ProcessWaitUntilFinished( &p ) ; if( st ){ _print( "check if a luks volume is a luks volume: PASSED\n" ) ; } } static int _loop_device_module_is_not_present( void ) { struct stat stlsmod ; int st = 0 ; process_t p ; const char * lsmod = "/sbin/lsmod" ; char * output = NULL ; if( stat( lsmod,&stlsmod ) != 0 ){ return 0 ; } p = Process( lsmod,NULL ) ; ProcessStart( p ) ; ProcessGetOutPut( p,&output,ProcessStdOut ) ; if( output ){ if( strstr( output,"\nloop" ) == NULL ){ st = 1 ; } free( output ) ; } ProcessWaitUntilFinished( &p ) ; return st ; } int zuluCryptRunTest( void ) { uid_t uid = getuid() ; struct stat st ; int r = seteuid( 0 ) ; r = setgid( uid ) ; r = setgroups( 1,&uid ) ; r = setegid( uid ) ; r = setuid( uid ) ; if( r ){} if( _loop_device_module_is_not_present() ){ printf( "\nWARNING: \"loop\" kernel module does not appear to be loaded,\n" ) ; printf( "tests and opening of encrypted containers in files will fail if the module was not built into the kernel\n\n" ) ; } createTestImages() ; createKeyFiles() ; _printLine() ; createVolume( luksTestVolume,"create a luks type volume using a key: ","-p","luks",NULL,NULL ) ; _printLine() ; checkIfDeviceIsLuks( luksTestVolume ) ; _printLine() ; createHeaderBackup( luksTestVolume,"create luks header backup: " ) ; _printLine() ; restoreHeaderBackup( luksTestVolume,"restore luks header from backup: " ) ; _printLine() ; createVolume( plainTestVolume,"create a plain type volume using a key: ","-p","plain",NULL,NULL ) ; _printLine() ; createVolume( tcryptTestVolume,"create a tcrypt type volume using a key: ","-p","tcrypt",NULL,NULL ) ; _printLine() ; createVolume( vcryptTestVolume,"create a vcrypt type volume with pim=10 using a key: ","-p","vcrypt","-g","/dev/urandom.aes.xts-plain64.256.sha512.10" ) ; _printLine() ; openVolume( plainTestVolume,"open a plain volume with a key: ","-p",NULL,NULL ) ; closeVolume( plainTestVolume,"closing a plain volume: " ) ; _printLine() ; openVolume( plainTestVolume,"open a plain volume with a keyfile: ","-f",NULL,NULL ) ; closeVolume( plainTestVolume,"closing a plain volume: " ) ; _printLine() ; openVolume( tcryptTestVolume,"open a tcrypt volume with a key: ","-p",NULL,NULL ) ; closeVolume( tcryptTestVolume,"closing a tcrypt volume: " ) ; _printLine() ; openVolume( vcryptTestVolume,"open a vcrypt volume with a key: ","-p","-t","vcrypt.10" ) ; closeVolume( vcryptTestVolume,"closing a vcrypt volume: " ) ; _printLine() ; if( stat( ZULUCRYPTTestPlugin,&st ) != 0 ){ _print( "test plugin not found,skip plain volume opening with a plugin\n" ) ; }else{ openVolumeWithPlugIn( plainTestVolume,"open a plain volume using a plugin: " ) ; closeVolume( plainTestVolume,"closing a plain volume: " ) ; } _printLine() ; openVolume( luksTestVolume,"open a luks volume with a key: ","-p",NULL,NULL ) ; closeVolume( luksTestVolume,"closing a luks volume: " ) ; _printLine() ; openVolume( luksTestVolume,"open a luks volume with a keyfile: ","-f",NULL,NULL ) ; closeVolume( luksTestVolume,"closing a luks volume: " ) ; _printLine() ; if( stat( ZULUCRYPTTestPlugin,&st ) != 0 ){ _print( "test plugin not found,skip luks volume opening with a plugin\n" ) ; }else{ openVolumeWithPlugIn( luksTestVolume,"open a luks volume using a plugin: " ) ; closeVolume( luksTestVolume,"closing a luks volume: " ) ; } _printLine() ; checkKeySlotsInUse( luksTestVolume ) ; _printLine() ; addKeysToLuks( luksTestVolume ) ; _printLine() ; checkKeySlotsInUse( luksTestVolume ) ; _printLine() ; removeKeysFromLuksVolume( luksTestVolume ) ; checkKeySlotsInUse( luksTestVolume ) ; _printLine() ; checkForOpenedMappers() ; EXIT( 0,NULL ) ; return 0 ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/volume_info.c000066400000000000000000000036261425361753700216100ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include int zuluMountPrintBitLockerProperties( const char * device,uid_t uid ) ; int zuluCryptEXEVolumeInfo( const char * mapper,const char * device,uid_t uid ) { char * output ; int xt = 2 ; string_t p ; zuluCryptSecurityGainElevatedPrivileges() ; if( zuluCryptDeviceHasAgivenFileSystem( device,zuluCryptBitLockerType() ) && zuluCryptDeviceManagedByDislocker( device,uid ) ){ xt = zuluMountPrintBitLockerProperties( device,uid ) ; }else{ /* * ZULUCRYPTlongMapperPath is set in ../constants.h * zuluCryptCreateMapperName() is defined at ../lib/create_mapper_name.c */ p = zuluCryptCreateMapperName( device,mapper,uid,ZULUCRYPTlongMapperPath ) ; /* *zuluCryptVolumeStatus() is defined in ../lib/status.c */ output = zuluCryptVolumeStatus( StringContent( p ) ) ; if( output != NULL ){ printf( "%s\n",output ) ; StringFree( output ) ; xt = 0 ; }else{ printf( gettext( "ERROR: Could not get volume properties,volume is not open or was opened by a different user\n" ) ) ; xt = 2 ; } StringDelete( &p ) ; } zuluCryptSecurityDropElevatedPrivileges() ; return xt ; } zuluCrypt-6.2.0/zuluCrypt-cli/bin/volumes.c000066400000000000000000000562651425361753700207670ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "udev_support.h" /* * NOTE: This source file was previously named "partition.c" */ static stringList_t _zuluCryptAddLVMVolumes( stringList_t stl ) { struct dirent * entry ; string_t st ; string_t xt ; DIR * dir = opendir( "/dev/mapper/" ) ; if( dir != NULL ){ st = String( "/dev/mapper/" ) ; while( ( entry = readdir( dir ) ) != NULL ){ if( !StringAtLeastOneMatch_1( entry->d_name,".","..","control",NULL ) ){ /* * zuluCryptConvertIfPathIsLVM() is defined in ../lib/resolve_paths.c */ xt = zuluCryptConvertIfPathIsLVM( StringAppendAt( st,12,entry->d_name ) ) ; if( StringStartsWith( xt,"/dev/mapper/" ) ){ StringDelete( &xt ) ; }else{ StringListAppendString_1( &stl,&xt ) ; } } } StringDelete( &st ) ; closedir( dir ) ; } return stl ; } static stringList_t _zuluCryptAddMDRAIDVolumes( stringList_t stl ) { DIR * dir = opendir( "/dev/md/" ) ; struct dirent * entry ; char * e ; const char * f ; string_t st ; if( dir != NULL ){ while( ( entry = readdir( dir ) ) != NULL ){ f = entry->d_name ; if( !StringAtLeastOneMatch_1( f,".","..","md-device-map",NULL ) ){ st = String( "/dev/md/" ) ; e = zuluCryptRealPath( StringAppend( st,f ) ) ; if( e != NULL ){ StringListRemoveString( stl,e ) ; StringFree( e ) ; } StringListAppendString_1( &stl,&st ) ; } } closedir( dir ) ; } return stl ; } /* * It is possible for a btrfs volume to cover multiple volumes and this routine * keeps only the first one seen and removes the rest. */ static stringList_t _remove_btfs_multiple_devices( stringList_t stl ) { stringList_t stx = StringListVoid ; stringList_t stz = StringListVoid ; StringListIterator it ; StringListIterator end ; string_t st ; const char * e ; blkid_probe blkid ; StringListGetIterators( stl,&it,&end ) ; zuluCryptSecurityGainElevatedPrivileges() ; while( it != end ){ st = *it ; it++ ; blkid = blkid_new_probe_from_filename( StringContent( st ) ) ; if( blkid != NULL ){ e = NULL ; blkid_do_probe( blkid ) ; blkid_probe_lookup_value( blkid,"TYPE",&e,NULL ) ; if( StringsAreEqual( e,"btrfs" ) ){ e = NULL ; blkid_probe_lookup_value( blkid,"UUID",&e,NULL ) ; if( StringListHasNoEntry( stx,e ) ){ /* * we got a btrfs volume with UUID we do not know about, * This will be the only device with this btrfs UUID we support and * all device operations must happen through this device and this device only. */ stz = StringListAppendString( stz,st ) ; stx = StringListAppend( stx,e ) ; }else{ /* * we already know this UUID and this device is not supported.Any operation on this * device should fail. */ } }else{ /* * not a btrfs volume */ stz = StringListAppendString( stz,st ) ; } blkid_free_probe( blkid ) ; }else{ stz = StringListAppendString( stz,st ) ; } } zuluCryptSecurityDropElevatedPrivileges() ; StringListMultipleDelete( &stl,&stx,NULL ) ; return stz ; } static int _not_removed( stringList_t stl,StringListIterator it,StringListIterator * end ) { string_t st = *it ; StringListIterator e = it + 1 ; if( StringStartsWithAtLeastOne( st,"/dev/sd","/dev/hd","/dev/vd","/dev/xvd","/dev/mmcblk","/dev/nvme",NULL ) ){ /* * we have a partition,lets continue */ if( e != *end ){ /* * we are not at the end of the list,ie,there is atleast one more entry */ if( StringStartsWith_1( *e,st ) ){ /* * *e will contain something like "/dev/sdc3" * st will contain something like "/dev/sdc" * * This device is partitioned and hence we remove the "/dev/sdc" entry * from the list since we dont care about it. */ StringListRemoveAt_1( stl,it,end ) ; return 0 ; } } } return 1 ; } /* * This routine will remove root addresses of a device if the device is found to contain partitions * and will leave the root path if the device is found to not contains partitions. * * Example: * A device with only "/dev/sdc" path will be left alone. * A device with "/dev/sdc" path together with "/dev/sdc1","/dev/sdc2","/dev/sdcN" will cause the * "/dev/sdc" path to be dropped. * * The rationale is that there is nothing useful in the root path if it has partitions beacuse all * useful contents are in partitions.A device with no partitions probably means the useful content is * on the root path */ static stringList_t _remove_root_devices( stringList_t stl ) { StringListIterator it ; StringListIterator end ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ if( _not_removed( stl,it,&end ) ){ it++ ; } } return stl ; } static int _supported_device( const char * device ) { return StringAtLeastOnePrefixMatch( device, "/dev/sd", "/dev/hd", "/dev/vd", "/dev/loop", "/dev/sr", "/dev/md", "/dev/mmcblk", "/dev/nvme", NULL ) ; } static stringList_t _zuluCryptVolumeList_0( int resolve_loop_devices ) { const char * device ; const char * e ; ssize_t index ; StringListIterator it ; StringListIterator end ; stringList_t stz = StringListVoid ; stringList_t stl = StringListVoid ; stringList_t stl_1 = StringListVoid ; string_t xt ; string_t st = StringGetFromVirtualFile( "/proc/partitions" ) ; string_t st_1 = String( "/dev/" ) ; stl = StringListStringSplit( st,'\n' ) ; StringDelete( &st ) ; if( stl == StringListVoid ){ return StringListVoid ; } StringListGetIterators( stl,&it,&end ) ; /* * skip the first entry */ it++ ; zuluCryptSecurityGainElevatedPrivileges() ; while( it != end ){ st = *it ; it++ ; index = StringLastIndexOfChar( st,' ' ) ; if( index == -1 ){ continue ; } e = StringContent( st ) + index + 1 ; device = StringAppendAt( st_1,5,e ) ; if( _supported_device( device ) ){ if( StringPrefixEqual( device,"/dev/loop" ) ){ if( it != end ){ xt = *it ; index = StringLastIndexOfChar( xt,' ' ) ; if( index != -1 ){ e = StringContent( xt ) + index + 1 ; if( StringPrefixEqual( e,device + 5 ) ){ /* * We will get here if the current entry has something * like "/dev/loop0" and the next entry has something * like "/dev/loop0p1. This means the current loop device * is a root loop path of a partitioned loop device and * we are skipping it because it doesnt have any useful * content. All the useful contents is in the loop partitions. */ continue ; } } }else{ } /* * zuluCryptLoopDeviceAddress_1() id defined in ../lib/create_loop_device.c */ e = zuluCryptLoopDeviceAddress_1( device ) ; if( !zuluCryptBitLockerVolume( e ) ){ if( zuluCryptMultiPartitionLoopDevice( device ) ){ stl_1 = StringListAppend( stl_1,device ) ; }else{ if( StringListHasNoEntry( stz,e ) ){ /* * Here we only keep one loop device if the volume file has * more than one loop device */ if( resolve_loop_devices ){ stl_1 = StringListAppend( stl_1,e ) ; }else{ stl_1 = StringListAppend( stl_1,device ) ; } } } stz = StringListAppend( stz,e ) ; } StringFree( e ) ; }else{ stl_1 = StringListAppendIfAbsent( stl_1,device ) ; } } } zuluCryptSecurityDropElevatedPrivileges() ; StringListMultipleDelete( &stl,&stz,NULL ) ; StringDelete( &st_1 ) ; return _zuluCryptAddLVMVolumes( _zuluCryptAddMDRAIDVolumes( _remove_root_devices( stl_1 ) ) ) ; } stringList_t zuluCryptVolumeList( void ) { return _zuluCryptVolumeList_0( 0 ) ; } stringList_t zuluCryptGetAListOfAllVolumes( void ) { return _remove_btfs_multiple_devices( _zuluCryptVolumeList_0( 1 ) ) ; } int zuluCryptDeviceIsSupported( const char * device,uid_t uid ) { stringList_t stl ; int r ; if( StringPrefixEqual( device,"/dev/loop" ) ){ return 1 ; }else{ stl = zuluCryptPartitions( ZULUCRYPTallPartitions,uid ) ; r = StringListHasEntry( stl,device ) ; StringListDelete( &stl ) ; if( r == 1 ){ return 1 ; }else{ /* * zuluCryptUserIsAMemberOfAGroup() is defined in security.c */ return zuluCryptUserIsAMemberOfAGroup( uid,"zulucrypt" ) ; } } } static int _zuluCryptCheckSYSifDeviceIsSystem( const char * device ) { /* * UDEV_SUPPORT is set at configure time by "-DUDEVSUPPORT=true" option,the option being absent equals "-DUDEVSUPPORT=false" * To set the option, configure with "-DUDEVSUPPORT=true" */ #if UDEV_SUPPORT /* * udev support is enabled */ int r ; size_t e ; ssize_t k ; string_t xt ; string_t st ; char dev[ PATH_MAX + 1 ] ; const char * path ; if( StringPrefixNotEqual( device,"/dev/" ) ){ /* * udev doesnt work with path to image files so return early */ return 0 ; } if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * udev thinks all loop devices are system devices and we disagree and hence we return early */ return 0 ; } path = realpath( device,dev ) ; if( path != NULL ){ st = String( path ) ; }else{ st = String( device ) ; } if( StringStartsWithAtLeastOne( st,"/dev/sd","/dev/hd","/dev/vd","/dev/xvd",NULL ) ){ /* * this path will convert something like: "/dev/sdc12" to "/dev/sdc" */ StringRemoveDigits( st ) ; }else if( StringStartsWithAtLeastOne( st,"/dev/mmc","/dev/nvme",NULL ) ){ /* * device path will be something like "/dev/mmcblk0p2" and what we want to do * is cut off the string from p to end iwth "/dev/mmcblk0" */ k = StringIndexOfChar( st,0,'p' ) ; if( k != -1 ){ e = StringLength( st ) - ( size_t )k ; StringRemoveRight( st,e ) ; } } StringReplaceString( st,"/dev/","/sys/block/" ) ; path = StringAppend( st,"/removable" ) ; /* * path will be something like "/sys/block/sda/removable" */ xt = StringGetFromVirtualFile( path ) ; StringDelete( &st ) ; if( xt == StringVoid ){ return 0 ; }else{ r = StringsAreEqual_2( xt,"0\n" ) ; StringDelete( &xt ) ; return r ; } #else if( device ){;} /* * udev support is disabled */ return 0 ; #endif } stringList_t zuluCryptPartitions( int option,uid_t uid ) { const char * device ; const char * e ; stringList_t non_system = StringListVoid ; stringList_t system = StringListVoid ; string_t st ; stringList_t p ; stringList_t stl = zuluCryptVolumeList() ; StringListIterator it ; StringListIterator end ; if( stl == StringListVoid ){ return StringListVoid ; } if( option == ZULUCRYPTallPartitions ){ return _remove_btfs_multiple_devices( stl ) ; } non_system = stl ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptGetFstabList() is defined in ../lib/parse_fstab.c */ stl = zuluCryptGetFstabList( uid ) ; zuluCryptSecurityDropElevatedPrivileges() ; StringListGetIterators( stl,&it,&end ) ; /* * gather an initial list of system and non system partitions by comparing entries in "/etc/fstab" and "/proc/partitions" * fstab entries makes an initial list of system partitions. * the difference btw list in "/proc/partitions" and "/etc/fstab" makes an initial list of non system partitions. */ while( it != end ){ st = *it ; it++ ; if( StringStartsWith( st,"/" ) ){ device = StringReplaceChar_1( st,0,' ','\0' ) ; system = StringListAppend( system,device ) ; StringListRemoveString( non_system,device ) ; } } StringListDelete( &stl ) ; /* * read entried from "crypttab" and then add them to "system" if absent in that * list and remove them from "non system" if present in that list */ p = zuluCryptGetPartitionFromCrypttab() ; if( p != StringListVoid ){ StringListGetIterators( p,&it,&end ) ; while( it != end ){ device = StringContent( *it ) ; it++ ; StringListAppendIfAbsent( system,device ) ; StringListRemoveIfPresent( non_system,device ) ; } StringListDelete( &p ) ; } /* * read entried from "zuluCrypt-system" and then add them to "system" if absent in that list and remove them from "non system" if present * in that list */ p = zuluCryptGetPartitionFromConfigFile( "/etc/zuluCrypt-system" ) ; if( p == StringListVoid ){ /* * This is the new path since zuluCrypt 4.6.9 */ p = zuluCryptGetPartitionFromConfigFile( "/etc/zuluCrypt/system_volumes.list" ) ; } if( p != StringListVoid ){ StringListGetIterators( p,&it,&end ) ; while( it != end ){ device = StringContent( *it ) ; it++ ; StringListAppendIfAbsent( system,device ) ; StringListRemoveIfPresent( non_system,device ) ; } StringListDelete( &p ) ; } /* * At this point: * "system" contains system devices gathered from fstab,zuluCrypt-system and crypttab * "non_system" contains non system devices gathered from /proc/partitions minus system partitions. */ StringListGetIterators( non_system,&it,&end ) ; /* * now we consult udev if enabled and we move partition in the "non system" list to "system" list if udev think they are system */ while( it != end ){ e = StringContent( *it ) ; if( _zuluCryptCheckSYSifDeviceIsSystem( e ) ){ StringListAppendIfAbsent( system,e ) ; StringListRemoveAt_1( non_system,it,&end ) ; }else{ it++ ; } } /* * Now we read from a config file that contains devices that are not to be considered system and remove them from * the system list if present in that list and add them to non system list if absent in that list */ p = zuluCryptGetPartitionFromConfigFile( "/etc/zuluCrypt-nonsystem" ) ; if( p == StringListVoid ){ /* * This is the new path since zuluCrypt 4.6.9 */ p = zuluCryptGetPartitionFromConfigFile( "/etc/zuluCrypt/nonsystem_volumes.list" ) ; } if( p != StringListVoid ){ StringListGetIterators( p,&it,&end ) ; while( it != end ){ device = StringContent( *it ) ; it++ ; StringListRemoveString( system,device ) ; StringListAppendIfAbsent( non_system,device ) ; } StringListDelete( &p ) ; } if( option == ZULUCRYPTsystemPartitions ){ StringListDelete( &non_system ) ; return _remove_btfs_multiple_devices( system ) ; }else{ StringListDelete( &system ) ; return _remove_btfs_multiple_devices( non_system ) ; } } int zuluCryptVolumeIsInSystemVolumeList( const char * device ) { stringList_t p = zuluCryptGetPartitionFromConfigFile( "/etc/zuluCrypt/system_volumes.list" ) ; int r = StringListHasEntry( p,device ) ; StringListDelete( &p ) ; return r ; } u_int64_t zuluCryptGetVolumeSize( const char * device ) { stringList_t stl = StringListVoid ; StringListIterator it ; StringListIterator end ; string_t xt ; const char * e ; u_int64_t r = 0 ; blkid_probe blkid = blkid_new_probe_from_filename( device ) ; if( blkid == NULL ){ return 0 ; } e = NULL ; blkid_do_probe( blkid ) ; blkid_probe_lookup_value( blkid,"TYPE",&e,NULL ) ; if( StringsAreNotEqual( e,"btrfs" ) ){ r = (u_int64_t)blkid_probe_get_size( blkid ) ; blkid_free_probe( blkid ) ; return r ; }else{ /* * we got a btrfs volume,this device could be one among a bunch of devices that makes the btfs volume. * iterate through all known devices and add their sizes to this device if they are a part of the same * btrfs volume. */ e = NULL ; if( blkid_probe_lookup_value( blkid,"UUID",&e,NULL ) == 0 ){ xt = String( e ) ; }else{ xt = StringVoid ; } blkid_free_probe( blkid ) ; if( xt == StringVoid ){ return 0 ; }else{ /* * zuluCryptVolumeList() is defined in this source file */ stl = zuluCryptVolumeList() ; zuluCryptSecurityGainElevatedPrivileges() ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ blkid = blkid_new_probe_from_filename( StringContent( *it ) ) ; it++ ; if( blkid != NULL ){ blkid_do_probe( blkid ) ; e = NULL ; if( blkid_probe_lookup_value( blkid,"UUID",&e,NULL ) == 0 ){ if( StringsAreEqual_2( xt,e ) ){ r += (u_int64_t)blkid_probe_get_size( blkid ) ; } } blkid_free_probe( blkid ) ; } } StringDelete( &xt ) ; StringListDelete( &stl ) ; return r ; } } } void zuluCryptPrintPartitionProperties( const char * device ) { #define SIZE 64 char buffer[ SIZE ] ; const char * e ; u_int64_t size ; blkid_probe blkid ; char * m ; zuluCryptSecurityGainElevatedPrivileges() ; if( zuluCryptNoPartitionLoopDevice( device ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../lib/create_loop_device.c */ e = zuluCryptLoopDeviceAddress_1( device ) ; if( e != NULL ){ printf( "%s\t",e ) ; StringFree( e ) ; }else{ printf( "%s\t",device ) ; } }else{ printf( "%s\t",device ) ; } size = zuluCryptGetVolumeSize( device ) ; blkid = blkid_new_probe_from_filename( device ) ; if( blkid == NULL ){ printf( "Nil\tNil\tNil\tNil\n" ) ; }else{ /* * zuluCryptFormatSize() is defined in ../lib/status.c */ zuluCryptFormatSize( size,buffer,SIZE ) ; printf( "%s\t",buffer ) ; blkid_do_probe( blkid ) ; if( blkid_probe_lookup_value( blkid,"LABEL",&e,NULL ) == 0 ){ printf( "%s\t",e ) ; }else{ printf( "Nil\t" ) ; } e = zuluCryptVolumeType( blkid,device ) ; if( StringPrefixEqual( e,"crypto_LUKS" ) ){ m = zuluCryptGetVolumeType_1( device ) ; if( m ){ printf( "%s\t",m ) ; StringFree( m ) ; }else{ printf( "%s\t",e ) ; } }else{ printf( "%s\t",e ) ; } if( blkid_probe_lookup_value( blkid,"UUID",&e,NULL ) == 0 ){ printf( "%s\n",e ) ; }else{ printf( "Nil\n" ) ; } blkid_free_probe( blkid ) ; } zuluCryptSecurityDropElevatedPrivileges() ; } static void _zuluCryptPrintUnMountedPartitionProperties( stringList_t stl ) { /* * zuluCryptGetMoutedList() is defined in ../lib/process_mountinfo.c */ stringList_t stx = zuluCryptGetMoutedList() ; StringListIterator it ; StringListIterator end ; string_t st ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ st = *it ; it++ ; if( StringListHasStartSequence( stx,StringAppend( st," " ) ) == -1 ){ zuluCryptPrintPartitionProperties( StringRemoveRight( st,1 ) ) ; } } StringListDelete( &stx ) ; } static void _print_list( stringList_t stl ) { const char * e ; char * z ; StringListIterator it ; StringListIterator end ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ e = StringContent( *it ) ; it++ ; if( zuluCryptNoPartitionLoopDevice( e ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../lib/create_loop_device.c */ z = zuluCryptLoopDeviceAddress_1( e ) ; if( z != NULL ){ puts( z ) ; StringFree( z ) ; }else{ puts( e ) ; } }else{ puts( e ) ; } } } int zuluCryptPrintPartitions( int option,int info,uid_t uid ) { stringList_t stl = StringListVoid ; switch( option ){ case 1 : stl = zuluCryptPartitions( ZULUCRYPTallPartitions,uid ) ;break ; case 2 : stl = zuluCryptPartitions( ZULUCRYPTsystemPartitions,uid ) ;break ; case 3 : stl = zuluCryptPartitions( ZULUCRYPTnonSystemPartitions,uid ) ;break ; } if( stl != StringListVoid ){ switch( info ){ case 1 : StringListForEachString( stl,zuluCryptPrintPartitionProperties ) ; break ; case 2 : _zuluCryptPrintUnMountedPartitionProperties( stl ) ; break ; default: _print_list( stl ) ; } StringListDelete( &stl ) ; } return 0 ; } static stringList_t _eval_path( string_t path,stringList_t stl_1 ) { string_t st ; const char * e ; char * ac ; if( StringStartsWith( path,"/" ) ){ /* * zuluCryptResolvePath_1() is defined in resolve_paths.c */ st = zuluCryptResolvePath_1( StringContent( path ) ) ; if( st != StringVoid ){ StringListAppendString_1( &stl_1,&st ) ; } }else if( StringStartsWith( path,"UUID=" ) ){ /* * check above did not find '/' character and we are in this block assuming the line uses UUID */ e = StringRemoveString( path,"\"" ) ; /* * zuluCryptEvaluateDeviceTags() is defined in path_access.c */ ac = zuluCryptEvaluateDeviceTags( "UUID",e + 5 ) ; if( ac != NULL ){ stl_1 = StringListAppend( stl_1,ac ) ; StringFree( ac ) ; } } return stl_1 ; } /* * this function will parse /etc/crypttab to see if it has any entries to be used as system partition. * * sample example of the file content this function was build on. * * secret /dev/sda15 none * secret_1 UUID=d2d210b8-0b1f-419f-9172-9d509ea9af0c none * */ stringList_t zuluCryptGetPartitionFromCrypttab( void ) { stringList_t stl = StringListVoid ; stringList_t stl_1 = StringListVoid ; stringList_t stz ; string_t st ; StringListIterator it ; StringListIterator end ; st = StringGetFromFile( "/etc/crypttab" ) ; stl = StringListStringSplit( st,'\n' ) ; StringDelete( &st ) ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ st = *it ; it++ ; if( !StringStartsWith( st,"#" ) ){ stz = StringListStringSplit( st,' ' ) ; st = StringListStringAtSecondPlace( stz ) ; stl_1 = _eval_path( st,stl_1 ) ; StringListDelete( &stz ) ; } } StringListDelete( &stl ) ; return stl_1 ; } stringList_t zuluCryptGetPartitionFromConfigFile( const char * path ) { StringListIterator it ; StringListIterator end ; stringList_t stl ; stringList_t stl_1 = StringListVoid ; string_t st = StringVoid ; zuluCryptSecurityGainElevatedPrivileges() ; st = StringGetFromFile( path ) ; zuluCryptSecurityDropElevatedPrivileges() ; stl = StringListStringSplit( st,'\n' ) ; StringDelete( &st ) ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ stl_1 = _eval_path( *it,stl_1 ) ; it++ ; } StringListDelete( &stl ) ; return stl_1 ; } int _zuluCryptPartitionIsSystemPartition( const char * dev,uid_t uid ) { stringList_t stl ; int r = 0 ; stl = zuluCryptPartitions( ZULUCRYPTsystemPartitions,uid ) ; if( stl != StringListVoid ){ r = StringListHasEntry( stl,dev ) ; StringListDelete( &stl ) ; } return r ; } int zuluCryptPartitionIsSystemPartition( const char * device,uid_t uid ) { char * dev ; int r ; if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../lib/create_loop_device.c */ dev = zuluCryptLoopDeviceAddress_1( device ) ; if( dev == NULL ){ return 0 ; }else{ r = _zuluCryptPartitionIsSystemPartition( dev,uid ) ; StringFree( dev ) ; return r ; } }else{ return _zuluCryptPartitionIsSystemPartition( device,uid ) ; } } zuluCrypt-6.2.0/zuluCrypt-cli/bin/write_device_with_junk.c000066400000000000000000000251341425361753700240170ustar00rootroot00000000000000 /* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include #include #include #include #include #include #include #include #define SIZE 1024 #define KEY_SIZE 128 #include #define _ignore_result( x ) if( x ){;} static int __exit_as_requested ; static int __sig_caught ; void sigTERMhandler( int sig ) { __exit_as_requested = 1 ; __sig_caught = sig ; printf( "\nINFO: caught signal %d,cleaning up\n",__sig_caught ) ; } /* * define in partition.c * * the function is used to check is a presented path is a system partition or not * */ static int zuluExit( stringList_t stl, int status ) { ssize_t index ; switch( status ){ case 0 : printf( gettext( "SUCCESS: Mapper created successfully\n" ) ) ; index = StringListHasStartSequence( stl,crypt_get_dir() ) ; if( index >= 0 ){ printf( gettext( "Opened mapper path: " ) ) ; StringListPrintLineAt( stl,(size_t)index ) ; } break ; case 1 : printf( gettext( "ERROR: Could not create mapper\n" ) ) ;break ; case 2 : printf( gettext( "ERROR: Could not resolve device path\n" ) ) ;break ; case 3 : printf( gettext( "\nSUCCESS: Random data successfully written\n" ) ) ;break ; case 5 : printf( gettext( "INFO: User chose not to proceed\n" ) ) ;break ; case 8 : printf( gettext( "ERROR: Insufficitied privilege to oped device \n" ) ) ;break ; case 9 : printf( gettext( "ERROR: Device path is invalid\n" ) ) ;break ; case 10: printf( gettext( "ERROR: Passphrase file does not exist\n" ) ) ;break ; case 11: printf( gettext( "ERROR: Could not get enought memory to hold the key file\n" ) ) ;break ; case 12: printf( gettext( "ERROR: Insufficient privilege to open key file for reading\n" ) ) ;break ; case 13: printf( gettext( "ERROR: Can not open a mapper on a device with an opened mapper\n" ) ) ;break ; case 14: printf( gettext( "ERROR: Can not open a mapper on a mounted device\n" ) ) ;break ; case 15: printf( gettext( "INFO: Signal caught,exiting prematurely\n" ) ) ;break ; case 16: printf( gettext( "ERROR: Can not get passphrase in silent mode\n" ) ) ;break ; case 17: printf( gettext( "ERROR: Insufficient memory to hold passphrase\n" ) ) ;break ; case 18: printf( gettext( "ERROR: Insufficient memory to hold 3 characters?really?\n" ) ) ;break ; case 19: printf( gettext( "ERROR: Insufficient privilege to open the file with your privileges?\n" ) ) ;break ; } StringListClearDelete( &stl ) ; return status ; } static int open_plain_as_me_1(const struct_opts * opts,const char * mapping_name,uid_t uid,int op ) { /* * Below is a form of memory management.All strings are collected in a stringlist object to easily delete them * when the function returns.This allows for the function to have multiple exit points without risks of leaking * memory from manually examining each exit point to make sure all strings are deleted or go with multiple goto * code deleting blocks to take into account different exit points. */ stringList_t stl ; string_t * stringArray = StringListArray( &stl,5 ) ; string_t * mapper = &stringArray[ 0 ] ; string_t * passphrase = &stringArray[ 1 ] ; string_t * p = &stringArray[ 2 ] ; string_t * dev_st = &stringArray[ 3 ] ; string_t * dev_1 = &stringArray[ 4 ] ; size_t len = 0 ; const char * source = opts->key_source ; const char * pass = opts->key ; int k = opts->ask_confirmation ; const char * cpass = NULL ; char * d ; const char * device = opts->device ; const char * dev = opts->device ; int j ; int n ; const char * cmapper ; if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress() is defined in ../lib/create_loop_device.c */ d = zuluCryptLoopDeviceAddress( device ) ; *dev_st = StringInherit( &d ) ; dev = StringContent( *dev_st ) ; *dev_1 = StringCopy( *dev_st ) ; device = StringReplaceString( * dev_1,"\\040"," " ) ; } /* * zuluCryptPartitionIsSystemPartition() is defined in ./partition.c */ if( zuluCryptPartitionIsSystemPartition( device,uid ) ){ if( zuluCryptExeOriginalUserIsNotRoot() ){ if( uid != 0 ){ return zuluExit( stl,8 ) ; } } } /* * ZULUCRYPTlongMapperPath and ZULUCRYPTshortMapperPath are in ../constants.h * zuluCryptCreateMapperName() is defined at ../lib/create_mapper_name.c */ *mapper = zuluCryptCreateMapperName( device,mapping_name,uid,ZULUCRYPTshortMapperPath ) ; *p = zuluCryptCreateMapperName( device,mapping_name,uid,ZULUCRYPTlongMapperPath ) ; j = zuluCryptCheckOpenedMapper( StringContent( *p ) ) ; /* * zuluCryptPartitionIsMounted() is defined in ../lib/process_mountinfo.c */ n = zuluCryptPartitionIsMounted( dev ) ; if( j == 1 ){ return zuluExit( stl,13 ) ; } if( n == 1 ){ return zuluExit( stl,14 ) ; } if( k == 0 ){ *passphrase = StringRandomString( 64 ) ; cpass = StringContent( *passphrase ) ; len = StringLength( *passphrase ) ; }else if( source == NULL ){ printf( gettext( "Enter passphrase: " ) ) ; /* * ZULUCRYPT_KEY_MAX_SIZE is set in ../constants.h */ switch( StringSilentlyGetFromTerminal_1( passphrase,ZULUCRYPT_KEY_MAX_SIZE ) ){ case 1 : return zuluExit( stl,16 ) ; case 2 : return zuluExit( stl,17 ) ; } printf( "\n" ) ; cpass = StringContent( *passphrase ) ; len = StringLength( *passphrase ) ; }else{ if( strcmp( source,"-p" ) == 0 ){ *passphrase = String( pass ) ; cpass = StringContent( *passphrase ) ; len = StringLength( *passphrase ) ; }else if( strcmp( source,"-f" ) == 0 ){ /* * zuluCryptGetPassFromFile() is defined at "path_access.c" */ switch( zuluCryptGetPassFromFile( NULL,pass,uid,passphrase ) ){ case 1 : return zuluExit( stl,10 ) ; case 2 : return zuluExit( stl,11 ) ; case 4 : return zuluExit( stl,12 ) ; } cpass = StringContent( *passphrase ) ; len = StringLength( *passphrase ) ; } } if( zuluCryptSecurityGainElevatedPrivileges() ){ /* * zuluCryptOpenPlain() is defined in ../lib/open_plain.c */ if( zuluCryptOpenPlain( device,StringContent( *mapper ),"rw",cpass,len ) != 0 ){ zuluCryptSecurityDropElevatedPrivileges() ; return zuluExit( stl,1 ) ; } } zuluCryptSecurityDropElevatedPrivileges() ; /* * Create a mapper path(usually at /dev/mapper) associated with opened plain mapper above. */ cmapper = StringMultiplePrepend( *mapper,"/",crypt_get_dir(),NULL ) ; /* * mapper path is usually a soft link to /dev/dm-X * resolve the mapper path to its respective /dev/dm-X and set permission on it. * * We set permission of /dev/dm-X pointing to the device to "u+rw" because we want notmal user to be able * to write to the device through the mapper. * * Useful when a normal user want to delete content of the device by writing random data to it. */ d = zuluCryptRealPath( cmapper ) ; if( zuluCryptSecurityGainElevatedPrivileges() ){ if( d != NULL ){ _ignore_result( chown( d,uid,0 ) ) _ignore_result( chmod( d,S_IRWXU ) ) StringFree( d ) ; } zuluCryptSecurityDropElevatedPrivileges() ; }else{ return zuluExit( stl,1 ) ; } if( op == 1 ){ return zuluExit( stl,0 ) ; }else{ StringListClearDelete( &stl ) ; return 0 ; } } int zuluCryptEXEOpenPlainAsMe(const struct_opts * opts,const char * mapping_name,uid_t uid ) { return open_plain_as_me_1( opts,mapping_name,uid,1 ) ; } /* * Purpose of this function is to open a device and write random data to it as a way of hiding information on the disk. * * The above is accomplished by opening a plain mapper against the device and then write to the device through the mapper * */ int zuluCryptEXEWriteDeviceWithJunk( const struct_opts * opts,const char * mapping_name,uid_t uid ) { stringList_t stl = StringListInit() ; string_t * mapper = StringListAssign( stl ) ; string_t * confirm = StringListAssign( stl ); double size ; double size_written ; const char * device = opts->device ; char buffer[ SIZE ] ; int ratio ; int prev_ratio ; int k ; struct sigaction sigac; memset( &sigac,'\0',sizeof( struct sigaction ) ) ; sigac.sa_handler = &sigTERMhandler ; sigaction( SIGINT,&sigac,NULL ) ; sigaction( SIGTERM,&sigac,NULL ) ; sigaction( SIGHUP,&sigac,NULL ) ; __exit_as_requested = 0 ; if( ( k = open_plain_as_me_1( opts,mapping_name,uid,0 ) ) != 0 ){ return k ; } *mapper = zuluCryptCreateMapperName( device,mapping_name,uid,ZULUCRYPTshortMapperPath ) ; StringMultiplePrepend( *mapper,"/",crypt_get_dir(),NULL ) ; if( opts->ask_confirmation ){ printf( gettext( "\nWARNING, device \"%s\" will be overwritten with random data destroying all present data.\n" ),device ) ; printf( gettext( "Are you sure you want to proceed? Type \"YES\" and press enter if you are sure: " ) ) ; *confirm = StringGetFromTerminal_1( 3 ) ; if( *confirm == StringVoid ){ return zuluExit( stl,17 ) ; }else{ k = StringsAreEqual_2( *confirm,gettext( "YES" ) ) ; if( k == 0 ){ if( zuluCryptSecurityGainElevatedPrivileges() ){ zuluCryptCloseMapper( StringContent( *mapper ) ) ; zuluCryptSecurityDropElevatedPrivileges() ; } return zuluExit( stl,5 ) ; } } } k = open( StringContent( *mapper ),O_WRONLY ) ; size = blkid_get_dev_size( k ) ; memset( buffer,0,SIZE ) ; size_written = 0 ; prev_ratio = -1 ; while( write( k,buffer,SIZE ) > 0 ){ if( __exit_as_requested == 1 ){ break ; } size_written += SIZE ; ratio = ( int ) ( ( size_written / size ) * 100 ) ; if( ratio > prev_ratio ){ printf( "\r%s %d%%",gettext( "percentage complete: " ),ratio ) ; fflush( stdout ); prev_ratio = ratio ; } } close( k ) ; if( zuluCryptSecurityGainElevatedPrivileges() ){ zuluCryptCloseMapper( StringContent( *mapper ) ) ; zuluCryptSecurityDropElevatedPrivileges() ; } if( __exit_as_requested == 1 ){ return zuluExit( stl,15 ) ; }else{ return zuluExit( stl,3 ) ; } } zuluCrypt-6.2.0/zuluCrypt-cli/constants.h000066400000000000000000000032661425361753700205370ustar00rootroot00000000000000 /* * * Copyright (c) 2011 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef EXECUTABLES_H #define EXECUTABLES_H #include "bin_path.h" #define ZULUCRYPTmkfs "/sbin/mkfs" #define ZULUCRYPTmount "/bin/mount" #define ZULUCRYPTumount "/bin/umount" #define ZULUCRYPTmkfs_dir "/sbin" #define ZULUCRYPTgroupadd "/usr/sbin/groupadd" #define ZULUCRYPTallPartitions 1 #define ZULUCRYPTsystemPartitions 2 #define ZULUCRYPTnonSystemPartitions 3 #define ZULUCRYPTshortMapperPath 1 #define ZULUCRYPTlongMapperPath 0 #define ZULUCRYPTread 1 #define ZULUCRYPTwrite 0 #define ZULUCRYPTtempFolder "/run/zuluCrypt" #define ZULUCRYPTmountPath "/run/media" #define ZULUCRYPtmountMiniPath "/run" #define ZULUCRYPT_LUKS2_MAX_HEADER_SIZE 33554432 /* * The below numbers are cryptsetup default numbers. */ #define ZULUCRYPT_KEY_MAX_SIZE 512 #define ZULUCRYPT_KEYFILE_MAX_SIZE 8192000 #define ZULUCRYPT_INT_MAX_KEYSIZE 8192000 #define ZULUCRYPT_CHAR_MAX_KEYSIZE "8192000" #endif zuluCrypt-6.2.0/zuluCrypt-cli/lib/000077500000000000000000000000001425361753700171115ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluCrypt-cli/lib/add_key.c000066400000000000000000000132011425361753700206520ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include "luks2_support.h" typedef struct arguments{ const char * key_0 ; size_t key_0_len ; const char * key_1 ; size_t key_1_len ; const char * options ; int ( *set_options )( int *,struct crypt_device *,const struct arguments * ) ; }arguments ; static int zuluExit( int st,struct crypt_device * cd ) { crypt_free( cd ) ; return st ; } static int _add_key( const char * device,const resolve_path_t * opts ) { struct crypt_device * cd ; const arguments * args = opts->args ; int key_slot ; if( zuluCryptVolumeIsNotLuks( device ) ){ return 3 ; } if( crypt_init( &cd,device ) != 0 ){ return 2 ; } if( crypt_load( cd,NULL,NULL ) != 0 ){ return zuluExit( 2,cd ) ; } args->set_options( &key_slot,cd,args ) ; if( crypt_keyslot_add_by_passphrase( cd, key_slot, args->key_0, args->key_0_len, args->key_1, args->key_1_len ) < 0 ){ return zuluExit( 1,cd ) ; }else{ return zuluExit( 0,cd ) ; } } int zuluCryptAddKey( const char * device,const char * existingkey, size_t existingkey_size,const char * newkey,size_t newkey_size ) { return zuluCryptAddKey_0( device, existingkey, existingkey_size, newkey, newkey_size, "-1.-1.argon2id.-1.-1.-1" ) ; } #ifdef CRYPT_LUKS2 static int _set_options( int * key_slot,struct crypt_device * cd,const arguments * args ) { stringList_t stl = StringListSplit( args->options,'.' ) ; size_t list_count = 0 ; char * const * list = NULL ; int r ; StringListStringArray_1( &list,&list_count,stl ) ; const char * pbkdf_type = NULL ; const char * max_memory = NULL ; const char * max_threads = NULL ; const char * time_cost = NULL ; const char * iterations = NULL ; const char * keySlot = NULL ; if( list_count >= 6 ){ time_cost = *( list + 0 ) ; iterations = *( list + 1 ) ; pbkdf_type = *( list + 2 ) ; max_memory = *( list + 3 ) ; max_threads = *( list + 4 ) ; keySlot = *( list + 5 ) ; } struct crypt_pbkdf_type pbkdf ; memset( &pbkdf,'\0',sizeof( pbkdf ) ) ; #if SUPPORT_crypt_get_pbkdf_default /* * added in cryptsetup 2.0.3 */ memcpy( &pbkdf,crypt_get_pbkdf_default( CRYPT_LUKS2 ),sizeof( struct crypt_pbkdf_type ) ) ; #else pbkdf.type = CRYPT_KDF_ARGON2I ; pbkdf.max_memory_kb = 1024 ; pbkdf.parallel_threads = 4 ; pbkdf.hash = "sha256" ; #endif if( StringsAreNotEqual( pbkdf_type,"pbkdf2" ) ){ if( max_memory && StringsAreNotEqual( max_memory,"-1" ) ){ pbkdf.max_memory_kb = ( unsigned int ) StringConvertToInt( max_memory ) ; } if( max_threads && StringsAreNotEqual( max_threads,"-1" ) ){ pbkdf.parallel_threads = ( unsigned int ) StringConvertToInt( max_threads ) ; } }else{ pbkdf.max_memory_kb = 0 ; pbkdf.parallel_threads = 0 ; } if( time_cost && StringsAreNotEqual( time_cost,"-1" ) ){ pbkdf.time_ms = (unsigned int) StringConvertToInt( time_cost ) ; } if( iterations && StringsAreNotEqual( iterations,"-1" ) ){ pbkdf.time_ms = 0 ; pbkdf.iterations = (unsigned int) StringConvertToInt( iterations ) ; pbkdf.flags |= CRYPT_PBKDF_NO_BENCHMARK ; } if( pbkdf_type ){ pbkdf.type = pbkdf_type ; } if( keySlot && StringsAreNotEqual( keySlot,"-1" ) ){ *key_slot = (int)StringConvertToInt( keySlot ) ; }else{ *key_slot = CRYPT_ANY_SLOT ; } r = crypt_set_pbkdf_type( cd,&pbkdf ) ; StringListDelete( &stl ) ; StringFree( list ) ; return r ; } #else static int _set_options( int * key_slot,struct crypt_device * cd, const arguments * args ) { if( cd && args ){} stringList_t stl = StringListSplit( args->options,'.' ) ; size_t list_count = 0 ; char * const * list = NULL ; StringListStringArray_1( &list,&list_count,stl ) ; const char * keySlot ; if( list_count >= 6 ){ keySlot = *( list + 5 ) ; if( keySlot && StringsAreNotEqual( keySlot,"-1" ) ){ *key_slot = (int)StringConvertToInt( keySlot ) ; }else{ *key_slot = CRYPT_ANY_SLOT ; } }else{ *key_slot = CRYPT_ANY_SLOT ; } StringListDelete( &stl ) ; StringFree( list ) ; return 0 ; } #endif int zuluCryptAddKey_0( const char * device, const char * existingkey, size_t existingkey_size, const char * newkey, size_t newkey_size, const char * options ) { /* * resolve_path_t is defined in includes.h */ resolve_path_t opts ; arguments args ; memset( &opts,'\0',sizeof( opts ) ) ; memset( &args,'\0',sizeof( args ) ) ; args.key_0 = existingkey ; args.key_0_len = existingkey_size ; args.key_1 = newkey ; args.key_1_len = newkey_size ; args.options = options ; args.set_options = _set_options ; opts.device = device ; opts.args = &args ; opts.open_mode = O_RDWR ; opts.error_value = 1 ; /* * zuluCryptResolveDevicePath() is defined in resolve_path.c */ return zuluCryptResolveDevicePath( _add_key,&opts ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/bitlocker.c000066400000000000000000000171541425361753700212430ustar00rootroot00000000000000/* * * Copyright (c) 2019 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include #include #include #include #include static int zuluExit( int st,struct crypt_device * cd ) { crypt_free( cd ) ; return st ; } const char * zuluCryptBitLockerType() { return "crypto_BitLocker" ; } const char * zuluCryptBitLockerFolderPrefix( void ) { return "cryptoBitlocker" ; } const char * zuluCryptCryptsetupBitLockerType() { #ifdef CRYPT_BITLK return CRYPT_BITLK ; #else return "" ; #endif } int zuluCryptUseCryptsetupBitLocker( int r ) { #ifdef CRYPT_BITLK return r ; #else return 0 ; #endif } int zuluCryptUseDislockerBitLocker( int r ) { return !zuluCryptUseCryptsetupBitLocker( r ) ; } int zuluCryptIsDislockerMapperPath( const char * e ) { return StringEndsWith_1( e,"/dislocker-file" ) ; } string_t zuluCryptBitLockerMapperPath( uid_t uid ) { const char * m = zuluCryptBitLockerFolderPrefix() ; return String_1( "/run/media/private/",getpwuid( uid )->pw_name,"/",m,NULL ) ; } string_t zuluCryptBitLockerMapperName( const char * e ) { string_t st ; if( zuluCryptNoPartitionLoopDevice( e ) ){ st = zuluCryptLoopDeviceAddress_2( e ) ; }else{ st = String( e ) ; } StringReplaceChar( st,'/','_' ) ; return st ; } string_t zuluCryptBitLockerVolumeFS( const char * e ) { int fd = open( e,O_RDONLY ) ; int r ; int fd_loop ; string_t st = StringVoid ; string_t xt = StringVoid ; if( fd != -1 ){ r = zuluCryptAttachLoopDeviceToFileUsingFileDescriptor( fd,&fd_loop,O_RDONLY,&st ) ; if( r == 1 ){ xt = zulucryptGetBlkidFileSystem( StringContent( st ) ) ; } close( fd ) ; close( fd_loop ) ; } StringDelete( &st ) ; return xt ; } string_t zuluCryptBitLockerFullMapperPath( uid_t uid,const char * e ) { string_t a = zuluCryptBitLockerMapperPath( uid ) ; string_t b = zuluCryptBitLockerMapperName( e ) ; StringAppendString( a,b ) ; StringAppend( a,"/dislocker-file" ) ; StringDelete( &b ) ; return a ; } int zuluCryptDeviceManagedByDislocker( const char * dev,uid_t uid ) { struct stat st ; string_t p = zuluCryptBitLockerFullMapperPath( uid,dev ) ; int r = stat( StringContent( p ),&st ) ; StringDelete( &p ) ; return r == 0 ; } int zuluCryptBitLockerVolume( const char * e ) { struct crypt_device * cd = NULL ; int r ; if( zuluCryptIsDislockerMapperPath( e ) ){ return 1 ; }else{ if( !StringPrefixEqual( e,crypt_get_dir() ) ){ return 0 ; } if( crypt_init_by_name( &cd,e ) != 0 ){ return 0 ; } r = StringsAreEqual( crypt_get_type( cd ),zuluCryptCryptsetupBitLockerType() ) ; crypt_free( cd ) ; return r ; } } char * zuluCryptBitLockerUnmountPath( const char * e ) { /* * e will contain something like "/woof/bar/meaw/dislocker-file" * and we want to remove the "/dislocker-file" part. */ char * m = StringCopy_2( e ) ; ssize_t s = StringLastIndexOfChar_1( m,'/' ) ; if( s != -1 ){ *( m + s ) = '\0' ; } return m ; } int zuluCryptBitLockerVolume_1( const char * e ) { stringList_t stl = StringListSplit( e,' ' ) ; int s = zuluCryptBitLockerVolume( StringListContentAtFirstPlace( stl ) ) ; StringListDelete( &stl ) ; return s ; } string_t zuluCryptBitLockerResolveMapperPath( const char * e,uid_t uid ) { string_t q = String( e ) ; string_t z = zuluCryptBitLockerMapperPath( uid ) ; StringRemoveString( q,StringContent( z ) ) ; StringRemoveString( q,"/dislocker-file" ) ; StringReplaceChar( q,'_','/' ) ; StringDelete( &z ) ; return q ; } const char * zuluCryptBitLockerCreateMapperPath( string_t e,uid_t uid ) { string_t st = zuluCryptBitLockerMapperPath( uid ) ; StringReplaceChar( e,'/','_' ) ; StringPrependString( e,st ) ; StringDelete( &st ) ; return StringAppend( e,"/dislocker-file" ) ; } int zuluCryptBitLockerlock( string_t mapperPath,char ** mount_point ) { const char * n = StringContent( mapperPath ) ; int s ; char * e = NULL ; char * m = zuluCryptGetALoopDeviceAssociatedWithAnImageFile( n ) ; int r ; if( m == NULL ){ return 6 ; } r = zuluCryptUnmountVolume( m,&e ) ; StringFree( m ) ; if( r == 0 ){ s = zuluCryptCloseMapper( n ) ; if( s == 0 ){ if( mount_point ){ *mount_point = e ; } }else{ StringFree( e ) ; } return s ; }else{ return r ; } } static const char * _dislocker_fuse_path() { struct stat st ; const char * e ; int i ; const char * exe[] = { "/usr/bin/dislocker-fuse", "/usr/sbin/dislocker-fuse", "/usr/local/bin/dislocker-fuse", "/usr/local/sbin/dislocker-fuse", "/bin/dislocker-fuse", "/sbin/dislocker-fuse", "/opt/bin/dislocker-fuse", "/opt/sbin/dislocker-fuse", NULL } ; for( i = 0 ; *( exe + i ) != NULL ; i++ ){ e = *( exe + i ) ; if( stat( e,&st ) == 0 ){ fprintf( stderr,"Looking for dislocker-fuse at \"%s\" : PASSED\n",e ) ; return e ; }else{ fprintf( stderr,"Looking for dislocker-fuse at \"%s\" : FAILED\n",e ) ; } } return NULL ; } static int _cryptsetup_unlock_bitlocker( const open_struct_t * opts,string_t * xt ) { int r ; struct crypt_device * cd = NULL ; uint32_t flags = 0 ; if( crypt_init( &cd,opts->device ) != 0 ){ return 4 ; } if( crypt_load( cd,zuluCryptCryptsetupBitLockerType(),NULL ) != 0 ){ return zuluExit( 4,cd ) ; } if( StringHasComponent( opts->m_opts,"ro" ) ){ flags = CRYPT_ACTIVATE_READONLY ; }else{ flags = CRYPT_ACTIVATE_ALLOW_DISCARDS ; } r = crypt_activate_by_passphrase( cd, opts->mapper_name, CRYPT_ANY_SLOT, opts->key, opts->key_len, flags ) ; if( r == 0 ){ *xt = String( opts->mapper_path ) ; return zuluExit( 0,cd ) ; }else{ return zuluExit( 4,cd ) ; } } static int _dislocker_unlock_bitlocker( const open_struct_t * opts,string_t * xt ) { int r ; string_t st ; const char * mapper_path ; process_t p ; string_t m ; char * env[ 2 ] = { NULL,NULL } ; const char * exe = _dislocker_fuse_path() ; if( exe == NULL ){ return 15 ; } st = String_1( opts->mapper_path,opts->mapper_name,NULL ) ; mapper_path = StringContent( st ) ; if( mkdir( mapper_path,S_IRWXU ) != 0 ){ StringDelete( &st ) ; return 2 ; }else{ m = String_1( "DISLOCKER_PASSWORD=",opts->key,NULL ) ; env[ 0 ] = ( char * )StringContent( m ) ; p = Process( exe,opts->device,"-u","--","-oallow_root",mapper_path,NULL ) ; ProcessSetEnvironmentalVariable( p,( char * const * )env ) ; ProcessStart( p ) ; r = ProcessWaitUntilFinished( &p ) ; StringDelete( &m ) ; if( r == 0 ){ StringAppend( st,"/dislocker-file" ) ; *xt = st ; return 0 ; }else{ rmdir( mapper_path ) ; StringDelete( &st ) ; return 4 ; } } } int zuluCryptBitLockerUnlock( const open_struct_t * opts,string_t * xt ) { if( zuluCryptUseCryptsetupBitLocker( opts->use_cryptsetup_for_bitlocker ) ){ return _cryptsetup_unlock_bitlocker( opts,xt ) ; }else{ return _dislocker_unlock_bitlocker( opts,xt ) ; } } zuluCrypt-6.2.0/zuluCrypt-cli/lib/blkid_evaluate_tag.c000066400000000000000000000123201425361753700230610ustar00rootroot00000000000000/* * * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include static char * _resolve_path( char * path ) { char * e ; if( path == NULL ){ return NULL ; }else{ /* * zuluCryptResolvePath_3() is defined in resolve_path.c */ e = zuluCryptResolvePath_3( path ) ; StringFree( path ) ; return e ; } } char * zuluCryptDeviceFromUUID( const char * uuid ) { return _resolve_path( blkid_evaluate_tag( "UUID",uuid,NULL) ) ; } char * zuluCryptDeviceFromLabel( const char * label ) { return _resolve_path( blkid_evaluate_tag( "LABEL",label,NULL ) ) ; } char * zuluCryptDeviceFromPARTUUID( const char * PARTUUID ) { return _resolve_path( blkid_evaluate_tag( "PARTUUID",PARTUUID,NULL ) ) ; } char * zuluCryptDeviceFromPARTLABEL( const char * PARTLABEL ) { return _resolve_path( blkid_evaluate_tag( "PARTLABEL",PARTLABEL,NULL ) ) ; } char * zuluCryptUUIDFromPath_1( const char * device ) { const char * c = NULL ; char * r = NULL ; blkid_probe blkid = blkid_new_probe_from_filename( device ) ; if( blkid != NULL ){ blkid_do_probe( blkid ) ; blkid_probe_lookup_value( blkid,"UUID",&c,NULL ) ; r = StringCopy_2( c ) ; blkid_free_probe( blkid ) ; } return r ; } int zuluCryptFileSystemIsFUSEbased( const char * device ) { const char * cf = NULL ; int st ; blkid_probe blkid = blkid_new_probe_from_filename( device ) ; if( blkid != NULL ){ blkid_do_probe( blkid ) ; blkid_probe_lookup_value( blkid,"TYPE",&cf,NULL ) ; #if 1 st = StringAtLeastOneMatch_1( cf,"ntfs","exfat",NULL ) ; #else st = StringAtLeastOneMatch_1( cf,"ntfs",NULL ) ; #endif blkid_free_probe( blkid ) ; return st ; }else{ return 0 ; } } string_t zulucryptGetBlkidFileSystem( const char * device ) { string_t st = StringVoid ; blkid_probe blkid = blkid_new_probe_from_filename( device ) ; if( blkid != NULL ){ blkid_do_probe( blkid ) ; st = String( zuluCryptVolumeType( blkid,device ) ) ; blkid_free_probe( blkid ) ; } return st ; } static string_t _zulucrypt_getloopfs( const char * device ) { string_t st ; char * e = zuluCryptGetALoopDeviceAssociatedWithAnImageFile( device ) ; if( e ){ st = zulucryptGetBlkidFileSystem( e ) ; StringFree( e ) ; return st ; }else{ return StringVoid ; } } string_t zuluCryptGetFileSystemFromDevice( const char * device ) { if( StringPrefixEqual( device,"/dev/" ) ){ return zulucryptGetBlkidFileSystem( device ) ; }else{ return _zulucrypt_getloopfs( device ) ; } } int zuluCryptNoPartitionLoopDevice( const char * e ) { if( StringPrefixEqual( e,"/dev/loop" ) ){ if( StringCharCount( e,'p' ) > 1 ){ /* * This loop device will be in "/dev/loopXpY" format, it is partitioned. */ return 0 ; }else{ /* * This loop device will be in "/dev/loopX, it is not partitioned. */ return 1 ; } }else{ /* * Not a loop device */ return 0 ; } } int zuluCryptMultiPartitionLoopDevice( const char * e ) { return StringCharCount( e,'p' ) > 1 ; } int zuluCryptDeviceHasAgivenFileSystem( const char * device,const char * fs ) { string_t s = zuluCryptGetFileSystemFromDevice( device ) ; int r = StringContains( s,fs ) ; StringDelete( &s ) ; return r ; } int zuluCryptDeviceHasEncryptedFileSystem( const char * device ) { string_t st = zuluCryptGetFileSystemFromDevice( device ) ; int r ; if( st == StringVoid ){ return 1 ; }else{ if( StringsAreEqual_2( st,"Nil" ) ){ r = 1 ; }else if( StringStartsWith( st,"crypto_" ) ){ r = 1 ; }else{ r = 0 ; } StringDelete( &st ) ; return r ; } } const char * zuluCryptVolumeType( blkid_probe blkid,const char * device ) { char buffer[ 16 ] ; const char * e ; const char * s ; string_t xt ; int fd ; int r ; if( blkid_probe_lookup_value( blkid,"TYPE",&e,NULL ) == 0 ){ xt = String( e ) ; s = StringToLowerCase( xt ) ; r = StringHasComponent( s,"bitlocker" ) ; StringDelete( &xt ) ; if( r ){ return zuluCryptBitLockerType() ; }else{ return e ; } }else{ /* * We are manually checking for signature because blkid has failed us. * Added to support checking for bitlocker signatures since this functionality * in blkid was added in version 2.33(released Nov 6th,2018) and i dont have it yet. */ fd = open( device,O_RDONLY ) ; if( fd != -1 ){ if( read( fd,buffer,11 ) ){} close( fd ) ; if( StringAtLeastOnePrefixMatch( buffer, "\xeb\x52\x90-FVE-FS-", "\xeb\x58\x90-FVE-FS-", "\xeb\x58\x90MSWIN4.1",NULL ) ){ return zuluCryptBitLockerType() ; } } return "Nil" ; } } zuluCrypt-6.2.0/zuluCrypt-cli/lib/close_mapper.c000066400000000000000000000040651425361753700217330ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include #include "includes.h" static int _close_cryptsetup( const char * mapper ) { int r = 1 ; struct crypt_device * cd ; if( crypt_init_by_name( &cd,mapper ) == 0 ){ r = crypt_deactivate( cd,mapper ) ; crypt_free( cd ) ; } return r ; } static int _close_dislocker( const char * mapper ) { char * m = zuluCryptBitLockerUnmountPath( mapper ) ; /* * doing it this way over calling umount() function is better * because the mount tool cleans up /etc/mtab */ int r = ProcessExecute( ZULUCRYPTumount,m,NULL ) ; if( r == 0 ){ rmdir( m ) ; } StringFree( m ) ; return r ; } static int _close_mapper( const char * mapper,int( *function )( const char * ) ) { int i ; int k = 1 ; for( i = 0 ; i < 5 ; i++ ){ k = function( mapper ) ; if( k == 0 ){ return 0 ; }else{ sleep( 1 ) ; } } fprintf( stderr,"Trouble ahead, failed to remove encryption mapper: %s\n",mapper ) ; return k ; } int zuluCryptCloseMapper( const char * mapper ) { if( zuluCryptPathIsNotValid( mapper ) ){ /* * Why are we getting here??? */ return 0 ; }else{ if( zuluCryptIsDislockerMapperPath( mapper ) ){ return _close_mapper( mapper,_close_dislocker ) ; }else{ return _close_mapper( mapper,_close_cryptsetup ) ; } } } zuluCrypt-6.2.0/zuluCrypt-cli/lib/close_volume.c000066400000000000000000000020151425361753700217470ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" int zuluCryptCloseVolume( const char * map,char ** mount_point ) { int i = zuluCryptUnmountVolume( map,mount_point ) ; if( i == 0 || i == 3 ){ if( zuluCryptCloseMapper( map ) == 0 ){ return 0 ; }else{ return 5 ; } }else{ return i ; } } zuluCrypt-6.2.0/zuluCrypt-cli/lib/create_loop_device.c000066400000000000000000000223251425361753700230740ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include #include #include #include #include static int zuluExit( int result,string_t st,int fd_loop,int fd_path ) { if( st == 0 ){ StringDelete( &st ) ; if( fd_loop != -1 ){ close( fd_loop ) ; } } if( fd_path != -1 ){ close( fd_path ) ; } return result ; } static string_t _StringGetFromVirtualFile( string_t * st ) { string_t xt = StringGetFromVirtualFile( StringContent( *st ) ) ; StringDelete( st ) ; return xt ; } static const char * _clean_loop_path( string_t xt ) { if( StringEndsWith( xt," (deleted)\n" ) ){ return StringRemoveString( xt," (deleted)\n" ) ; }else if( StringEndsWith( xt,"\n" ) ){ return StringRemoveRight( xt,1 ) ; }else{ return StringContent( xt ) ; } } /* * We only care about loop device path that are in a form of "/dev/loopX. * * We dont care about loop device path that are in a form of /dev/loopXpY * and this method converts the latter path to the former if found. */ static string_t _loop_device_path( const char * device ) { string_t st ; char * e = StringCopy_2( device ) ; char * s = e + 10 ; while( *s ){ if( *s == 'p' ){ *s = '\0' ; break ; }else{ s++ ; } } st = String_1( "/sys/block/",e + 5,"/loop/backing_file",NULL ) ; StringFree( e ) ; return st ; } string_t zuluCryptLoopDeviceAddress_2( const char * device ) { int fd ; char * path ; struct loop_info64 l_info ; string_t st = _loop_device_path( device ) ; string_t xt = _StringGetFromVirtualFile( &st ) ; if( xt == StringVoid ){ memset( &l_info,'\0',sizeof( struct loop_info64 ) ) ; fd = open( device,O_RDONLY ) ; ioctl( fd,LOOP_GET_STATUS64,&l_info ) ; path = zuluCryptRealPath( ( char * ) l_info.lo_file_name ) ; close( fd ) ; xt = StringInherit( &path ) ; } _clean_loop_path( xt ) ; /* * zuluCryptEncodeMountEntry() is defined in mount_volume.c */ zuluCryptEncodeMountEntry( xt ) ; return xt ; } char * zuluCryptLoopDeviceAddress( const char * device ) { string_t st = zuluCryptLoopDeviceAddress_2( device ) ; return StringDeleteHandle( &st ) ; } char * zuluCryptLoopDeviceAddress_1( const char * device ) { int fd ; char * path ; struct loop_info64 l_info ; string_t st = _loop_device_path( device ) ; string_t xt = _StringGetFromVirtualFile( &st ) ; if( xt == StringVoid ){ memset( &l_info,'\0',sizeof( struct loop_info64 ) ) ; fd = open( device,O_RDONLY ) ; ioctl( fd,LOOP_GET_STATUS64,&l_info ) ; path = zuluCryptRealPath( ( char * ) l_info.lo_file_name ) ; close( fd ) ; st = String( path ) ; StringFree( path ) ; _clean_loop_path( st ) ; return StringDeleteHandle( &st ) ; }else{ _clean_loop_path( xt ) ; return StringDeleteHandle( &xt ) ; } } char * zuluCryptGetALoopDeviceAssociatedWithAnImageFile( const char * path ) { u_int64_t i ; string_t st = String( "" ) ; const char * e ; char * f ; for( i = 0 ; i < 255 ; i++ ){ StringReplace( st,"/dev/loop" ) ; e = StringAppendInt( st,i ) ; f = zuluCryptLoopDeviceAddress_1( e ) ; if( StringsAreEqual( path,f ) ){ StringFree( f ) ; return StringDeleteHandle( &st ) ; }else{ StringFree( f ) ; } } StringDelete( &st ) ; return NULL ; } char * zuluCryptGetLoopDeviceAddress( const char * device ) { char * z = NULL ; const char * e ; string_t st = StringVoid ; string_t xt = StringVoid ; u_int64_t i ; int r ; z = zuluCryptLoopDeviceAddress_1( device ) ; if( z == NULL ){ return NULL ; }else{ st = String( "" ) ; for( i = 0 ; i < 255 ; i++ ){ StringReplace( st,"/sys/block/loop" ) ; StringAppendInt( st,i ) ; xt = StringGetFromVirtualFile( StringAppend( st,"/loop/backing_file" ) ) ; e = _clean_loop_path( xt ) ; r = StringsAreEqual( e,z ) ; StringDelete( &xt ) ; if( r ){ StringReplace( st,"/dev/loop" ) ; e = StringAppendInt( st,i ) ; if( StringsAreNotEqual( device,e ) ){ break ; } }else{ StringReset( st ) ; } } StringFree( z ) ; if( StringIsEmpty( st ) ){ StringDelete( &st ) ; return NULL ; }else{ return StringDeleteHandle( &st ) ; } } } char * zuluCryptGetFileNameFromFileDescriptor( int fd ) { char * e ; char * c ; string_t xt = String( "/proc/self/fd/" ) ; e = zuluCryptRealPath( StringAppendInt( xt,(u_int64_t)fd ) ) ; /* * zuluCryptResolvePath_4() is defined in resolve_paths.c */ c = zuluCryptResolvePath_4( e ) ; StringFree( e ) ; StringDelete( &xt ) ; return c ; } /* * Here,we check if the path we sent to open() is the path open() used. This check is necessary to * guard against some known hypothetical exploits */ static int _paths_are_not_sane( int fd,const char * path ) { char * c = zuluCryptGetFileNameFromFileDescriptor( fd ) ; int st = StringsAreNotEqual( c,path ) ; StringFree( c ) ; return st ; } static int open_loop_device_1( string_t * loop_device ) { string_t st = String( "" ) ; u_int64_t i ; int fd ; const char * path ; struct loop_info64 l_info ; int r = 0 ; for( i = 0 ; i < 255 ; i++ ){ StringReplace( st,"/dev/loop" ) ; path = StringAppendInt( st,i ) ; fd = open( path,O_RDONLY ) ; if( fd == -1 ){ r = 0 ; break ; } if( ioctl( fd,LOOP_GET_STATUS64,&l_info ) != 0 ){ if( errno == ENXIO) { *loop_device = StringCopy( st ) ; close( fd ) ; r = 1 ; break ; } } close( fd ) ; } StringDelete( &st ) ; return r ; } static int open_loop_device( string_t * loop_device ) { int devnr ; int fd_loop ; fd_loop = open( "/dev/loop-control",O_RDONLY ) ; if( fd_loop == -1 ){ return open_loop_device_1( loop_device ) ; }else{ devnr = ioctl( fd_loop,LOOP_CTL_GET_FREE ) ; close( fd_loop ) ; if( devnr < 0 ){ return open_loop_device_1( loop_device ) ; }else{ *loop_device = String( "/dev/loop" ) ; StringAppendInt( *loop_device,(u_int64_t)devnr ) ; return 1 ; } } } static int attach_device_to_loop( int fd_path,int * fd_loop, string_t loop_device,int mode ) { char * path ; size_t size ; struct loop_info64 l_info ; *fd_loop = open( StringContent( loop_device ),mode ) ; memset( &l_info,'\0',sizeof( struct loop_info64 ) ) ; if( *fd_loop == -1 ){ return 0 ; } if( ioctl( *fd_loop,LOOP_SET_FD,fd_path ) == -1 ){ return 0 ; } if( ioctl( *fd_loop,LOOP_GET_STATUS64,&l_info ) == -1 ){ return 0; } l_info.lo_flags |= LO_FLAGS_AUTOCLEAR; path = zuluCryptGetFileNameFromFileDescriptor( fd_path ) ; if( path == NULL ){ return 0 ; }else{ size = sizeof( l_info.lo_file_name ) ; strncpy( ( char * )l_info.lo_file_name,path,size ) ; l_info.lo_file_name[ size - 1 ] = '\0' ; free( path ) ; if( ioctl( *fd_loop,LOOP_SET_STATUS64,&l_info ) == -1 ){ return 0 ; }else{ return 1 ; } } } static int _attach_loop_device_to_file( const char * path,int mode, int * loop_fd,string_t * loop_device ) { string_t loopd = StringVoid ; int fd_loop = -1 ; int fd_path = -1 ; if( !open_loop_device( &loopd ) ){ return zuluExit( 0,loopd,fd_loop,fd_path ) ; } fd_path = open( path,mode ) ; if( fd_path == -1 ){ return zuluExit( 0,loopd,fd_loop,fd_path ) ; } fcntl( fd_path,F_SETFD,FD_CLOEXEC ) ; if( _paths_are_not_sane( fd_path,path ) ){ return zuluExit( 0,loopd,fd_loop,fd_path ) ; } if( attach_device_to_loop( fd_path,&fd_loop,loopd,mode ) ){ *loop_device = loopd ; *loop_fd = fd_loop ; return zuluExit( 1,loopd,fd_loop,fd_path ) ; }else{ return zuluExit( 0,loopd,fd_loop,fd_path ) ; } } int zuluCryptAttachLoopDeviceToFile( const char * path,int mode, int * loop_fd,string_t * loop_device ) { int i = 0 ; int j ; /* * try to attach a loop device multiple times */ for( j = 0 ; j < 3 ; j++ ){ i = _attach_loop_device_to_file( path,mode,loop_fd,loop_device ) ; if( i == 1 ){ break ; }else{ sleep( 1 ) ; } } return i ; } static int _attach_loop_device( int fd_path,int * fd_loop,int mode,string_t * loop_device ) { string_t loopd = StringVoid ; if( !open_loop_device( &loopd ) ){ return 0 ; }else{ if( attach_device_to_loop( fd_path,fd_loop,loopd,mode ) ){ *loop_device = loopd ; return 1 ; }else{ return 0 ; } } } int zuluCryptAttachLoopDeviceToFileUsingFileDescriptor( int fd_path, int * fd_loop, int mode, string_t * loop_device ) { int i = 0 ; int j ; /* * try to attach a loop device multiple times */ for( j = 0 ; j < 3 ; j++ ){ i = _attach_loop_device( fd_path,fd_loop,mode,loop_device ) ; if( i == 1 ){ break ; }else{ sleep( 1 ) ; } } return i ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/create_luks.c000066400000000000000000000265141425361753700215660ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include #include #include "luks2_support.h" typedef struct arguments{ size_t key_len ; size_t key_size ; const char * key ; const char * type ; const char * hash ; const char * algo ; const char * cipher ; const char * rng ; const char * label ; const char * subsystem ; const char * integrity ; const char * pbkdf_type ; const char * pbkdf_memory ; const char * pbkdf_threads ; void * params ; void * pbkdf ; unsigned int time_ms ; unsigned int iterations ; int allowDiscard ; void *( *function )( const struct arguments * ) ; int ( *format )( struct crypt_device * ) ; void ( *set_persistent_flags )( const struct arguments *,struct crypt_device * cd ) ; }arguments ; static void _debug( int a,const char * b,void * c ) { if( c ){} if( a == CRYPT_LOG_ERROR ){ if( b ){ printf( "log level: %d,log msg: %s",a,b ) ; }else{ printf( "log level: %d,log msg: NULL",a ) ; } } } void zuluCryptPrintLogOutPut( void * cd ) { crypt_set_log_callback( cd,_debug,NULL ) ; } static int zuluExit( int st,stringList_t stl,char * const * options ) { StringFree( options ) ; StringListDelete( &stl ) ; return st ; } static int zuluExit_1( int st,struct crypt_device * cd ) { crypt_free( cd ) ; return st ; } static int _not_supported_argument_encountered( char * const * options ) { const char * e = *( options + 1 ) ; /* * supported algorithms are: aes,serpent and twofish */ if( StringAtLeastOneMatch_1( e,"aes","serpent","twofish",NULL ) ){ e = *( options + 2 ) ; /* * supported ciphers are: xts-plain64 and cbc-essiv:sha256 */ if( StringAtLeastOneMatch_1( e,"xts-plain64","cbc-essiv:sha256",NULL ) ){ e = *( options + 3 ) ; /* * supported keysizes in bits are: 256 and 512 */ if( StringAtLeastOneMatch_1( e,"256","512",NULL ) ){ e = *( options + 4 ) ; /* * supported hashes are: sha1,sha256,sha512,ripemd160 and whirlpool */ if( StringsAreEqual( e,"whirlpool" ) ){ /* * zuluCryptWhirlpoolIsSupported() is defined in include.h */ if( zuluCryptWhirlpoolIsSupported() ){ return 0 ; }else{ return 1 ; } } if( StringAtLeastOneMatch_1( e,"sha1","sha256","sha512","ripemd160",NULL ) ){ return 0 ; } } } } return 1 ; } static int _create_luks( const char * device,const resolve_path_t * opts ) { struct crypt_device * cd = NULL ; const arguments * args = opts->args ; if( crypt_init( &cd,device ) != 0 ){ return 1 ; } if( args->integrity != NULL ){ zuluCryptPrintLogOutPut( cd ) ; } if( StringsAreEqual( args->rng,"/dev/random" ) ){ crypt_set_rng_type( cd,CRYPT_RNG_RANDOM ) ; }else{ crypt_set_rng_type( cd,CRYPT_RNG_URANDOM ) ; } if( args->time_ms != 0 && StringsAreEqual( args->type,CRYPT_LUKS1 )){ crypt_set_iteration_time( cd,args->time_ms ) ; } if( crypt_format( cd,args->type,args->algo,args->cipher,NULL,NULL, args->key_size,args->params ) != 0 ){ return zuluExit_1( 2,cd ) ; } args->set_persistent_flags( args,cd ) ; if( crypt_keyslot_add_by_volume_key( cd,CRYPT_ANY_SLOT,NULL,args->key_size, args->key,args->key_len ) < 0 ){ return zuluExit_1( 3,cd ) ; }else{ if( args->integrity ){ if( args->format( cd ) == 0 ){ return zuluExit_1( 0,cd ) ; }else{ return zuluExit_1( 3,cd ) ; } }else{ return zuluExit_1( 0,cd ) ; } } } static int _create_luks_0( arguments * args,const char * device,const char * key, size_t key_len,const char * options ) { /* * resolve_path_t is defined in includes.h */ resolve_path_t opts ; size_t list_count = 0 ; char * const * list = NULL ; stringList_t stl ; const char * m ; /* * options is structure expected to be in a format of: * rng.algo.cipher.keysize.hash.iteration_count */ if( StringHasNothing( options ) ){ stl = StringList( "/dev/urandom" ) ; }else{ stl = StringListSplit( options,'.' ) ; } StringListStringArray_1( &list,&list_count,stl ) ; if( list_count == 1 ){ args->hash = "sha256" ; args->cipher = "xts-plain64" ; args->algo = "aes" ; args->key_size = 64 ; args->rng = *( list + 0 ) ; }else if( list_count >= 5 ){ if( _not_supported_argument_encountered( list ) ){ return zuluExit( 1,stl,list ) ; }else{ args->rng = *( list + 0 ) ; args->algo = *( list + 1 ) ; args->cipher = *( list + 2 ) ; args->key_size = ( unsigned long ) StringConvertToInt( *( list + 3 ) ) / 8 ; args->hash = *( list + 4 ) ; if( list_count > 5 ){ m = *( list + 5 ) ; if( StringsAreNotEqual( m,"-1" ) ){ args->time_ms = ( unsigned int ) StringConvertToInt( m ) ; } } if( list_count > 6 ){ m = *( list + 6 ) ; if( StringsAreNotEqual( m,"-1" ) ){ args->iterations = ( unsigned int ) StringConvertToInt( m ) ; } } if( list_count > 7 ){ m = *( list + 7 ) ; if( StringsAreNotEqual( m,"null" ) ){ args->integrity = m ; } } if( list_count > 8 ){ m = *( list + 8 ) ; if( StringsAreNotEqual( m,"null" ) ){ args->pbkdf_type = m ; } } if( list_count > 9 ){ m = *( list + 9 ) ; if( StringsAreNotEqual( m,"-1" ) ){ args->pbkdf_memory = m ; } } if( list_count > 10 ){ m = *( list + 10 ) ; if( StringsAreNotEqual( m,"-1" ) ){ args->pbkdf_threads = m ; } } if( list_count > 11 ){ m = *( list + 11 ) ; if( StringsAreNotEqual( m,"null" ) ){ args->label = m ; } } if( list_count > 12 ){ m = *( list + 12 ) ; if( StringsAreNotEqual( m,"null" ) ){ args->subsystem = m ; } } if( list_count > 13 ){ m = *( list + 13 ) ; args->allowDiscard = ( int ) StringConvertToInt( m ) ; } } }else{ return zuluExit( 1,stl,list ) ; } args->key = key ; args->key_len = key_len ; args->params = args->function( args ) ; opts.args = args ; opts.device = device ; opts.open_mode = O_RDWR ; opts.error_value = 2 ; /* * zuluCryptResolveDevicePath() is defined in resolve_path.c */ return zuluExit( zuluCryptResolveDevicePath( _create_luks,&opts ),stl,list ) ; } static void * _luks1( const arguments * args ) { struct crypt_params_luks1 * params = args->params ; params->hash = args->hash ; params->data_alignment = 4096 ; return params ; } static int _format_0( struct crypt_device * cd ) { if( cd ){} return 0 ; } static void _set_persistent_flags_0( const arguments * args,struct crypt_device * cd ) { if( args && cd ){} } int zuluCryptCreateLuks( const char * device,const char * key,size_t key_len,const char * options ) { struct crypt_params_luks1 params ; arguments args ; memset( &args,'\0',sizeof( args ) ) ; memset( ¶ms,'\0',sizeof( params ) ) ; args.params = ¶ms ; args.function = _luks1 ; args.type = CRYPT_LUKS1 ; args.format = _format_0 ; args.set_persistent_flags = _set_persistent_flags_0 ; return _create_luks_0( &args,device,key,key_len,options ) ; } #ifdef CRYPT_LUKS2 static int _tools_wipe_progress( uint64_t size,uint64_t offset,void * usrptr ) { int * progress = usrptr ; int x = ( int )( offset * 100 / size ) ; if( x > *progress ){ printf( "%s complete: %d\n","%",x ) ; *progress = x ; } return 0 ; } static int _format( struct crypt_device * cd ) { int progress = 0 ; int i ; string_t s = String_1( crypt_get_dir(),"/",NULL ) ; string_t m = String( "zuluCrypt-wipe-volume-" ) ; const char * mapper = StringAppendInt( m,(u_int64_t)syscall( SYS_gettid ) ) ; int r = crypt_activate_by_volume_key( cd, mapper, NULL, 0, CRYPT_ACTIVATE_PRIVATE | CRYPT_ACTIVATE_NO_JOURNAL ) ; if( r < 0 ){ return 3 ; } printf( "----Starting to wipe an integrity device----\n" ) ; crypt_wipe( cd, StringAppendString( s,m ), CRYPT_WIPE_ZERO, 0, 0, (size_t)crypt_get_sector_size( cd ) * 512, 0, _tools_wipe_progress, &progress ) ; printf( "----Finish wiping an integrity device----\n" ) ; for( i = 0 ; i < 3 ; i++ ){ if( crypt_deactivate( cd,mapper ) == 0 ){ break ; }else{ sleep( 1 ) ; } } StringDelete( &m ) ; StringDelete( &s ) ; return 0 ; } static void _set_persistent_flags( const arguments * args,struct crypt_device * cd ) { if( args->allowDiscard ){ crypt_persistent_flags_set( cd,CRYPT_FLAGS_ACTIVATION,CRYPT_ACTIVATE_ALLOW_DISCARDS ) ; } } void zuluCryptDisableMetadataLocking( void ) { crypt_metadata_locking( NULL,0 ) ; } static void * _luks2( const arguments * args ) { struct crypt_pbkdf_type * pbkdf = args->pbkdf ; struct crypt_params_luks2 * params = args->params ; params->sector_size = 512 ; params->integrity = args->integrity ; params->label = args->label ; params->subsystem = args->subsystem ; #if SUPPORT_crypt_get_pbkdf_default /* * added in cryptsetup 2.0.3 */ memcpy( pbkdf,crypt_get_pbkdf_default( CRYPT_LUKS2 ),sizeof( struct crypt_pbkdf_type ) ) ; #else pbkdf->type = CRYPT_KDF_ARGON2I ; pbkdf->max_memory_kb = 1024 ; pbkdf->parallel_threads = 4 ; #endif if( StringsAreNotEqual( args->pbkdf_type,"pbkdf2" ) ){ if( args->pbkdf_memory ){ pbkdf->max_memory_kb = ( unsigned int ) StringConvertToInt( args->pbkdf_memory ) ; } if( args->pbkdf_threads ){ pbkdf->parallel_threads = ( unsigned int ) StringConvertToInt( args->pbkdf_threads ) ; } }else{ pbkdf->max_memory_kb = 0 ; pbkdf->parallel_threads = 0 ; } if( args->time_ms != 0 ){ pbkdf->time_ms = args->time_ms ; } if( args->iterations != 0 ){ pbkdf->time_ms = 0 ; pbkdf->iterations = args->iterations ; pbkdf->flags |= CRYPT_PBKDF_NO_BENCHMARK ; } if( args->pbkdf_type ){ pbkdf->type = args->pbkdf_type ; } pbkdf->hash = args->hash ; params->pbkdf = pbkdf ; return params ; } int zuluCryptCreateLuks2( const char * device,const char * key,size_t key_len,const char * options ) { struct crypt_params_luks2 params ; struct crypt_pbkdf_type pbkdf ; arguments args ; memset( &args,'\0',sizeof( args ) ) ; memset( ¶ms,'\0',sizeof( params ) ) ; memset( &pbkdf,'\0',sizeof( pbkdf ) ) ; args.pbkdf = &pbkdf ; args.params = ¶ms ; args.function = _luks2 ; args.type = CRYPT_LUKS2 ; args.format = _format ; args.set_persistent_flags = _set_persistent_flags ; return _create_luks_0( &args,device,key,key_len,options ) ; } #else void zuluCryptDisableMetadataLocking( void ) { } int zuluCryptCreateLuks2( const char * device,const char * pass,size_t pass_size,const char * options ) { if( 0 && device && pass && pass_size && options ){;} return 2 ; } #endif zuluCrypt-6.2.0/zuluCrypt-cli/lib/create_mapper_name.c000066400000000000000000000062141425361753700230670ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include /* * This function is responsible for creating a mapper name,the mapper name will show up at "/dev/mapper" if the volume * is successfully opened. * * mapping_name is taken from a path to a volume presented by the user and then "zuluCrypt-XXX-YYYY-ZZZZ-AAAA is added to it to give * a mapper name unique to zuluCrypt. * * XXX is the UID of the user that run the program,YYYY tells if the volume uses UUID or not."NAAN" pads the volume length * to make sure the length of "zuluCrypt-XXX-YYYY" is always the same regardless of what the user provided. * * XXX is there for security reason.It makes sure one user can not manage another user's mappers * * ZZZZ is taken from the last component of the device path. * * AAAA is hash of the string to prevent collissions if two different volumes that ends with the same ZZZZ are used. * * A successfully constructed "ZULUCRYPTshortMapperPath mapper path" will look like "zuluCrypt-500-NAAN-mdraid-2355849641" */ string_t zuluCryptCreateMapperName( const char * device,const char * mapping_name,uid_t uid,int i ) { string_t p ; unsigned long z ; char * e ; /* * ZULUCRYPTshortMapperPath is set in ../constants.h */ if( i == ZULUCRYPTshortMapperPath ){ p = String( "zuluCrypt-" ) ; }else{ /* * zuluCryptMapperPrefix() is defined in include.h */ p = String_1( zuluCryptMapperPrefix(),"/zuluCrypt-",NULL ) ; } StringAppendInt( p,uid ) ; if( StringPrefixEqual( mapping_name,"UUID-" ) ){ StringMultipleAppend( p,"-",mapping_name,"-",NULL ) ; z = StringJenkinsOneAtATimeHash( mapping_name ) ; }else{ StringMultipleAppend( p,"-NAAN-",mapping_name,"-",NULL ) ; if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ./create_loop_device.c */ e = zuluCryptLoopDeviceAddress_1( device ) ; if( e != NULL ){ z = StringJenkinsOneAtATimeHash( e ) ; StringFree( e ) ; }else{ z = StringJenkinsOneAtATimeHash( device ) ; } }else{ z = StringJenkinsOneAtATimeHash( device ) ; } } StringAppendInt( p,z ) ; StringReplaceCharString( p,'_',BASH_SPECIAL_CHARS ) ; return p ; } static const char * _zuluCryptMapperPrefix = NULL ; const char * zuluCryptMapperPrefix( void ) { if( _zuluCryptMapperPrefix == NULL ){ _zuluCryptMapperPrefix = crypt_get_dir() ; return _zuluCryptMapperPrefix ; }else{ return _zuluCryptMapperPrefix ; } } zuluCrypt-6.2.0/zuluCrypt-cli/lib/create_tcrypt.c000066400000000000000000000313171425361753700221320ustar00rootroot00000000000000 /* * * Copyright (c) 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include #include #include #include #include #include "zuluplay_api.h" static const int TRUE = 1 ; static const int FALSE = 0 ; static int _zuluCryptVeraCryptPIM( const char * device,const char * hash,int pim ) { if( device && hash ){} if( pim > 0 ){ return 15000 + ( pim * 1000 ) ; }else{ return 0 ; } } #if 0 static int _zuluCryptSystemVeraCryptPIM( const char * device,const char * hash,int pim ) { if( StringHasAtLeastOneComponent_1( hash,"SHA512","whirlpool",NULL ) ){ return _zuluCryptVeraCryptPIM( device,hash,pim ) ; }else{ return pim * 2048 ; } } #endif static int _create_file_system( const create_tcrypt_t * e,int iteration_count ) { string_t m = StringVoid ; int r ; const char * device_mapper ; const char * mapper ; size_t len ; open_struct_t opts ; memset( &opts,'\0',sizeof( open_struct_t ) ) ; m = String( crypt_get_dir() ) ; len = StringLength( m ) ; StringAppend( m,"/zuluCrypt-" ) ; device_mapper = StringAppendInt( m,(u_int64_t)syscall( SYS_gettid ) ) ; mapper = device_mapper + len + 1 ; opts.volume_type = TCRYPT_NORMAL ; opts.device = e->device ; opts.mapper_name = mapper ; opts.m_opts = "rw" ; opts.key = e->passphrase ; opts.key_len = e->passphrase_size ; if( e->keyfiles != NULL ){ opts.tcrypt_keyfiles = e->keyfiles ; opts.tcrypt_keyfiles_count = e->keyfiles_number ; } opts.veraCrypt_volume = e->veraCrypt_volume ; opts.iteration_count = iteration_count ; /* * zuluCryptOpenTcrypt_1 is defined in open_tcrypt.c */ r = zuluCryptOpenTcrypt_1( &opts ) ; if( r == 0 ){ /* * zuluCryptCreateFileSystemInAVolume() is defined in create_volume.c */ if( zuluCryptCreateFileSystemInAVolume( e->fs,device_mapper ) == 0 ){ r = 0 ; }else{ r = 3 ; } /* * zuluCryptCloseMapper() is defined in close_mapper.c */ zuluCryptCloseMapper( device_mapper ) ; } if( r == 0 && e->hidden_volume_size > 0 ){ opts.volume_type = TCRYPT_HIDDEN ; opts.key = e->passphrase_h ; opts.key_len = e->passphrase_h_size ; if( e->keyfiles_h != NULL ){ opts.tcrypt_keyfiles = e->keyfiles_h ; opts.tcrypt_keyfiles_count = e->keyfiles_h_number ; } r = zuluCryptOpenTcrypt_1( &opts ) ; if( r == 0 ){ if( zuluCryptCreateFileSystemInAVolume( e->fs_h,device_mapper ) == 0 ){ r = 0 ; }else{ r = 3 ; } /* * zuluCryptCloseMapper() is defined in close_mapper.c */ zuluCryptCloseMapper( device_mapper ) ; } } StringDelete( &m ) ; return r ; } static string_t _root_device( const char * device,const char ** sys_device ) { size_t e ; ssize_t r ; string_t st = String( device ) ; if( StringStartsWithAtLeastOne( st,"/dev/sd","/dev/hd",NULL ) ){ /* * this path will convert something like: "/dev/sdc12" to "/dev/sdc". * basically,it removes digits from the end of the string to give the root device * required by tcplay's system volume or fde volume */ *sys_device = StringRemoveDigits( st ) ; }else if( StringStartsWith( st,"/dev/mmc" ) ){ /* * device path will be something like "/dev/mmcblk0p2" and what we want to do * is cut off the string from p to end iwth "/dev/mmcblk0" */ r = StringIndexOfChar( st,0,'p' ) ; if( r != -1 ){ e = StringLength( st ) - ( size_t )r ; *sys_device = StringRemoveRight( st,e ) ; }else{ *sys_device = StringContent( st ) ; } }else{ *sys_device = StringContent( st ) ; } return st ; } static int _modify_tcrypt_header( const char * device,const resolve_path_t * opts ) { tc_api_task task ; int r = !TC_OK ; const char * sys_device = NULL ; const info_t * info = opts->args ; string_t st = StringVoid ; if( info->device == NULL ){ return r ; } if( tc_api_init( 0 ) == TC_OK ){ task = tc_api_task_init( "modify" ) ; if( task != 0 ){ if( StringsAreEqual( info->opt,"sys" ) ){ tc_api_task_set( task,"dev",device ) ; st = _root_device( device,&sys_device ) ; tc_api_task_set( task,"sys",sys_device ) ; }else if( StringsAreEqual( info->opt,"fde" ) ){ st = _root_device( device,&sys_device ) ; tc_api_task_set( task,"dev",sys_device ) ; tc_api_task_set( task,"fde",TRUE ) ; }else{ tc_api_task_set( task,"dev",device ) ; } //tc_api_task_set( task,"veracrypt_mode",info->veraCrypt_volume ) ; /* * zuluCryptVeraCryptPIM() is defined in create_tcrypt.c */ tc_api_task_set( task,"iteration_count", _zuluCryptVeraCryptPIM( device,NULL,info->iteration_count ) ) ; tc_api_task_set( task,"hidden_size_bytes",( u_int64_t )0 ) ; tc_api_task_set( task,info->header_source,info->tmp_path ) ; tc_api_task_set( task,info->header_key_source,info->header_key ) ; tc_api_task_set( task,info->header_new_key_source,info->header_new_key ) ; tc_api_task_set( task,"weak_keys_and_salt",StringsAreEqual( info->rng,"/dev/urandom" ) ) ; r = tc_api_task_do( task ) ; tc_api_task_uninit( task ) ; } tc_api_uninit() ; } StringDelete( &st ) ; return r ; } int zuluCryptModifyTcryptHeader( const info_t * info ) { /* * resolve_path_t is defined in includes.h */ resolve_path_t opts ; memset( &opts,'\0',sizeof( resolve_path_t ) ) ; opts.device = info->device ; opts.args = info ; opts.error_value = 3 ; opts.open_mode = O_RDWR ; /* * zuluCryptResolveDevicePath() is defined in resolve_path.c */ return zuluCryptResolveDevicePath( _modify_tcrypt_header,&opts ) ; } static int _zuluExit( int r,char * const * options,stringList_t stl ) { StringFree( options ) ; StringListDelete( &stl ) ; return r ; } static const struct hashes{ const char * hash ; const char * tcplayHash[ 2 ] ; }Hashes[] = { { "ripemd160",{ "RIPEMD160","RIPEMD160-VC" } }, { "whirlpool",{ "whirlpool","whirlpool-VC" } }, { "sha512" ,{ "SHA512","SHA512-VC" } }, { "sha256" ,{ "SHA256","SHA256-VC" } }, { NULL ,{ NULL,NULL } }, } ; static const char * _set_hash( int type,const char * e ) { const struct hashes * h = Hashes ; for( ; h->hash != NULL ; h++ ){ if( StringsAreEqual( h->hash,e ) ){ return h->tcplayHash[ type ] ; } } return NULL ; } static const struct cipher_chains{ const char * first ; const char * second ; }cipherChains[] = { { "aes" ,"AES-256-XTS" }, { "twofish" ,"TWOFISH-256-XTS" }, { "serpent" ,"SERPENT-256-XTS" }, { "twofish:aes" ,"TWOFISH-256-XTS,AES-256-XTS" }, { "aes:serpent" ,"AES-256-XTS,SERPENT-256-XTS" }, { "serpent:twofish" ,"SERPENT-256-XTS,TWOFISH-256-XTS" }, { "aes:twofish:serpent","AES-256-XTS,TWOFISH-256-XTS,SERPENT-256-XTS" }, { "serpent:twofish:aes","SERPENT-256-XTS,TWOFISH-256-XTS,AES-256-XTS" }, { NULL ,NULL } } ; static const char * _set_cipher_chain( const char * e ) { const struct cipher_chains * s = cipherChains ; for( ; s->first != NULL ; s++ ) { if( StringsAreEqual( s->first,e ) ){ return s->second ; } } return NULL ; } /* * e->encryption_options will contain a structure in the following format: * rng.algorithm.cipher mode.key size in bits.hash function * * different components of the structure are separated by "." character * multiple algorithms are separated by ":" character. * * example structures: * /dev/urandom.aes.xts-plain64.256.ripemd160 * /dev/urandom.aes:twofish:serpent.xts-plain64.256.ripemd160 * * key size field and cipher mode field are currently not in use */ static int _create_tcrypt_volume( const char * device,const resolve_path_t * opts ) { tc_api_task task ; int r = !TC_OK ; size_t i ; size_t k ; const char * const * z ; const char * cipher_chain ; const char * hash ; const char * rng ; char * const * options = NULL ; size_t options_count = 0 ; int iteration_count = 0 ; stringList_t stl ; const create_tcrypt_t * e = opts->args ; if( StringHasNothing( e->encryption_options ) ){ stl = StringList( "/dev/urandom" ) ; }else{ stl = StringListSplit( e->encryption_options,'.' ) ; } StringListStringArray_1( &options,&options_count,stl ) ; if( options_count == 1 ){ cipher_chain = "aes" ; rng = *( options + 0 ) ; if( e->veraCrypt_volume ){ hash = _set_hash( e->veraCrypt_volume,"sha512" ) ; }else{ hash = _set_hash( e->veraCrypt_volume,"ripemd160" ) ; } }else if( options_count >= 5 ){ rng = *( options + 0 ) ; cipher_chain = _set_cipher_chain( *( options + 1 ) ) ; hash = _set_hash( e->veraCrypt_volume,*( options + 4 ) ) ; if( hash == NULL ){ return _zuluExit( !TC_OK,options,stl ) ; } if( options_count >= 6 ){ iteration_count = ( int )StringConvertToInt( *( options + 5 ) ) ; } }else{ return _zuluExit( !TC_OK,options,stl ) ; } if( tc_api_init( 0 ) == TC_OK ){ task = tc_api_task_init( "create" ) ; if( task != 0 ){ tc_api_task_set( task,"iteration_count",_zuluCryptVeraCryptPIM( device,hash,iteration_count ) ) ; tc_api_task_set( task,"dev",device ) ; tc_api_task_set( task,"secure_erase",FALSE ) ; tc_api_task_set( task,"prf_algo",hash ) ; tc_api_task_set( task,"cipher_chain",cipher_chain ) ; tc_api_task_set( task,"passphrase",e->passphrase ) ; tc_api_task_set( task,"weak_keys_and_salt",StringsAreEqual( rng,"/dev/urandom" ) ) ; z = e->keyfiles ; k = e->keyfiles_number ; for( i = 0 ; i < k ; i++ ){ tc_api_task_set( task,"keyfiles",*( z + i ) ) ; } if( e->hidden_volume_size > 0 ){ tc_api_task_set( task,"hidden_size_bytes",e->hidden_volume_size ) ; tc_api_task_set( task,"h_prf_algo",hash ) ; tc_api_task_set( task,"h_cipher_chain",cipher_chain ) ; tc_api_task_set( task,"h_passphrase",e->passphrase_h ) ; z = e->keyfiles_h ; k = e->keyfiles_h_number ; for( i = 0 ; i < k ; i++ ){ tc_api_task_set( task,"h_keyfiles",*( z + i ) ) ; } } r = tc_api_task_do( task ) ; tc_api_task_uninit( task ) ; if( r == TC_OK ){ r = _create_file_system( e,iteration_count ) ; } } tc_api_uninit() ; } return _zuluExit( r,options,stl ) ; } int zuluCryptCreateTCryptVolume( const create_tcrypt_t * tcrypt ) { /* * resolve_path_t is defined in includes.h */ resolve_path_t opts ; memset( &opts,'\0',sizeof( resolve_path_t ) ) ; opts.device = tcrypt->device ; opts.args = tcrypt ; opts.error_value = 3 ; opts.open_mode = O_RDWR ; /* * zuluCryptResolveDevicePath() is defined in resolve_path.c */ return zuluCryptResolveDevicePath( _create_tcrypt_volume,&opts ) ; } int zuluCryptCreateTCrypt( const char * device,const char * file_system,const char * rng, const char * key,size_t key_len,int key_source, u_int64_t hidden_volume_size, const char * file_system_h,const char * key_h,size_t key_len_h,int key_source_h ) { string_t st = StringVoid ; string_t xt = StringVoid ; const char * keyFile ; const char * keyFile_h ; int r ; create_tcrypt_t tcrypt ; memset( &tcrypt,'\0',sizeof( create_tcrypt_t ) ) ; tcrypt.device = device ; tcrypt.fs = file_system ; tcrypt.fs_h = file_system_h ; tcrypt.hidden_volume_size = hidden_volume_size ; tcrypt.encryption_options = rng ; if( key_source == TCRYPT_PASSPHRASE ){ tcrypt.passphrase = key ; }else{ /* * zuluCryptCreateKeyFile() is defined in open_tcrypt.c */ st = zuluCryptCreateKeyFile( key,key_len,"create_tcrypt-1-" ) ; keyFile = StringContent( st ) ; tcrypt.keyfiles = &keyFile ; tcrypt.keyfiles_number = 1 ; } if( tcrypt.hidden_volume_size > 0 ){ if( key_source_h == TCRYPT_PASSPHRASE ){ tcrypt.passphrase_h = key_h ; }else{ xt = zuluCryptCreateKeyFile( key_h,key_len_h,"create_tcrypt-2-" ) ; keyFile_h = StringContent( xt ) ; tcrypt.keyfiles_h = &keyFile_h ; tcrypt.keyfiles_h_number = 1 ; } } r = zuluCryptCreateTCryptVolume( &tcrypt ) ; /* * zuluCryptDeleteFile_1() is defined in file_path_security.c */ if( st != StringVoid ){ zuluCryptDeleteFile_1( st ) ; StringDelete( &st ) ; } if( xt != StringVoid ){ zuluCryptDeleteFile_1( xt ) ; StringDelete( &xt ) ; } return r ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/create_volume.c000066400000000000000000000125251425361753700221140ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include #include #include #include int zuluCryptOpenPlain_2( const char * device, const char * mapper, const char * mode, const char * key, size_t key_len, const char * rng ) ; static int zuluExit( int st,string_t m ) { StringDelete( &m ) ; return st ; } int zuluCryptCreateFileSystemInAVolume( const char * fs,const char * device_mapper ) { int r ; char * e = NULL ; process_t p ; if( StringsAreEqual( fs,"none" ) ){ return 0 ; } /* * zulucryptFileSystemIsSupported() is defined in mount_fs_options.c */ if( zulucryptFileSystemIsSupported( fs ) == 0 ){ return 1 ; } p = Process( ZULUCRYPTmkfs,NULL ) ; if( StringAtLeastOneMatch_1( fs,"ext2","ext3","ext4",NULL ) ){ ProcessSetArgumentList( p,"-t",fs,"-m","1",device_mapper,NULL ) ; }else if( StringsAreEqual( fs,"reiserfs" ) ){ ProcessSetArgumentList( p,"-t",fs,"-f","-f","-q",device_mapper,NULL ) ; }else if( StringsAreEqual( fs,"jfs" ) ){ ProcessSetArgumentList( p,"-t",fs,"-q",device_mapper,NULL ) ; }else if( StringsAreEqual( fs,"ntfs" ) ){ ProcessSetArgumentList( p,"-t",fs,"-f",device_mapper,NULL ) ; }else if( StringsAreEqual( fs,"xfs" ) ){ ProcessSetArgumentList( p,"-t",fs,"-f",device_mapper,NULL ) ; }else{ ProcessSetArgumentList( p,"-t",fs,device_mapper,NULL ) ; /* * unhandled fs are processed here.They are given 60 seconds to accomplish their task * and are assumed to be running in interactive more and are blocked waiting for user input * when they fail to return in time and hence are killed since we cant get to them from GUI */ ProcessSetOptionTimeout( p,60,SIGKILL ) ; } ProcessStart( p ) ; r = ProcessExitStatus( p ) ; if( r != 0 ){ ProcessGetOutPut( p,&e,ProcessStdError ) ; if( e ){ puts( e ) ; StringFree( e ) ; } } ProcessCleanUp( &p ) ; return r ; } typedef struct{ const char * fs ; const char * type ; const char * pass ; size_t pass_size ; const char * rng ; }arguments ; static int _create_volume( const char * device,const resolve_path_t * opts ) { int r ; const char * e ; const char * mapper ; const arguments * args = opts->args ; string_t xt = StringVoid ; string_t m = String( "/zuluCrypt-create-volume-" ) ; mapper = StringAppendInt( m,(u_int64_t)syscall( SYS_gettid ) ) + 1 ; if( StringsAreEqual( args->type,"plain.keyfile" ) ){ if( StringsAreEqual( args->rng,"/dev/urandom" ) ){ e = "/dev/urandom.aes.cbc-essiv:sha256.256.null.0" ; }else if( StringsAreEqual( args->rng,"/dev/random" ) ){ e = "/dev/random.aes.cbc-essiv:sha256.256.null.0" ; }else{ xt = zuluCryptUpdatePlainDmcryptProperties( args->rng ) ; e = StringContent( xt ) ; } if( zuluCryptOpenPlain_2( device,mapper,"rw",args->pass,args->pass_size,e ) != 0 ){ StringDelete( &xt ) ; return zuluExit( 3,m ) ; } StringDelete( &xt ) ; }else if( StringsAreEqual( args->type,"plain" ) ){ if( zuluCryptOpenPlain_2( device,mapper,"rw",args->pass,args->pass_size,args->rng ) != 0 ){ return zuluExit( 3,m ) ; } }else{ if( StringAtLeastOneMatch_1( args->type,"luks","luks1",NULL ) ){ if( zuluCryptCreateLuks( device,args->pass,args->pass_size,args->rng ) != 0 ){ return zuluExit( 3,m ) ; } }else if( StringsAreEqual( args->type,"luks2" ) ){ if( zuluCryptCreateLuks2( device,args->pass,args->pass_size,args->rng ) != 0 ){ return zuluExit( 3,m ) ; } }else{ return zuluExit( 3,m ) ; } if( zuluCryptOpenLuks( device,mapper,"rw",args->pass,args->pass_size ) != 0 ){ return zuluExit( 3,m ) ; } } mapper = StringPrepend( m,crypt_get_dir() ) ; r = zuluCryptCreateFileSystemInAVolume( args->fs,mapper ) ; /* * zuluCryptCloseMapper() is defined in close_mapper.c */ zuluCryptCloseMapper( mapper ) ; if( r == 0 ){ return zuluExit( 0,m ) ; }else{ return zuluExit( 3,m ) ; } } int zuluCryptCreateVolume( const char * device,const char * fs, const char * type,const char * pass, size_t pass_size,const char * rng ) { /* * resolve_path_t is defined in includes.h */ resolve_path_t opts ; arguments args ; memset( &opts,'\0',sizeof( opts ) ) ; memset( &args,'\0',sizeof( args ) ) ; args.fs = fs ; args.type = type ; args.pass = pass ; args.pass_size = pass_size ; args.rng = rng ; opts.device = device ; opts.args = &args ; opts.open_mode = O_RDWR ; opts.error_value = 3 ; /* * zuluCryptResolveDevicePath() is defined in resolve_path.c */ return zuluCryptResolveDevicePath( _create_volume,&opts ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/empty_slots.c000066400000000000000000000151651425361753700216470ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "luks_slot_status.h" #include "includes.h" #include #include #include static char * zuluExit( char * c,struct crypt_device * cd ) { if( cd != NULL ){ crypt_free( cd ) ; } return c ; } static const char * _crypt_init( struct crypt_device ** cd, const char * device, const resolve_path_t * opts ) { const char * type ; if( opts ){} if( crypt_init( cd,device ) != 0 ){ return NULL ; } if( crypt_load( *cd,NULL,NULL ) != 0 ){ return NULL ; } type = crypt_get_type( *cd ) ; if( type == NULL ){ return zuluExit( NULL,*cd ) ; }else{ return type ; } } static char * _empty_slots( const char * device,const resolve_path_t * opts ) { struct crypt_device * cd ; int j ; int k ; string_t p ; const char * type = _crypt_init( &cd,device,opts ) ; if( type == NULL ){ return zuluExit( NULL,cd ) ; } k = crypt_keyslot_max( type ) ; if( k < 0 ){ return zuluExit( NULL,cd ) ; } p = StringEmpty() ; for( j = 0 ; j < k ; j++ ){ switch( crypt_keyslot_status( cd,j ) ){ case CRYPT_SLOT_INACTIVE : StringAppend( p,"0" ) ; break ; case CRYPT_SLOT_ACTIVE : StringAppend( p,"1" ) ; break ; case CRYPT_SLOT_INVALID : StringAppend( p,"2" ) ; break ; case CRYPT_SLOT_ACTIVE_LAST: StringAppend( p,"3" ) ; break ; default : ; } } return zuluExit( StringDeleteHandle( &p ),cd ) ; } char * zuluCryptEmptySlots( const char * device ) { /* * resolve_path_t is defined in includes.h */ resolve_path_t opts ; memset( &opts,'\0',sizeof( opts ) ) ; opts.device = device ; opts.open_mode = O_RDONLY ; opts.error_value_1 = NULL ; /* * zuluCryptResolveDevicePath_1() is defined in resolve_path.c */ return zuluCryptResolveDevicePath_1( _empty_slots,&opts ) ; } #if SUPPORT_crypt_keyslot_get_pbkdf const char * _to_string( unsigned int s ) { static char buffer[ 1024 ] ; snprintf( buffer,sizeof( buffer ),"%d",( int )s ) ; return buffer ; } static void _get_slot_property( string_t q,int j,const char * type,struct crypt_device * cd ) { size_t key_size ; struct crypt_pbkdf_type pbkdf ; if( crypt_keyslot_get_pbkdf( cd,j,&pbkdf ) == 0 ){ StringMultipleAppend( q,"PBKDF type: ",pbkdf.type,"\n",NULL ) ; if( StringsAreEqual( type,CRYPT_LUKS1 ) ){ StringMultipleAppend( q,"PBKDF hash: ",pbkdf.hash,"\n",NULL ) ; StringMultipleAppend( q,"PBKDF iterations: ",_to_string( pbkdf.iterations ),NULL ) ; }else if( StringsAreEqual( type,CRYPT_LUKS2 ) ){ const char * e = crypt_keyslot_get_encryption( cd,j,&key_size ) ; key_size *= 8 ; if( e ){ StringMultipleAppend( q,"Cipher: ",e,"\n",NULL ) ; }else{ StringMultipleAppend( q,"Cipher: ","N/A","\n",NULL ) ; } StringMultipleAppend( q,"Cipher key: ",_to_string( ( unsigned int )key_size )," bits\n",NULL ) ; switch( crypt_keyslot_get_priority( cd,j ) ) { case CRYPT_SLOT_PRIORITY_INVALID : StringAppend( q,"Priority: Invalid\n" ) ; break ; case CRYPT_SLOT_PRIORITY_IGNORE : StringAppend( q,"Priority: Ignore\n" ) ; break ; case CRYPT_SLOT_PRIORITY_NORMAL : StringAppend( q,"Priority: Normal\n" ) ; break ; case CRYPT_SLOT_PRIORITY_PREFER : StringAppend( q,"Priority: Prefer\n" ) ; break ; default: StringAppend( q,"Priority: Unknown\n" ) ; break ; } if( StringsAreEqual( pbkdf.type,"pbkdf2" ) ){ StringMultipleAppend( q,"Hash: ",pbkdf.hash,"\n",NULL ) ; StringMultipleAppend( q,"Iterations: ",_to_string( pbkdf.iterations ),"\n",NULL ) ; }else{ StringMultipleAppend( q,"Time Cost: ",_to_string( pbkdf.iterations ),"\n",NULL ) ; StringMultipleAppend( q,"Memory: ",_to_string( pbkdf.max_memory_kb ),"\n",NULL ) ; StringMultipleAppend( q,"Threads: ",_to_string( pbkdf.parallel_threads ),NULL ) ; } } StringAppend( q,"\n\n" ) ; } } static char * _slots_status( const char * device,const resolve_path_t * opts ) { struct crypt_device * cd ; int j ; int k ; string_t q ; const char * type = _crypt_init( &cd,device,opts ) ; if( type == NULL ){ return zuluExit( NULL,cd ) ; } k = crypt_keyslot_max( type ) ; if( k < 0 ){ return zuluExit( NULL,cd ) ; } k = crypt_keyslot_max( type ) ; if( k < 0 ){ return zuluExit( NULL,cd ) ; } crypt_keyslot_info info ; q = String_1( type," header information\n\n",NULL ) ; for( j = 0 ; j < k ; j++ ){ info = crypt_keyslot_status( cd,j ) ; if( info == CRYPT_SLOT_ACTIVE || info == CRYPT_SLOT_ACTIVE_LAST ) { StringMultipleAppend( q,"Slot Number: ",_to_string( ( unsigned int )j ),"\n",NULL ) ; StringAppend( q,"Slot Status: Active\n" ) ; _get_slot_property( q,j,type,cd ) ; }else if( info == CRYPT_SLOT_INACTIVE ){ StringMultipleAppend( q,"Slot Number: ",_to_string( ( unsigned int )j ),"\n",NULL ) ; StringAppend( q,"Slot Status: Inactive\n\n" ) ; }else if( info == CRYPT_SLOT_INVALID ){ StringMultipleAppend( q,"Slot Number: ",_to_string( ( unsigned int )j ),"\n",NULL ) ; StringAppend( q,"Slot Status: Invalid\n\n" ) ; }else if( info == CRYPT_SLOT_UNBOUND ){ StringMultipleAppend( q,"Slot Number: ",_to_string( ( unsigned int )j ),"\n",NULL ) ; StringAppend( q,"Slot Status: Unbound\n\n" ) ; }else{ StringMultipleAppend( q,"Slot Number: ",_to_string( ( unsigned int )j ),"\n",NULL ) ; StringAppend( q,"Slot Status: Unknown\n\n" ) ; } } return zuluExit( StringDeleteHandle( &q ),cd ) ; } #else static char * _slots_status( const char * device,const resolve_path_t * opts ) { if( device && opts ){} return NULL ; } #endif char * zuluCryptSlotsStatus( const char * device ) { /* * resolve_path_t is defined in includes.h */ resolve_path_t opts ; memset( &opts,'\0',sizeof( opts ) ) ; opts.device = device ; opts.open_mode = O_RDONLY ; opts.error_value_1 = NULL ; /* * zuluCryptResolveDevicePath_1() is defined in resolve_path.c */ return zuluCryptResolveDevicePath_1( _slots_status,&opts ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/file_path_security.c000066400000000000000000000155241425361753700231460ustar00rootroot00000000000000/* * * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include #include #include #include #include #include #define _ignore_result( x ) if( x ){;} int zuluCryptSecureOpenFile( const char * path,int * fd,string_t * file,uid_t uid ) { int st ; int f = -1 ; uid_t org = geteuid() ; char * dev ; _ignore_result( seteuid( uid ) ) f = open( path,O_RDONLY ) ; if( f != -1 ){ dev = zuluCryptGetFileNameFromFileDescriptor( f ) ; *file = StringInherit( &dev ) ; *fd = f ; st = 1 ; }else{ st = 0 ; } _ignore_result( seteuid( org ) ) return st ; } void zuluCryptDeleteFile( const char * file ) { int fd ; void * map ; struct stat st ; if( file != NULL ){ fd = open( file,O_WRONLY ) ; if( fd != -1 ){ fstat( fd,&st ) ; map = mmap( 0,(unsigned long)st.st_size,PROT_WRITE,MAP_PRIVATE,fd,0 ) ; if( map != MAP_FAILED ){ memset( map,'\0',(unsigned long)st.st_size ) ; munmap( map,(unsigned long)st.st_size ) ; } close( fd ) ; } unlink( file ) ; } } void zuluCryptDeleteFile_1( string_t st ) { zuluCryptDeleteFile( StringContent( st ) ) ; } static int _check_if_device_is_supported( int st,uid_t uid,char ** dev ) { string_t fs ; if( st == 0 ){ _ignore_result( seteuid( 0 ) ) /* * zuluCryptGetFileSystemFromDevice() is defined in blkid_evaluate_tag.c */ fs = zuluCryptGetFileSystemFromDevice( *dev ) ; _ignore_result( seteuid( uid ) ) if( fs != StringVoid ){ if( StringHasAtLeastOneComponent( fs,"member","swap",NULL ) ){ st = 100 ; } StringDelete( &fs ) ; } }else{ /* * safely do free( *dev ) followed by *dev = NULL */ StringFree_1( dev ) ; } return st ; } int zuluCryptGetDeviceFileProperties( const char * file,int * fd_path,int * fd_loop,char ** dev,uid_t uid ) { int st = 100 ; int xt = 0 ; int lfd ; const char * dev_1 = NULL ; string_t st_dev = StringVoid ; struct stat stat_st ; struct stat stat_st_1 ; /* * try to open the device with user privileges */ _ignore_result( seteuid( uid ) ) *dev = NULL ; *fd_path = open( file,O_RDONLY ) ; if( *fd_path != -1 ){ fstat( *fd_path,&stat_st ) ; fcntl( *fd_path,F_SETFD,FD_CLOEXEC ) ; /* * A user has access to the device.They should get here only with paths to files they have access to. * Allow access to files only */ if( S_ISREG( stat_st.st_mode ) ){ /* * we can open file in read mode,let see if we can in write mode too */ lfd = open( file,O_RDWR ) ; if( lfd != -1 ){ /* * we can open the file in read write mode */ fstat( lfd,&stat_st_1 ) ; fcntl( lfd,F_SETFD,FD_CLOEXEC ) ; /* * check to make sure the file we got earlier is the same one we got now. * ie check to make sure the file wasnt changed btw calls. */ if( stat_st.st_dev == stat_st_1.st_dev && stat_st.st_ino == stat_st_1.st_ino ){ close( *fd_path ) ; *fd_path = lfd ; _ignore_result( seteuid( 0 ) ) /* * zuluCryptAttachLoopDeviceToFileUsingFileDescriptor() is defined in ./create_loop_device.c */ xt = zuluCryptAttachLoopDeviceToFileUsingFileDescriptor( *fd_path,fd_loop,O_RDWR,&st_dev ) ; _ignore_result( seteuid( uid ) ) *dev = StringDeleteHandle( &st_dev ) ; } }else{ /* * we can not open the file in write mode,continue with read only access */ _ignore_result( seteuid( 0 ) ) /* * zuluCryptAttachLoopDeviceToFileUsingFileDescriptor() is defined in ./create_loop_device.c */ xt = zuluCryptAttachLoopDeviceToFileUsingFileDescriptor( *fd_path,fd_loop,O_RDONLY,&st_dev ) ; _ignore_result( seteuid( uid ) ) *dev = StringDeleteHandle( &st_dev ) ; } if( xt != 1 ){ st = 100 ; _ignore_result( close( *fd_path ) ) *fd_path = -1 ; }else{ dev_1 = zuluCryptGetFileNameFromFileDescriptor( *fd_path ) ; if( StringPrefixEqual( dev_1,"/dev/shm/" ) ){ st =1 ; _ignore_result( close( *fd_path ) ) *fd_path = -1 ; }else{ st = 0 ; } StringFree( dev_1 ) ; } }else{ if( S_ISBLK( stat_st.st_mode ) ){ if( uid == 0 ){ /* * we got a block device and we are root,accept it */ *dev = zuluCryptGetFileNameFromFileDescriptor( *fd_path ) ; st = 0 ; }else{ /* * odd,normal user has access to a block device,allow it only if the * device is in "/dev/" but not in "/dev/shm" */ *dev = zuluCryptGetFileNameFromFileDescriptor( *fd_path ) ; if( StringPrefixEqual( *dev,"/dev/shm/" ) ){ st = 1 ; }else if( StringPrefixEqual( *dev,"/dev/" ) ){ st = 0 ; } } }else if( S_ISDIR( stat_st.st_mode ) ){ st = 2 ; }else{ /* * whatever it is,it cant be good,reject it */ st = 100 ; } _ignore_result( close( *fd_path ) ) *fd_path = -1 ; } }else{ /* * failed to open above with users privileges,try to open the device with root's privileges. * We should only accept block devices in "/dev/" but not in "/dev/shm". */ _ignore_result( seteuid( 0 ) ) *fd_path = open( file,O_RDONLY ) ; if( *fd_path != -1 ){ fstat( *fd_path,&stat_st ) ; /* * zuluCryptGetFileNameFromFileDescriptor() is defined in ./create_loop_device.c */ *dev = zuluCryptGetFileNameFromFileDescriptor( *fd_path ) ; if( S_ISBLK( stat_st.st_mode ) ){ if( StringPrefixEqual( *dev,"/dev/shm/" ) ){ /* * we do not support this path */ st = 1 ; }else if( StringPrefixEqual( *dev,"/dev/" ) ){ /* * got a block device,accept it */ st = 0 ; }else{ /* * reject others */ st = 100 ; } }else{ /* * whatever it is,it cant be good,reject it */ st = 100 ; } /* * We are closing the file because we dont need to hold on to it as paths in "/dev/" can not be moved under us by * normal users. */ _ignore_result( close( *fd_path ) ) *fd_path = -1 ; }else{ /* * invalid path or something i dont know,reject */ st = 100 ; } _ignore_result( seteuid( uid ) ) } return _check_if_device_is_supported( st,uid,dev ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/includes.h000066400000000000000000000425341425361753700211000ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ZULUCRYPT_LIB #define ZULUCRYPT_LIB #include "../utility/string/String.h" #include "../utility/string/StringList.h" #include "../utility/process/process.h" #include "../constants.h" #include "libzuluCrypt.h" #include "../bin/bash_special_chars.h" #include #include #include "support_whirlpool.h" /* * below header is created at build time,it is set by CMakeLists.txt located in the root folder */ #include "version.h" typedef struct{ const char * device ; const char * m_point ; const char * fs ; const char * opts ; uid_t uid ; unsigned long m_flags ; const char * fs_flags ; }m_struct; typedef struct{ const char * device ; const char * header_source ; const char * tmp_path ; const char * opt ; const char * key ; const char * rng ; const char * header_key ; const char * header_key_source ; const char * header_new_key ; const char * header_new_key_source ; uid_t uid ; int veraCrypt_volume ; int iteration_count ; string_t ( *getKey )( int * ) ; }info_t ; typedef struct{ const char * device ; const char * plain_dm_properties ; const char * mapper_name ; const char * mapper_path ; const char * key ; const char * m_point ; const char * fs_opts ; const char * m_opts ; const char * luks_detached_header ; size_t key_len ; size_t tcrypt_keyfiles_count ; uid_t uid ; int volume_type ; int key_source ; int iteration_count ; int veraCrypt_volume ; int trueCrypt_volume ; int bitlocker_volume ; int system_volume ; int key_source_is_keyFile ; int use_cryptsetup_for_bitlocker ; const char ** tcrypt_keyfiles ; unsigned long m_flags ; int use_backup_header ; int use_hidden_header ; void * variables ; }open_struct_t ; typedef struct{ const char * device ; const char * passphrase ; size_t passphrase_size ; const char ** keyfiles ; int keyfiles_number ; const char * passphrase_h ; size_t passphrase_h_size ; const char ** keyfiles_h ; size_t keyfiles_h_number ; const char * encryption_options ; u_int64_t hidden_volume_size ; const char * fs ; const char * fs_h ; int veraCrypt_volume ; }create_tcrypt_t ; typedef struct{ const char * device ; int error_value ; char * error_value_1 ; int open_mode ; const void * args ; }resolve_path_t ; /* * we only support whirlpool with cryptsetup >= 1.6.4 and libgcrypt >= 1.6.1 * * read section 8.3 of cryptsetup FAQ for more info. */ static inline int zuluCryptWhirlpoolIsSupported( void ) { #ifdef GCRYPT_VERSION_NUMBER return GCRYPT_VERSION_NUMBER >= 0x010601 && SUPPORT_WHIRLPOOL ; #else return SUPPORT_WHIRLPOOL ; #endif } /* * zuluCryptVeraCryptPIM() is defined in volume_type.c */ const char * zuluCryptBitLockerType( void ) ; /* * zuluCryptVeraCryptPIM() is defined in volume_type.c */ const char * zuluCryptBitLockerFolderPrefix( void ) ; /* * zuluCryptResolveDevicePath() is defined in resolve_path.c */ int zuluCryptResolveDevicePath( int( * )( const char *,const resolve_path_t * ), const resolve_path_t * ) ; /* * zuluCryptResolveDevicePath_1() is defined in resolve_path.c */ char * zuluCryptResolveDevicePath_1( char *( * )( const char *,const resolve_path_t * ), const resolve_path_t * ) ; /* * zuluCryptResolveDevicePath_0() is defined in resolve_path.c */ int zuluCryptResolveDevicePath_0( int( * )( const char *,const resolve_path_t * ), const open_struct_t *,int ) ; /* * zuluCryptCreateTCryptVolume() is defined in create_tcrypt.c */ int zuluCryptCreateTCryptVolume( const create_tcrypt_t * ) ; /* * zuluCryptOpenVolume_1() is defined in open_volume.c */ int zuluCryptOpenVolume_1( const open_struct_t * ) ; /* * zuluCryptOpenVolume_1() is defined in open_volume.c */ int zuluCryptOpenVolume_2( const open_struct_t * ) ; /* * zuluCryptOpenPlain_1() is defined in open_plain.c */ int zuluCryptOpenPlain_1( const open_struct_t * ) ; /* * zuluCryptOpenLuks_1() is defined in open_luks.c */ int zuluCryptOpenLuks_1( const open_struct_t * ) ; /* * zuluCryptOpenLuks_2() is defined in open_luks.c */ int zuluCryptOpenLuks_2( const open_struct_t * ) ; /* * zuluCryptOpenTcrypt_1() is defined in open_tcrypt.c */ int zuluCryptOpenTcrypt_1( const open_struct_t * ) ; /* * zuluCryptOpenVolume_0() is defined in open_volume.c */ int zuluCryptOpenVolume_0( int( *function )( const open_struct_t * ),const open_struct_t * ) ; /* * this function is defined in create_loop_device.c */ int zuluCryptAttachLoopDeviceToFileUsingFileDescriptor( int fd_path,int * fd_loop,int mode,string_t * loop_device ) ; /* * this function is defined in status.c */ int zuluCryptVolumeManagedByTcplay( const char * mapper ) ; /* * this function is defined in status.c */ void zuluCryptFileSystemProperties( string_t p,const char * mapper,const char * m_point ) ; /* * this function is defined in create_mapper_name.c */ const char * zuluCryptMapperPrefix( void ) ; /* * zuluCryptConvertCipher() is defined in create_tcrypt.c */ const char * zuluCryptConvertCipher( const char * ) ; /* * this function is defined in create_mapper_name.c */ string_t zuluCryptCreateMapperName( const char * device,const char * mapping_name,uid_t uid,int i ) ; /* * this function checks if path exists or not. * return 1 if the path exists * return 0 if it does not */ int zuluCryptPathIsValid( const char * path ) ; /* * this function checks if a path exists or not * return 1 if the path does not exists * return 0 if the path exist */ int zuluCryptPathIsNotValid( const char * path ) ; /* * this function checks if a path exists or not * return 1 if the path does not exists * return 0 if the path exist */ int zuluCryptPathIsNotValid_0( string_t path ) ; /* * zuluCryptDecodeMountEntry() is defined in mount_volume.c */ const char * zuluCryptDecodeMountEntry( string_t ) ; /* * zuluCryptDecodeMountEntry() is defined in mount_volume.c */ const char * zuluCryptEncodeMountEntry( string_t ) ; /* *this function is deined in ../lib/open_volume.c */ string_t zuluCryptUpdatePlainDmcryptProperties( const char * ) ; /* *this function is deined in ../lib/process_mountinfo.c */ stringList_t zuluCryptOpenedVolumesList( uid_t ) ; /* * this is defined in print_mounted_volumes.c */ int zuluCryptPartitionIsMounted( const char * device ) ; /* * parse "/etc/fstab" and return a field at position "pos" on a line * that corresponds to device "device". */ #define MOUNTPOINT 1 #define FILESYSTEM 2 #define MOUNTOPTIONS 3 #define DUMPOPTION 4 #define FSCKOPTION 5 string_t zuluCryptGetMountOptionsFromFstab( const char * device,int pos,uid_t uid ) ; /* * this function is defined in process_mountinfo.c */ string_t zuluCryptGetMountEntry( const char * path ) ; /* * this function is defined in process_mountinfo.c */ string_t zuluCryptGetMountEntry_1( stringList_t stl,const char * path ) ; /* * this function is defined in is_luks.c */ int zuluCryptVolumeIsNotLuks( const char * dev ) ; /* * this function is defined in ./create_loop_device.c */ int zuluCryptAttachLoopDeviceToFile( const char * path,int mode,int * fd,string_t * loop_device ) ; /* * this function is defined in ./blkid_evaluate_tag.c */ string_t zuluCryptGetFileSystemFromDevice( const char * device ) ; /* * this function is defined in ./blkid_evaluate_tag.c */ int zuluCryptDeviceHasEncryptedFileSystem( const char * device ) ; /* * this function is defined in ./blkid_evaluate_tag.c */ const char * zuluCryptVolumeType( blkid_probe blkid,const char * device ) ; /* * this function is defined in ./blkid_evaluate_tag.c */ int zuluCryptDeviceHasAgivenFileSystem( const char * device,const char * fs ) ; /* * this function is defined in ./blkid_evaluate_tag.c */ int zuluCryptMultiPartitionLoopDevice( const char * e ) ; /* * this function is defined in ./blkid_evaluate_tag.c */ int zuluCryptNoPartitionLoopDevice( const char * e ) ; /* * this function is defined in ./create_loop_device.c */ char * zuluCryptLoopDeviceAddress( const char * device ) ; /* * this function is defined in ./mountinfo.c */ int zuluCryptFUSEVolumeIsSupported( const char * fs ) ; /* * this function is defined in ./mountinfo.c */ int zuluCryptFUSEVolumeIsSupportedStartsWith( const char * device ) ; /* * this function is defined in ./create_loop_device.c */ char * zuluCryptLoopDeviceAddress_1( const char * device ) ; /* * this function is defined in ./create_luks.c */ void zuluCryptDisableMetadataLocking( void ) ; /* * this function is defined in ./create_luks.c */ void zuluCryptPrintLogOutPut( void * ) ; /* * this function is defined in ./create_loop_device.c */ string_t zuluCryptLoopDeviceAddress_2( const char * device ) ; /* * this function is defined in ./create_loop_device.c */ char * zuluCryptGetLoopDeviceAddress( const char * device ) ; /* * this function is defined in ./process_mountinfo.c */ char * zuluCryptGetMountPointFromPath( const char * path ) ; /* * this function is defined in ./process_mountinfo.c */ char * zuluCryptGetMountPointFromPath_1( const char * path ) ; /* * this function is defined in ./process_mountinfo.c */ char * zuluCryptResolveDevRoot( void ) ; /* * this function is defined in ./process_mountinfo.c */ stringList_t zuluCryptGetFstabEntryList( const char * device,uid_t uid ) ; /* * this function is defined in blkid_evaluate_tag.c */ char * zuluCryptDeviceFromUUID( const char * uuid ) ; /* * this function is defined in blkid_evaluate_tag.c */ char * zuluCryptDeviceFromLabel( const char * label ) ; /* * this function is defined in blkid_evaluate_tag.c */ char * zuluCryptDeviceFromPARTUUID( const char * p_uuid ) ; /* * this function is defined in blkid_evaluate_tag.c */ char * zuluCryptDeviceFromPARTLABEL( const char * p_label ) ; /* * this function is defined in blkid_evaluate_tag.c */ char * zuluCryptUUIDFromPath_1( const char * device ) ; /* * this function is defined in volume_types.c */ int zuluCryptGetVolumeType( const char * device,const char * pass,size_t pass_size ) ; /* * this function is defined in open_tcrypt.c */ int zuluCryptVolumeIsTcrypt( const char * device,const char * key,int key_source ) ; /* * this function is defined in mount_fs_options.c */ int zuluCryptMountHasNotAllowedFileSystemOptions( uid_t uid,const char * fs_opts,string_t s ) ; /* * this functioon is defined in ./real_path.c */ int zuluCryptPathDidNotChange( const char * path ) ; /* * this functioon is defined in ./real_path.c */ int zuluCryptPathDeviceIsBlockDevice( const char * device ) ; /* * this function is defined in mount_fs_options */ int zulucryptFileSystemIsSupported( const char * fs ) ; /* * this function is defined in user_home_path.c */ string_t zuluCryptGetUserName( uid_t uid ) ; /* * this function is defined in bitlocker.c */ string_t zuluCryptBitLockerMapperPath( uid_t uid ) ; /* * this function is defined in bitlocker.c */ string_t zuluCryptBitLockerFullMapperPath( uid_t uid,const char * e ) ; /* * this function is defined in bitlocker.c */ string_t zuluCryptBitLockerMapperName( const char * ) ; /* * this function is defined in bitlocker.c */ string_t zuluCryptBitLockerResolveMapperPath( const char * e,uid_t ) ; /* * this function is defined in bitlocker.c */ int zuluCryptBitLockerUnlock( const open_struct_t * opts,string_t * st ) ; /* * this function is defined in bitlocker.c */ int zuluCryptBitLockerlock( string_t mapperPath,char ** mount_point ) ; /* * this function is defined in bitlocker.c */ int zuluCryptBitLockerlock_1( const char * ) ; /* * this function is defined in bitlocker.c */ const char * zuluCryptBitLockerCreateMapperPath( string_t e,uid_t uid ) ; /* * this function is defined in bitlocker.c */ int zuluCryptBitLockerVolume( const char * e ) ; /* * this function is defined in bitlocker.c */ char * zuluCryptBitLockerUnmountPath( const char * e ) ; /* * this function is defined in bitlocker.c */ string_t zuluCryptBitLockerVolumeFS( const char * e ) ; /* * this function is defined in blkid_evaluate_tag.c */ string_t zulucryptGetBlkidFileSystem( const char * device ) ; /* * this function is defined in bitlocker.c */ int zuluCryptBitLockerVolume_1( const char * e ) ; /* * this function is defined in real_path.c */ char * zuluCryptRealPath( const char * path ) ; /* * this function is defined in create_loop_device.c */ char * zuluCryptGetFileNameFromFileDescriptor( int fd ) ; /* * this function is defined in file_path_security.c */ int zuluCryptGetDeviceFileProperties( const char * file,int * fd_path,int * fd_loop,char ** dev,uid_t uid ) ; /* * this function is defined in file_path_security.c */ int zuluCryptSecureOpenFile( const char * path,int * fd_path,string_t * file,uid_t uid ) ; /* * this function is defined in mount_volume.c */ stringList_t zuluCryptGetFstabList( uid_t ) ; /* * this function is defined in process_mountinfo.c */ stringList_t zuluCryptGetMountInfoList( void ) ; /* * this function is defined in process_mountinfo.c */ stringList_t zuluCryptGetMountInfoList_1( void ) ; /* * this function is defined in status.c */ char * zuluCryptGetVolumeTypeFromMapperPath( const char * mapper ) ; /* * this function is defined in status.c */ char * zuluCryptGetVolumeType_1( const char * m ) ; /* * this function is defined in create_volume.c */ int zuluCryptCreateFileSystemInAVolume( const char * fs,const char * device_mapper ) ; /* * this function is defined in resolve_paths.c */ string_t zuluCryptConvertIfPathIsLVM( const char * path ) ; /* * this function is defined in resolve_paths.c */ char * zuluCryptResolveMDPath( const char * path ) ; /* * this function is defined in resolve_paths.c */ string_t zuluCryptResolveMDPath_1( const char * path ) ; /* * this function is defined in file_path_security.c */ void zuluCryptDeleteFile( const char * file ) ; /* * this function is defined in file_path_security.c */ void zuluCryptDeleteFile_1( string_t file ) ; /* * this function is defined in blkid_evaluate_tag.c */ int zuluCryptFileSystemIsFUSEbased( const char * device ) ; /* * this function is defined in status.c */ void zuluCryptFormatSize( u_int64_t number,char * buffer,size_t buffer_size ) ; /* * zuluCryptCreateKeyFile() is defined in open_tcrypt.c */ string_t zuluCryptCreateKeyFile( const char * key,size_t key_len,const char * fileName ) ; /* * zuluCryptCreateKeyFile_1() is defined in open_tcrypt.c */ string_t zuluCryptCreateKeyFile_1( string_t key,const char * fileName ) ; /* * zuluCryptResolvePath_2() is defined in resolve_paths.c */ string_t zuluCryptResolvePath_2( const char * path ) ; /* * zuluCryptResolvePath_1() is defined in resolve_paths.c */ string_t zuluCryptResolvePath_1( const char * path ) ; /* * zuluCryptResolvePath_3() is defined in resolve_paths.c */ char * zuluCryptResolvePath_3( const char * path ) ; /* * zuluCryptResolvePath_4() is defined in resolve_paths.c */ char * zuluCryptResolvePath_4( const char * path ) ; /* * zuluCryptResolvePath() is defined in resolve_paths.c */ char * zuluCryptResolvePath( const char * path ) ; /* * zuluCryptGetMoutedList_1() is defined in process_mountinfo.c */ stringList_t zuluCryptGetMoutedList_1( void ) ; /* * zuluCryptGetMoutedList() is defined in process_mountinfo.c */ stringList_t zuluCryptGetMoutedList( void ) ; /* * zuluCryptMountPointIsActive() is defined in process_mountinfo.c */ int zuluCryptMountPointIsActive( const char * ) ; /* * zuluCryptGetALoopDeviceAssociatedWithAnImageFile() is defined in create_loop_device.c */ char * zuluCryptGetALoopDeviceAssociatedWithAnImageFile( const char * path ) ; /* * zuluCryptGetAListOfMountedVolumes() is defined in process_mountinfo.c */ stringList_t zuluCryptGetAListOfMountedVolumes( void ) ; /* * zuluCryptModifyTcryptHeader() is defined in create_tcplay.c */ int zuluCryptModifyTcryptHeader( const info_t * info ) ; /* * this function is defined in mount_fs_options.c */ int zuluCryptUserIsAMemberOfAGroup( uid_t uid,const char * groupname ) ; /* * this function is defined in bitlocker.c */ int zuluCryptUseCryptsetupBitLocker( int ) ; /* * this function is defined in bitlocker.c */ int zuluCryptUseDislockerBitLocker( int ) ; /* * this function is defined in open_tcrypt.c */ void * zuluCryptCryptsetupTCryptVCrypt( const open_struct_t * opt ) ; /* * this function is defined in bitlocker.c */ const char * zuluCryptCryptsetupBitLockerType( void ) ; /* * this function is defined in open_tcrypt.c */ const char * zuluCryptCryptsetupTCRYPTType( void ) ; /* * this function is defined in bitlocker.c */ int zuluCryptIsDislockerMapperPath( const char * ) ; /* * this function is defined in bitlocker.c */ int zuluCryptDeviceManagedByDislocker( const char * device,uid_t ) ; /* * this function is defined in empty_slots.c */ char * zuluCryptSlotsStatus( const char * device ) ; #endif zuluCrypt-6.2.0/zuluCrypt-cli/lib/is_luks.c000066400000000000000000000030141425361753700207240ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include static int _is_luks( const char * dev,const resolve_path_t * opts ) { struct crypt_device * cd ; int st ; if( opts ){} if( crypt_init( &cd,dev ) != 0 ){ return 0 ; } st = crypt_load( cd,NULL,NULL ) ; crypt_free( cd ) ; return st == 0 ; } int zuluCryptVolumeIsLuks( const char * device ) { /* * resolve_path_t is defined in includes.h */ resolve_path_t opts ; memset( &opts,'\0',sizeof( opts ) ) ; opts.device = device ; opts.error_value = 0 ; /* * zuluCryptResolveDevicePath() is defined in resolve_path.c */ return zuluCryptResolveDevicePath( _is_luks,&opts ) ; } int zuluCryptVolumeIsNotLuks( const char * dev ) { return !zuluCryptVolumeIsLuks( dev ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/is_path_valid.c000066400000000000000000000021351425361753700220640ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include int zuluCryptPathIsValid( const char * path ) { struct stat st ; return stat( path,&st ) == 0 ; } int zuluCryptPathIsNotValid( const char * path ) { struct stat st ; return stat( path,&st ) != 0 ; } int zuluCryptPathIsNotValid_0( string_t path ) { return zuluCryptPathIsNotValid( StringContent( path ) ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/libzuluCrypt.h000066400000000000000000000447071425361753700220060ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ZULUCRYPT #define ZULUCRYPT #ifdef __cplusplus extern "C" { #endif #include /* * version 3.1.0 */ #define ZULUCRYPT310 /* * This version adds zuluCryptCreateTCrypt() and zuluCryptOpenTcrypt() function * These function are used specifically to handle truecrypt volumes since their functionality * is too different from cryptsetup volumes necessitating different APIs */ #define ZULUCRYPT320 /** * Return the version string of the library * */ const char * zuluCryptVersion( void ) ; /** * This function checks to see if a volume is a luks volume or not. * * input : path to a partition/file to be checked if it is a luks device * return values: * 1 - the device is a cryptsetup device of type "luks" * 0 - the device is not a crptsetup device of type "luks". */ int zuluCryptVolumeIsLuks( const char * device ) ; /** * This function openes a LUKS or PLAIN volume and mount it at m_point,the volume is only opened if m_point is NULL * * return values: * 0 - success, the encrypted volume was opened and mounted successfully * 1 - ERROR: failed to mount ntfs file system using ntfs-3g,is ntfs-3g package installed? * 2 - ERROR: There seem to already be an opened volume associated with "mapping_name" argument * 3 - ERROR: device does not exist. * 4 - ERROR: wrong passphrase * 6 - ERROR: key file does not exist : * 8 - ERROR: failed to open device * 12- ERROR: could not get a lock on /etc/mtab~ * 15- ERROR: could not remove mapper */ int zuluCryptOpenVolume( const char * device, /* path to a file/partition to be opened */ const char * mapper, /* mapper name( will show up in /dev/mapper/ ) */ const char * m_point,/* mount point path, opened volume will be mounted on this path */ uid_t id, /* owner of the mount point will have this id with rwx------ permissions */ unsigned long m_opts, /* option as expected by the second from last argument of mount() command */ const char * fs_opts, /* options as expected by the last command ofr mount() */ const char * pass, /* encrypted volume passphrase to be used to open the volume */ size_t pass_size /* passphrase size */ ) ; /** * This function unmount the mounted opened volume,delete the mount point and then close the volume. * * input : mapper name used when the volume was opened * output: mount point path, just incase you need it. You can pass NULL if you dont. * * path to mount point will be allocated dynamically on success and hence you should free it ONLY when * the function return with a success. * * return values: * 0 - success * 1 - ERROR: unmounting the mount point failed,mount point or one or more files are in use * 2 - ERROR: close failed, encrypted volume associated with mapping_name argument is not opened * */ int zuluCryptCloseVolume(const char * mapper, /* mapper is the full address of the volume as it appears at /dev/mapper */ char ** mount_point ) ; /* returned pointer to mount point */ /** * This function closes a mapper * * return values: * 0 - success * 1 - ERROR: could not close the mapper. */ int zuluCryptCloseMapper( const char * mapper ) ;/* mapper is the full address of the volume as it */ /* appears at /dev/mapper */ /** * This function unmounts a volume* * * return values * 0 - success * 1 - ERROR: mapper does not have an entry in fstab * 2 - ERROR: the mount point and/or one or more files are in use * 3 - ERROR: volume does not have an entry in /etc/mtab * 4 - ERROR: could not get a lock on /etc/mtab~ */ int zuluCryptUnmountVolume( const char * mapper, /*mapper is the full address of the volume as it appears at /dev/mapper */ char ** m_point ) ; /*mount point will be returned on this variable if closing succeeded.useful for deleting */ /*mount point folder.Its the caller's responsibility to free() this return value */ /** * This function mounts a volume * * return values: * 0 - success * -1 - failed to mount a file system,wrong file system type or option or permission denied * 4 - ERROR: mount failed, couldnt find valid file system in the volume * 12 - ERROR: could not get a lock on /etc/mtab~ * */ int zuluCryptMountVolume( const char * mapper, /* path to a file or partition to mount */ const char * m_point,/* mount point */ unsigned long fs_opts,/* file system option as expected by the second from last argument of mount()*/ const char * m_opts, /* file system option as expected by the last command of mount() */ uid_t id ) ; /* user id the mount point should use */ /** * This function returns a pointer to string with volume status information. * An example output: * * /dev/mapper/zuluCrypt-luks is active and is in use. * type: LUKS1 * cipher: cbc-essiv:sha256 * keysize: 256 bits * device: /dev/loop1 * loop: /home/ink/luks * offset: 4096 sectors * size: 200704 sectors * mode: readonly * * input : mapper name used when the volume was opened. Mapper name is the name that shows up in /dev/mapper * * output is a pointer to a string with volume info. * * remember to free() the returned pointer when done with the output. */ char * zuluCryptVolumeStatus( const char * mapper ); /* mapper is the full address of the volume as it */ /* appears at /dev/mapper */ /** * This function creates an encrypted LUKS or PLAIN volume. * return values: * 0 - success * 1 - ERROR: device argument does not point to a file or partition * 2 - ERROR: wrong argument. (probably mistyped fs or rng arguments) * 3 - ERROR: could not create the volume * * opts argument is not used for PLAIN volumes, * for LUKS volumes,the argument is a string with the format of "rng.algorithm.cipher mode,key size in bits.hash" * possible combinations are: * rng can either be: "/dev/random" or "/dev/urandom" * algorithm can be either" "aes" or "serpent" or "twofish" * cipher mode can be either" "xts-plain64" or "cbc-essiv:sha256" * key size can be either" "256" or "512" * hash can be either: "sha1" or "sha256" or "sha512" or "ripemd160" or "whirlpool" * * The default string to set is: "/dev/urandom.aes.xts-plain64.256.sha1" * * NOTE: This function expected mkfs executable to be present and its full path to be /sbin/mkfs */ int zuluCryptCreateVolume( const char * device, /* path to a file or partition */ const char * fs, /* file system to use in the volume(ext2,ext3.ext4,vfat etc) */ const char * type, /* type of volume to create( luks or plain ) */ const char * passphrase,/* passphrase to use to create the volume */ size_t passphrase_size, /* passphrase size */ const char * opts ); /* volume creation options */ /*mrequired when creating luks volume, just pick one if you */ /* creating a plain device, it will be ignored */ /** * This function adds a key to a luks volume * * return value: * 0 - success, the new key was added successfully * 1 - ERROR: The presented key does not exist in the volume * 2 - ERROR: could not open encrypted volume * 3 - ERROR: device either doesnt exist or not a luks device */ int zuluCryptAddKey( const char * device, /* path to an encrypted file or partition */ const char * existingkey,/* a key that already exist in the encrypted volume */ size_t existingkey_size, /* size of existingkey */ const char * newkey, /* new key to be added to the volume */ size_t newkey_size ); /* size of the new key */ int zuluCryptAddKey_0( const char * device, /* path to an encrypted file or partition */ const char * existingkey,/* a key that already exist in the encrypted volume */ size_t existingkey_size, /* size of existingkey */ const char * newkey, /* new key to be added to the volume */ size_t newkey_size, /* size of the new key */ const char * options ) ; /* Options in dot separated string */ /** * This function deletes a key from a luks volume. * * return value: * 0 - success - a key is successfully removed * 1 - ERROR: device is not a luks device or does not exist * 2 - ERROR: passphrase is not present in the volume * 3 - ERROR: could not open luks device */ int zuluCryptRemoveKey( const char * device , /* path to an encrypted device */ const char * passphrase, /* a key already in the volume to be removed */ size_t passphrase_size ) ; /* passphrase size */ int zuluCryptRemoveKey_0( const char * device , /* path to an encrypted device */ const char * passphrase, /* a key already in the volume to be removed */ size_t passphrase_size, /* passphrase size */ int key_slot ) ; /* a key slot number to remove a key */ /** *This function gives information about slots in a luks volume. * * return value: * NULL if an error occurs(if the device path is invalid or does not point to luks device. * * If no error occur a string made up of 0,1,2 and 3 is returned. Make sure to free it when you are done. * * 0 is for disabled/unoccupied/inactive * 1 is for enabled/occupied/active * 2 is for invalid * 3 is for last active key * * example: * 00100000 means, slot number 3 is occupied/enabled, the rest are not(emply/disabled). * * Remember to free() the return value when done with the pointer */ char * zuluCryptEmptySlots( const char * device ) ; /** * This function just opens a luks volume, doesnt create a mount point and doesnt mount it. * *return values: * 0 - success * 1 - ERROR: presented key does not exist in the volume * 2 - ERROR: failed to open device * 3 - ERROR: device path does not point to a device * 4 - ERROR: key file does not exist */ int zuluCryptOpenLuks( const char * device, /* path to encrypted file or partition */ const char * mapping_name,/* mapper name to use */ const char * mode, /* "ro" or "rw" for opening in read only or read and write */ const char * passphrase, /* passphrase to use to open the volume */ size_t passphrase_size ); /* the length of the passphrase */ /** * This function creates a luks volume * * return values: * 0 - success * 1 - ERROR: could not initialize the device * 2 - ERROR: could not format the device * 3 - ERROR: could not add passphrase to the device * 4 - ERROR: device path does not point to a device * */ int zuluCryptCreateLuks( const char * device, /* path to a file or partition to create a volume in */ const char * passphrase,/* passphrase to use to create a volume */ size_t passphrase_size, /* size of the passphrase */ const char * rng ) ; /*random number generator( /dev/random or /dev/urandom) */ int zuluCryptCreateLuks2( const char * device, /* path to a file or partition to create a volume in */ const char * passphrase,/* passphrase to use to create a volume */ size_t passphrase_size, /* size of the passphrase */ const char * rng ) ; /*random number generator( /dev/random or /dev/urandom)*/ /** * This function just opens a plain volume, it doesnt create a mount point and it doesnt mount it. * return values: * 0 - success * 2 - ERROR: failed to open the volume. * 3 - ERROR: device path does not point to a device * 4 - ERROR: key file does not exist */ int zuluCryptOpenPlain( const char * device, /* path to encrypted file or partition */ const char * mapping_name,/* mapper name to use */ const char * mode, /* "ro" or "rw" for opening in read only or read and write */ const char * passphrase, /* passphrase to use to open the volume */ size_t passphrase_size ); /* passphrase length */ /* * truecrypt treats passphrases differently from keyfiles. * * Below 3 constants are used in the "key_source" source argument below. * * TCRYPT_KEYFILE_FILE option means the "key" argument is a path to a key file,if this option is used,then * use "0" for "key_len" argument,the argument is not used. * * TCRYPT_KEYFILE option means the "key" argument is a memory buffer containing the content of a keyfile.This is useful * if you want the API to treat the content of a buffer as if they are a keyfile. * * TCRYPT_PASSPHRASE option means the "key" argument is a pointer to a memory buffer containing the passphrase. * */ #define TCRYPT_PASSPHRASE 0 #define TCRYPT_KEYFILE 1 #define TCRYPT_KEYFILE_FILE 2 #define TCRYPT_NORMAL 1 #define TCRYPT_HIDDEN 0 /** * This function opens a truecrypt volume. * return values: * 0 - success * 1 - ERROR: presented key does not exist in the volume */ int zuluCryptOpenTcrypt( const char * device, /* path to an encrypted file or partition */ const char * mapper, /* mapper name to use */ const char * key, /* key material */ size_t key_len, /* length of key */ int key_source, /* source of key material,options explained above */ int volume_type,/* option could be TCRYPT_NORMAL or TCRYPT_HIDDEN */ const char * m_point, /* mount point to mount the file system,if NULL,mapper will be opened onlu */ uid_t uid, /* uid of the person to associate the mount point with,not necessary if m_point == NULL */ unsigned long m_opts, /* mount points,option is passed to second from last argument of mount() */ const char * fs_opts /* passed to last argument of mount() */ ) ; /** * This function creates a truecrypt volume * return values: * 0 - success * 3 - ERROR: could not create a volume,possible reason: truecrypt support is not available in the library * * opts argument is expected to be in format of: "rng.algorithm.cipher mode,key size in bits.hash" * * possible combinations are: * rng can either be: "/dev/random" or "/dev/urandom" * algorithm can be either" "aes" or "serpent" or "twofish" or "twofish:aes" or "aes:serpent" or "serpent:twofish" or "aes:twofish:serpent" or "serpent:twofish:aes" * only cipher supported is: "xts-plain64" * only key size supported: "256" * hash can be either: "sha512" or "ripemd160" or "whirlpool" * * The default string to set is: "/dev/urandom.aes.xts-plain64.256.ripemd160" */ int zuluCryptCreateTCrypt( const char * device, /* path a device or file to put an encrypted volume */ const char * file_system, /* file system to use in the volume */ const char * opts, /* volume creation options */ const char * key, /* key material to use */ size_t key_len, /* length of key */ int key_source, /* key material source,either pass TCRYPT_KEYFILE or TCRYPT_PASSPHRASE */ u_int64_t hidden_volume_size, /* pass "0" if a volume without a hidden volume is to be created or */ /* a non negative number to represent the size of the hidden volume to be created */ const char * file_system_h, /* file system of the hidden volume,pass NULL if no hidden volume will be created */ const char * key_h, /* key material to use for creation of hidden volume */ size_t key_len_h, /* length of hidden key */ int key_source_h /* hidden key source material,either pass TCRYPT_KEYFILE or TCRYPT_PASSPHRASE */ ); /** * This function returns a device address given a mapper address. * Ex. IF a mapper address exists named "/dev/mapper/XYZ" and this mapper opens a volume * in /dev/sdc1, then calling this function wih the mentioned mapper address will return "/dev/sdc1". * * If the mapper open a regular file, the full path to the file is returned and not its loop back device. * * NOTE: The address is stored in memory created by "malloc" command and hence you must free it with "free" command * when done with it * * NULl is returned if the mapper device can not be opened for the reasons that include the mapper not being cryptsetup mapper. * * Remember to free() the return value when done with the pointer(if it is not NULL ofcourse) * */ char * zuluCryptVolumeDeviceName( const char * mapper ) ; /** * This function encrypts a file given by argument source to a file given by argument dest using plain mapper * opened with key of length key_len * * output: 0 - success * 1 - encryption failed,could not open mapper * */ int zuluCryptEncryptFile( const char * source,const char * dest,const char * key,u_int64_t key_len ) ; /** * This function decrypts a file given by argument source to a file given by argument dest using plain mapper * opened with key of length key_len * * output: 0 - success * 1 - decryption failed,could not open mapper * 2 - decryption failed,wrong passphrase * */ int zuluCryptDecryptFile( const char * source,const char * dest,const char * key,u_int64_t key_len ) ; #ifdef __cplusplus } #endif #endif zuluCrypt-6.2.0/zuluCrypt-cli/lib/mount_fs_options.c000066400000000000000000000141001425361753700226560ustar00rootroot00000000000000/* * * Copyright (c) 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "../bin/includes.h" #include #include #include static int _fileSystemIsSupported( const char * fs ) { string_t xt = StringGetFromVirtualFile( "/proc/filesystems" ) ; stringList_t stl = StringListStringSplit( xt,'\n' ) ; StringListIterator it ; StringListIterator end ; int r = 0 ; StringDelete( &xt ) ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ xt = *it ; it++ ; if( !StringStartsWith( xt,"nodev" ) ){ if( StringContains( xt,fs ) ){ r = 1 ; break ; } } } StringListDelete( &stl ) ; return r ; } int zulucryptFileSystemIsSupported( const char * fs ) { const char * f[] = { "none","xfs","ntfs","vfat","exfat","msdos","umsdos","affs","hfs","iso9660","jfs","jfs", "romfs","udf","ext2","ext3","ext4","reiserfs","reiser4","btrfs","squashfs","btrfs",NULL } ; const char ** e = f ; if( fs == NULL ){ return 0 ; }else{ while( 1 ){ if( *e == NULL ){ return _fileSystemIsSupported( fs ) ; }else if( StringsAreEqual( fs,*e ) ){ return 1 ; }else{ e++ ; } } } } static inline int _check_options( const char ** e,stringList_t stl ) { while( *e != NULL ){ StringListRemoveIfStringContains( stl,*e ) ; e++ ; } return StringListSize( stl ) > 0 ; } static inline int allowed_vfat( stringList_t stl ) { /* * is it ok to allow one user to mount a volume with another user as owner of files and folders? */ const char * f[] = { "uid=","gid=","shortname=","dmask=","umask=","fmask=","utf8","iocharset=",NULL } ; return _check_options( f,stl ) ; } static inline int allowed_ntfs( stringList_t stl ) { const char * f[] = { "uid=","gui=","umask=","dmask=","fmask=","dmask=","locale=","norecover", "ignore_case","windows_names","compression","nocompression","ignore_case","windows_names",NULL } ; return _check_options( f,stl ) ; } static inline int allowed_iso9660( stringList_t stl ) { const char * f[] = { "norock","nojoliet","fmask=","iocharset=","mode=","dmode=",NULL } ; return _check_options( f,stl ) ; } static inline int allowed_udf( stringList_t stl ) { const char * f[] = { "iocharset=","umask=",NULL } ; return _check_options( f,stl ) ; } static inline int allowed_btrfs( stringList_t stl ) { const char * f[] = { "subvol=","subvolid=",NULL } ; return _check_options( f,stl ) ; } static inline int _option_contain_not_allowed( const char * fs,const char * fs_opts ) { stringList_t stl = StringListSplit( fs_opts,',' ) ; int r = 1 ; if( stl != StringListVoid ){ if( StringHasAtLeastOneComponent_1( fs,"fat","dos",NULL ) ){ r = allowed_vfat( stl ) ; }else if( StringsAreEqual( fs,"ntfs" ) ){ r = allowed_ntfs( stl ) ; }else if( StringsAreEqual( fs,"udf" ) ){ r = allowed_udf( stl ) ; }else if( StringsAreEqual( fs,"iso9660" ) ){ r = allowed_iso9660( stl ) ; }else if( StringsAreEqual( fs,"btrfs" ) ){ r = allowed_btrfs( stl ) ; }else{ r = 1 ; } StringListDelete( &stl ) ; }else{ r = 1 ; } return r ; } int zuluCryptUserIsAMemberOfAGroup( uid_t uid,const char * groupname ) { int i ; struct group * grp ; struct passwd * pass ; const char * e ; if( groupname == NULL ){ return 0 ; }else if( uid == 0 ){ return 1 ; }else{ pass = getpwuid( uid ) ; if( pass == NULL ){ return 0 ; }else{ grp = getgrnam( groupname ) ; if( grp == NULL ){ return 0 ; }else{ for( i = 0 ; ; i++ ){ e = *( grp->gr_mem + i ) ; if( e == NULL ){ return 0 ; }else{ if( StringsAreEqual( e,pass->pw_name ) ){ return 1 ; } } } return 0 ; } } } } static inline int _userIsAllowed( uid_t uid,const char * fs ) { if( fs ){} if( uid == 0 ){ /* * cant say No to root */ return 1 ; }else{ /* * user is attempting to use not supported file system options.Allow them only if * they are a member of a supported group */ return zuluCryptUserIsAMemberOfAGroup( uid,"zulumount" ) ; } } int zuluCryptMountHasNotAllowedFileSystemOptions( uid_t uid,const char * fs_opts,string_t s ) { const char * fs = StringContent( s ) ; if( fs == NULL ){ /* * cant mount a volume with no file system,shouldnt even get here */ return 1 ; } if( zulucryptFileSystemIsSupported( fs ) ){ /* * file system is supported */ if( fs_opts == NULL ){ /* * file system is supported and user did not change default fs option. * return early with success */ return 0 ; } if( _option_contain_not_allowed( fs,fs_opts ) ){ /* * file system options are not supported,only privileged users should be allowed to mount */ if( _userIsAllowed( uid,fs ) ){ /* * user is allowed to use non default fs options */ return 0 ; }else{ /* * user not allowed to use non default fs options */ return 1 ; } }else{ /* * supported file system with default options,allow it */ return 0 ; } }else{ /* * not supported file system */ if( _userIsAllowed( uid,fs ) ){ /* * user is allowed to use a not supported file system. * We cant check for supported fs options in a non supported file system so just return * with success. */ return 0 ; }else{ /* * user not allowed to use the file system,return early with error since we cant support * file system options in a not supported file system */ return 1 ; } } } zuluCrypt-6.2.0/zuluCrypt-cli/lib/mount_volume.c000066400000000000000000000267021425361753700220150ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include #include #include #include #include /* * These functions are moved to parse_fstab.c * * string_t zuluCryptGetFstabEntry( const char * device ) * string_t zuluCryptGetMountOptionsFromFstab( const char * device,int pos ) * stringList_t zuluCryptGetFstabEntryList( const char * device ) */ typedef enum { FAT_FAMILY_FS,OTHER_FAMILY_FS,READ_ONLY_FS,DEFAULT_FS_TYPE } FS_TYPE ; static int zuluExit( int st,int fd,string_t x,string_t y,string_t z ) { StringMultipleDelete( &x,&y,&z,NULL ) ; if( fd != -1 ){ close( fd ) ; } return st ; } static FS_TYPE fs_family( const char * fs ) { if( StringAtLeastOneMatch_1( fs,"ntfs","vfat","fat","msdos","umsdos","exfat",NULL ) ){ return FAT_FAMILY_FS ; }else if( StringAtLeastOneMatch_1( fs,"affs","hfs",NULL ) ){ return OTHER_FAMILY_FS ; }else if( StringAtLeastOneMatch_1( fs,"iso9660","udf","squashfs",NULL ) ){ return READ_ONLY_FS ; }else{ return DEFAULT_FS_TYPE ; } } /* * custom options per file system */ static void _get_file_system_options_from_config_file_1( const char * fs,string_t st ) { const char * e ; StringListIterator it ; StringListIterator end ; string_t zt ; string_t xt = StringGetFromFile( "/etc/zuluCrypt/generic_fs_options" ) ; stringList_t stl = StringListStringSplit( xt,'\n' ) ; stringList_t stz ; StringDelete( &xt ) ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ zt = *it ; it++ ; if( StringStartsWith( zt,fs ) ){ stz = StringListStringSplit( zt,' ' ) ; e = StringListContentAtSecondPlace( stz ) ; StringMultipleAppend( st,",",e,NULL ) ; StringListDelete( &stz ) ; break ; } } StringListDelete( &stl ) ; } /* * custom options per volume set through file system's UUID */ static void _get_file_system_options_from_config_file( const char * device,string_t st ) { char * f ; const char * e ; StringListIterator it ; StringListIterator end ; string_t xt = StringGetFromFile( "/etc/zuluCrypt/fs_options" ) ; stringList_t stl = StringListStringSplit( xt,'\n' ) ; stringList_t stz ; StringDelete( &xt ) ; /* * zuluCryptUUIDFromPath_1() is defined in resolve_paths.c */ f = zuluCryptUUIDFromPath_1( device ) ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ e = StringRemoveString( *it,"\"" ) ; it++ ; if( StringPrefixMatch( e,"UUID=",5 ) ){ if( StringPrefixEqual( e + 5,f ) ){ stz = StringListSplit( e,' ' ) ; e = StringListContentAtSecondPlace( stz ) ; StringMultipleAppend( st,",",e,NULL ) ; StringListDelete( &stz ) ; break ; } } } StringListDelete( &stl ) ; StringFree( f ) ; } static const char * _remove_duplicates( string_t st ) { const char ** z = StringPointer( st ) ; while( StringHasComponent( *z,",," ) ){ StringReplaceString( st,",,","," ) ; } if( StringEndsWithChar( st,',' ) ){ return StringRemoveRight( st,1 ) ; }else{ return StringContent( st ) ; } } static string_t set_mount_options( m_struct * mst ) { /* * zuluCryptGetMountOptionsFromFstab() is defined in parse_fstab.c */ string_t opt = zuluCryptGetMountOptionsFromFstab( mst->device,MOUNTOPTIONS,mst->uid ) ; FS_TYPE fsFamily = fs_family( mst->fs ) ; const char * f[] = { "nouser","users","user","defaults","noauto","auto","nodev","dev", "noexec","exec","nosuid","suid","bind","mandlock","move","noatime","nodiratime","remount","silent", "synchronous",NULL } ; const char ** z = f ; const char * e ; if( opt == StringVoid ){ if( mst->fs_flags != NULL ){ opt = String( mst->fs_flags ) ; }else{ opt = StringEmpty() ; } }else{ if( StringContains( opt,"ro" ) ){ mst->m_flags |= MS_RDONLY ; } StringMultipleAppend( opt,",",mst->fs_flags,NULL ) ; } _get_file_system_options_from_config_file_1( mst->fs,opt ) ; _get_file_system_options_from_config_file( mst->device,opt ) ; if( fsFamily == FAT_FAMILY_FS ){ if( StringDoesNotContain( opt,"dmask=" ) ){ StringAppend( opt,",dmask=0000" ) ; } if( StringDoesNotContain( opt,"umask=" ) ){ StringAppend( opt,",umask=0000" ) ; } if( StringDoesNotContain( opt,"uid=" ) ){ StringAppend( opt,",uid=" ) ; StringAppendInt( opt,mst->uid ) ; } if( StringDoesNotContain( opt,"gid=" ) ){ StringAppend( opt,",gid=" ) ; StringAppendInt( opt,mst->uid ) ; } if( StringDoesNotContain( opt,"fmask=" ) ){ StringAppend( opt,",fmask=0111" ) ; } if( StringsAreEqual( mst->fs,"vfat" ) ){ if( StringDoesNotContain( opt,"flush" ) ){ StringAppend( opt,",flush" ) ; } if( StringDoesNotContain( opt,"shortname=" ) ){ StringAppend( opt,",shortname=mixed" ) ; } } if( StringsAreEqual( mst->fs,"ntfs" ) ){ if( StringDoesNotContain( opt,"big_writes" ) ){ StringAppend( opt,",big_writes" ) ; } } }else if( fsFamily == OTHER_FAMILY_FS ){ if( StringDoesNotContain( opt,"uid=" ) ){ StringAppend( opt,",uid=" ) ; StringAppendInt( opt,mst->uid ) ; } if( StringDoesNotContain( opt,"gid=" ) ){ StringAppend( opt,",gid=" ) ; StringAppendInt( opt,mst->uid ) ; } }else if( fsFamily == READ_ONLY_FS ){ mst->m_flags |= MS_RDONLY ; }else{ /* * ext file systems and raiserfs among others go here * we dont set any options for them. */ } /* * remove mount options to leave only file system options */ while( 1 ){ e = *z ; z++ ; if( e == NULL ){ break ; }else{ StringRemoveString( opt,e ) ; } } /* * remove below two now because we are going to add them below,reason for removing them * and readding them is because we want to make sure they are at the beginning of the string */ StringRemoveString( opt,"ro" ) ; StringRemoveString( opt,"rw" ) ; if( mst->m_flags & MS_RDONLY ){ StringPrepend( opt,"ro," ) ; }else{ StringPrepend( opt,"rw," ) ; } mst->opts = _remove_duplicates( opt ) ; return opt ; } static const char * _mount_options( unsigned long flags,string_t st ) { if( flags & MS_NODEV ){ StringAppend( st,",nodev" ) ; } if( flags & MS_NOEXEC ){ StringAppend( st,",noexec" ) ; } if( flags & MS_NOSUID ){ StringAppend( st,",nosuid" ) ; } if( flags & MS_BIND ){ StringAppend( st,",bind" ) ; } if( flags & MS_MANDLOCK ){ StringAppend( st,",mandlock" ) ; } if( flags & MS_MOVE ){ StringAppend( st,",move" ) ; } if( flags & MS_NOATIME ){ StringAppend( st,",noatime" ) ; } if( flags & MS_NODIRATIME ){ StringAppend( st,",nodiratime" ) ; } if( flags & MS_RELATIME ){ StringAppend( st,",relatime" ) ; } if( flags & MS_REMOUNT ){ StringAppend( st,",remount" ) ; } if( flags & MS_SILENT ){ StringAppend( st,",silent" ) ; } if( flags & MS_STRICTATIME ){ StringAppend( st,",strictatime" ) ; } if( flags & MS_SYNCHRONOUS ){ StringAppend( st,",synchronous" ) ; } return _remove_duplicates( st ) ; } static int _mount_FUSEfs( const m_struct * mst,string_t st ) { const char * opts = _mount_options( mst->m_flags,st ) ; process_t p = Process( ZULUCRYPTmount,NULL ) ; if( StringsAreEqual( mst->fs,"ntfs" ) ){ if( StringHasComponent( opts,"ignore_case" ) ){ ProcessSetArgumentList( p,"-n","-t","lowntfs-3g","-o",opts,mst->device,mst->m_point,NULL ) ; }else{ ProcessSetArgumentList( p,"-n","-t","ntfs-3g","-o",opts,mst->device,mst->m_point,NULL ) ; } }else{ ProcessSetArgumentList( p,"-t",mst->fs,"-o",opts,mst->device,mst->m_point,NULL ) ; } ProcessStart( p ) ; return ProcessWaitUntilFinished( &p ) ; } static int _mount( const m_struct * mst,string_t st ) { int h = mount( mst->device,mst->m_point,mst->fs,mst->m_flags,mst->opts + 3 ) ; if( st ){} if( h == 0 && mst->m_flags != MS_RDONLY ){ chmod( mst->m_point,S_IRWXU|S_IRWXG|S_IRWXO ) ; } return h ; } static int _mount_volume( int ( *function )( const m_struct *,string_t ), const m_struct * m,string_t st ) { int e = function( m,st ) ; if( e != 0 ){ /* * mount failed for some reason,wait 2 second and then try again */ sleep( 2 ) ; e = function( m,st ) ; } return e ; } const char * zuluCryptDecodeMountEntry( string_t st ) { StringReplaceString( st,"\\012","\n" ) ; StringReplaceString( st,"\\040"," " ) ; StringReplaceString( st,"\\134","\\" ) ; return StringReplaceString( st,"\\011","\\t" ) ; } const char * zuluCryptEncodeMountEntry( string_t st ) { StringReplaceString( st,"\\","\\134" ) ; StringReplaceString( st,"\n","\\012" ) ; StringReplaceString( st," ","\\040" ) ; return StringReplaceString( st,"\\t","\\011" ) ; } int zuluCryptMountVolume( const char * path,const char * m_point,unsigned long mount_opts,const char * fs_opts,uid_t uid ) { int h ; string_t opts = StringVoid ; string_t fs = StringVoid ; string_t loop = StringVoid ; int fd = -1 ; m_struct mst ; mst.device = path ; mst.m_point = m_point ; mst.uid = uid ; mst.m_flags = mount_opts ; int bitLockerVolumeUsingDislocker = zuluCryptIsDislockerMapperPath( path ) ; if( bitLockerVolumeUsingDislocker ) { fs = zuluCryptBitLockerVolumeFS( path ) ; }else{ /* * zuluCryptGetFileSystemFromDevice() is defined in blkid_evaluate_tag.c */ fs = zuluCryptGetFileSystemFromDevice( path ) ; } if( StringsAreEqual_2( fs,"Nil" ) || fs == StringVoid ){ /* * failed to read file system,probably because the volume does have any or * a plain volume was opened with a wrong key */ return zuluExit( 4,fd,opts,fs,loop ) ; } if( StringStartsWith( fs,"crypto" ) ){ /* * we cant mount an encrypted volume, exiting */ return zuluExit( 4,fd,opts,fs,loop ) ; } /* * zuluCryptMountHasNotAllowedFileSystemOptions() is defined in ./mount_fs_options.c */ if( zuluCryptMountHasNotAllowedFileSystemOptions( uid,fs_opts,fs ) ){ return zuluExit( -1,fd,opts,fs,loop ) ; } mst.fs_flags = fs_opts ; mst.fs = StringContent( fs ) ; opts = set_mount_options( &mst ) ; if( StringPrefixNotEqual( path,"/dev/" ) || bitLockerVolumeUsingDislocker ){ /* * zuluCryptAttachLoopDeviceToFile() is defined in ./create_loop_device.c */ if( zuluCryptAttachLoopDeviceToFile( mst.device,O_RDWR,&fd,&loop ) ){ mst.device = StringContent( loop ) ; }else{ return zuluExit( -1,fd,opts,fs,loop ) ; } } /* * zuluCryptFileSystemIsFUSEbased() is defined in blkid_evaluate_tag.c */ if( zuluCryptFileSystemIsFUSEbased( path ) ){ /* * These file systems dont see to work with mount() command for some reason. * Them being FUSE based could be a reason. */ switch( _mount_volume( _mount_FUSEfs,&mst,opts ) ){ case 0 : return zuluExit( 0,fd,opts,fs,loop ) ; case 16 : return zuluExit( 12,fd,opts,fs,loop ) ; case 32 : return zuluExit( -1,fd,opts,fs,loop ) ; default : return zuluExit( 1,fd,opts,fs,loop ) ; } }else{ h = _mount_volume( _mount,&mst,opts ) ; } return zuluExit( h,fd,opts,fs,loop ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/mountinfo.c000066400000000000000000000220531425361753700212750ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "share_mount_prefix_path.h" typedef struct{ const char * device ; const char * mountPoint ; const char * fileSystem ; const char * mountOptions ; const char * rootPath ; }vInfo ; static int _valid_entry( const vInfo * e ) { if( StringsAreEqual( e->device,"/dev/fuse" ) ){ /* * We dont support these fuse devices. */ return 0 ; } if( StringAtLeastOnePrefixMatch( e->mountPoint,"/var/run/media/public", "/var/run/media/private",NULL ) ){ /* * some distributions auto generate these extra mount points and we * ignore them as they confuse us. */ return 0 ; } if( StringsAreEqual( e->rootPath,"/" ) || StringsAreEqual( e->fileSystem,"btrfs" ) ){ /* * we only support bind mount on btrfs. */ return 1 ; } return 0 ; } int zuluCryptFUSEVolumeIsSupported( const char * fs ) { return StringAtLeastOneMatch_1( fs, "fuse.encfs","fuse.Encfs", "fuse.cryfs","fuse.Cryfs", "fuse.securefs","fuse.Securefs", "fuse.gocryptfs","fuse.Gocryptfs", "ecryptfs",NULL ) ; } int zuluCryptFUSEVolumeIsSupportedStartsWith( const char * device ) { return StringAtLeastOnePrefixMatch( device, "encfs@","Encfs@", "cryfs@","Cryfs@", "securefs@","Securefs@", "gocryptfs@","Gocryptfs@", NULL ) ; } static void _add_entry( string_t ( *function )( const vInfo * ),stringList_t tmp, stringList_t * stx,char * const ** entry,size_t * entry_len ) { string_t st ; u_int64_t e ; vInfo volumeInfo ; StringListStringArray_1( entry,entry_len,tmp ) ; volumeInfo.device = *( *entry + *entry_len - 2 ) ; volumeInfo.mountPoint = *( *entry + 4 ) ; volumeInfo.fileSystem = *( *entry + *entry_len - 3 ) ; volumeInfo.mountOptions = *( *entry + 5 ) ; volumeInfo.rootPath = *( *entry + 3 ) ; if( zuluCryptFUSEVolumeIsSupported( volumeInfo.fileSystem ) ){ if( zuluCryptFUSEVolumeIsSupportedStartsWith( volumeInfo.device ) ){ volumeInfo.device += StringFirstIndexOfChar_1( volumeInfo.device,'@' ) + 1 ; }else{ st = StringListStringAt( tmp,*entry_len - 2 ) ; StringReset( st ) ; e = StringJenkinsOneAtATimeHash( volumeInfo.mountPoint ) ; volumeInfo.device = StringAppendInt( st,e ) ; } } if( _valid_entry( &volumeInfo ) ){ st = function( &volumeInfo ) ; StringListAppendString_1( stx,&st ) ; } } static stringList_t _volumeList( string_t ( *function )( const vInfo * ) ) { char * const * entry = NULL ; size_t entry_len = 0 ; stringList_t tmp ; stringList_t stx = StringListVoid ; stringList_t stl ; StringListIterator it ; StringListIterator end ; string_t st = StringGetFromVirtualFile( "/proc/self/mountinfo" ) ; stl = StringListStringSplit( st,'\n' ) ; StringDelete( &st ) ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ tmp = StringListStringSplit( *it,' ' ) ; it++ ; _add_entry( function,tmp,&stx,&entry,&entry_len ) ; StringListDelete( &tmp ) ; } StringFree( entry ) ; StringListDelete( &stl ) ; return stx ; } static string_t _mount_properties( string_t ( *function )( const char * ),const vInfo * e ) { string_t st = function( e->device ) ; StringMultipleAppend( st," ",e->mountPoint," ",e->fileSystem," ",e->mountOptions,NULL ) ; return st ; } static string_t _resolve_path_1( const vInfo * e ) { /* * zuluCryptResolvePath_1() is defined in resolve_paths.c */ return _mount_properties( zuluCryptResolvePath_1,e ) ; } stringList_t zuluCryptGetMoutedList( void ) { return _volumeList( _resolve_path_1 ) ; } static string_t _resolve_path_2( const vInfo * e ) { /* * zuluCryptResolvePath_2() is defined in resolve_paths.c */ return _mount_properties( zuluCryptResolvePath_2,e ) ; } stringList_t zuluCryptGetMoutedList_1( void ) { return _volumeList( _resolve_path_2 ) ; } static string_t _get_mounted_device_list( const vInfo * e ) { return zuluCryptResolvePath_1( e->device ) ; } stringList_t zuluCryptGetAListOfMountedVolumes( void ) { return _volumeList( _get_mounted_device_list ) ; } static int _mounted( ssize_t( *function )( stringList_t,const char * ),string_t st ) { stringList_t stl = zuluCryptGetMoutedList() ; ssize_t r = function( stl,StringContent( st ) ) ; StringListDelete( &stl ) ; StringDelete( &st ) ; return r != -1 ; } int zuluCryptMountPointIsActive( const char * m_point ) { return _mounted( StringListHasSequence,String_1( " ",m_point," ",NULL ) ) ; } int zuluCryptPartitionIsMounted( const char * path ) { return _mounted( StringListHasStartSequence,String_1( path," ",NULL ) ) ; } stringList_t zuluCryptOpenedVolumesList( uid_t uid ) { const char * e ; const char * c ; const char * d ; const char * t ; char * f ; char * g ; StringListIterator it ; StringListIterator end ; ssize_t k ; string_t q ; string_t z ; string_t j ; stringList_t stx ; stringList_t list = StringListVoid ; stringList_t stl = zuluCryptGetMoutedList() ; if( uid ){} /* * zuluCryptMapperPrefix() is defined in create_mapper_name.c */ j = String_1( zuluCryptMapperPrefix(),"/zuluCrypt-",NULL ) ; /* * t will probably contain "/dev/mapper/zuluCrypt-" */ t = StringContent( j ) ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ c = StringContent( *it ) ; it++ ; if( StringPrefixNotEqual( c,t ) && !zuluCryptBitLockerVolume_1( c ) ){ /* * we only care about zuluCrypt volumes and these volumes that we care about starts with * "/dev/mapper/zuluCrypt-" * * We also care about dislocker volumes so we let them through. These volumes ends with * "dislocker-file" */ continue ; } if( StringHasComponent( c,SHARE_MOUNT_PREFIX "/" ) ){ /* * dont show mirror images due to bind mounts */ continue ; } stx = StringListSplit( c,' ' ) ; e = StringListContentAtFirstPlace( stx ) ; k = StringHasComponent_1( e,"-UUID-" ) ; if( k != -1 ) { q = StringListStringAtFirstPlace( stx ) ; /* * zuluCryptDecodeMountEntry() is defined in mount_volume.c */ d = zuluCryptDecodeMountEntry( StringListStringAtSecondPlace( stx ) ) ; /* * zuluCryptGetVolumeTypeFromMapperPath() is defined in status.c */ f = zuluCryptGetVolumeTypeFromMapperPath( StringContent( q ) ) ; e = StringSubChar( q,(size_t)StringLastIndexOfChar( q,'-' ),'\0' ) + k + 6 ; z = String_1( "UUID=\"",e,"\"\t",d,"\t",f,NULL ) ; StringListAppendString_1( &list,&z ) ; StringFree( f ) ; }else if( zuluCryptIsDislockerMapperPath( e ) ){ q = zuluCryptBitLockerResolveMapperPath( e,uid ) ; d = zuluCryptDecodeMountEntry( StringListStringAtSecondPlace( stx ) ) ; StringMultipleAppend( q,"\t",d,"\t",zuluCryptBitLockerType(),NULL ) ; StringListAppendString_1( &list,&q ) ; }else{ /* * zuluCryptVolumeDeviceName() is defined in status.c */ g = zuluCryptVolumeDeviceName( e ) ; if( g != NULL ){ d = zuluCryptDecodeMountEntry( StringListStringAtSecondPlace( stx ) ) ; /* * zuluCryptGetVolumeTypeFromMapperPath() is defined in status.c */ f = zuluCryptGetVolumeTypeFromMapperPath( StringListContentAtFirstPlace( stx ) ) ; z = String_1( g,"\t",d,"\t",f,NULL ) ; StringListAppendString_1( &list,&z ) ; StringFree( f ) ; StringFree( g ) ; } } StringListDelete( &stx ) ; } StringListDelete( &stl ) ; StringDelete( &j ) ; return list ; } string_t zuluCryptGetMountEntry( const char * path ) { stringList_t stl = zuluCryptGetMoutedList() ; string_t st = zuluCryptGetMountEntry_1( stl,path ) ; StringListDelete( &stl ) ; return st ; } string_t zuluCryptGetMountEntry_1( stringList_t stl,const char * path ) { string_t st ; string_t xt ; if( stl == StringListVoid ){ return StringVoid ; }else{ /* * zuluCryptResolvePath_1() is defined in resolve_paths.c */ st = zuluCryptResolvePath_1( path ) ; xt = StringListHasStartSequence_1( stl,StringAppend( st," " ) ) ; StringDelete( &st ) ; return StringCopy( xt ) ; } } char * zuluCryptGetMountPointFromPath( const char * path ) { string_t st = zuluCryptGetMountEntry( path ) ; stringList_t stl ; if( st == StringVoid ){ return NULL ; }else{ stl = StringListStringSplit( st,' ' ) ; StringDelete( &st ) ; if( stl == StringListVoid ){ return NULL ; }else{ st = StringListCopyStringAtSecondPlace( stl ) ; StringListDelete( &stl ) ; zuluCryptDecodeMountEntry( st ) ; return StringDeleteHandle( &st ) ; } } } zuluCrypt-6.2.0/zuluCrypt-cli/lib/open_luks.c000066400000000000000000000055251425361753700212630ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include /* * This header file is created by the build process and it checks if the version of cryptsetup >= 1.4.0 */ #include "luks_external_header.h" static int zuluExit( int st,struct crypt_device * cd ) { crypt_free( cd ) ; return st ; } static int _open_luks_2( const char * device,const resolve_path_t * opt ) { struct crypt_device * cd ; uint32_t flags ; int st ; /* * open_struct_t is defined in includes.h */ const open_struct_t * opts = opt->args ; if( zuluCryptPathIsNotValid( device ) ){ return 3 ; } if( opts->luks_detached_header ){ #if LUKS_EXTERNAL_HEADER if( crypt_init( &cd,opts->luks_detached_header ) != 0 ){ return 1 ; } if( crypt_load( cd,NULL,NULL ) != 0 ){ return zuluExit( 2,cd ) ; } if( crypt_set_data_device( cd,device ) != 0 ){ return zuluExit( 1,cd ) ; } #else return 1 ; #endif }else{ if( crypt_init( &cd,device ) != 0 ){ return 2 ; } if( crypt_load( cd,NULL,NULL ) != 0 ){ return zuluExit( 2,cd ) ; } } if( opt->open_mode == O_RDONLY ){ flags = CRYPT_ACTIVATE_READONLY ; }else{ flags = CRYPT_ACTIVATE_ALLOW_DISCARDS ; } st = crypt_activate_by_passphrase( cd,opts->mapper_name,CRYPT_ANY_SLOT, opts->key,opts->key_len,flags ) ; if( st >= 0 ){ return zuluExit( 0,cd ) ; }else if( st == -1 ){ return zuluExit( 1,cd ) ; }else{ return zuluExit( 2,cd ) ; } } int zuluCryptOpenLuks( const char * device,const char * mapper, const char * mode,const char * key,size_t key_len ) { open_struct_t opts ; memset( &opts,'\0',sizeof( open_struct_t ) ) ; opts.device = device ; opts.mapper_name = mapper ; opts.m_opts = mode ; opts.key = key ; opts.key_len = key_len; return zuluCryptOpenLuks_2( &opts ) ; } int zuluCryptOpenLuks_1( const open_struct_t * opts ) { return zuluCryptOpenLuks_2( opts ) ; } int zuluCryptOpenLuks_2( const open_struct_t * opts ) { /* * zuluCryptResolveDevicePath_0() is defined in resolve_path.c */ return zuluCryptResolveDevicePath_0( _open_luks_2,opts,2 ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/open_plain.c000066400000000000000000000117761425361753700214150ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include typedef struct{ const char * rng ; const char * algo ; const char * cipher ; const char * keySize ; const char * hash ; const char * offset ; }args ; static int zuluExit( int st,struct crypt_device * cd ) { crypt_free( cd ) ; return st ; } static const char * _remove_letters( char * e ) { char * m = e ; while( *e ){ if( !( *e >= '0' && *e <= '9' ) ){ *e = '\0' ; break ; } e++ ; } return m ; } static u_int64_t _offset( const char * offset ) { char * e ; u_int64_t r = 0 ; size_t s = StringSize( offset ) ; if( s == 0 ){ return 0 ; }else{ e = StringCopy_2( offset ) ; if( StringEndsWithAtLeastOne( e,"m","MB","mb","Mb","M",NULL ) ){ r = StringConvertToInt( _remove_letters( e ) ) ; r = 2 * 1024 * r ; }else if( StringEndsWithAtLeastOne( e,"g","GB","gb","Gb","G",NULL ) ){ r = StringConvertToInt( _remove_letters( e ) ) ; r = 2 * 1024 * 1024 * r ; }else if( StringEndsWithAtLeastOne( e,"t","TB","tb","Tb","T",NULL ) ){ r = StringConvertToInt( _remove_letters( e ) ) ; r = (u_int64_t)( 1.0 * 2 * 1024 * 1024 * 1024 * r ) ; }else if( StringEndsWithAtLeastOne( e,"k","KB","kb","Kb","K",NULL ) ){ r = StringConvertToInt( _remove_letters( e ) ) ; r = 2 * r ; }else if( StringEndsWithAtLeastOne( e,"b","B",NULL ) ){ r = StringConvertToInt( _remove_letters( e ) ) ; if( r < 512 ){ r = 0 ; }else{ r = r / 512 ; } }else { r = StringConvertToInt( offset ) ; } StringFree( e ) ; } return r ; } static int _open_plain( const char * device,const resolve_path_t * opts ) { uint32_t flags ; struct crypt_device * cd ; struct crypt_params_plain params ; size_t size ; /* * open_struct_t is defined in includes.h */ const open_struct_t * opt = opts->args ; const args * e = opt->variables ; memset( ¶ms,'\0',sizeof( struct crypt_params_plain ) ) ; if( StringsAreNotEqual( e->hash,"null" ) ){ params.hash = e->hash ; } if( zuluCryptPathIsNotValid( device ) ){ return 3 ; } if( crypt_init( &cd,device ) != 0 ){ return 2 ; } params.offset = _offset( e->offset ) ; if( opts->open_mode == O_RDONLY ){ flags = CRYPT_ACTIVATE_READONLY ; }else{ flags = CRYPT_ACTIVATE_ALLOW_DISCARDS ; } size = ( size_t ) StringConvertToInt( e->keySize ) / 8 ; if( crypt_format( cd,CRYPT_PLAIN,e->algo,e->cipher,NULL,NULL,size,¶ms ) != 0 ){ return zuluExit( 2,cd ) ; } if( crypt_activate_by_passphrase( cd,opt->mapper_name,CRYPT_ANY_SLOT, opt->key,opt->key_len,flags ) < 0 ){ return zuluExit( 2,cd ) ; }else{ return zuluExit( 0,cd ) ; } } int zuluCryptOpenPlain_2( const char * device,const char * mapper, const char * mode,const char * key,size_t key_len, const char * options ) { open_struct_t opt ; stringList_t stl ; int r ; char * const * e = NULL ; size_t n = 0 ; args s = { "/dev/urandom","aes","cbc-essiv:sha256","256","ripemd160","0" } ; memset( &opt,'\0',sizeof( open_struct_t ) ) ; opt.device = device ; opt.mapper_name = mapper ; opt.key = key ; opt.key_len = key_len ; opt.m_opts = mode ; opt.variables = &s ; stl = StringListSplit( options,'.' ) ; StringListStringArray_1( &e,&n,stl ) ; if( n == 6 ){ s.rng = *( e + 0 ) ; s.algo = *( e + 1 ) ; s.cipher = *( e + 2 ) ; s.keySize = *( e + 3 ) ; s.hash = *( e + 4 ) ; s.offset = *( e + 5 ) ; }else if( n == 5 ){ s.algo = *( e + 0 ) ; s.cipher = *( e + 1 ) ; s.keySize = *( e + 2 ) ; s.hash = *( e + 3 ) ; s.offset = *( e + 4 ) ; } /* * zuluCryptResolveDevicePath_0() is defined in resolve_path.c */ r = zuluCryptResolveDevicePath_0( _open_plain,&opt,2 ) ; StringListDelete( &stl ) ; StringFree( e ) ; return r ; } int zuluCryptOpenPlain( const char * device,const char * mapper, const char * mode,const char * key,size_t key_len ) { return zuluCryptOpenPlain_2( device, mapper, mode, key, key_len, "/dev/urandom.aes.cbc-essiv:sha256.256.ripemd160.0" ) ; } int zuluCryptOpenPlain_1( const open_struct_t * opt ) { return zuluCryptOpenPlain_2( opt->device, opt->mapper_name, opt->m_opts, opt->key, opt->key_len, opt->plain_dm_properties ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/open_tcrypt.c000066400000000000000000000167021425361753700216310ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include #include #include #include #include #include "veracrypt_pim.h" static void _chown( const char * x,uid_t y,gid_t z ) { if( chown( x,y,z ) ){} } static void _chmod( const char * x,mode_t y ) { if( chmod( x,y ) ){} } static void _write( int x,const void * y,size_t z ) { if( write( x,y,z ) ){} } static void _close( int x ) { if( close( x ) ){} } const char * zuluCryptCryptsetupTCRYPTType() { #ifdef CRYPT_TCRYPT return CRYPT_TCRYPT ; #else return "" ; #endif } void * zuluCryptCryptsetupTCryptVCrypt( const open_struct_t * opt ) { #ifdef CRYPT_TCRYPT struct crypt_params_tcrypt * m = malloc( sizeof( struct crypt_params_tcrypt ) ) ; memset( m,'\0',sizeof( struct crypt_params_tcrypt ) ) ; m->passphrase = opt->key ; m->passphrase_size = opt->key_len ; m->keyfiles = opt->tcrypt_keyfiles ; m->keyfiles_count = ( unsigned int )opt->tcrypt_keyfiles_count ; m->flags = CRYPT_TCRYPT_LEGACY_MODES ; if( opt->system_volume ){ m->flags |= CRYPT_TCRYPT_SYSTEM_HEADER ; } if( opt->use_backup_header ){ m->flags |= CRYPT_TCRYPT_BACKUP_HEADER ; } if( opt->use_hidden_header ){ m->flags |= CRYPT_TCRYPT_HIDDEN_HEADER ; } #if SUPPORT_VERACRYPT_PIM m->veracrypt_pim = ( unsigned int ) opt->iteration_count ; #endif #ifdef CRYPT_TCRYPT_VERA_MODES if( opt->veraCrypt_volume ){ m->flags |= CRYPT_TCRYPT_VERA_MODES ; } #endif return m ; #else return NULL ; #endif } string_t zuluCryptCreateKeyFile( const char * key,size_t key_len,const char * fileName ) { string_t st = StringVoid ; int fd ; const char * file ; struct stat statstr ; if( key == NULL || key_len == 0 || fileName == NULL ){ return StringVoid ; } #define path_does_not_exist( x ) stat( x,&statstr ) != 0 if( path_does_not_exist( "/run" ) ){ mkdir( "/run",S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH | S_IROTH ) ; _chown( "/run",0,0 ) ; } if( path_does_not_exist( "/run/zuluCrypt" ) ){ mkdir( "/run/zuluCrypt",S_IRWXU ) ; _chown( "/run/zuluCrypt",0,0 ) ; } st = String_1( "/run/zuluCrypt/",fileName,NULL ) ; file = StringAppendInt( st,(u_int64_t)syscall( SYS_gettid ) ) ; fd = open( file,O_WRONLY | O_CREAT,S_IRUSR | S_IWUSR | S_IRGRP |S_IROTH ) ; if( fd == -1 ){ StringDelete( &st ) ; }else{ _write( fd,key,key_len ) ; _close( fd ) ; _chown( file,0,0 ) ; _chmod( file,S_IRWXU ) ; } return st ; } string_t zuluCryptCreateKeyFile_1( string_t st,const char * fileName ) { return zuluCryptCreateKeyFile( StringContent( st ),StringLength( st ),fileName ) ; } static int zuluExit( int st,struct crypt_device * cd, void * m ) { free( m ) ; crypt_free( cd ) ; return st ; } static int _open_tcrypt_volume( const char * device,const open_struct_t * opt ) { struct crypt_device * cd ; uint32_t flags ; int st ; void * m ; if( crypt_init( &cd,device ) != 0 ){ return 2 ; } m = zuluCryptCryptsetupTCryptVCrypt( opt ) ; if( crypt_load( cd,zuluCryptCryptsetupTCRYPTType(),m ) != 0 ){ return zuluExit( 2,cd,m ) ; } if( StringHasComponent( opt->m_opts,"ro" ) ){ flags = CRYPT_ACTIVATE_READONLY ; }else{ flags = CRYPT_ACTIVATE_ALLOW_DISCARDS ; } st = crypt_activate_by_volume_key( cd,opt->mapper_name,NULL,0,flags ) ; if( st == 0 ){ return zuluExit( 0,cd,m ) ; }else{ return zuluExit( 1,cd,m ) ; } } static int _open_tcrypt_volume_1( const char * device,const resolve_path_t * opt ) { int r ; open_struct_t opts ; memcpy( &opts,opt->args,sizeof( opts ) ) ; if( opts.trueCrypt_volume ){ r = _open_tcrypt_volume( device,&opts ) ; if( r == 0 ){ return 0 ; } opts.use_backup_header = 1 ; r = _open_tcrypt_volume( device,&opts ) ; if( r == 0 ){ return 0 ; } opts.use_backup_header = 0 ; opts.use_hidden_header = 1 ; r = _open_tcrypt_volume( device,&opts ) ; if( r == 0 ){ return 0 ; } opts.use_backup_header = 0 ; opts.use_hidden_header = 0 ; opts.system_volume = 1 ; return _open_tcrypt_volume( device,&opts ) ; }else{ if( opts.system_volume || opts.use_hidden_header ){ return _open_tcrypt_volume( device,&opts ) ; }else{ if( _open_tcrypt_volume( device,&opts ) == 0 ){ return 0 ; }else{ opts.use_hidden_header = 1 ; return _open_tcrypt_volume( device,&opts ) ; } } } } static int _open_tcrypt_0( const open_struct_t * opt ) { /* * zuluCryptResolveDevicePath_0() is defined in resolve_path.c */ return zuluCryptResolveDevicePath_0( _open_tcrypt_volume_1,opt,1 ) ; } int zuluCryptOpenTcrypt( const char * device,const char * mapper,const char * key,size_t key_len, int key_source,int volume_type,const char * m_point, uid_t uid,unsigned long m_flags,const char * fs_opts ) { open_struct_t opts ; string_t st ; int r ; const char * keyfile ; memset( &opts,'\0',sizeof( open_struct_t ) ) ; opts.device = device ; opts.mapper_name = mapper ; opts.volume_type = volume_type ; opts.m_point = m_point ; opts.uid = uid ; opts.m_flags = m_flags ; opts.fs_opts = fs_opts ; if( m_flags & MS_RDONLY ){ opts.m_opts = "ro" ; }else{ opts.m_opts = "rw" ; } if( key_source == TCRYPT_KEYFILE ){ st = zuluCryptCreateKeyFile( key,key_len,"open_tcrypt-" ) ; if( st != StringVoid ){ keyfile = StringContent( st ) ; opts.tcrypt_keyfiles_count = 1 ; opts.tcrypt_keyfiles = &keyfile ; r = zuluCryptOpenTcrypt_1( &opts ) ; /* * zuluCryptDeleteFile() is defined in open_path_security.c */ zuluCryptDeleteFile( keyfile ) ; StringDelete( &st ) ; }else{ r = 1 ; } }else if( key_source == TCRYPT_KEYFILE_FILE ){ opts.tcrypt_keyfiles_count = 1 ; opts.tcrypt_keyfiles = &key ; r = zuluCryptOpenTcrypt_1( &opts ) ; }else{ opts.key_len = key_len ; opts.key = key ; r = zuluCryptOpenTcrypt_1( &opts ) ; } return r ; } int zuluCryptOpenTcrypt_1( const open_struct_t * opts ) { /* * zuluCryptOpenVolume_0() is defined in open_volume.c */ return zuluCryptOpenVolume_0( _open_tcrypt_0,opts ) ; } /* * 1 is returned if a volume is a truecrypt volume. * 0 is returned if a volume is not a truecrypt volume or functionality is not supported */ int zuluCryptVolumeIsTcrypt( const char * device,const char * key,int key_source ) { void * m ; open_struct_t s ; struct crypt_device * cd = NULL; memset( &s,'\0',sizeof( open_struct_t ) ) ; if( key_source ){} if( crypt_init( &cd,device ) < 0 ){ return 0 ; }else{ s.key = key ; s.key_len = StringSize( key ) ; m = zuluCryptCryptsetupTCryptVCrypt( &s ) ; if( m == NULL ){ return 0 ; } if( crypt_load( cd,zuluCryptCryptsetupTCRYPTType(),m ) == 0 ){ return zuluExit( 1,cd,m ) ; }else{ return zuluExit( 0,cd,m ) ; } } } zuluCrypt-6.2.0/zuluCrypt-cli/lib/open_volume.c000066400000000000000000000152031425361753700216060ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include static inline int zuluExit( int x,string_t p ) { StringDelete( &p ) ; return x ; } static int _mount_volume( const char * mapper, const open_struct_t * opts, int( *function )( const char * ) ) { /* * zuluCryptMountVolume() is defined in mount_volume.c */ int h = zuluCryptMountVolume( mapper,opts->m_point,opts->m_flags,opts->fs_opts,opts->uid ) ; if( h != 0 ){ function( mapper ) ; } return h ; } int zuluCryptOpenVolume_0( int( *function )( const open_struct_t * ),const open_struct_t * opts ) { int h ; string_t p ; const char * mapper ; /* * zuluCryptPathIsNotValid() is defined in is_path_valid.c */ if( zuluCryptPathIsNotValid( opts->device ) ){ return 3 ; } /* * zuluCryptMapperPrefix() is defined in create_mapper_name.c */ p = String( zuluCryptMapperPrefix() ) ; mapper = StringMultipleAppend( p,"/",opts->mapper_name,NULL ) ; /* * zuluCryptPathIsValid() is defined in is_path_valid.c */ if( zuluCryptPathIsValid( mapper ) ){ return zuluExit( 2,p ) ; } h = function( opts ) ; switch( h ){ case 1 : return zuluExit( 4,p ) ; case 2 : return zuluExit( 8,p ) ; case 3 : return zuluExit( 3,p ) ; } if( opts->m_point != NULL ){ h = _mount_volume( mapper,opts,zuluCryptCloseMapper ) ; } return zuluExit( h,p ) ; } int zuluCryptOpenVolume( const char * dev,const char * mapper,const char * m_point,uid_t uid, unsigned long m_flags,const char * fs_opts,const char * key,size_t key_len ) { open_struct_t opts ; memset( &opts,'\0',sizeof( open_struct_t ) ) ; opts.device = dev ; opts.mapper_name = mapper ; opts.m_point = m_point ; opts.uid = uid ; opts.m_flags = m_flags ; opts.fs_opts = fs_opts ; opts.key = key ; opts.key_len = key_len ; if( m_flags & MS_RDONLY ){ opts.m_opts = "ro" ; }else{ opts.m_opts = "rw" ; } return zuluCryptOpenVolume_1( &opts ) ; } static int _open_mapper( const open_struct_t * opts ) { int r ; /* * zuluCryptVolumeIsLuks() is defined in is_luks.c */ if( opts->luks_detached_header ){ /* * zuluCryptOpenLuks_1() is defined in open_luks.c */ r = zuluCryptOpenLuks_1( opts ) ; }else if( zuluCryptVolumeIsLuks( opts->device ) ){ /* * zuluCryptOpenLuks_2() is defined in open_luks.c */ r = zuluCryptOpenLuks_2( opts ) ; if( r != 0 ){ /* * just assumed wrong password when a volume fail to unlock */ r = 1 ; } }else{ /* * zuluCryptOpenPlain_1() is defined in open_plain.c */ r = zuluCryptOpenPlain_1( opts ) ; } return r ; } /* * this function tries to unlock luks and plain volumes only */ int zuluCryptOpenVolume_1( const open_struct_t * opts ) { return zuluCryptOpenVolume_0( _open_mapper,opts ) ; } string_t zuluCryptUpdatePlainDmcryptProperties( const char * e ) { stringList_t stx = StringListSplit( e,'.' ) ; size_t n = StringListSize( stx ) ; string_t xt = String( StringListContentAt( stx,0 ) ) ; size_t s ; if( StringPrefixEqual( e,"/dev/" ) ){ s = 4 ; }else{ s = 3 ; } for( size_t m = 1 ; m < n ; m++ ){ if( m == s ){ StringAppend( xt,".null" ) ; }else{ StringMultipleAppend( xt,".",StringListContentAt( stx,m ),NULL ) ; } } StringListDelete( &stx ) ; return xt ; } static int _open_plain( const open_struct_t * opts ) { string_t st ; open_struct_t opts_1 ; /* * zuluCryptOpenPlain_1() is defined in open_plain.c */ int r = zuluCryptOpenVolume_0( zuluCryptOpenPlain_1,opts ) ; if( r != 0 ){ memcpy( &opts_1,opts,sizeof( open_struct_t ) ) ; if( opts_1.plain_dm_properties == NULL ){ opts_1.plain_dm_properties = "/dev/urandom.aes.cbc-essiv:sha256.256.null.0" ; r = zuluCryptOpenVolume_0( zuluCryptOpenPlain_1,&opts_1 ) ; }else{ st = zuluCryptUpdatePlainDmcryptProperties( opts->plain_dm_properties ) ; opts_1.plain_dm_properties = StringContent( st ) ; r = zuluCryptOpenVolume_0( zuluCryptOpenPlain_1,&opts_1 ) ; StringDelete( &st ) ; } } return r ; } static int _unlock_tcrypt_vcrypt( const open_struct_t * opts ) { int r ; open_struct_t opts_1 ; string_t zt = StringVoid ; const char * keyfile ; memcpy( &opts_1,opts,sizeof( open_struct_t ) ) ; if( opts_1.key_source == TCRYPT_KEYFILE ){ /* * zuluCryptCreateKeyFile() is defined in open_tcrypt.c */ zt = zuluCryptCreateKeyFile( opts_1.key,opts_1.key_len,"keyfile" ) ; if( zt != StringVoid ){ keyfile = StringContent( zt ) ; opts_1.tcrypt_keyfiles_count = 1 ; opts_1.tcrypt_keyfiles = &keyfile ; opts_1.key = "" ; opts_1.key_len = 0 ; r = zuluCryptOpenTcrypt_1( &opts_1 ) ; /* * zuluCryptDeleteFile() is defined in file_path_security.c */ zuluCryptDeleteFile( keyfile ) ; StringDelete( &zt ) ; }else{ r = -1 ; } }else{ r = zuluCryptOpenTcrypt_1( &opts_1 ) ; } return r ; } /* * this function tries to unlock luks,plain and truecrypt volumes */ int zuluCryptOpenVolume_2( const open_struct_t * opts ) { int r ; string_t xt = StringVoid ; const char * mapper ; if( opts->bitlocker_volume ){ r = zuluCryptBitLockerUnlock( opts,&xt ) ; if( r == 0 ){ mapper = StringContent( xt ) ; r = _mount_volume( mapper,opts,zuluCryptCloseMapper ) ; } StringDelete( &xt ) ; }else if( opts->plain_dm_properties != NULL ){ r = _open_plain( opts ) ; }else if( opts->luks_detached_header || zuluCryptVolumeIsLuks( opts->device ) ){ /* * zuluCryptOpenLuks_2() is defined in open_luks.c */ r = zuluCryptOpenVolume_0( zuluCryptOpenLuks_2,opts ) ; }else if( opts->veraCrypt_volume || opts->trueCrypt_volume ){ r = _unlock_tcrypt_vcrypt( opts ) ; if( r != 0 ){ r = 4 ; } }else{ r = _open_plain( opts ) ; if( r != 0 ){ open_struct_t opts_1 ; memcpy( &opts_1,opts,sizeof( open_struct_t ) ) ; opts_1.trueCrypt_volume = 1 ; r = _unlock_tcrypt_vcrypt( &opts_1 ) ; if( r != 0 ){ r = 4 ; } } } return r ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/parse_fstab.c000066400000000000000000000101641425361753700215500ustar00rootroot00000000000000/* * * Copyright (c) 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../lib/includes.h" #include #include #include static void _add_entry( string_t xt,ssize_t r,char * e ) { StringSubChar( xt,(size_t)r,' ' ) ; if( e != NULL ){ StringRemoveLeft( xt,(size_t)r ) ; StringPrepend( xt,e ) ; StringFree( e ) ; } } stringList_t zuluCryptGetFstabList( uid_t uid ) { string_t xt = StringGetFromFile( "/etc/fstab" ) ; stringList_t stl = StringListVoid ; StringListIterator it ; StringListIterator end ; ssize_t index ; const char * entry ; if( uid ){} stl = StringListStringSplit( xt,'\n' ) ; StringDelete( &xt ) ; StringListRemoveIfStringStartsWith( stl,"#" ) ; StringListRemoveIfStringStartsWith( stl,"//" ) ; if( StringListSize( stl ) < 1 ){ StringListDelete( &stl ) ; return StringListVoid ; } StringListGetIterators( stl,&it,&end ) ; while( it != end ){ xt = *it ; it++ ; index = StringIndexOfChar( xt,0,' ' ) ; if( index != -1 ){ entry = StringSubChar( xt,(size_t)index,'\0' ) ; if( StringPrefixEqual( entry,"/dev/" ) ){ /* * zuluCryptResolvePath() is defined in resolve_paths.c */ _add_entry( xt,index,zuluCryptResolvePath( entry ) ) ; }else if( StringAtLeastOnePrefixMatch( entry,"UUID=","uuid=",NULL ) ){ entry = StringRemoveString( xt,"\"" ) ; /* * zuluCryptDeviceFromUUID() is defined in blkid_evaluate_tag.c */ _add_entry( xt,index,zuluCryptDeviceFromUUID( entry + 5 ) ) ; }else if( StringAtLeastOnePrefixMatch( entry,"LABEL=","label=",NULL ) ){ entry = StringRemoveString( xt,"\"" ) ; /* * zuluCryptDeviceFromLabel() is defined in blkid_evaluate_tag.c */ _add_entry( xt,index,zuluCryptDeviceFromLabel( entry + 6 ) ) ; }else if( StringAtLeastOnePrefixMatch( entry,"PARTUUID=","partuuid=",NULL ) ){ entry = StringRemoveString( xt,"\"" ) ; /* * zuluCryptDeviceFromPARTUUID() is defined in blkid_evaluate_tag.c */ _add_entry( xt,index,zuluCryptDeviceFromPARTUUID( entry + 9 ) ) ; }else if( StringAtLeastOnePrefixMatch( entry,"PARTLABEL=","partlabel=",NULL ) ){ entry = StringRemoveString( xt,"\"" ) ; /* * zuluCryptDeviceFromPARTLABEL() is defined in blkid_evaluate_tag.c */ _add_entry( xt,index,zuluCryptDeviceFromPARTLABEL( entry + 10 ) ) ; }else{ entry = StringSubChar( xt,(size_t)index,' ' ) ; } } } return stl ; } string_t zuluCryptGetFstabEntry( const char * device,uid_t uid ) { string_t st = StringVoid ; string_t xt = String( device ) ; stringList_t stl = zuluCryptGetFstabList( uid ) ; ssize_t index = StringListHasStartSequence( stl,StringAppend( xt," " ) ) ; if( index >= 0 ){ st = StringListCopyStringAt( stl,(size_t)index ) ; } StringDelete( &xt ) ; StringListDelete( &stl ) ; return st ; } string_t zuluCryptGetMountOptionsFromFstab( const char * device,int pos,uid_t uid ) { stringList_t stl ; string_t st = zuluCryptGetFstabEntry( device,uid ) ; if( st != StringVoid ){ stl = StringListStringSplit( st,' ' ) ; StringDelete( &st ) ; st = StringListCopyStringAt( stl,(size_t)pos ) ; StringListDelete( &stl ) ; } return st ; } stringList_t zuluCryptGetFstabEntryList( const char * device,uid_t uid ) { stringList_t stl = StringListVoid; string_t st = zuluCryptGetFstabEntry( device,uid ) ; if( st != StringVoid ){ stl = StringListStringSplit( st,' ' ) ; StringDelete( &st ) ; } return stl ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/real_path.c000066400000000000000000000041001425361753700212070ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include /* PATH_MAX */ #include #include #include #include #include "includes.h" #include char * zuluCryptRealPath( const char * path ) { string_t st ; string_t xt ; char * e = realpath( path,NULL ) ; if( StringPrefixEqual( e,"/dev/dm-" ) ){ st = String_1( "/sys/block/",e + 5,"/dm/name",NULL ) ; xt = StringGetFromVirtualFile( StringContent( st ) ) ; StringRemoveRight( xt,1 ) ; StringPrepend( xt,"/dev/mapper/" ) ; StringFree( e ) ; StringDelete( &st ) ; return StringDeleteHandle( &xt ) ; }else{ return e ; } } int zuluCryptPathStartsWith( const char * path,const char * start ) { int st = 0 ; char * p = zuluCryptRealPath( path ) ; if( p != NULL ){ st = StringPrefixEqual( p,start ) ; StringFree( p ) ; } return st ; } int zuluCryptPathDoesNotStartsWith( const char * path,const char * start ) { int st = 0; char * p = zuluCryptRealPath( path ) ; if( p != NULL ){ st = StringPrefixEqual( p,start ) ; StringFree( p ) ; } return st == 0 ; } int zuluCryptPathDidNotChange( const char * path ) { char * p = zuluCryptRealPath( path ) ; int st = 0 ; if( p != NULL ){ st = StringsAreEqual( path,p ) ; StringFree( p ) ; } return st ; } int zuluCryptPathDeviceIsBlockDevice( const char * device ) { if( device ){} return 0 ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/remove_key.c000066400000000000000000000053071425361753700214270ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include typedef struct{ const char * key ; size_t key_len ; int slot_number ; }arguments ; static int zuluExit( int st,struct crypt_device * cd ) { crypt_free( cd ) ; return st ; } static int _remove_key( const char * device,const resolve_path_t * opts ) { int slot ; struct crypt_device * cd ; const arguments * args = opts->args ; if( zuluCryptVolumeIsNotLuks( device ) ){ return 1 ; } if( crypt_init( &cd,device ) != 0 ){ return 3 ; } if( crypt_load( cd,NULL,NULL ) != 0 ){ return zuluExit( 3,cd ) ; } slot = crypt_activate_by_passphrase( cd,NULL,CRYPT_ANY_SLOT,args->key,args->key_len,0 ) ; if( slot < 0 ){ return zuluExit( 2,cd ) ; } if( args->slot_number == CRYPT_ANY_SLOT ){ /* * Behaves like luksRemoveKey */ if( crypt_keyslot_destroy( cd,slot ) < 0 ){ return zuluExit( 2,cd ) ; }else{ return zuluExit( 0,cd ) ; } }else{ /* * Behaves like luksKillSlot */ if( crypt_keyslot_destroy( cd,args->slot_number ) < 0 ){ return zuluExit( 2,cd ) ; }else{ return zuluExit( 0,cd ) ; } } } int zuluCryptRemoveKey( const char * device ,const char * pass,size_t pass_size ) { return zuluCryptRemoveKey_0( device,pass,pass_size,CRYPT_ANY_SLOT ) ; } int zuluCryptRemoveKey_0( const char * device ,const char * pass,size_t pass_size,int key_slot ) { /* * resolve_path_t is defined in includes.h */ resolve_path_t opts ; arguments args ; memset( &opts,'\0',sizeof( opts ) ) ; memset( &args,'\0',sizeof( args ) ) ; args.key = pass ; args.key_len = pass_size ; if( key_slot == -1 ){ args.slot_number = CRYPT_ANY_SLOT ; }else{ args.slot_number = key_slot ; } opts.device = device ; opts.args = &args ; opts.open_mode = O_RDWR ; opts.error_value = 2 ; /* * zuluCryptResolveDevicePath() is defined in resolve_path.c */ return zuluCryptResolveDevicePath( _remove_key,&opts ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/resolve_paths.c000066400000000000000000000212211425361753700221310ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include static char * _zuluCryptResolveDevRoot( void ) { char * device = NULL ; string_t st = StringGetFromVirtualFile( "/proc/cmdline" ) ; stringList_t stl = StringListStringSplit( st,' ' ) ; StringListIterator it ; StringListIterator end ; StringDelete( &st ) ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ st = *it ; it++ ; if( StringStartsWith( st,"root=/dev/" ) ){ device = zuluCryptResolvePath( StringContent( st ) + 5 ) ; break ; }else if( StringStartsWith( st,"root=UUID=" ) ){ /* * zuluCryptDeviceFromUUID() is defined in blkid_evaluate_tag.c */ device = zuluCryptDeviceFromUUID( StringContent( st ) + 10 ) ; break ; } } StringListDelete( &stl ) ; return device ; } static string_t zuluExit( DIR * dir,string_t st ) { if( dir != NULL ){ closedir( dir ) ; } return st ; } /* * raid path can be in format /dev/mdX or /dev/md/X. * We prefer the latter and if given the former,convert it to the latter if possible */ string_t zuluCryptResolveMDPath_1( const char * path ) { struct dirent * entry ; char * e ; const char * f = "/dev/md/" ; DIR * dir = opendir( f ) ; string_t st = String( f ) ; if( dir != NULL ){ while( ( entry = readdir( dir ) ) != NULL ){ f = entry->d_name ; if( !StringAtLeastOneMatch_1( f,".","..",NULL ) ){ e = zuluCryptRealPath( StringAppendAt( st,8,f ) ) ; if( StringsAreEqual( path,e ) ){ StringFree( e ) ; return zuluExit( dir,st ) ; }else{ StringFree( e ) ; } } } } StringReplace( st,path ) ; return zuluExit( dir,st ) ; } char * zuluCryptResolveMDPath( const char * path ) { string_t st = zuluCryptResolveMDPath_1( path ) ; return StringDeleteHandle( &st ) ; } /* * An assumption is made here that the path is an LVM path if "path" * is in /dev/mapper/abc-def format and there exist a path at /dev/abc/def. * * Info in lvm path structures can be found here: * https://www.redhat.com/archives/linux-lvm/2014-January/msg00014.html */ string_t zuluCryptConvertIfPathIsLVM( const char * path ) { const char * e ; const char ** z ; struct stat st ; StringIterator a ; StringIterator b ; StringIterator c ; StringIterator d ; string_t q = String( path ) ; StringGetIterators( q,&c,&d ) ; for( c = c + 3 ; c < d ; c++ ){ a = c - 2 ; b = c - 1 ; if( *a != '-' && *b == '-' && *c != '-' ){ /* * found a place with a single dash,replace the dash with a slash */ *b = '/' ; /* * replace double dashes if present. */ z = StringPointer( q ) ; while( StringHasComponent( *z,"--" ) ){ StringReplaceString( q,"--","-" ) ; } e = StringReplaceString( q,"/dev/mapper/","/dev/" ) ; if( stat( e,&st ) == 0 ){ /* * The path appear to be an LVM path since * "/dev/mapper/ABC-DEF" input path has a corresponding * "/dev/ABC/DEF" path */ }else{ /* * Not an LVM volume,replace the string to its original */ StringReplace( q,path ) ; } break ; } } return q ; } static char * _convert_if_path_is_lvm( const char * path ) { string_t st = zuluCryptConvertIfPathIsLVM( path ) ; return StringDeleteHandle( &st ) ; } /* * dm path is a path like "/dev/dm-5". * this routine will transform the path to /dev/abc/def if the path is * an lvm path or to /dev/mapper/xyz if the volume is any other device manager volume. */ char * zuluCryptResolveDMPath( const char * path ) { char * e = zuluCryptRealPath( path ) ; char * f = _convert_if_path_is_lvm( e ) ; StringFree( e ) ; return f ; } char * zuluCryptResolvePath( const char * path ) { char * e ; char * f ; if( StringsAreEqual( path,"/dev/root" ) ){ e = _zuluCryptResolveDevRoot() ; if( e == NULL ){ return StringCopy_2( path ) ; }else{ return e ; } }else if( StringPrefixEqual( path,"/dev/disk/by-" ) ){ /* * zuluCryptRealPath() is defined in real_path.c */ e = zuluCryptRealPath( path ) ; if( e == NULL ){ return StringCopy_2( path ) ; }else{ if( StringPrefixEqual( e,"/dev/mapper/" ) ){ f = _convert_if_path_is_lvm( e ) ; StringFree( e ) ; return f ; }else{ return e ; } } }else if( StringPrefixEqual( path,"/dev/mapper/" ) ){ return _convert_if_path_is_lvm( path ) ; }else if( StringPrefixEqual( path,"/dev/md" ) ){ return zuluCryptResolveMDPath( path ) ; }else if( StringPrefixEqual( path,"/dev/dm-" ) ){ return zuluCryptResolveDMPath( path ) ; }else if( zuluCryptNoPartitionLoopDevice( path ) ){ /* * zuluCryptLoopDeviceAddress() is defined in create_loop_device.c */ return zuluCryptLoopDeviceAddress( path ) ; }else{ return StringCopy_2( path ) ; } } string_t zuluCryptResolvePath_1( const char * path ) { char * e = zuluCryptResolvePath( path ) ; return StringInherit( &e ) ; } string_t zuluCryptResolvePath_2( const char * path ) { if( zuluCryptNoPartitionLoopDevice( path ) ){ return String( path ) ; }else{ return zuluCryptResolvePath_1( path ) ; } } char * zuluCryptResolvePath_3( const char * path ) { if( zuluCryptNoPartitionLoopDevice( path ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in create_loop_device.c */ return zuluCryptLoopDeviceAddress_1( path ) ; }else{ return zuluCryptResolvePath( path ) ; } } char * zuluCryptResolvePath_4( const char * path ) { if( StringPrefixEqual( path,"/dev/loop" ) ){ return StringCopy_2( path ) ; }else{ return zuluCryptResolvePath( path ) ; } } typedef struct{ int result_0 ; int error_0 ; char * result_1 ; char * error_1 ; const resolve_path_t * opts ; int( *function_0 )( const char *,const resolve_path_t * ) ; char *( *function_1 )( const char *,const resolve_path_t * ) ; } arguments; static void _get_result_0( const char * device,arguments * args ) { if( args->function_0 != NULL ){ args->result_0 = args->function_0( device,args->opts ) ; }else{ args->result_1 = args->function_1( device,args->opts ) ; } } static void _get_error( arguments * args ) { if( args->function_0 != NULL ){ args->result_0 = args->error_0 ; }else{ args->result_1 = args->error_1 ; } } static void _get_result( arguments * args ) { string_t st ; int fd ; const char * device = args->opts->device ; if( StringPrefixEqual( device,"/dev/" ) ){ _get_result_0( device,args ) ; }else{ /* * zuluCryptAttachLoopDeviceToFile() is defined in create_loop_device.c */ if( zuluCryptAttachLoopDeviceToFile( device,args->opts->open_mode,&fd,&st ) ){ _get_result_0( StringContent( st ),args ) ; StringDelete( &st ) ; close( fd ) ; }else{ _get_error( args ) ; } } } static int _get_result_1( int( *function )( const char *,const resolve_path_t * ), const resolve_path_t * opts,int error ) { arguments args ; memset( &args,'\0',sizeof( args ) ) ; args.function_0 = function ; args.error_0 = error ; args.opts = opts ; _get_result( &args ) ; return args.result_0 ; } int zuluCryptResolveDevicePath( int( *function )( const char *,const resolve_path_t * ), const resolve_path_t * opts ) { return _get_result_1( function,opts,opts->error_value ) ; } int zuluCryptResolveDevicePath_0( int( *function )( const char *,const resolve_path_t * ), const open_struct_t * opt,int error ) { /* * resolve_path_t is defined in includes.h */ resolve_path_t opts ; memset( &opts,'\0',sizeof( opts ) ) ; opts.args = opt ; opts.device = opt->device ; if( StringHasComponent( opt->m_opts,"ro" ) ){ opts.open_mode = O_RDONLY ; }else{ opts.open_mode = O_RDWR ; } return _get_result_1( function,&opts,error ) ; } char * zuluCryptResolveDevicePath_1( char * ( *function )( const char *,const resolve_path_t * ), const resolve_path_t * opts ) { arguments args ; memset( &args,'\0',sizeof( args ) ) ; args.function_1 = function ; args.error_1 = opts->error_value_1 ; args.opts = opts ; _get_result( &args ) ; return args.result_1 ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/status.c000066400000000000000000000331011425361753700205760ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include #include #include #include #include #include #include #include "luks2_support.h" #include "share_mount_prefix_path.h" #define SIZE 1024 #define TYPE 3 #define UUID 4 /* * zuluCryptLoopDeviceAddress() is moved to create_loop.c */ char * zuluCryptGetMountPointFromPath( const char * path ) ; typedef struct{ string_t integrity_hash ; string_t integrity_keysize ; }authenticated_luks2 ; #ifdef CRYPT_LUKS2 static int _is_authenticated_luks2( struct crypt_device * cd ) { struct crypt_params_integrity m ; memset( &m,'\0',sizeof( m ) ) ; if( crypt_get_integrity_info( cd,&m ) == 0 ){ return m.integrity != NULL ; }else{ return 0 ; } } static void _authenticated_luks2( struct crypt_device * cd,authenticated_luks2 * s ) { char buffer[ 1024 ] ; struct crypt_params_integrity m ; memset( &m,'\0',sizeof( m ) ) ; memset( buffer,'\0',sizeof( buffer ) ) ; if( crypt_get_integrity_info( cd,&m ) == 0 ){ if( m.integrity != NULL ){ s->integrity_hash = String_1( "/integrity: ",m.integrity,NULL ) ; } if( m.integrity_key_size != 0 ){ snprintf( buffer,sizeof( buffer ), "/integrity: %d bits", ( int )m.integrity_key_size * 8 ) ; s->integrity_keysize = String( buffer ) ; } } } #else static void _authenticated_luks2( struct crypt_device * cd,authenticated_luks2 * s ) { if( s && cd ){} } static int _is_authenticated_luks2( struct crypt_device * cd ) { if( cd ){} return 0 ; } #endif static void _convert( char * buffer,size_t buffer_size,const char * s,u_int64_t y,u_int64_t z ) { snprintf( buffer,buffer_size,"%.1f %s",( double )y/z,s ) ; } void zuluCryptFormatSize( u_int64_t number,char * buffer,size_t buffer_size ) { const char * z = StringIntToString_1( buffer,buffer_size,number ) ; switch( StringSize( z ) ){ case 0 : case 1 : case 2 : case 3 : snprintf( buffer,buffer_size,"%d B",( int )number ) ; break ; case 4 : case 5 : case 6 : _convert( buffer,buffer_size,"KB",number,1024 ) ; break ; case 7 : case 8 : case 9 : _convert( buffer,buffer_size,"MB",number,1024 * 1024 ) ; break ; case 10: case 11 : case 12 : _convert( buffer,buffer_size,"GB",number,1024 * 1024 * 1024 ) ; break ; case 13: case 14 : case 15 : _convert( buffer,buffer_size,"TB",number,1024 * 1024 * 1024 * 1024ll ) ; break ; default: _convert( buffer,buffer_size,"TB",number,1024 * 1024 * 1024 * 1024ll ) ; break ; } } static string_t _get_mapper_property_from_udev( const char * mapper,const char * prefix,size_t position ) { DIR * dir = opendir( "/dev/disk/by-id/" ) ; struct dirent * e ; const char * f = mapper + StringSize( crypt_get_dir() ) + 1 ; stringList_t stl ; string_t st = StringVoid ; if( dir != NULL ){ while( ( e = readdir( dir ) ) != NULL ){ if( StringStartsAndEndsWith( e->d_name,prefix,f ) ){ stl = StringListSplit( e->d_name,'-' ) ; st = StringListCopyStringAt( stl,position ) ; StringListDelete( &stl ) ; break ; } } closedir( dir ) ; } return st ; } static char * _get_uuid_from_udev( const char * mapper ) { string_t st = _get_mapper_property_from_udev( mapper,"dm-uuid-CRYPT-LUKS",UUID ) ; return StringDeleteHandle( &st ) ; } static char * _get_type_from_udev( const char * mapper ) { string_t st = _get_mapper_property_from_udev( mapper,"dm-uuid-CRYPT-",TYPE ) ; if( st == StringVoid ){ return StringCopy_2( "Nil" ) ; }else{ StringPrepend( st,"crypto_" ) ; return StringDeleteHandle( &st ) ; } } static string_t _get_type_from_udev_1( const char * mapper ) { string_t st = _get_mapper_property_from_udev( mapper,"dm-uuid-CRYPT-",TYPE ) ; if( st == StringVoid ){ /* * failed to discover volume type */ return String( "Nil" ) ; }else{ StringToLowerCase( st ) ; return st ; } } char * zuluCryptGetUUIDFromMapper( const char * mapper ) { string_t uuid ; struct crypt_device * cd ; const char * id ; const char * e = " UUID: \t\"Nil\"" ; char * f ; if( crypt_init_by_name( &cd,mapper ) < 0 ){ uuid = String( e ) ; }else{ id = crypt_get_uuid( cd ) ; if( id == NULL ){ /* * Either not a LUKS volume or a LUKS volume but with a detached header. * consult udev to see if it can sort this volume out. */ f = _get_uuid_from_udev( mapper ) ; if( f == NULL ){ uuid = String( e ) ; }else{ uuid = String_1( " UUID: \t\"",f,"\"",NULL ) ; StringFree( f ) ; } }else{ uuid = String_1( " UUID: \t\"",id,"\"",NULL ) ; } crypt_free( cd ) ; } return StringDeleteHandle( &uuid ) ; } void zuluCryptFileSystemProperties( string_t p,const char * mapper,const char * m_point ) { const char * e ; blkid_probe blkid ; struct statvfs vfs ; u_int64_t total ; u_int64_t used ; u_int64_t unused ; u_int64_t block_size ; char buff[ SIZE ] ; char * buffer = buff ; string_t q ; ssize_t index ; struct stat statstr ; blkid = blkid_new_probe_from_filename( mapper ) ; if( blkid == NULL ){ return ; } blkid_do_probe( blkid ) ; StringMultipleAppend( p,"\n file system:\t",zuluCryptVolumeType( blkid,mapper ),NULL ) ; blkid_free_probe( blkid ) ; if( statvfs( m_point,&vfs ) != 0 ){ return ; } block_size = vfs.f_frsize ; total = block_size * vfs.f_blocks ; unused = block_size * vfs.f_bavail ; used = total - unused ; zuluCryptFormatSize( total,buffer,SIZE ) ; StringMultipleAppend( p,"\n total space:\t",buffer,NULL ) ; zuluCryptFormatSize( used,buffer,SIZE ) ; StringMultipleAppend( p,"\n used space:\t",buffer,NULL ) ; zuluCryptFormatSize( unused,buffer,SIZE ) ; StringMultipleAppend( p,"\n free space:\t",buffer,NULL ) ; if( used == total ){ StringAppend( p,"\n used%: \t100%\n" ) ; }else if( used == 0 ){ StringAppend( p,"\n used%: \t0%\n" ) ; }else{ snprintf( buff,SIZE,"%.2f%%",100 * (double)( ( float ) used / ( float ) total ) ) ; StringMultipleAppend( p,"\n used%: \t",buff,"\n",NULL ) ; } buffer = zuluCryptGetUUIDFromMapper( mapper ) ; StringAppend( p,buffer ) ; StringFree( buffer ) ; StringMultipleAppend( p,"\n mount point1:\t",m_point,NULL ) ; q = String( m_point ) ; index = StringLastIndexOfChar( q,'/' ) ; if( index == -1 ){ StringAppend( p,"\n mount point2:\tNil" ) ; }else{ StringRemoveLeft( q,(size_t)index ) ; e = StringPrepend( q,SHARE_MOUNT_PREFIX ) ; if( stat( e,&statstr ) == 0 ){ StringMultipleAppend( p,"\n mount point2:\t",e,NULL ) ; }else{ StringAppend( p,"\n mount point2:\tNil" ) ; } } StringDelete( &q ) ; } int zuluCryptVolumeManagedByTcplay( const char * mapper ) { if( mapper ){} return 0 ; } static char * _get_type( struct crypt_device * cd,const char * mapper ) { char * r ; string_t st ; const char * type = crypt_get_type( cd ) ; if( type == NULL ){ if( StringHasComponent( mapper,"veracrypt" ) ){ r = StringCopy_2( "crypto_VCRYPT" ) ; }else if( StringHasComponent( mapper,"truecrypt" ) ){ r = StringCopy_2( "crypto_TCRYPT" ) ; }else{ r = _get_type_from_udev( mapper ) ; } }else{ if( _is_authenticated_luks2( cd ) ){ st = String_1( "crypto_",type,"+",NULL ) ; }else{ st = String_1( "crypto_",type,NULL ) ; } r = StringDeleteHandle( &st ) ; } return r ; } char * zuluCryptGetVolumeTypeFromMapperPath( const char * mapper ) { struct crypt_device * cd ; char * r ; if( zuluCryptBitLockerVolume( mapper ) ){ return StringCopy_2( zuluCryptBitLockerType() ) ; } if( crypt_init_by_name( &cd,mapper ) < 0 ){ return StringCopy_2( "Nil" ) ; } r = _get_type( cd,mapper ) ; crypt_free( cd ) ; return r ; } char * zuluCryptGetVolumeType_1( const char * device ) { struct crypt_device * cd ; char * r ; if( crypt_init( &cd,device ) != 0 ){ return StringCopy_2( "Nil" ) ; } if( crypt_load( cd,NULL,NULL ) != 0 ){ crypt_free( cd ) ; return StringCopy_2( "Nil" ) ; } r = _get_type( cd,"" ) ; crypt_free( cd ) ; return r ; } static void _device_info( string_t p,const char * device ) { char * path ; if( device == NULL ){ StringMultipleAppend( p,"\n device: \t","Nil","\n loop: \t","Nil",NULL ) ; }else if( StringPrefixEqual( device,"/dev/loop" ) ){ if( zuluCryptMultiPartitionLoopDevice( device ) ){ StringMultipleAppend( p,"\n device: \t",device,"\n loop: \t",device,NULL ) ; }else{ path = zuluCryptLoopDeviceAddress_1( device ) ; if( path != NULL ){ StringMultipleAppend( p,"\n device: \t",device,"\n loop: \t",path,NULL ) ; StringFree( path ) ; }else{ StringMultipleAppend( p,"\n device: \t",device,"\n loop: \tNil",NULL ) ; } } }else{ /* * zuluCryptResolvePath() is defined in resolve_path.c */ path = zuluCryptResolvePath( device ) ; StringMultipleAppend( p,"\n device: \t",path,"\n loop: \tNil",NULL ) ; StringFree( path ) ; } } typedef struct{ const char * mapper ; string_t st ; } volume_properties ; static string_t _get_crypto_info_from_cryptsetup( const char * mapper ) { char buff[ SIZE ] ; char * buffer = buff ; const char * z ; const char * type ; uint64_t e ; string_t q ; string_t p ; int k ; int i = 0 ; int j ; authenticated_luks2 auth_luks2 ; crypt_status_info info ; struct crypt_device * cd ; struct crypt_active_device cad ; if( crypt_init_by_name( &cd,mapper ) != 0 ){ return StringVoid ; } memset( &auth_luks2,'\0',sizeof( auth_luks2 ) ) ; _authenticated_luks2( cd,&auth_luks2 ) ; p = String( mapper ) ; info = crypt_status( cd,mapper ) ; switch( info ){ case CRYPT_INACTIVE : StringAppend( p," is inactive.\n" ) ; break ; case CRYPT_INVALID : StringAppend( p," is invalid.\n" ) ; break ; case CRYPT_ACTIVE : StringAppend( p," is active.\n" ) ; break ; case CRYPT_BUSY : StringAppend( p," is active and is in use.\n" ) ; break ; default : StringAppend( p," is invalid.\n" ) ; } if( info == CRYPT_ACTIVE || info == CRYPT_BUSY ){ StringAppend( p," type: \t" ) ; type = crypt_get_type( cd ) ; if( type != NULL ){ if( StringsAreEqual( type,zuluCryptCryptsetupBitLockerType() ) ){ q = String( zuluCryptBitLockerType() ) ; StringReplaceString( q,"crypto_","" ) ; }else{ q = String( type ) ; } StringAppend( p,StringToLowerCase( q ) ) ; if( StringsAreEqual_2( q,"luks2" ) && auth_luks2.integrity_hash ){ StringAppend( p,"+" ) ; } StringDelete( &q ) ; }else{ q = _get_type_from_udev_1( mapper ) ; StringAppendString( p,q ) ; StringDelete( &q ) ; } z = crypt_get_cipher( cd ) ; if( z != NULL ){ StringMultipleAppend( p,"\n cipher:\t",z,"-",NULL ) ; }else{ StringAppend( p,"\n cipher:\tNil-" ) ; } z = crypt_get_cipher_mode( cd ) ; if( z != NULL ){ StringAppend( p,z ) ; }else{ StringAppend( p,"Nil" ) ; } StringAppendString( p,auth_luks2.integrity_hash ) ; z = StringIntToString_1( buffer,SIZE,(u_int64_t)( 8 * crypt_get_volume_key_size( cd ) ) ) ; StringMultipleAppend( p,"\n keysize:\t",z," bits",NULL ) ; StringAppendString( p,auth_luks2.integrity_keysize ) ; e = crypt_get_data_offset( cd ) ; z = StringIntToString_1( buffer,SIZE,e ) ; StringMultipleAppend( p,"\n offset:\t",z," sectors",NULL ) ; zuluCryptFormatSize( e * 512,buffer,SIZE ) ; StringMultipleAppend( p," / ",buffer,NULL ) ; _device_info( p,crypt_get_device_name( cd ) ) ; crypt_get_active_device( NULL,mapper,&cad ) ; if( cad.flags == 1 ){ StringAppend( p,"\n mode: \tread only" ) ; }else{ StringAppend( p,"\n mode: \tread and write" ) ; } k = crypt_keyslot_max( crypt_get_type( cd ) ) ; if( k > 0 ){ i = 0 ; for( j = 0 ; j < k ; j++ ){ switch( crypt_keyslot_status( cd,j ) ){ case CRYPT_SLOT_ACTIVE_LAST : i++ ; break ; case CRYPT_SLOT_ACTIVE : i++ ; break ; default : ; } } StringMultipleAppend( p,"\n active slots:\t",StringIntToString_1( buffer,SIZE,(u_int64_t)i ),NULL ) ; StringMultipleAppend( p," / ",StringIntToString_1( buffer,SIZE,(u_int64_t)k ),NULL ) ; }else{ StringAppend( p,"\n active slots:\tNil" ) ; } } crypt_free( cd ) ; StringDelete( &auth_luks2.integrity_hash ) ; StringDelete( &auth_luks2.integrity_keysize ) ; return p ; } char * zuluCryptVolumeStatus( const char * mapper ) { char * path ; string_t p = _get_crypto_info_from_cryptsetup( mapper ) ; if( p == StringVoid ){ return NULL ; }else{ /* * zuluCryptGetMountPointFromPath() is defined in mountinfo.c */ path = zuluCryptGetMountPointFromPath( mapper ) ; if( path != NULL ){ zuluCryptFileSystemProperties( p,mapper,path ) ; StringFree( path ) ; } return StringDeleteHandle( &p ) ; } } char * zuluCryptVolumeDeviceName( const char * mapper ) { struct crypt_device * cd ; char * f = NULL ; const char * e ; if( crypt_init_by_name( &cd,mapper ) == 0 ){ e = crypt_get_device_name( cd ) ; if( e != NULL ){ f = zuluCryptResolvePath_3( e ) ; } crypt_free( cd ) ; } return f ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/unmount_volume.c000066400000000000000000000121521425361753700223520ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include #include #include #include #include static int _unmount_rest( const char * m_dir ) { return umount( m_dir ) ; } static int _unmount_fuse( const char * m_dir ) { /* * ZULUCRYPTumount is defined in ../constants.h */ return ProcessExecute( ZULUCRYPTumount,m_dir,NULL ) ; } static int _unmount( int( *function )( const char * m_dir ),const char * m_dir ) { int h = -1 ; int i ; /* * try 5 times on one second intervals to umount the volume. * Trying to unmount more than once seem to be necessary sometimes */ for( i = 0 ; i < 5 ; i++ ){ h = function( m_dir ) ; if( h == 0 ){ break ; }else{ sleep( 1 ) ; } } return h ; } static int _zuluCryptUnmountVolume_0( string_t st,char ** m_point,char ** m_point_2 ) { int h ; stringList_t stl = StringListStringSplit( st,' ' ) ; StringListIterator it = StringListBegin( stl ) ; /* * zuluCryptDecodeMountEntry() is defined in mount_volume.c */ const char * mout_point = zuluCryptDecodeMountEntry( *( it + 1 ) ) ; if( StringContains( *( it + 2 ),"fuse" ) ){ /* * Dont know whats going on but FUSE based file systems do not seem to work with umount() */ h = _unmount( _unmount_fuse,mout_point ) ; if( h == 32 ){ /* * errno value of 32 means "broken pipe, we will get this when trying * to unmount a file system on a device that is no longer attached */ h = _unmount( _unmount_rest,mout_point ) ; } }else{ h = _unmount( _unmount_rest,mout_point ) ; } if( h == 0 && m_point != NULL ){ *m_point = StringCopy_2( mout_point ) ; } if( m_point_2 != NULL ){ *m_point_2 = StringCopy_2( mout_point ) ; } StringListDelete( &stl ) ; return h ; } static stringList_t _get_mount_entries( const char * device ) { /* * zuluCryptGetMountEntry() is defined in mountinfo.c */ stringList_t stl = zuluCryptGetMoutedList() ; StringListIterator it ; StringListIterator end ; string_t st = String_1( device," ",NULL ) ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ if( StringStartsWith_1( *it,st ) ){ it++ ; }else{ StringListRemoveAt_1( stl,it,&end ) ; } } StringDelete( &st ) ; return stl ; } int zuluCryptUnmountVolume( const char * device,char ** m_point ) { int h = 3 ; char * e ; size_t s ; stringList_t stl ; StringListIterator it ; StringListIterator end ; ssize_t r ; string_t st ; string_t xt ; if( zuluCryptNoPartitionLoopDevice( device ) ){ /* * zuluCryptLoopDeviceAddress() is defined in create_loop_device.c */ e = zuluCryptLoopDeviceAddress( device ) ; if( e == NULL ){ return h ; }else{ stl = _get_mount_entries( e ) ; StringFree( e ) ; } }else{ stl = _get_mount_entries( device ) ; } s = StringListSize( stl ) ; if( s == 0 ){ /* * volume appear to not be mounted. */ }else if( s == 1 ){ /* * there is only one mount point for the volume,unmount it normally */ h = _zuluCryptUnmountVolume_0( StringListStringAtFirstPlace( stl ),m_point,NULL ) ; }else{ /* * There are multiple mount points for the same volume. * * Try to figure out which one among the mount points is ours and then try * first to unmount the rest of them. */ r = StringListHasSequence( stl," /run/media/private/" ) ; if( r == -1 ){ /* * Probable reason for getting here is if a user use a home mount point path, * we dont know the path because we dont know the user we are serving * and hence we bail out with an error. */ h = 10 ; }else{ /* * We got our mount point,take it out of the list to use it last */ st = StringListDetachAt( stl,(size_t)r ) ; StringListGetIterators( stl,&it,&end ) ; while( it != end ){ xt = *it ; it++ ; if( _zuluCryptUnmountVolume_0( xt,NULL,&e ) != 0 ){ printf( "Failed to unmount third party mount point: \"%s\"\n",e ) ; StringFree( e ) ; /* * Failed to unmount one of the extra mount points, * bail out with an error. */ h = 10 ; break ; } } if( h != 10 ){ /* * Attempt to unmount our mount point last. */ h = _zuluCryptUnmountVolume_0( st,m_point,NULL ) ; } StringDelete( &st ) ; } } if( h != 0 && h != 3 && h != 4 && h != 1 && h != 10 ){ h = 2 ; } StringListDelete( &stl ) ; return h ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/user_home_path.c000066400000000000000000000017661425361753700222710ustar00rootroot00000000000000 /* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "includes.h" string_t zuluCryptGetUserHomePath( uid_t uid ) { return String_1( getpwuid( uid )->pw_dir,"/",NULL ) ; } string_t zuluCryptGetUserName( uid_t uid ) { return String( getpwuid( uid )->pw_name ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/version.c000066400000000000000000000015151425361753700207440ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" const char * zuluCryptVersion(void) { return VERSION_STRING ; } zuluCrypt-6.2.0/zuluCrypt-cli/lib/volume_type.c000066400000000000000000000026521425361753700216320ustar00rootroot00000000000000 /* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #ifdef CRYPT_TCRYPT int zuluCryptGetVolumeType( const char * device,const char * pass,size_t pass_size ) { /* * zuluCryptVolumeIsLuks() is defined in is_luks.c * zuluCryptVolumeIsTcrypt() is defined in open_tcrypt.c */ if( zuluCryptVolumeIsLuks( device ) ){ return 1 ; }else if( zuluCryptVolumeIsTcrypt( device,pass,pass_size ) ){ return 2 ; }else{ return 3 ; } } #else int zuluCryptGetVolumeType( const char * device,const char * pass,size_t pass_size ) { if( pass && pass_size ){} /* * zuluCryptVolumeIsLuks() is defined in is_luks.c */ if( zuluCryptVolumeIsLuks( device ) ){ return 1 ; }else{ return 3 ; } } #endif zuluCrypt-6.2.0/zuluCrypt-cli/pluginManager/000077500000000000000000000000001425361753700211345ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluCrypt-cli/pluginManager/libzuluCryptPluginManager.h000066400000000000000000000057671425361753700265060ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ZULUCRYPTPLUGINMANAGER #define ZULUCRYPTPLUGINMANAGER #include #include #ifdef __cplusplus extern "C" { #endif /* * This header and its associated library with the same name provide a plugin infrastructure * that allow passage of keys from a key module to zuluCrypt-cli in a safe way. * * In your key module, call functions in this header file to pass the key to zuluCrypt-cli * * The following options will be passed to the module. * argv[0] - the name of the module * argv[1] - the device path with the encrypted volume to be opened * argv[2] - the UUID of the encrypted volume or "Nil" if the encrypted volume has no UUID( plain volume ) * argv[3] - a token to be used for communication btw the plugin and zuluCrypt-cli. * argv[4] - the maximum number of bytes that will be read. * argv[5] - the command line argument list as presented to zuluCrypt-cli */ /* * This function opens a connection btw the plugin and zuluCrypt-cli. * * NULL is returned if the connection can not be made. * This function will block while trying to establish a connection. */ void * zuluCryptPluginManagerOpenConnection( const char * token ) ; /* * This function sends the key to zuluCrypt-cli through a connection established by the command above. * The first argument is a handle returned above * The second argument is a buffer to the key to be sent * The third argument is the length of the buffer */ ssize_t zuluCryptPluginManagerSendKey( void * handle,const char * key,size_t length ) ; /* * Close the connection and free up all used memory. */ void zuluCryptPluginManagerCloseConnection( void * handle ) ; /* * Sample plugin on how to use the library * * #include * #include * * int main( int argc,char * argv[] ) * { * const char * exe = argv[0] ; * const char * device = argv[1] ; * const char * uuid = argv[2] ; * const char * token = argv[3] ; * int len = atoi( argv[4] ) ; * const char * arg = argv[ 5 ] ; * * void * handle = zuluCryptPluginManagerOpenConnection( token ) ; * * zuluCryptPluginManagerSendKey( handle,"xyz",3 ) ; * * zuluCryptPluginManagerCloseConnection( handle ) ; * * return 0 ; * } */ #ifdef __cplusplus } #endif #endif zuluCrypt-6.2.0/zuluCrypt-cli/pluginManager/zuluCryptPluginManager.c000066400000000000000000000121141425361753700257720ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include #include #include #include #include #include #include "libzuluCryptPluginManager.h" #include "../utility/process/process.h" #include "../utility/socket/socket.h" #include "../utility/string/String.h" #include "../constants.h" #include "../bin/includes.h" #include "../bin/libzuluCrypt-exe.h" #define _ignore_result( x ) if( x ){;} /* * below header file is created at config time. */ #include "plugin_path.h" #define zuluDEBUG 0 static void _debug_0( process_t p,ProcessIO std_io ) { char * e = NULL ; if( std_io == ProcessStdOut ){ puts( "--------stdout------------" ) ; }else{ puts( "--------stderror----------" ) ; } while( 1 ){ ProcessGetOutPut( p,&e,std_io ) ; if( e ){ printf( "%s",e ) ; fflush( stdout ) ; free( e ) ; e = NULL ; }else{ break ; } } } static void _debug( process_t p ) { if( zuluDEBUG ){ _debug_0( p,ProcessStdOut ) ; _debug_0( p,ProcessStdError ) ; } } void zuluCryptGetKeyFromSocket( const char * sockpath,string_t * key,uid_t uid ) { ssize_t e ; char * buffer = NULL ; socket_t client ; socket_t server = SocketLocal( sockpath ) ; *key = StringVoid ; if( uid ){} errno = 0 ; if( SocketBind( server ) ){ if( SocketListen( server ) ){ client = SocketAccept( server ) ; /* * ZULUCRYPT_INT_MAX_KEYSIZE is set in ../constants.h */ e = SocketGetData_1( client,&buffer,ZULUCRYPT_INT_MAX_KEYSIZE ) ; if( e == 0 ){ *key = StringEmpty() ; }else if( e == -1 ){ perror( "Failed to read data from socket" ) ; }else{ *key = StringInheritWithSize( &buffer,(size_t)e,(size_t)e + 1 ) ; } SocketClose( &client ) ; }else{ perror( "Socket listen failed" ) ; } SocketClose( &server ) ; }else{ perror( "Socket bind failed" ) ; } } void * zuluCryptPluginManagerOpenConnection( const char * sockpath ) { int i ; socket_t client ; for( i = 0 ; i < 10 ; i++ ){ client = SocketLocal( sockpath ) ; if( SocketConnect( &client ) ){ return client ; }else{ sleep( 1 ) ; } } printf( "Client: Failed to open connection at:%s\n",sockpath ) ; perror( "Reason:" ) ; return NULL ; } ssize_t zuluCryptPluginManagerSendKey( void * client,const char * key,size_t length ) { return SocketSendData( client,key,length ) ; } void zuluCryptPluginManagerCloseConnection( void * e ) { socket_t client = e ; SocketClose( &client ) ; } static void _create_path( const char * path,uid_t uid ) { if( mkdir( path,0700 ) == 0 ){ _ignore_result( chmod( path,0700 ) ) _ignore_result( chown( path,uid,uid ) ) } } string_t zuluCryptPluginManagerGetKeyFromModule( const char * device,const char * plugin, const char * uuid, uid_t uid, const struct_opts * opts, const char * run_path, int * r ) { process_t p ; struct stat st ; const char * sockpath ; const char * argv = opts->argv ; const char * args[ 7 ] ; ProcessStructure * str ; string_t key = StringVoid ; string_t plugin_path = StringVoid ; string_t path = StringVoid ; struct passwd * pass = getpwuid( uid ) ; if( pass == NULL ){ return key ; } /* * ZULUCRYPTpluginPath is set at config time at it equals $prefix/lib(64)/zuluCrypt/ */ plugin_path = String( ZULUCRYPTpluginPath ) ; plugin = plugin + StringLastIndexOfChar_1( plugin,'/' ) + 1 ; plugin = StringAppend( plugin_path,plugin ) ; if( stat( plugin,&st ) == 0 && S_ISREG( st.st_mode ) ) { _create_path( run_path,uid ) ; path = String( run_path ) ; sockpath = StringAppendInt( path,(u_int64_t)syscall( SYS_gettid ) ) ; *( args + 0 ) = plugin ; *( args + 1 ) = device ; if( uuid != NULL ){ *( args + 2 ) = uuid ; }else{ *( args + 2 ) = "Nil" ; } *( args + 3 ) = sockpath ; /* * ZULUCRYPT_CHAR_MAX_KEYSIZE is set in ../constants.h */ *( args + 4 ) = ZULUCRYPT_CHAR_MAX_KEYSIZE ; *( args + 5 ) = argv ; *( args + 6 ) = NULL ; p = Process( NULL,NULL ) ; str = ProcessArgumentStructure( p ) ; str->args = ( char * const * )args ; str->env = ( char * const * )opts->env ; str->user_id = uid ; ProcessStart( p ) ; zuluCryptGetKeyFromSocket( sockpath,&key,uid ) ; _debug( p ) ; *r = ProcessWaitUntilFinished( &p ) ; }else{ *r = 1 ; } StringMultipleDelete( &plugin_path,&path,NULL ) ; return key ; } zuluCrypt-6.2.0/zuluCrypt-cli/utility/000077500000000000000000000000001425361753700200465ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluCrypt-cli/utility/process/000077500000000000000000000000001425361753700215245ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluCrypt-cli/utility/process/process.c000066400000000000000000000261751425361753700233610ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "process.h" #include #include #include #include #include #include #include #include #include #include #include #include #define _ignore_result( x ) if( x ){;} struct ProcessType_t{ pid_t pid ; int fd_0[ 2 ] ; /* this variable is used to write to child process */ int fd_1[ 2 ] ; /* this variable is used to read from child's std out */ int fd_2[ 2 ] ; /* this variable is used to read from child's std error */ ProcessStatus state ; int std_io ; char * exe ; char ** args ; int signal ; int wait_status ; pthread_t * thread ; ProcessStructure str ; }; static void _f( void ) { } static void ( *_memory_error )( void ) = _f ; void ProcessExitOnMemoryExaustion( void ( *f )( void ) ) { _memory_error = f ; } static void * _ProcessError( void ) { _memory_error() ; return NULL ; } ProcessStructure * ProcessArgumentStructure( process_t p ) { if( p == ProcessVoid ){ return NULL ; }else{ return &p->str ; } } void ProcessSetEnvironmentalVariable( process_t p,char * const * env ) { if( p != ProcessVoid ){ p->str.env = env ; } } static process_t _process( const char * path ) { process_t p ; size_t len ; if( path == NULL ){ len = 0 ; }else{ len = strlen( path ) ; } p = malloc( sizeof( struct ProcessType_t ) ) ; if( p == NULL ){ return _ProcessError() ; } if( len == 0 ){ p->exe = malloc( sizeof( char ) ) ; if( p->exe == NULL ){ free( p ) ; return _ProcessError() ; } p->exe[ 0 ] = '\0' ; }else{ p->exe = malloc( sizeof( char ) * ( len + 1 ) ) ; if( p->exe == NULL ){ free( p ) ; return _ProcessError() ; } memcpy( p->exe,path,len + 1 ) ; } p->std_io = 0 ; p->wait_status = -1 ; p->thread = NULL ; p->fd_0[ 0 ] = -1 ; p->args = NULL ; p->str.args = NULL ; p->str.timeout = -1 ; p->str.env = NULL ; p->str.user_id = -1 ; p->str.priority = 0 ; p->str.signal = SIGTERM ; p->state = ProcessHasNotStarted ; return p ; } void ProcessSetArgumentList( process_t p,... ) { char * entry ; char ** args ; char ** e ; size_t size = sizeof( char * ) ; int index = 1 ; va_list list ; if( p == ProcessVoid ){ return ; } args = p->args ; va_start( list,p ) ; while( 1 ){ entry = va_arg( list,char * ) ; e = realloc( args,( 1 + index ) * size ) ; if( e == NULL ){ free( args ) ; va_end( list ) ; _ProcessError() ; return ; }else{ args = e ; } if( entry == NULL ){ *( args + index ) = NULL ; break ; }else{ *( args + index ) = entry ; index++ ; } } va_end( list ) ; p->args = args ; p->args[ 0 ] = p->exe ; p->str.args = args ; } process_t Process( const char * path,... ) { char * entry ; char ** args ; char ** e ; size_t size = sizeof( char * ) ; int index = 1 ; va_list list ; process_t p ; if( path == NULL ){ return _process( NULL ) ; } p = _process( path ) ; if( p == ProcessVoid ){ return ProcessVoid ; } args = p->args ; va_start( list,path ) ; while( 1 ){ entry = va_arg( list,char * ) ; e = realloc( args,( 1 + index ) * size ) ; if( e == NULL ){ ProcessCleanUp( &p ) ; free( args ) ; va_end( list ) ; _ProcessError() ; return ProcessVoid ; }else{ args = e ; } if( entry == NULL ){ *( args + index ) = NULL ; break ; }else{ *( args + index ) = entry ; index++ ; } } va_end( list ) ; p->args = args ; p->args[ 0 ] = p->exe ; p->str.args = args ; return p ; } int ProcessExecute( const char * exe,... ) { char * entry ; char ** args ; char ** e ; size_t size = sizeof( char * ) ; int index = 1 ; va_list list ; process_t p ; if( exe == NULL ){ return -1 ; } p = _process( exe ) ; if( p == ProcessVoid ){ return -1 ; } args = p->args ; va_start( list,exe ) ; while( 1 ){ entry = va_arg( list,char * ) ; e = realloc( args,( 1 + index ) * size ) ; if( e == NULL ){ ProcessCleanUp( &p ) ; free( args ) ; va_end( list ) ; _ProcessError() ; return -1 ; }else{ args = e ; } if( entry == NULL ){ *( args + index ) = NULL ; break ; }else{ *( args + index ) = entry ; index++ ; } } va_end( list ) ; p->args = args ; p->args[ 0 ] = p->exe ; p->str.args = args ; ProcessStart( p ) ; return ProcessWaitUntilFinished( &p ) ; } static void * __timer( void * x ) { process_t p = x ; sleep( p->str.timeout ) ; kill( p->pid,p->str.signal ) ; p->state = ProcessCancelled ; return NULL ; } static void __ProcessStartTimer( process_t p ) { p->thread = malloc( sizeof( pthread_t ) ) ; if( p->thread == NULL ){ _ProcessError() ; }else{ pthread_create( p->thread,NULL,__timer,p ) ; } } void ProcessSetOptionPriority( process_t p,int priority ) { if( p != ProcessVoid ){ p->str.priority = priority ; } } static void _execve( process_t p,char * const * env ) { execve( p->str.args[ 0 ],p->str.args,env ) ; } pid_t ProcessStart( process_t p ) { char * const env[] = { "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin",NULL } ; if( pipe( p->fd_0 ) == -1 ){ return -1 ; } if( pipe( p->fd_1 ) == -1 ){ return -1 ; } if( pipe( p->fd_2 ) == -1 ){ return -1 ; } p->pid = fork() ; if( p->pid == -1 ){ return -1 ; } if( p->pid == 0 ){ if( p->str.user_id != ( uid_t )-1 ){ /* * drop privileges permanently */ _ignore_result( seteuid( 0 ) ) ; _ignore_result( setgid( p->str.user_id ) ) ; _ignore_result( setgroups( 1,&p->str.user_id ) ) ; _ignore_result( setegid( p->str.user_id ) ) ; _ignore_result( setuid( p->str.user_id ) ) ; } dup2( p->fd_0[ 1 ],0 ) ; dup2( p->fd_1[ 1 ],1 ) ; dup2( p->fd_2[ 1 ],2 ) ; close( p->fd_1[ 0 ] ) ; close( p->fd_0[ 0 ] ) ; close( p->fd_2[ 0 ] ) ; if( p->str.priority != 0 ){ setpriority( PRIO_PROCESS,0,p->str.priority ) ; } if( p->str.env == NULL || p->str.env[ 0 ] == NULL ){ if( environ[ 0 ] == NULL ){ _execve( p,env ) ; }else{ _execve( p,environ ) ; } }else{ _execve( p,p->str.env ) ; } /* * execv has failed :-( */ _Exit( 1 ) ; /* * child process block ends here */ } /* * parent process continues from here */ close( p->fd_0[ 0 ] ) ; close( p->fd_1[ 1 ] ) ; close( p->fd_2[ 1 ] ) ; p->state = ProcessIsStillRunning ; if( p->str.timeout != -1 ){ __ProcessStartTimer( p ) ; } return p->pid ; } #define FACTOR 2 static inline char * __bufferExpandMemory( char * buffer,size_t new_size,size_t * buffer_size ) { char * e ; if( new_size >= *buffer_size ) { *buffer_size = new_size * FACTOR ; e = realloc( buffer,*buffer_size ) ; if( e == NULL ){ free( buffer ) ; _ProcessError() ; return NULL ; }else{ return e ; } }else{ return buffer ; } } size_t ProcessGetOutPut( process_t p,char ** data,ProcessIO std_io ) { #define SIZE 64 #define BUFFER_SIZE 128 char * buffer ; char * e ; char buff[ SIZE ] ; size_t size = 0 ; size_t count ; size_t buffer_size = BUFFER_SIZE ; int fd ; if( p == ProcessVoid ){ return 0 ; } switch( std_io ){ case ProcessStdOut : fd = p->fd_1[ 0 ] ; break ; case ProcessStdError : fd = p->fd_2[ 0 ] ; break ; default : return 0 ; } buffer = malloc( sizeof( char ) * BUFFER_SIZE ) ; if( buffer == NULL ){ _ProcessError() ; return 0 ; } while( 1 ) { count = read( fd,buff,SIZE ) ; buffer = __bufferExpandMemory( buffer,size + count,&buffer_size ) ; if( buffer == NULL ){ _ProcessError() ; return 0 ; }else{ memcpy( buffer + size,buff,count ) ; } size += count ; if( count < SIZE ){ break ; } } if( size > 0 ){ e = realloc( buffer,size + 1 ) ; if( e == NULL ){ free( buffer ) ; _ProcessError() ; return 0 ; }else{ *( e + size ) = '\0' ; *data = e ; } } return size ; } ProcessStatus ProcessState( process_t p ) { if( p != ProcessVoid ){ return p->state ; }else{ return ProcessStatusUndefined ; } } ssize_t ProcessGetOutPut_1( process_t p,char * buffer,int size,ProcessIO std_io ) { if( p != ProcessVoid ){ switch( std_io ){ case ProcessStdOut : return read( p->fd_1[ 1 ],buffer,size ) ; case ProcessStdError : return read( p->fd_2[ 1 ],buffer,size ) ; default : return -1 ; } }else{ return -1 ; } } size_t ProcessWrite( process_t p,const char * data,size_t len ) { if( p != ProcessVoid ){ return write( p->fd_0[ 1 ],data,len ) ; }else{ return 0 ; } } void ProcessCloseStdWrite( process_t p ) { close( p->fd_0[ 1 ] ) ; p->fd_0[ 1 ] = -1 ; } void ProcessSetOptionTimeout( process_t p,int timeout,int signal ) { if( p != ProcessVoid ){ p->str.signal = signal ; p->str.timeout = timeout ; } } static void _ProcessDelete( process_t px ) { if( px->thread != NULL ){ pthread_cancel( *( px->thread ) ) ; free( px->thread ) ; } close( px->fd_2[ 1 ] ) ; close( px->fd_1[ 1 ] ) ; if( px->fd_0[ 0 ] != -1 ){ close( px->fd_0[ 0 ] ) ; } if( px->wait_status == -1 ){ waitpid( px->pid,0,WNOHANG ) ; } free( px->args ) ; free( px->exe ) ; free( px ) ; } void ProcessCleanUp( process_t * p ) { if( p != NULL && *p != ProcessVoid ){ _ProcessDelete( *p ) ; *p = ProcessVoid ; } } int ProcessTerminate( process_t p ) { int st ; if( p == ProcessVoid ){ return -1 ; }else{ p->state = ProcessCancelled ; st = kill( p->pid,SIGTERM ) ; waitpid( p->pid,0,WNOHANG ) ; p->wait_status = 1 ; return st ; } } void ProcessSetOptionUser( process_t p,uid_t uid ) { if( p != ProcessVoid ){ p->str.user_id = uid ; } } int ProcessKill( process_t p ) { int st ; if( p == ProcessVoid ){ return -1 ; }else{ p->state = ProcessCancelled ; st = kill( p->pid,SIGKILL ) ; waitpid( p->pid,0,WNOHANG ) ; p->wait_status = 1 ; return st ; } } int ProcessWaitUntilFinished( process_t * e ) { int s ; process_t p ; if( e == NULL || *e == ProcessVoid ){ return -1 ; }else{ p = *e ; *e = ProcessVoid ; s = ProcessExitStatus( p ) ; _ProcessDelete( p ) ; return s ; } } int ProcessExitStatus( process_t p ) { int s ; if( p == ProcessVoid ){ return -1 ; }else{ waitpid( p->pid,&s,0 ) ; p->state = ProcessCompleted ; p->wait_status = 1 ; if( WIFEXITED( s ) == 0 ){ return -1 ; }else{ return WEXITSTATUS( s ) ; } } } void ProcessWait( process_t p ) { ProcessExitStatus( p ) ; } void ProcessSetArguments( process_t p,char * const s[] ) { if( p != ProcessVoid ){ p->str.args = s ; } } zuluCrypt-6.2.0/zuluCrypt-cli/utility/process/process.h000066400000000000000000000167241425361753700233650ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef PROCESS #define PROCESS #ifdef __cplusplus extern "C" { #endif #include typedef struct{ /* * if this variable is set,then it is expect to be in the same format the last argument of execv() expect */ char * const * args ; /* * this variable is set will cause the program to be executed will run with the identify of this user. */ uid_t user_id ; /* * If this variable is set,then it is expected to be in the format the last argument of execve() expect */ char * const * env ; /* * If this variable is set,the process will be terminate if its still running after timeout seconds * The default signal sent is sigterm */ int timeout ; /* * if this variable is set,then this signal will be sent when the timeout above expires */ int signal ; /* * priority of forked process will run with */ int priority ; }ProcessStructure ; typedef struct ProcessType_t * process_t ; #define ProcessVoid ( ( process_t ) 0 ) /* * Examples on how to use the library are at the end of this header file */ /* * Takes a pointer to a function to be called when memory allocation can not take place * ie if the system has run out of memory and malloc() or realloc() has failed. * This function is optional and "ProcessVoid" will be returned on memory exaustion if the function * isnt set. */ void ProcessExitOnMemoryExaustion( void (*)( void ) ) ; /* * create a handle to a process that will be started. * Path to executable to be started must be in full path format */ process_t Process( const char * path,... ) __attribute__ ( ( sentinel ) ) ; /* * run exe process with its NULL terminated arguments and then return the * process' exit status */ int ProcessExecute( const char * exe,... ) __attribute__ ( ( sentinel ) ) ; /* * This structure can be used an an alternative way to set various options. * There exist a separate function to set each one of them */ ProcessStructure * ProcessArgumentStructure( process_t ) ; /* * call fork() and then exec and run a program specified when handle p was created. * return value: pid of the child process */ pid_t ProcessStart( process_t p ) ; /* * pass data to the child process,the child process will get the data from reading its stdin. * ProcessSetOption( p,WRITE_STD_IN ) must be called first for this to work. * */ size_t ProcessWrite( process_t p,const char * data,size_t len ) ; /* * close the writing connection to the child process.This maybe necessary if a child process * blocks waiting for more data in its std in until EOF is received. */ void ProcessCloseStdWrite( process_t p ) ; /* * send a forked process sigterm to terminate it. */ int ProcessTerminate( process_t ) ; /* * run the child process with privileges of a user with UID of uid */ void ProcessSetOptionUser( process_t,uid_t uid ) ; /* * set the nice value the forked process will run with */ void ProcessSetOptionPriority( process_t,int priority ) ; /* * send a forked process sigkill to kill it */ int ProcessKill( process_t ) ; /* * the forked process will be started with arguments list given by the second argument * look at the example at the end of this header file for info on how to use the API */ void ProcessSetArguments( process_t p,char * const argv[] ) ; /* * look at the example at the end of this header file for info on how to use the API */ void ProcessSetArgumentList( process_t p,... ) __attribute__ ( ( sentinel ) ) ; /* * set the child process to start with the given enviromental variables */ void ProcessSetEnvironmentalVariable( process_t p,char * const * env ) ; /* * get state of the process handled by handle p */ typedef enum{ ProcessHasNotStarted, ProcessIsStillRunning, ProcessCompleted, ProcessCancelled, ProcessStatusUndefined }ProcessStatus; ProcessStatus ProcessState( process_t p ) ; /* * wait for "timeout" seconds and then send the forked process a signal "signal" */ void ProcessSetOptionTimeout( process_t p,int timeout,int signal ) ; /* * block waiting for the forked process to exit and then get its exit status. */ int ProcessExitStatus( process_t ) ; /* * block waiting for the forked process to exit. */ void ProcessWait( process_t ) ; /* * block waiting for the forked process to exit and then get its exit status and then clean up * used resources. * * Use this function if you have to wait for the forked process to finish so that you can * get its exit status. */ int ProcessWaitUntilFinished( process_t * ) ; /* * clean up used resources and dont wait for the forked process. * Use this function if you dont want to wait for the exit status or if the forked * process is meant to live past the life of the parent process. */ void ProcessCleanUp( process_t * ) ; /* * get contents of std out/std error from the process. * remember to free() the return buffer when done with it. * * return value is the size of the data. * this function must be called after ProcessStart() */ typedef enum{ ProcessStdIn, ProcessStdOut, ProcessStdError }ProcessIO; size_t ProcessGetOutPut( process_t,char ** data,ProcessIO ) ; /* * read size number of bytes from the ourput of the forket process. */ ssize_t ProcessGetOutPut_1( process_t,char * buffer,int size,ProcessIO ) ; #ifdef __cplusplus } #endif #endif /* * Example use case of ProcessSetArgumentList API */ #if 0 #include "process.h" #include #include int main( void ) { process_t p = Process( "/bin/ls","-l",NULL ) ; ProcessStart( p ) ; char * c = NULL ; while( 1 ){ ProcessGetOutPut( p,&c,ProcessStdOut ) ; if( c ){ printf( "%s",c ) ; free( c ) ; c = NULL ; }else{ break ; } } ProcessWaitUntilFinished( &p ) ; return 0 ; } #endif /* * Example use case of ProcessSetArguments API */ #if 0 #include "process.h" #include #include int main( void ) { const char * argv[ 3 ] ; process_t p = Process( NULL,NULL ) ; argv[ 0 ] = "/bin/ls" ; argv[ 1 ] = "-l" ; argv[ 2 ] = NULL ; ProcessSetArguments( p,argv ) ; ProcessStart( p ) ; char * c = NULL ; while( 1 ){ ProcessGetOutPut( p,&c,ProcessStdOut ) ; if( c ){ printf( "%s",c ) ; free( c ) ; c = NULL ; }else{ break ; } } ProcessWaitUntilFinished( &p ) ; return 0 ; } #endif /* * Example use case of ProcessArgumentStructure API */ #if 0 #include "process.h" #include #include int main( void ) { const char * argv[ 3 ] ; process_t p = Process( NULL,NULL ) ; argv[ 0 ] = "/bin/ls" ; argv[ 1 ] = "-l" ; argv[ 2 ] = NULL ; ProcessStructure * str = ProcessArgumentStructure( p ) ; str->args = argv ; ProcessStart( p ) ; char * c = NULL ; while( 1 ){ ProcessGetOutPut( p,&c,ProcessStdOut ) ; if( c ){ printf( "%s",c ) ; free( c ) ; c = NULL ; }else{ break ; } } ProcessWaitUntilFinished( &p ) ; return 0 ; } #endif zuluCrypt-6.2.0/zuluCrypt-cli/utility/socket/000077500000000000000000000000001425361753700213365ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluCrypt-cli/utility/socket/socket.c000066400000000000000000000401201425361753700227670ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "socket.h" #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct SocketType_t { int socket_server ; int type ; int protocol ; int cmax ; int domain ; socklen_t size ; int fd ; void * socket ; char * inetAddress ; }; static void ( *_fcn_ )( void ) = NULL ; void SocketExitOnMemoryExaustion( void ( *f )( void ) ) { _fcn_ = f ; } static socket_t _SocketError( void ) { if( _fcn_ != NULL ){ _fcn_() ; } return SocketVoid ; } static inline socket_t _SocketLocal( void ) { socket_t s = malloc( sizeof( struct SocketType_t ) ) ; struct sockaddr_un * e ; if( s == NULL ){ return SocketVoid ; }else{ memset( s,'\0',sizeof( struct SocketType_t ) ) ; s->socket = malloc( sizeof( struct sockaddr_un ) ) ; if( s->socket == NULL ){ free( s ) ; return _SocketError() ; }else{ s->size = sizeof( struct sockaddr_un ) ; memset( s->socket,'\0',s->size ) ; e = s->socket ; e->sun_family = AF_UNIX ; return s ; } } } static inline socket_t _SocketNet( void ) { socket_t s = malloc( sizeof( struct SocketType_t ) ) ; struct sockaddr_in * e ; if( s == NULL ){ return SocketVoid ; }else{ memset( s,'\0',sizeof( struct SocketType_t ) ) ; s->socket = malloc( sizeof( struct sockaddr_in ) ) ; if( s->socket == NULL ){ free( s ) ; return _SocketError() ; }else{ s->inetAddress = NULL ; s->size = sizeof( struct sockaddr_in ) ; memset( s->socket,'\0',s->size ) ; e = s->socket ; e->sin_family = AF_INET ; return s ; } } } static inline socket_t _SocketNet6( void ) { socket_t s = malloc( sizeof( struct SocketType_t ) ) ; struct sockaddr_in6 * e ; if( s == NULL ){ return SocketVoid ; }else{ memset( s,'\0',sizeof( struct SocketType_t ) ) ; s->socket = malloc( sizeof( struct sockaddr_in6 ) ) ; if( s->socket == NULL ){ free( s ) ; return _SocketError() ; }else{ s->inetAddress = NULL ; s->size = sizeof( struct sockaddr_in6 ) ; memset( s->socket,'\0',s->size ) ; e = s->socket ; e->sin6_family = AF_INET6 ; return s ; } } } socket_t Socket( int domain,int type,int protocol ) { socket_t s = SocketVoid ; int fd ; if( domain != AF_UNIX && domain != AF_INET && domain != AF_INET6 ){ return SocketVoid ; } fd = socket( domain,type,protocol ) ; if( fd == -1 ){ return SocketVoid ; } fcntl( fd,F_SETFD,FD_CLOEXEC ) ; switch( domain ){ case AF_UNIX : s = _SocketLocal() ; break ; case AF_INET : s = _SocketNet() ; break ; case AF_INET6: s = _SocketNet6() ; break ; } if( s == SocketVoid ){ close( fd ) ; return SocketVoid ; }else{ s->domain = domain ; s->type = type ; s->protocol = protocol ; s->cmax = 1 ; s->socket_server = 0 ; s->fd = fd ; return s ; } } int SocketFileDescriptor( socket_t s ) { if( s == SocketVoid ){ return -1 ; }else{ return s->fd ; } } socket_t SocketLocalWithOptions( const char * address,int type,int protocol ) { socket_t s = Socket( AF_UNIX,type,protocol ) ; struct sockaddr_un * e ; size_t l = sizeof( e->sun_path ) - 1 ; if( s != SocketVoid ){ e = s->socket ; memset( e->sun_path,'\0',sizeof( e->sun_path ) ) ; strncpy( e->sun_path,address,l ) ; } return s ; } socket_t SocketLocal( const char * address ) { return SocketLocalWithOptions( address,SOCK_STREAM,0 ) ; } socket_t SocketNetWithOptions( const char * address,int port,int type,int protocol ) { socket_t s = SocketVoid ; struct addrinfo * info ; struct addrinfo hint ; struct sockaddr_in * e ; memset( &hint,'\0',sizeof( hint ) ) ; hint.ai_family = AF_INET ; hint.ai_socktype = type ; hint.ai_protocol = protocol ; if( getaddrinfo( address,NULL,&hint,&info) == 0 ){ s = Socket( AF_INET,type,protocol ) ; if( s != SocketVoid ){ e = s->socket ; memcpy( e,info->ai_addr,info->ai_addrlen ) ; e->sin_port = htons( (uint16_t)port ) ; } freeaddrinfo( info ) ; } return s ; } socket_t SocketNet( const char * address,int port ) { return SocketNetWithOptions( address,port,SOCK_STREAM,0 ) ; } socket_t SocketNetWithOptions6( const char * address,int port,int type,int protocol ) { socket_t s = SocketVoid ; struct addrinfo hint ; struct addrinfo * info ; struct sockaddr_in6 * e ; memset( &hint,'\0',sizeof( struct addrinfo ) ) ; hint.ai_family = AF_INET6 ; hint.ai_socktype = type ; hint.ai_protocol = protocol ; if( getaddrinfo( address,NULL,&hint,&info ) == 0 ){ s = Socket( AF_INET6,type,protocol ) ; if( s != SocketVoid ){ e = s->socket ; memcpy( e,info->ai_addr,info->ai_addrlen ) ; e->sin6_port = htons( (uint16_t) port ) ; } freeaddrinfo( info ) ; } return s ; } socket_t SocketNet6( const char * address,int port ) { return SocketNetWithOptions6( address,port,SOCK_STREAM,0 ) ; } static inline const char * _SocketNetAddress( socket_t s ) { const char * c ; struct sockaddr_in * e = s->socket ; if( s->inetAddress == NULL ){ s->inetAddress = malloc( sizeof( char ) * INET_ADDRSTRLEN ) ; if( s->inetAddress == NULL ){ _SocketError() ; return NULL ; } c = inet_ntop( AF_INET,&e->sin_addr,s->inetAddress,INET_ADDRSTRLEN ) ; if( c == NULL ){ free( s->inetAddress ) ; s->inetAddress = NULL ; return NULL ; } } return s->inetAddress ; } static inline const char * _SocketNetAddress6( socket_t s ) { const char * c ; struct sockaddr_in6 * e = s->socket ; if( s->inetAddress == NULL ){ s->inetAddress = malloc( sizeof( char ) * INET6_ADDRSTRLEN ) ; if( s->inetAddress == NULL ){ _SocketError() ; return NULL ; } c = inet_ntop( AF_INET6,&e->sin6_addr,s->inetAddress,INET6_ADDRSTRLEN ) ; if( c == NULL ){ free( s->inetAddress ) ; s->inetAddress = NULL ; return NULL ; } } return s->inetAddress ; } static inline const char * _SocketLocalAddress( socket_t s ) { struct sockaddr_un * e = s->socket ; return e->sun_path ; } const char * SocketAddress( socket_t s ) { if( s == SocketVoid ){ return NULL ; }else{ switch( s->domain ){ case AF_UNIX : return _SocketLocalAddress( s ) ; case AF_INET : return _SocketNetAddress( s ) ; case AF_INET6: return _SocketNetAddress6( s ) ; default : return NULL ; } } } int SocketBind( socket_t s ) { struct sockaddr * e ; struct sockaddr_un * f ; size_t m ; char buffer[ sizeof( f->sun_path ) + 1 ] ; if( s == SocketVoid ){ return 0 ; } e = s->socket ; if( s->domain == AF_UNIX ){ m = sizeof( f->sun_path ) ; s->socket_server = 1 ; f = s->socket ; strncpy( buffer,f->sun_path,m ) ; *( buffer + sizeof( f->sun_path ) ) = '\0' ; unlink( buffer ) ; return bind( s->fd,e,s->size ) == 0 ; }else if( s->domain == AF_INET ){ return bind( s->fd,e,s->size ) == 0 ; }else if (s->domain == AF_INET6 ){ return bind( s->fd,e,s->size ) == 0 ; }else{ return 0 ; } } static inline socket_t _SocketAcceptLocal( socket_t s ) { struct sockaddr_un * e ; struct sockaddr_un * z ; struct sockaddr * f ; size_t size = sizeof( struct sockaddr_un ) ; socket_t x = malloc( sizeof( struct SocketType_t ) ) ; size_t m ; if( x == NULL ){ return _SocketError() ; }else{ memset( x,'\0',sizeof( struct SocketType_t ) ) ; x->socket = malloc( size ) ; if( x->socket == NULL ){ free( x ) ; x = _SocketError() ; }else{ x->size = (unsigned int)size ; memset( x->socket,'\0',size ) ; f = x->socket ; x->fd = accept( s->fd,f,&x->size ) ; if( x->fd == -1 ){ free( x->socket ) ; free( x ) ; x = SocketVoid ; }else{ m = sizeof( z->sun_path ) ; e = s->socket ; z = x->socket ; strncpy( z->sun_path,e->sun_path,m ) ; x->inetAddress = NULL ; x->domain = s->domain ; x->type = s->type ; x->protocol = s->protocol ; x->cmax = 1 ; x->socket_server = 0 ; } } return x ; } } static inline socket_t _SocketAcceptNet( socket_t s ) { struct sockaddr * f ; size_t size = sizeof( struct sockaddr_in ) ; socket_t x = ( socket_t ) malloc( sizeof( struct SocketType_t ) ) ; if( x == NULL ){ return _SocketError() ; }else{ memset( x,'\0',sizeof( struct SocketType_t ) ) ; x->socket = malloc( size ) ; if( x->socket == NULL ){ free( x ) ; x = _SocketError() ; }else{ x->size = (unsigned int)size ; memset( x->socket,'\0',size ) ; f = x->socket ; x->fd = accept( s->fd,f,&x->size ) ; if( x->fd == -1 ){ free( x->socket ) ; free( x ) ; x = SocketVoid ; }else{ x->inetAddress = NULL ; x->domain = s->domain ; x->type = s->type ; x->protocol = s->protocol ; x->cmax = 1 ; x->socket_server = 0 ; } } return x ; } } static inline socket_t _SocketAcceptNet6( socket_t s ) { struct sockaddr * f ; size_t size = sizeof( struct sockaddr_in6 ) ; socket_t x = malloc( sizeof( struct SocketType_t ) ) ; if( x == NULL ){ return _SocketError() ; }else{ memset( x,'\0',sizeof( struct SocketType_t ) ) ; x->socket = malloc( size ) ; if( x->socket == NULL ){ free( x ) ; x = _SocketError() ; }else{ x->size = (unsigned int)size ; memset( x->socket,'\0',size ) ; f = x->socket ; x->fd = accept( s->fd,f,&x->size ) ; if( x->fd == -1 ){ free( x->socket ) ; free( x ) ; x = SocketVoid ; }else{ x->inetAddress = NULL ; x->domain = s->domain ; x->type = s->type ; x->protocol = s->protocol ; x->cmax = 1 ; x->socket_server = 0 ; } } return x ; } } socket_t SocketAccept( socket_t s ) { switch( s->domain ){ case AF_UNIX : return _SocketAcceptLocal( s ) ; case AF_INET : return _SocketAcceptNet( s ) ; case AF_INET6: return _SocketAcceptNet6( s ) ; default : return SocketVoid ; } } int SocketIsBlocking( socket_t s ) { int flags ; if( s == SocketVoid ){ return -1 ; }else{ flags = fcntl( s->fd,F_GETFL,0 ) ; return flags != ( flags | O_NONBLOCK ) ; } } #define READ 1 #define WRITE 0 static inline int _SocketNotTimedOut( socket_t s,time_t time,int mode ) { int fd = s->fd ; fd_set fdset ; struct timeval interval ; memset( &interval,'\0',sizeof( struct timeval ) ) ; interval.tv_sec = time ; interval.tv_usec = 0 ; FD_ZERO( &fdset ) ; FD_SET( fd,&fdset ) ; if( mode == READ ){ select( fd + 1,&fdset,NULL,NULL,&interval ) ; return FD_ISSET( fd,&fdset ) ; }else{ select( fd + 1,NULL,&fdset,NULL,&interval ) ; return FD_ISSET( fd,&fdset ) ; } } socket_t SocketAcceptWithTimeOut( socket_t s,time_t time ) { if( _SocketNotTimedOut( s,time,READ ) ){ return SocketAccept( s ) ; }else{ return SocketVoid ; } } static inline void _SocketClose( socket_t * p ) { socket_t s = *p ; int fd = s->fd ; struct sockaddr_un * e ; *p = SocketVoid ; shutdown( fd,SHUT_RDWR ) ; close( fd ) ; if( s->domain == AF_UNIX ) { if( s->socket_server ){ e = s->socket ; unlink( e->sun_path ) ; } } free( s->socket ) ; free( s->inetAddress ) ; free( s ) ; } void SocketClose( socket_t * p ) { if( p != NULL && *p != SocketVoid ){ _SocketClose( p ) ; } } void SocketCloseWriteChannel( socket_t s ) { if( s != NULL ){ shutdown( s->fd,SHUT_WR ) ; } } void SocketCloseReadChannel( socket_t s ) { if( s != NULL ){ shutdown( s->fd,SHUT_RD ) ; } } static inline int _SocketConnect( socket_t s ) { return connect( s->fd,s->socket,s->size ) == 0 ; } int SocketConnect( socket_t * s ) { if( s == NULL || *s == SocketVoid ){ return 0 ; } if( _SocketConnect( *s ) ){ return 1 ; }else{ _SocketClose( s ) ; return 0 ; } } void SocketSetListenMaximum( socket_t s,int m ) { if( s != SocketVoid ){ s->cmax = m ; } } int SocketSetDoNotBlock( socket_t s ) { int flags ; if( s == SocketVoid ){ return -1 ; }else{ flags = fcntl( s->fd,F_GETFL,0 ); if( flags == -1 ){ return -1 ; }else{ return fcntl( s->fd,F_SETFL,flags | O_NONBLOCK ) ; } } } int SocketSetBlock( socket_t s ) { int flags ; if( s == SocketVoid ){ return -1 ; }else{ flags = fcntl( s->fd,F_GETFL,0 ); if( flags == -1 ){ return -1 ; }else{ return fcntl( s->fd,F_SETFL,flags & ~O_NONBLOCK ) ; } } } int SocketListen( socket_t s ) { if( s == SocketVoid ){ return 0 ; }else{ return listen( s->fd,s->cmax ) == 0 ; } } ssize_t SocketGetData_2( socket_t s,char * buffer,size_t len ) { ssize_t e ; if( s == SocketVoid ){ return -1 ; }else{ len = len - 1 ; e = read( s->fd,buffer,len ) ; if( e >= 0 ){ buffer[ e ] = '\0' ; } return e ; } } ssize_t SocketGetData_3( socket_t s,char * buffer,size_t len,int timeout ) { if( _SocketNotTimedOut( s,( time_t )timeout,READ ) ){ return SocketGetData_2( s,buffer,len ) ; }else{ return -1 ; } } #define BUFFSIZE 32 #define BUFFERINIT 64 #define FACTOR 2 static inline char * __expandBuffer( char * buffer,size_t new_size,size_t * buff_size ) { char * e ; if( new_size >= *buff_size ){ *buff_size = *buff_size * FACTOR ; e = realloc( buffer,*buff_size ) ; if( e == NULL ){ free( buffer ) ; _SocketError() ; return NULL ; }else{ return e ; } }else{ return buffer ; } } ssize_t SocketGetData( socket_t s,char ** e ) { int fd ; ssize_t result ; size_t total = 0 ; size_t buff_size = BUFFERINIT ; char buffer[ BUFFSIZE ] ; char * d ; char * f ; if( s == SocketVoid ){ return -1 ; } f = malloc( sizeof( char ) * buff_size ) ; if( f == NULL ){ _SocketError() ; return -1 ; }else{ fd = s->fd ; while( 1 ){ result = read( fd,buffer,BUFFSIZE ) ; if( result <= 0 ){ if( total ){ break ; }else{ free( f ) ; if( result < 0 ){ return -1 ; }else{ return 0 ; } } }else{ d = __expandBuffer( f,total + (size_t)result,&buff_size ) ; if( d == NULL ){ _SocketError() ; return -1 ; }else{ f = d ; memcpy( f + total,buffer,(size_t)result ) ; total = total + (size_t)result ; } } } if( total ){ d = ( char * ) realloc( f,total + 1 ) ; if( d == NULL ){ free( f ) ; _SocketError() ; return -1 ; }else{ d[ total ] = '\0' ; *e = d ; } }else{ free( f ) ; } return (ssize_t)total ; } } ssize_t SocketGetData_1( socket_t s,char ** e,size_t len ) { int fd ; ssize_t result ; size_t total = 0 ; size_t buff_size = BUFFERINIT ; char buffer[ BUFFSIZE ] ; char * d ; char * f ; if( s == SocketVoid ){ return -1 ; } f = malloc( sizeof( char ) * buff_size ) ; if( f == NULL ){ _SocketError() ; return -1 ; }else{ fd = s->fd ; while( 1 ){ result = read( fd,buffer,BUFFSIZE ) ; if( result <= 0 ){ if( total ){ break ; }else{ free( f ) ; if( result < 0 ){ return -1 ; }else{ return 0 ; } } }else{ d = __expandBuffer( f,total + (size_t)result,&buff_size ) ; if( d == NULL ){ _SocketError() ; return -1 ; }else{ f = d ; memcpy( f + total,buffer,(size_t)result ) ; total = total +(size_t)result ; if( total >= len ){ total = len ; break ; } } } } if( total ){ d = realloc( f,total + 1 ) ; if( d == NULL ){ free( f ) ; _SocketError() ; return 0 ; }else{ d[ total ] = '\0' ; *e = d ; } }else{ free( f ) ; } return (ssize_t)total ; } } ssize_t SocketSendData( socket_t s,const char * buffer,size_t len ) { if( s == SocketVoid || buffer == NULL || len == 0 ){ return -1 ; }else{ return write( s->fd,buffer,len ) ; } } zuluCrypt-6.2.0/zuluCrypt-cli/utility/socket/socket.h000066400000000000000000000216751425361753700230120ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef SOCKET #define SOCKET #ifdef __cplusplus extern "C" { #endif #include typedef struct SocketType_t * socket_t ; #define SocketVoid ( ( socket_t ) 0 ) /* * Takes a pointer to a function to be called when memory allocation can not take place * ie if the system has run out of memory and malloc() or realloc() has failed. * This function is optional and "SocketVoid" will be returned on memory exaustion if the function * isnt set. */ void SocketExitOnMemoryExaustion( void (*)( void ) ) ; /* * creates a local unix socket * SocketVoid is returned on error * socket is created with default type of SOCK_STREAM and protocol value of 0 */ socket_t SocketLocal( const char * address ) ; /* * creates a local unix socket * type is the second argument to socket() * protocol is the third argument to socket() * SocketVoid is returned on error */ socket_t SocketLocalWithOptions( const char * address,int type,int protocol ) ; /* * create an IPv4 internet socket with an address of "address" and at port number "port" * eg socket_t socket = SocketNetByName( "google.com",80 ) ; * * address could be something like "google.com" or "192.168.1.1" * * SocketVoid is returned on error * socket is created with default type of SOCK_STREAM and protocol value of 0 */ socket_t SocketNet( const char * address,int port ) ; /* * create an internet socket with an address of "address" and at port number "port" * eg socket_t socket = SocketNetByName( "google.com",80 ) ; * * type is the second argument to socket() * protocol is the third argument to socket() * * SocketVoid is returned on error */ socket_t SocketNetWithOptions( const char * address,int port,int type,int protocol ) ; /* * create an IPv6 internet socket with an address of "address" and at port number "port" * eg socket_t socket = SocketNet6( "google.com",80 ) ; * * address could be something like "google.com" * * SocketVoid is returned on error * socket is created with default type of SOCK_STREAM and protocol value of 0 */ socket_t SocketNet6( const char * address,int port ) ; /* * create an IPv6 internet socket with an address of "address" and at port number "port" * eg socket_t socket = SocketNetWithOptions6( "google.com",80,SOCK_STREAM,0 ) ; * * type is the second argument to socket() * protocol is the third argument to socket() * * SocketVoid is returned on error */ socket_t SocketNetWithOptions6( const char * address,int port,int type,int protocol ) ; /* * return an address associated with the socket. * * NULL is returned if SocketVoid is passed or on error */ const char * SocketAddress( socket_t ) ; /* * bind a socket. This will make a socket a server socket * 1 is returned on success * 0 is returned on error */ int SocketBind( socket_t ) ; /* * return a file descriptor associated with a socket */ int SocketFileDescriptor( socket_t ) ; /* * Accept a socket * SocketVoid is returned on error */ socket_t SocketAccept( socket_t ) ; /* * Wait for upto time seconds for an attempt to connect. * SocketVoid is returned if time time expire or on error. * A socket_t object is returned on success. */ socket_t SocketAcceptWithTimeOut( socket_t,time_t time ) ; /* * connect to a server a client socket is to connect to * 1 is returned on success * 0 is returned on error and the socket is invalidated, a new socket will have to be create to repeat * the operation */ int SocketConnect( socket_t * client ) ; /* * listen for an incomming connection * 1 is returned on success * 0 is returned on error */ int SocketListen( socket_t ) ; /* * get bounded amount of data from socket and allocate memory dynamically for it and return a pointer to the allocated memory through pointer "buffer" * * on success,the returned value is greater than 0 and the buffer should be free() when done with it. * on error,the returned value is 0 and no memory is allocated * * get only len number of bytes. * * The buffer is NULL terminated * * It is the responsibility of the caller to free() the buffer * This function will block until len bytes are read on the other side close the connection * * eg * char * data ; * socket_t client = SocketNetByIPAddress( "127.0.0.1",1331 ) ; * SocketConnect( client ) ; * SocketGetData_1( client,&data,32 ) ; * puts( data ) ; * free( data ) ; * SocketClose( client ) ; * SocketDelete( &clien ) ; * * returned value is the number of bytes read or -1 on error */ ssize_t SocketGetData_1( socket_t,char ** buffer,size_t len ) ; /* * get an unbounded amount of data from socket,create memory for it dynamically and return a pointer to the allocated memory through pointer "buffer" * * on success,the returned value is greater than 0 and the buffer should be free() when done with it. * on error,the returned value is 0 and no memory is allocated * returned value is the number of bytes read or -1 on error * The buffer is NULL terminated * * It is the responsibility of the caller to free() the buffer */ ssize_t SocketGetData( socket_t,char ** buffer ) ; /* * get data from a socket and put in a user managed buffer "buffer" of size len * The buffer will be null terminated and hence must have additional space to accomodate null character. * If you expect to read a maximum of 32 bytes from the socket for example, you must have a buffer with atleast 33 blocks in size * and you must pass 33 to the function. * returned value is the number of bytes read or -1 on error * The buffer is not NULL terminated */ ssize_t SocketGetData_2( socket_t,char * buffer,size_t len ) ; /* * this function behaves like SocketGetData_2 but it takes an additional argument * of time in seconds for how long the function should wait for data and it returns * -1 if timer expired */ ssize_t SocketGetData_3( socket_t,char * buffer,size_t len,int timeout ) ; /* * send data to a socket, * return number of bytes sent or -1 on error */ ssize_t SocketSendData( socket_t,const char * buffer,size_t len ) ; /* * set the socket to not block the calling thread waiting for events over the socket * -1 is returned on error, other numbers on success */ int SocketSetDoNotBlock( socket_t ) ; /* * set the socket to a block the calling thread waiting for events over the socket * This is the default setting. * -1 is returned on error, other numbers on success */ int SocketSetBlock( socket_t ) ; /* * return 1 if a socket is a blocking socket * return 0 if a socket is a non blocking socket * return -1 on error( if socket is SocketVoid ). */ int SocketIsBlocking( socket_t ) ; /* * close a socket and free up all used resources */ void SocketClose( socket_t * ) ; /* * close the write channel on the socket */ void SocketCloseWriteChannel( socket_t ) ; /* * close the read channel on the socket */ void SocketCloseReadChannel( socket_t ) ; /* * set the maximum number of connections to accept. * This function must be called before SocketListen() to change the default from 1. */ void SocketSetListenMaximum( socket_t,int ) ; /* examples: a server program that listens for new connections and print data they send until it receices "exit" message #include "socket.h" #include #include int main( void ) { //socket_t server = SocketLocal( "/tmpt/socketLocal" ) ; socket_t server = SocketNetByName( "localhost",4000 ) ; socket_t client ; SocketBind( server ) ; char data[ 33 ] ; while( 1 ){ SocketListen( server ) ; client = SocketAccept( server ) ; SocketGetData_2( client,data,sizeof( data ) ) ; if( strcmp( data,"exit" ) == 0 ){ printf( "exit command received, exiting\n" ) ; SocketClose( &client ) ; break ; }else{ printf( "message received: %s\n",data ) ; SocketClose( &client ) ; } } SocketClose( &server ) ; return 0 ; } A client program that sends a message to a server #include "socket.h" #include #include int main( int argc,char * argv[] ) { if( argc != 2 ) return printf( "wrong number of arguments,expecting one argument\n" ) ; const char * data = argv[ 1 ] ; //socket_t client = SocketLocal( "/tmpt/socketLocal" ) ; socket_t client = SocketNetByName( "localhost",4000 ) ; SocketConnect( &client ) ; SocketSendData( client,data,strlen( data ) ) ; SocketClose( &client ) ; return 0 ; } */ #ifdef __cplusplus } #endif #endif zuluCrypt-6.2.0/zuluCrypt-cli/utility/string/000077500000000000000000000000001425361753700213545ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluCrypt-cli/utility/string/String.c000066400000000000000000001041561425361753700227750ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "String.h" #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #define ignore_result( x ) if( x ){;} /* * a string memory block gows by below factor when it expands */ #define FACTOR 2 /* * when an empty string is initialized,star it with below buffer size */ #define STRING_INIT_SIZE 32 struct StringType { /* * pointer to the string */ char * string ; /* *the size of the string */ size_t size ; /* * the size of the string buffer */ size_t length ; /* * contains info if the string is owned by stringlist */ int owned ; }; static void _f( void ) { } static void ( *_memory_error )( void ) = _f ; void StringExitOnMemoryExaustion( void ( *f )( void ) ) { _memory_error = f ; } static void * _StringError( void ) { _memory_error() ; return NULL ; } int StringOwned( string_t st ) { if( st == StringVoid ){ return 0 ; }else{ return st->owned ; } } const char * StringToLowerCase( string_t st ) { char * it ; const char * end ; if( st == StringVoid ){ return NULL ; }else{ end = st->string + st->size ; for( it = st->string ; it != end ; it++ ){ if( *it >= 'A' && *it <= 'Z' ){ *it += 32 ; } } return st->string ; } } static inline char * __StringExpandMemory( string_t st,size_t new_size ) { char * p ; if( new_size >= st->length ){ st->length = new_size * FACTOR ; p = realloc( st->string,st->length ) ; if( p == NULL ){ return _StringError() ; }else{ return p ; } }else{ return st->string ; } } void StringGetIterators( string_t st,StringIterator * begin,StringIterator * end ) { if( st == StringVoid ){ *begin = NULL ; *end = NULL ; }else{ *begin = st->string ; *end = st->string + st->size ; } } int StringLock( string_t st ) { if( st != StringVoid ){ return mlock( st->string,st->size ) ; }else{ return -1 ; } } int StringUnlock( string_t st ) { if( st != StringVoid ){ return munlock( st->string,st->size ) ; }else{ return -1 ; } } void StringDelete( string_t * st ) { string_t s ; if( st != NULL ){ s = *st ; if( s != StringVoid ){ if( s->owned == 0 ){ *st = StringVoid ; free( s->string ) ; free( s ) ; } } } } void StringClearDelete( string_t * st ) { string_t s ; char * e ; if( st != NULL ){ s = *st ; if( s != StringVoid ){ if( s->owned == 0 ){ *st = StringVoid ; e = s->string ; memset( e,'\0',s->length ) ; free( e ) ; free( s ) ; } } } } void StringMultipleDelete( string_t * xt,... ) { string_t * entry ; va_list list ; string_t st ; if( xt == NULL ){ return ; } st = *xt ; if( st != StringVoid ){ if( st->owned == 0 ){ free( st->string ) ; free( st ) ; *xt = StringVoid ; } } va_start( list,xt ) ; while( 1 ){ entry = va_arg( list,string_t * ) ; if( entry == NULL ){ break ; } st = *entry ; if( st != StringVoid ){ if( st->owned == 0 ){ free( st->string ) ; free( st ) ; *entry = StringVoid ; } } } va_end( list ) ; } char * StringDeleteHandle( string_t * xt ) { char * c = NULL ; string_t st ; if( xt == NULL ){ return NULL ; } st = *xt ; if( st == StringVoid ){ return NULL ; } if( st->owned == 0 ){ *xt = StringVoid ; c = st->string ; free( st ) ; }else{ c = malloc( sizeof( char ) * ( st->size + 1 ) ) ; if( c == NULL ){ return _StringError() ; }else{ memcpy( c,st->string,st->size + 1 ) ; } } return c ; } string_t StringCopy( string_t st ) { string_t xt ; char * c ; if( st == StringVoid ){ return StringVoid ; } c = malloc( sizeof( char ) * ( st->size + 1 ) ) ; if( c == NULL ){ return _StringError() ; } xt = malloc( sizeof( struct StringType ) ) ; if( xt == NULL ){ free( c ) ; return _StringError() ; }else{ memcpy( c,st->string,st->size + 1 ) ; xt->size = st->size ; xt->length = st->size + 1 ; xt->string = c ; xt->owned = 0 ; return xt ; } } string_t StringEmpty() { return StringBuffer( 8 ) ; } string_t StringBuffer( size_t s ) { string_t st = ( string_t ) malloc( sizeof( struct StringType ) ) ; if( st == NULL ){ return _StringError() ; }else{ st->string = malloc( s * sizeof( char ) ) ; if( st->string == NULL ){ free( st ) ; return _StringError() ; }else{ st->string[ 0 ] = '\0' ; st->size = 0 ; st->owned = 0 ; st->length = s ; return st ; } } } string_t String( const char * cstring ) { size_t size ; string_t st ; if( cstring == NULL ){ return StringVoid ; } size = strlen( cstring ) ; st = malloc( sizeof( struct StringType ) ) ; if( st == NULL ){ return _StringError() ; } if( size < STRING_INIT_SIZE / 2 ){ st->string = malloc( sizeof( char ) * STRING_INIT_SIZE ) ; if( st->string == NULL ){ free( st ) ; return _StringError() ; }else{ memcpy( st->string,cstring,size + 1 ) ; st->size = size ; st->length = STRING_INIT_SIZE ; st->owned = 0 ; return st ; } }else{ st->string = malloc( sizeof( char ) * ( size + 1 ) ); if( st->string == NULL ){ free( st ) ; return _StringError() ; }else{ memcpy( st->string,cstring,size + 1 ) ; st->size = size ; st->length = size + 1 ; st->owned = 0 ; return st ; } } } string_t String_1( const char * cstring,... ) { string_t st = String( cstring ) ; const char * entry ; va_list list ; va_start( list,cstring ) ; while( 1 ){ entry = va_arg( list,const char * ) ; if( entry == NULL ){ break ; } StringAppend( st,entry ) ; } va_end( list ) ; return st ; } void StringReadToBuffer( string_t st,char * buffer,size_t size ) { if( buffer != NULL ){ memcpy( buffer,st->string,size ) ; } } string_t StringInherit( char ** data ) { size_t l ; if( data != NULL ){ if( *data != NULL ){ l = strlen( *data ) ; return StringInheritWithSize( data,l,l + 1 ) ; }else{ return StringVoid ; } }else{ return StringVoid ; } } void StringPrint( string_t st ) { if( st != StringVoid ){ printf( "%s",st->string ) ; } } void StringPrintLine( string_t st ) { if( st != StringVoid ){ printf( "%s\n",st->string ) ; } } int StringContains( string_t st,const char * str ) { if( st == StringVoid || str == NULL ){ return 0 ; }else{ return strstr( st->string,str ) != NULL ; } } string_t StringInheritWithSize( char ** data,size_t size,size_t length ) { string_t st ; if( data == NULL || *data == NULL ){ return StringVoid ; } if( length == 0 ){ return StringVoid ; } st = malloc( sizeof( struct StringType ) ) ; if( st == NULL ){ return _StringError() ; } st->owned = 0 ; st->size = size ; st->length = length ; st->string = *data ; *data = NULL ; return st ; } string_t StringWithSize( const char * s,size_t len ) { char * c ; if( s == NULL ){ return StringVoid ; } c = malloc( sizeof( char ) * ( len + 1 ) ) ; if( c == NULL ){ return _StringError() ; } memcpy( c,s,len ) ; *( c + len ) = '\0' ; return StringInheritWithSize( &c,len,len + 1 ) ; } ssize_t StringIndexOfString( string_t st,size_t p,const char * s ) { char * c ; if( st == StringVoid || s == NULL ){ return -1 ; } if( p >= st->size ){ return -1 ; } c = strstr( st->string + p,s ) ; if( c == NULL ){ return -1 ; }else{ return c - st->string ; } } ssize_t StringLastIndexOfChar( string_t st,char s ) { char * c ; char * d ; if( st == StringVoid ){ return -1 ; } d = st->string ; c = d + st->size ; while( --c != d ){ if( *c == s ){ return c - d ; } } return -1 ; } ssize_t StringLastIndexOfString( string_t st,const char * s ) { ssize_t p = -1 ; char * c ; char * d ; char * e ; size_t len ; if( s == NULL ){ return -1 ; } if( st == StringVoid ){ return -1 ; } len = strlen( s ) ; if( len == 0 ){ return -1 ; } e = d = st->string ; while( 1 ) { c = strstr( d,s ) ; if( c != NULL ){ p = c - e ; d = d + len ; }else{ break ; } } return p ; } ssize_t StringIndexOfChar( string_t st,size_t p,char s ) { char * c ; char d[ 2 ] ; *( d + 1 ) = '\0' ; *( d + 0 ) = s ; if( st == StringVoid ){ return -1 ; } c = strstr( st->string + p,d ) ; if( c == NULL ){ return -1 ; }else{ return c - st->string ; } } const char * StringRemoveLength( string_t st,size_t x ,size_t y ) { if( st == StringVoid ){ return NULL ; } if( x >= st->size ){ return st->string ; } if( x + y >= st->size ){ y = st->size - x ; } memmove( st->string + x,st->string + x + y,st->size - y - x + 1 ) ; st->size -= y ; return st->string ; } const char * StringRemoveDigits( string_t st ) { char * e ; char * f ; char k ; size_t z ; if( st == StringVoid ){ return NULL ; }else{ z = st->size ; e = st->string ; f = e ; while( 1 ){ k = *e ; if( k == '\0' ){ break ; }else if( k >= '0' && k <= '9' ){ z-- ; f++ ; }else{ e++ ; f++ ; } *e = *f ; } st->size = z ; return st->string ; } } void StringClear( string_t st ) { if( st != StringVoid ){ memset( st->string,'\0',st->size ) ; st->size = 0 ; } } void StringReset( string_t st ) { if( st != StringVoid ){ st->string[ 0 ] = '\0' ; st->size = 0 ; } } const char * StringRemoveRight( string_t st,size_t x ) { if( x >= st->size ){ st->string[ 0 ] = '\0' ; st->size = 0 ; }else{ st->size = st->size - x ; *( st->string + st->size ) = '\0' ; } return st->string ; } const char * StringRemoveLeft( string_t st,size_t x ) { return StringRemoveLength( st,0,x ) ; } const char * StringCrop( string_t st,size_t x,size_t y ) { ssize_t s ; if( st == StringVoid ){ return NULL ; } if( x >= st->size ){ x = st->size - 1 ; } if( y >= st->size ){ y = st->size - 1 ; } memmove( st->string,st->string + x,st->size - x + 1 ) ; s = st->size - x - y ; if( s < 0 ){ st->size = 0 ; }else{ st->size = s ; } *( st->string + st->size ) = '\0'; return st->string ; } size_t StringLength( string_t st ) { if( st == StringVoid ){ return 0 ; }else{ return st->size ; } } int StringLengthMatch( string_t st,size_t s ) { if( st == StringVoid ){ return 0 ; }else{ return st->size == s ; } } #if 0 const char * StringContent( string_t st ) { if( st == StringVoid ){ return NULL ; }else{ return st->string ; } } const char ** StringPointer( string_t st ) { if( st == StringVoid ){ return NULL ; }else{ return ( const char ** )&st->string ; } } #endif char * StringCopy_1( string_t st ) { if( st == StringVoid ){ return NULL ; }else{ return StringCopy_3( st,st->size ) ; } } char * StringCopy_2( const char * str ) { char * c ; size_t len ; if( str == NULL ){ c = malloc( sizeof( char ) ) ; if( c == NULL ){ return _StringError() ; }else{ *c = '\0' ; return c ; } }else{ len = strlen( str ) ; c = malloc( sizeof( char ) * ( len + 1 ) ) ; if( c == NULL ){ return _StringError() ; }else{ memcpy( c,str,len + 1 ) ; return c ; } } } char * StringCopy_3( string_t st,size_t l ) { char * c ; if( st == StringVoid ){ c = malloc( sizeof( char ) ) ; if( c == NULL ){ return _StringError() ; }else{ *c = '\0' ; return c ; } }else{ c = malloc( sizeof( char ) * ( l + 1 ) ) ; if( c == NULL ){ return _StringError() ; }else{ memcpy( c,st->string,l ) ; *( c + l ) = '\0' ; return c ; } } } static int _string_ends_with( const char * e,size_t ee,const char * s,size_t ss ) { if( ee >= ss ){ return memcmp( e + ee - ss,s,ss ) == 0 ; }else{ return 0 ; } } int StringEndsWith( string_t st,const char * s ) { if( st == StringVoid || s == NULL ){ return 0 ; }else{ return _string_ends_with( st->string,st->size,s,strlen( s ) ) ; } } int StringEndsWith_1( const char * e,const char * s ) { if( e == NULL || s == NULL ){ return 0 ; }else{ return _string_ends_with( e,strlen( e ),s,strlen( s ) ) ; } } int StringEndsWith_2( string_t e,string_t s ) { if( e == StringVoid || s == StringVoid ){ return 0 ; }else{ return _string_ends_with( e->string,e->size,s->string,s->size ) ; } } int StringStartsAndEndsWith( const char * a,const char * b,const char * c ) { if( a == NULL || b == NULL || c == NULL ){ return 0 ; }else{ if( strncmp( a,b,strlen( b ) ) == 0 ){ return _string_ends_with( a,strlen( a ),c,strlen( c ) ) ; }else{ return 0 ; } } } int StringStartsWith( string_t st,const char * s ) { if( st == StringVoid || s == NULL ){ return 0 ; }else{ return strncmp( st->string,s,strlen( s ) ) == 0 ; } } int StringStartsWith_1( string_t st,string_t xt ) { if( st == StringVoid || xt == StringVoid ){ return 0 ; }else{ return strncmp( st->string,xt->string,xt->size ) == 0 ; } } int StringEndsWithChar( string_t st,char s ) { if( st == StringVoid || st->size < 1 ){ return 0 ; }else{ return st->string[ st->size - 1 ] == s ; } } char StringCharAt( string_t st,size_t p ) { if( st == StringVoid ){ return '\0' ; } if( p >= st->size ){ return '\0' ; } return *( st->string + p ) ; } char StringCharAtLast( string_t st ) { if( st == StringVoid ){ return '\0' ; } if( st->size == 0 ){ return '\0' ; } return * ( st->string + st->size - 1 ) ; } const char * StringStringAt( string_t st,size_t p ) { if( st == StringVoid ){ return NULL ; } if( p >= st->size ){ return NULL ; } return st->string + p ; } const char * StringSubChar( string_t st,size_t x,char s ) { if( st == StringVoid ){ return NULL ; } if( x >= st->size ){ return st->string ; } st->string[ x ] = s ; return st->string ; } static void Stringsrcs__( string_t st,char x,const char * y,size_t p ) { size_t i ; size_t j ; size_t k ; size_t l ; char * c ; if( st == StringVoid ){ return ; } if( y == NULL ){ return ; } if( p >= st->size ){ return ; } c= st->string ; l = st->size ; k = strlen( y ) ; for( j = p ; j < l ; j++ ){ for( i = 0 ; i < k ; i++ ){ if( *( c + j ) == * ( y + i ) ){ *( c + j ) = x ; break ; } } } } const char * StringReplaceCharStringPos( string_t st,char x,const char * y,size_t p ) { Stringsrcs__( st,x,y,p ) ; return st->string ; } const char * StringReplaceCharString( string_t st,char x,const char * y ) { return StringReplaceCharStringPos( st,x,y,0 ) ; } const char * StringSubString( string_t st, size_t x,const char * s ) { size_t k ; if( st == StringVoid ){ return NULL ; } if( x >= st->size || s == NULL ){ return st->string ; } k = strlen( s ) ; if( x + k >= st->size ){ return NULL ; } memcpy( st->string + x,s,k ); return st->string ; } const char * StringInsertChar( string_t st,size_t x,char s ) { char c[ 2 ] = { '\0' } ; *c = s ; return StringInsertString( st,x,c ) ; } const char * StringAppendAt( string_t st,size_t x,const char * s ) { size_t len ; char * c ; if( st == StringVoid ){ return NULL ; } if( x > st->size || s == NULL ){ return st->string ; } len = strlen( s ) ; c = __StringExpandMemory( st,st->size + len ) ; if( c != NULL ){ memcpy( c + x,s,len + 1 ) ; st->string = c ; st->size = x + len ; } return c ; } const char * StringReplace( string_t st,const char * s ) { size_t len ; char * c ; if( st == StringVoid ){ return s ; } if( s == NULL ){ return NULL ; }else{ len = strlen( s ) ; if( len < st->length ){ c = st->string ; memcpy( c,s,len + 1 ) ; st->size = len ; return c ; }else{ c = __StringExpandMemory( st,st->size + len ) ; if( c != NULL ){ memcpy( c,s,len + 1 ) ; st->string = c ; st->size = len ; } return c ; } } } const char * StringPrepend( string_t st,const char * s ) { char * c ; size_t len ; if( st == StringVoid ){ return NULL ; } if( s == NULL ){ return st->string ; } len = strlen( s ) ; c = __StringExpandMemory( st,st->size + len ) ; if( c != NULL ){ st->string = c ; memmove( st->string + len,st->string,st->size + 1 ) ; memcpy( st->string,s,len ) ; st->size += len ; } return c ; } const char * StringPrependString( string_t st,string_t xt ) { return StringPrepend( st,xt->string ) ; } const char * StringPrependChar( string_t st,char c ) { char s[ 2 ] = { '\0' } ; *s = c ; return StringPrepend( st,s ) ; } const char * StringAppend( string_t st,const char * s ) { char * c ; size_t len ; if( st == StringVoid ){ return NULL ; } if( s == NULL ){ return st->string ; } len = strlen( s ) ; c = __StringExpandMemory( st,st->size + len ) ; if( c != NULL ){ st->string = c ; memcpy( st->string + st->size,s,len + 1 ) ; st->size += len ; } return c ; } int StringStartsWithAtLeastOne( string_t st,... ) { int r = 0 ; const char * entry ; va_list list ; va_start( list,st ) ; if( st != StringVoid ){ while( 1 ){ entry = va_arg( list,const char * ) ; if( entry == NULL ){ break ; }else{ if( strncmp( st->string,entry,strlen( entry ) ) == 0 ){ r = 1 ; break ; } } } } va_end( list ) ; return r ; } int StringEndsWithAtLeastOne( const char * e,... ) { const char * entry ; va_list list ; va_start( list,e ) ; int r = 0 ; while( 1 ){ entry = va_arg( list,const char * ) ; if( entry == NULL ){ break ; }else if( StringEndsWith_1( e,entry ) ){ r = 1 ; break ; } } va_end( list ) ; return r ; } const char * StringMultipleAppend( string_t st,... ) { const char * entry ; va_list list ; va_start( list,st ) ; while( 1 ){ entry = va_arg( list,const char * ) ; if( entry == NULL ){ break ; } StringAppend( st,entry ) ; } va_end( list ) ; return st->string ; } const char * StringAppendMultipleString( string_t st,... ) { string_t entry ; va_list list ; va_start( list,st ) ; while( 1 ){ entry = va_arg( list,string_t ) ; if( entry == NULL ){ break ; } StringAppend( st,entry->string ) ; } va_end( list ) ; return st->string ; } const char * StringMultiplePrepend( string_t st,... ) { const char * entry ; va_list list ; va_start( list,st ) ; while( 1 ){ entry = va_arg( list,const char * ) ; if( entry == NULL ){ break ; } StringPrepend( st,entry ) ; } va_end( list ) ; return st->string ; } const char * StringPrependMultipleString( string_t st,... ) { string_t entry ; va_list list ; va_start( list,st ) ; while( 1 ){ entry = va_arg( list,string_t ) ; if( entry == NULL ){ break ; } StringPrepend( st,entry->string ) ; } va_end( list ) ; return st->string ; } const char * StringAppendString( string_t st,string_t xt ) { if( xt != StringVoid ){ return StringAppend( st,xt->string ) ; }else{ return StringContent( st ) ; } } const char * StringAppendChar( string_t st,char c ) { char * d = __StringExpandMemory( st,st->size + 1 ) ; if( d != NULL ){ st->string = d ; st->string[ st->size ] = c ; st->string[ st->size + 1 ] = '\0' ; st->size += 1 ; } return d ; } const char * StringInsertString( string_t st,size_t x,const char * s ) { char * c ; size_t len ; if( s == NULL ){ return NULL ; } len = strlen( s ) ; c = __StringExpandMemory( st,len ) ; if( c != NULL ){ st->string = c ; memmove( st->string + len + x,st->string + x,st->size - x + 1 ) ; memcpy( st->string + x,s,len ) ; st->size += len ; } return c ; } string_t StringMidString( string_t st,size_t x,size_t y ) { char * c ; c = malloc( sizeof( char ) * ( y + 1 ) ) ; if( c == NULL ){ return _StringError() ; } strncpy( c,st->string + x, y ) ; *( c + y ) = '\0' ; return StringInheritWithSize( &c,y,y + 1 ) ; } static char * StringRS__( string_t st,const char * x,const char * s,size_t p ) { char * c ; char * d ; char * e ; size_t j ; size_t k ; size_t len ; if( st == StringVoid ){ return NULL ; } if( x == NULL || s == NULL || p >= st->size ){ return st->string ; } d = st->string ; e = st->string + p ; j = strlen( s ) ; k = strlen( x ) ; if( j == k ){ while( ( c = strstr( e,x ) ) != NULL ){ memcpy( c,s,j ) ; e = e + j ; } }else if( j > k ){ while( ( c = strstr( e,x ) ) != NULL ){ len = c - st->string ; d = __StringExpandMemory( st,st->size + j ) ; if( d != NULL ){ st->string = d ; c = st->string + len ; memmove( c + j,c + k,st->size - ( c - st->string ) + 1 ) ; memcpy( c,s,j ) ; st->size = st->size + j - k ; e = st->string + len + j ; } } }else if( k > j ){ while( ( c = strstr( e,x ) ) != NULL ){ len = c - st->string ; memmove( c + j,c + k,st->size - ( c - st->string + k ) + 1 ) ; memcpy( c,s,j ) ; if( d != NULL ){ st->string = d ; st->size = st->size +j - k ; e = st->string + len ; } } } return d ; } const char * StringReplaceStringPos( string_t st,const char * x,const char * s,size_t p ) { return StringRS__( st,x,s,p ) ; } const char * StringReplaceString( string_t st,const char * x,const char * s ) { return StringReplaceStringPos( st,x,s,0 ) ; } const char * StringRemoveStringPos( string_t st,const char * s,size_t p ) { return StringRS__( st,s,"",p ) ; } const char * StringRemoveString( string_t st,const char * s ) { return StringRemoveStringPos( st,s,0 ) ; } int StringIsEmpty( string_t x ) { if( x == StringVoid ){ return 0 ; }else{ return x->string[ 0 ] == '\0' ; } } static char * StringCRC__( string_t st, char x,char y,size_t p ) { char * c ; if( st == StringVoid ){ return NULL ; } if( p >= st->size ){ return st->string ; } c = st->string - 1 + p ; while( *++c ){ if( *c == x ){ *c = y ; } } return st->string ; } const char * StringReplaceCharPos( string_t st,char x,char y,size_t p ) { return StringCRC__( st,x,y,p ) ; } const char * StringReplaceChar_1( string_t st,size_t index,char x,char y ) { char * e ; if( st == StringVoid ){ return NULL ; } if( index >= st->size ){ return NULL ; } e = strchr( st->string + index,x ) ; if( e != NULL ){ *e = y ; return st->string ; }else{ return NULL ; } } const char * StringReplaceChar( string_t st,char x,char y ) { return StringReplaceCharPos( st,x,y,0 ) ; } /* * 2^64 has a maximum of 19 digits,64 byte buffer is more that enough */ #define BUFFSIZE 64 #define BUFFLIMIT 63 static inline char * _intToString( char * buffer,u_int64_t z ) { int i = BUFFLIMIT ; do{ i-- ; buffer[ i ] = z % 10 + '0' ; z = z / 10 ; }while( z != 0 && i != 0 ) ; return buffer + i ; } string_t StringIntToString( u_int64_t z ) { char buffer[ BUFFSIZE ] = { '\0' }; return String( _intToString( buffer,z ) ); } const char * StringAppendInt( string_t st,u_int64_t z ) { char buffer[ BUFFSIZE ] = { '\0' }; return StringAppend( st,_intToString( buffer,z ) ) ; } u_int64_t StringConvertToInt( const char * s ) { u_int64_t r = 0 ; char c ; if( s == NULL ){ return 0 ; } while( 1 ){ c = *s ; s++ ; if( c == '\0' ){ break ; }else{ r = r * 10 + ( c - '0' ) ; } } return r ; } const char * StringSubStringWithInt( string_t st,const char * str,u_int64_t z ) { char buffer[ BUFFSIZE ] = { '\0' }; return StringReplaceString( st,str,_intToString( buffer,z ) ) ; } char * StringIntToString_1( char * x,size_t y,u_int64_t z ) { char * c ; if( x == NULL ){ return NULL ; }else{ c = x + y - 1 ; *c-- = '\0' ; do{ *c-- = z % 10 + '0' ; z = z / 10 ; }while( z != 0 ) ; return ++c ; } } int StringsAreEqual_1( string_t x,string_t y ) { if( x == StringVoid || y == StringVoid || x->size != y->size ){ return 0 ; }else{ return strcmp( x->string,y->string ) == 0 ; } } int StringsAreEqual_2( string_t x,const char * y ) { if( x == StringVoid ){ return 0 ; }else{ return strcmp( x->string,y ) == 0 ; } } int StringAtLeastOneMatch( string_t st,... ) { va_list list ; int r = 0 ; const char * e ; const char * f ; va_start( list,st ) ; if( st != StringVoid ){ f = st->string ; while( 1 ){ e = va_arg( list,const char * ) ; if( e == NULL ){ break ; }else if( strcmp( f,e ) == 0 ){ r = 1 ; break ; } } } va_end( list ) ; return r ; } int StringAtLeastOneMatch_1( const char * x,... ) { va_list list ; int r = 0 ; const char * e ; va_start( list,x ) ; if( x != NULL ){ while( 1 ){ e = va_arg( list,const char * ) ; if( e == NULL ){ break ; }else if( strcmp( x,e ) == 0 ){ r = 1 ; break ; } } } va_end( list ) ; return r ; } int StringHasAtLeastOneComponent_1( const char * x,... ) { va_list list ; int r = 0 ; const char * e ; va_start( list,x ) ; if( x != NULL ){ while( 1 ){ e = va_arg( list,const char * ) ; if( e == NULL ){ break ; }else if( strstr( x,e ) != NULL ){ r = 1 ; break ; } } } va_end( list ) ; return r ; } int StringHasAtLeastOneComponent( string_t st,... ) { va_list list ; int r = 0 ; const char * e ; const char * f ; va_start( list,st ) ; if( st != StringVoid ){ f = st->string ; while( 1 ){ e = va_arg( list,const char * ) ; if( e == NULL ){ break ; }else if( strstr( f,e ) != NULL ){ r = 1 ; break ; } } } va_end( list ) ; return r ; } int StringAtLeastOnePrefixMatch( const char * x,... ) { va_list list ; int r = 0 ; const char * e ; va_start( list,x ) ; if( x != NULL ){ while( 1 ){ e = va_arg( list,const char * ) ; if( e == NULL ){ break ; }else if( strncmp( x,e,strlen( e ) ) == 0 ){ r = 1 ; break ; } } } va_end( list ) ; return r ; } static char * StringICS__( string_t st,char x,const char * s,size_t p ) { const char * d ; char * e ; char * f ; size_t pos ; if( st == StringVoid ){ return NULL ; } if( p >= st->size || s == NULL ){ return st->string ; } d = s - 1 ; while( *++d ){ f = st->string - 1 + p ; while( *++f ){ if( *d == *f ){ pos = f - st->string ; e = __StringExpandMemory( st,st->size + 2 ) ; if( e != NULL ){ st->string = e ; memmove( e + pos + 1,e + pos,st->size - pos + 1 ) ; *( e + pos ) = x ; f = e + pos + 1 ; st->size++ ; } } } } return st->string ; } const char * StringInsertCharStringPos( string_t st,char x,const char * s,size_t p ) { return StringICS__( st,x,s,p ) ; } const char * StringInsertCharString( string_t st,char x,const char * s ) { return StringInsertCharStringPos( st,x,s,0 ) ; } const char * StringInsertCharChar( string_t st,char x,char y ) { char c[2] ; c[0] = y ; c[1] = '\0' ; return StringInsertCharString( st,x,c ) ; } string_t StringGetFromTerminal( void ) { int c ; const char * d ; string_t p = String( "" ) ; while( 1 ){ c = getchar() ; if( c == '\n' || c == EOF ){ break ; }else{ d = StringAppendChar( p,( char )c ) ; if( d == NULL ){ StringDelete( &p ) ; return StringVoid ; } } } return p ; } string_t StringGetFromTerminal_1( size_t s ) { int c ; const char * d ; string_t p = String( "" ) ; while( 1 ){ if( s == 0 ){ /* * we already got the requested number of characters,now clear the buffer * by reading until we get a newline or EOF character */ while( 1 ){ c = getchar() ; if( c == '\n' || c == EOF ){ break ; } } return p ; } c = getchar() ; if( c == '\n' || c == EOF ){ break ; }else{ s-- ; d = StringAppendChar( p,( char )c ) ; if( d == NULL ){ StringDelete( &p ) ; return StringVoid ; } } } return p ; } static inline int __terminalEchoOff( struct termios * old,struct termios * new ) { if( tcgetattr ( 1,old ) != 0 ){ return 1 ; } *new = *old; new->c_lflag &= ~ECHO; if( tcsetattr ( 1,TCSAFLUSH,new ) != 0 ){ return 1 ; }else{ return 0 ; } } int StringSilentlyGetFromTerminal( string_t * q ) { string_t p ; struct termios old ; struct termios new ; if( __terminalEchoOff( &old,&new ) == 1 ){ return 1 ; } p = StringGetFromTerminal() ; if( p == StringVoid ){ return 2 ; } tcsetattr( 1,TCSAFLUSH,&old ); *q = p ; return 0 ; } int StringSilentlyGetFromTerminal_1( string_t * q,size_t s ) { string_t p ; struct termios old ; struct termios new ; if( __terminalEchoOff( &old,&new ) == 1 ){ return 1 ; } p = StringGetFromTerminal_1( s ) ; if( p == StringVoid ){ return 2 ; } tcsetattr ( 1,TCSAFLUSH,&old ); *q = p ; return 0 ; } string_t StringRandomString( size_t size ) { string_t s = StringVoid ; char * e ; char c ; int f ; size_t g = 0 ; if( size < 1 ){ return s ; } e = malloc( sizeof( char ) * ( size + 1 ) ) ; if( e == NULL ){ return s ; } f = open( "/dev/urandom",O_RDONLY ) ; if( f == -1 ){ free( e ) ; return s ; } while( g < size ){ ignore_result( read( f,&c,1 ) ) ; if( c >= ' ' && c <= '~' ){ *( e + g ) = c ; g++ ; } } *( e + size ) = '\0' ; close( f ) ; s = StringInheritWithSize( &e,size,size + 1 ) ; if( s == StringVoid ){ free( e ) ; } return s ; } u_int32_t StringJenkinsOneAtATimeHash( const char * key ) { size_t l ; u_int32_t hash = 0; u_int32_t i ; if( key != NULL ){ l = strlen( key ) ; for( i = 0 ; i < l ; i++ ){ hash += key[ i ]; hash += ( hash << 10 ); hash ^= ( hash >> 6 ); } hash += ( hash << 3 ); hash ^= ( hash >> 11 ); hash += ( hash << 15 ); } return hash; } u_int32_t StringJenkinsOneAtATimeHash_1( string_t st ) { size_t l ; u_int32_t hash = 0; u_int32_t i ; const char * e ; if( st != StringVoid ){ e = st->string ; l = st->size ; for( i = 0 ; i < l ; i++ ){ hash += e[ i ]; hash += ( hash << 10 ); hash ^= ( hash >> 6 ); } hash += ( hash << 3 ); hash ^= ( hash >> 11 ); hash += ( hash << 15 ); } return hash ; } int StringGetFromFile_1( string_t * str,const char * path ) { struct stat st ; if( stat( path,&st ) != 0 ){ return 1 ; }else{ return StringGetFromFile_3( str,path,0,st.st_size ) ; } } int StringGetFromFile_3( string_t * str,const char * path,size_t offset,size_t length ) { int fd ; char * c ; ssize_t size ; struct stat xt ; *str = StringVoid ; if( path == NULL ){ return 1 ; } if( stat( path,&xt ) != 0 ){ return 1 ; } if( ( fd = open( path,O_RDONLY ) ) == -1 ){ return 2 ; } if( lseek( fd,offset,SEEK_SET ) == -1 ){ close( fd ) ; return 2 ; } c = malloc( sizeof( char ) * ( length + 1 ) ) ; if( c == NULL ) { close( fd ) ; _StringError() ; return 3 ; } size = read( fd,c,length ) ; if( size <= 0 ){ free( c ) ; close( fd ) ; return 2 ; } close( fd ) ; *( c + length ) = '\0' ; *str = StringInheritWithSize( &c,( size_t )size,length + 1 ) ; if( *str == StringVoid ){ free( c ) ; return 3 ; }else{ return 0 ; } } int StringGetFromFileMemoryLocked( string_t * str,const char * path,size_t offset,ssize_t length ) { int fd ; char * c ; ssize_t size ; ssize_t file_size ; size_t reserve_memory_size ; struct stat xt ; if( path == NULL ){ return 1 ; } if( stat( path,&xt ) != 0 ){ return 1 ; } if( ( fd = open( path,O_RDONLY ) ) == -1 ){ return 1 ; } if( lseek( fd,offset,SEEK_SET ) == -1 ){ close( fd ) ; return 1 ; } file_size = xt.st_size - offset ; if( file_size <= 0 ){ close( fd ) ; return 1 ; } if( length <= 0 ){ reserve_memory_size = xt.st_size ; }else if( file_size > length ){ reserve_memory_size = length ; }else{ reserve_memory_size = file_size ; } c = malloc( sizeof( char ) * ( reserve_memory_size + 1 ) ) ; if( c == NULL ) { close( fd ) ; _StringError() ; return 2 ; } mlock( c,reserve_memory_size + 1 ) ; size = read( fd,c,reserve_memory_size ) ; close( fd ) ; if( size <= 0 ){ munlock( c,reserve_memory_size + 1 ) ; free( c ) ; return 1 ; } *( c + reserve_memory_size ) = '\0' ; *str = StringInheritWithSize( &c,( size_t )size,reserve_memory_size + 1 ) ; if( *str == StringVoid ){ free( c ) ; return 2 ; }else{ return 0 ; } } string_t StringGetFromFile_2( const char * path,int * status ) { string_t st = NULL ; struct stat xt ; if( stat( path,&xt ) != 0 ){ *status = 1 ; return StringVoid ; }else{ *status = StringGetFromFile_3( &st,path,0,xt.st_size ) ; return st ; } } string_t StringGetFromFile( const char * path ) { string_t st = StringVoid ; StringGetFromFile_1( &st,path ) ; return st ; } void StringWriteToFile( string_t st,const char * path,int mode ) { int fd ; if( st == StringVoid ){ return ; } if( mode == 1 ){ fd = open( path,O_WRONLY | O_CREAT | O_TRUNC,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ; }else{ fd = open( path,O_WRONLY | O_CREAT | O_APPEND,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ; } if( fd == -1 ){ return ; } ignore_result( write( fd,st->string,st->size ) ) ; close( fd ) ; ignore_result( chown( path,getuid(),getgid() ) ) ; chmod( path,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ; } static inline string_t _freeBuffer( char * buffer,int fd ) { close( fd ) ; if( buffer != NULL ){ free( buffer ); return _StringError() ; }else{ return _StringError() ; } } string_t StringGetFromVirtualFile( const char * path ) { #define SIZE 64 char * buffer = NULL ; char * e ; size_t size = SIZE ; size_t size_1 = 0 ; size_t strLen ; size_t bufferLen ; ssize_t j ; int fd = open( path,O_RDONLY ) ; if( fd == -1 ){ buffer = malloc( sizeof( char ) ) ; if( buffer == NULL ){ return _StringError() ; }else{ buffer[0] = '\0' ; return StringInheritWithSize( &buffer,0,1 ) ; } } while( 1 ){ e = realloc( buffer,size ) ; if( e == NULL ){ return _freeBuffer( buffer,fd ) ; }else{ buffer = e ; j = read( fd,buffer + size_1,SIZE ) ; if( j < SIZE ){ if( j <= 0 ){ e = realloc( buffer,size_1 + 1 ) ; if( e != NULL ){ buffer = e ; buffer[ size_1 ] = '\0' ; strLen = size_1 ; bufferLen = size_1 + 1 ; }else{ return _freeBuffer( buffer,fd ) ; } }else{ buffer[ size_1 + j ] = '\0' ; strLen = size_1 + j ; bufferLen = size ; } break ; }else{ size += SIZE ; size_1 += j ; } } } close( fd ) ; return StringInheritWithSize( &buffer,strLen,bufferLen ) ; } zuluCrypt-6.2.0/zuluCrypt-cli/utility/string/String.h000066400000000000000000000727531425361753700230110ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef STRINGTYPE #define STRINGTYPE #ifdef __cplusplus extern "C" { #endif #include #include #include /* * Takes a pointer to a function to be called when memory allocation can not take place * ie if the system has run out of memory and malloc() or realloc() has failed. * This function is optional and "StringVoid" will be returned on memory exaustion if the function * isnt set. */ void StringExitOnMemoryExaustion( void (*)( void ) ) ; /* * string_t type is a string handle,all string operation should happen through this handle. */ typedef struct StringType * string_t ; /* * create a custom type to represent a string_t pointing to NULL while hiding the pointer nature of string_t * string_t is an opaque handle and NULL assignment "gives unnecessary info" about its nature. */ #define StringVoid ( ( string_t ) 0 ) typedef char * StringIterator ; /* * Get stl style iterator on the managed string */ void StringGetIterators( string_t,StringIterator * begin,StringIterator * end ) ; /* * initialize a handle with a C string */ string_t String( const char * cstring ) ; /* * initialize a handle with multiple C strings concatenated together. */ string_t String_1( const char * cstring,... ) __attribute__ ( ( sentinel ) ) ; /* * initialize a handle with an empty C string */ string_t StringEmpty( void ) ; /* * initialize a handle with a buffer of size s */ string_t StringBuffer( size_t s ) ; /* * ininitialize a string handle by memcpy() length characters from a string * a NULL character will be appended to the string. */ string_t StringWithSize( const char * string,size_t length ) ; /* * Append a string pointer to by s into a string handled by handle st * * On success,a concatenated string is returned. * On error,NULL is returned and the original string remain intact. */ const char * StringAppend( string_t st,const char * s ) ; /* * Append a u_int64_t number to the string */ const char * StringAppendInt( string_t,u_int64_t ) ; /* * subsititue all occurance of string str with a number num */ const char * StringSubStringWithInt( string_t st,const char * str,u_int64_t num ) ; /* * Append multitple const char * strings to a string handled by handle st. * NOTE: The list must be terminated a NULL character. * example usage * string_t st = String( "abc" ) ; * StringMultipleAppend( st,"def","ghi",NULL ) ; */ const char * StringMultipleAppend( string_t st,... ) __attribute__ ( ( sentinel ) ) ; /* * Append a string handled by xt into a string handled by handle st * * On success,a concatenated string is returned. * On error,NULL is returned and the original string remain intact. */ const char * StringAppendString( string_t st,string_t xt ) ; /* * check if a string handled by st has str in it * return 1 if str is found * return 0 if str is not found */ int StringContains( string_t st,const char * str ) ; /* * check if a string handled by st has str in it * return 0 if str is found * return 1 if str is not found */ static __inline__ int StringDoesNotContain( string_t st,const char * str ) { return !StringContains( st,str ) ; } /* * Append multiple string_t to a string handled by handle st . * Same requirement as StringMultipleAppend apply * NOTE:The series must be NULL terminated. */ const char * StringAppendMultipleString( string_t st,... ) __attribute__ ( ( sentinel ) ) ; /* * Append a char c into a string handled by handle st * * On success,a concatenated string is returned. * On error,NULL is returned and the original string remain intact. */ const char * StringAppendChar( string_t st,char c ) ; /* * Prepend a string pointed to by s into a string handled by handle st * * On success,a concatenated string is returned * On error,NULL is returned and the original string remain intact */ const char * StringPrepend( string_t st,const char * s ) ; /* * prepend multiple const char * to a string handled by string_t st. * NOTE: entries will be prepended in the order they are presented * NOTE: a list of entries must be NULL terminated * example usage * string_t st = String( "ghi" ) ; * StringMultipleAppend( st,"def","abc",NULL ) ; */ const char * StringMultiplePrepend( string_t st,... ) __attribute__ ( ( sentinel ) ) ; /* * prepend multiple string_t to a string handled by string_t st. * NOTE: entries will be prepended in the order they are presented * NOTE: a list of entries must be NULL terminated */ const char * StringMultiplePrependString( string_t st,... ) __attribute__ ( ( sentinel ) ) ; /* * Prepend a string_t xt into a string handled by handle st * * On success,a concatenated string is returned * On error,NULL is returned and the original string remain intact */ const char * StringPrependString( string_t st,string_t xt ) ; /* * Prepend a char c into a string handled by handle st * * On success,a concatenated string is returned * On error,NULL is returned and the original string remain intact */ const char * StringPrependChar( string_t st,char c ) ; /* * Inherit a string pointed to by data and return a string handle to the string on success or NULL on error. * This function should inherit strings only from a dynamically created memory. * The original string remains intact when the function error out. */ string_t StringInherit( char ** data ) ; /* * Inherit a string of size s pointed to by data and return a string handle to the string on success or NULL on error. * This function should inherit strings only from a dynamically created memory. * The original string remains intacct when the function error out. * size is the size of the string * length is the size of the buffer holding the string */ string_t StringInheritWithSize( char ** data,size_t size,size_t length ) ; /* * Returns a const pointer to a string handled by handle st. * The returned pointer is guaranteed to be valid only if no further operation is performed on the string. */ static __inline__ const char * StringContent( string_t st ) ; /* * This function returns a pointer to a string and is guaranteed to be valid as long as StringDelete() is * not called on the string. * * The underlying string can be obtained after the returned double pointer is derefenced. */ static __inline__ const char ** StringPointer( string_t st ) ; /* * printf() the string handled by handle st * */ void StringPrint( string_t st ) ; /* * printf() the string handled by handle st and followed by a newline * it has the same effect as StringPrint() followed by printf("\n") */ void StringPrintLine( string_t st ) ; /* * Returns an editable string copy of a string handled by handle st. * Remember to free it when you are done using it. * NULL is returned when the copy can not be made. */ char * StringCopy_1( string_t st ) ; /* * Make a copy of string_t st * return NULL on error. */ string_t StringCopy( string_t st ) ; /* * returns a copy of a string. * remember to free() it when done with it */ char * StringCopy_2( const char * ) ; /* * Returns an editable copy of a string made up of upto x characters * Remember to free string when you are done with it. * returns NULL on error. * */ char * StringCopy_3( string_t st,size_t x ) ; /* * Write "size" amount of content of a string handled by "st" to a buffer pointed by "buffer" * */ void StringReadToBuffer( string_t st,char * buffer,size_t size ) ; /* * Remember to clean after yourself. * Always call this function when you are done with the string handled by handle st. * The function will not attempt to double delete,or delete unassigned handle( NULL handle ),for * this to work,make sure your handles are NULL ininitialized. * NULL is assigned to handle to invalidate it */ void StringDelete( string_t * st ); /* * convert all upper case characters to lower case */ const char * StringToLowerCase( string_t ) ; /* * clear the string before StringDelete() it */ void StringClearDelete( string_t * st ) ; /* * Remember to clean after yourself. * delete multitple string_t objects. * NOTE: a list of entries must be NULL terminated * The function will not attempt to double delete,or delete unassigned handle( NULL handle ),for * this to work,make sure your handled are NULL ininitialized. * NULL is assigned to each handle to invalidate them */ void StringMultipleDelete( string_t * st,... ) __attribute__ ( ( sentinel ) ) ; /* * input argument: String handle * return value: a pointer to the string managed by the handle. * * This function deletes the handle presented through argument st and returns * a pointer to the string handled by st. * * Remember to free the pointer( using free() ) when you are done with it * * Use this function when you no longer need the handle i.e dont want to do string * manipulation through the handle but want the pointer to the string it managed. */ char * StringDeleteHandle( string_t * st ) ; /* * Return the length of the string handled by handle st. */ size_t StringLength( string_t st ) ; /* * Return 1 if the the length of the string managed by st equals s. * Return 0 otherwise. */ int StringLengthMatch( string_t st,size_t s ) ; /* * Return a character at position p.First position is at "0". * * NOTE: it is your responsibility to make sure p is within range */ char StringCharAt( string_t st,size_t p ) ; /* * Returns the last character in the string */ char StringCharAtLast( string_t st ) ; /* * return the position of the first occurance of character s starting from position p. * * -1 is returned if the character is not in the string. * * NOTE: first character in the string is at position 0 */ ssize_t StringIndexOfChar( string_t st,size_t p,char s ) ; /* * return the position of the first occurance of string s starting from position p. * * -1 is returned if s isnt in the string * * NOTE: first character in the string is at position 0 */ ssize_t StringIndexOfString( string_t st,size_t p,const char * s ) ; /* * Return the position of the last occurance of character s * * -1 is returned if the character isnt in the string */ ssize_t StringLastIndexOfChar( string_t st,char s ) ; /* * Returns the last occurance of a string pointed by s * * -1 is returned of the string is not found. * * NOTE: first character in the string is at position 0 * */ ssize_t StringLastIndexOfString( string_t st,const char * s ) ; /* * Return a const string starting at position p. First position is at 0 * * NOTE: it is your responsibility to make sure p is within range. */ const char * StringStringAt( string_t st,size_t p ) ; /* * return 1 if a string is a part of stringlist * return 0 otherwise or if StringVoid */ int StringOwned( string_t ) ; /* * call mlock() on the string */ int StringLock( string_t ) ; /* * call munlock() on the string */ int StringUnlock( string_t ) ; /* * Check to see if the string pointer by st ends with string s. * * return 1 is it does * * return 0 if it doesnt */ int StringEndsWith( string_t st,const char * s ) ; /* * Check to see if a string e ends with string s. * * return 1 is it does * * return 0 if it doesnt */ int StringEndsWith_1( const char * e,const char * s ) ; /* * Check to see if string e ends with atleast one of other arguments. * * return 1 is it does * * return 0 if it doesnt */ int StringEndsWithAtLeastOne( const char * e,... ) __attribute__ ( ( sentinel ) ) ; /* * Check to see if a string e ends with a string s. * * return 1 is it does * * return 0 if it doesnt */ int StringEndsWith_2( string_t e,string_t s ) ; /* * check to see if the string handled by handle st starts with a string s * return 1 if it does * return 0 if it doesnt */ int StringStartsWith( string_t st,const char * s ) ; /* * check to see if the string handled by handle st starts with a string handled by handle xt * return 1 if it does * return 0 if it doesnt */ int StringStartsWith_1( string_t st,string_t xt ) ; /* * check if string a starts with string b and ends with string c * return 1 if it does * return 0 if it doesnt */ int StringStartsAndEndsWith( const char * a,const char * b,const char * c ) ; /* * check to see the string_t object starts with atleast one of the arbitrary number of cstrings * return 1 if it does * return 0 if it does not * * exampe: * st = String( "abcdef" ) ; * int r = StringStartsWithAtLeastOne( st,"rrr","www","abc",NULL ) ; * r will contain "1" since "abc" argument match the beginning of the string_t object * NOTE:The series must be NULL terminated. */ int StringStartsWithAtLeastOne( string_t st,... ) __attribute__ ( ( sentinel ) ) ; /* *Check to see if the string pointer by st ends with char s. * * return 1 is it does * * return 0 if it doesnt * */ int StringEndsWithChar( string_t st,char s ) ; /* * Insert a string s from position x and returns a pointer to the new string * * on error returns NULL and the original string remains intact */ const char * StringInsertString( string_t st,size_t x,const char * s ) ; /* * Insert a char s at position x and returns a pointer to the new string * * on error returns NULL and the original string remains intact */ const char * StringInsertChar( string_t st,size_t x,char s ) ; /* * subsititue whatever character is at position x by character s * returns a pointer to the string containing the subsititue */ const char * StringSubChar( string_t st,size_t x,char s ) ; /* * start from position x and subsititue all characters in the string by string s. * returns a pointer with the substitution. */ const char * StringSubString( string_t st,size_t x,const char * s ) ; /* * remove all character after index x and then insert string s at index. */ const char * StringAppendAt( string_t st,size_t x,const char * s ) ; /* * start at position x and remove y character(s) going right and returns a pointer * to the new string or NULL on error and the original string remain intact. * Careful though,make sure you dont delete past the string length */ const char * StringRemoveLength( string_t st,size_t x,size_t y ) ; /* * remove all occurances of string s in a string handled by handle st. * return a pointer to the resulting string on success and NULL on error and the original string * remain intact * */ const char * StringRemoveString( string_t st,const char * s ) ; /* * starting at position p,remove all occurances of string s in a string handled by handle st. * return a pointer to the resulting string on success and NULL on error and the original string * remain intact * */ const char * StringRemoveStringPos( string_t st,const char * s,size_t p ) ; /* * remove the first x characters counting from the right ie,remove the last x characters from the string * Returns a pointer to the result,NULL on error and the original string remain intact */ const char * StringRemoveRight( string_t st,size_t x ) ; /* * Clear the string by writing '\0' using memset() essentiall wipe out all of its current content. * This is a bit more expensive but useful if you want to start afresh with an empty string. */ void StringClear( string_t st ) ; /* * forget about all content in the string and start afresh as if the string is not allocated. * The old data is still there and will be overwritten by new data as the string get filled up */ void StringReset( string_t st ) ; /* * remove the first x characters from the string counting from the left * Returns a pointer to the result,NULL on error and the original string remain intact */ const char * StringRemoveLeft( string_t st,size_t x ) ; /* * remove all occurances numbers in the string,ie '0','1','2' etc */ const char * StringRemoveDigits( string_t ) ; /* * Return a sub string starting at position x and made up of y characters * * NULL is returned if the operation fail. * * Remember to free the returned string when done with it. * */ string_t StringMidString( string_t st,size_t x,size_t y ) ; /* * replace all occurance of string x by string y * return a pointer to the resulting string on success or NULL on error and the original string * remain intact. */ const char * StringReplaceString( string_t st,const char * x,const char * y ) ; /* * replace the string managed by string_t object by string str * return a pointer to the new string managed by string_t object or NULL if either of the argument is NULL */ const char * StringReplace( string_t,const char * str ) ; /* * starting at position p,replace all occurance of string x by string y * return a pointer to the resulting string on success or NULL on error and the original string * remain intact. */ const char * StringReplaceStringPos( string_t st,const char * x,const char * y,size_t p ) ; /* * replace all occurance of char x by char y * Return a const pointer to a modified string */ const char * StringReplaceChar( string_t st,char x,char y ) ; /* * start at index z,replace the first occurance of character x by character y * Only the first character will be subsituted if found * NULL is returned if substitution could not take place * modified string is returned if substitution took place */ const char * StringReplaceChar_1( string_t st,size_t z,char x,char y ) ; /* * starting at position p,replace all occurance of char x by char y * Return a const pointer to a modified string */ const char * StringReplaceCharPos( string_t st,char x,char y,size_t p ) ; /* * Replace all characters in y by x in a string handled by st */ const char * StringReplaceCharString( string_t st,char x,const char * y ) ; /* * Starting at position,Replace all characters in y by x in a string handled by st */ const char * StringReplaceCharStringPos( string_t st,char x,const char * y,size_t p ) ; /* * convert a number z into a string and store the result into array x of size y. * * return value: a pointer to the beginning of the result(use this pointer and not x). * * NOTE: Its your responsibility to make sure the resulting string fit into array x. * If z has N digits,then the array must be atleast N+1 in size,null character * takes the last spot. */ char * StringIntToString_1( char * x,size_t y,u_int64_t z ) ; /* * convert a number z into a string */ string_t StringIntToString( u_int64_t ) ; /* * convert a string made up of digits to a u_int64_t value * eg: * u_int64_t x = StringConvertToInt( "43542" ) ; */ u_int64_t StringConvertToInt( const char * ) ; /* * Compare a string handled by handle x to a string handled by handle y. * return 1 if they are equal * return 0 if they are not equal */ int StringsAreEqual_1( string_t x,string_t y ) ; /* * Compare a string handled by handle x to a string pointer to by y. * return 1 if they are equal * return 0 if they are not equal */ int StringsAreEqual_2( string_t x,const char * y ) ; /* * return 1 if x holds an empty string * return 0 if x holds a non empty string * return 0 if x is StringVoid */ int StringIsEmpty( string_t x ) ; /* * Compare a string handled by handle x to a string pointer to by y. * return 0 if they are equal * return 1 if they are not equal */ static __inline__ int StringsAreNotEqual_2( string_t x,const char * y ) { return !StringsAreEqual_2( x,y ) ; } /* * compare string managed by x with a series of cstrings and return true if atleast one of them match * NOTE:the series of strings must be NULL terminated * eg. * string_t st = String( "abc" ) ; * int equal = StringMatchOneAtLeastOne( st,"def","ugf",NULL ) ; */ int StringAtLeastOneMatch( string_t x,... ) __attribute__ ( ( sentinel ) ) ; /* * compare cstring x with a series of cstrings and return true if atleast one of them match * NOTE:the series of strings must be NULL terminated * eg. * int equal = StringMatchOneAtLeastOne_1( "def","ugf","rrt",NULL ) ; */ int StringAtLeastOneMatch_1( const char * x,... ) __attribute__ ( ( sentinel ) ) ; /* * Insert character x infront of every character that appear in string y in a string handled by handle st. * Retun a poiter to the final string on success and NULL on error and the original string remain intact */ const char * StringInsertCharString( string_t st,char x,const char * y ) ; /* * Starting at position p,insert character x infront of every character that appear in string y in a string handled by handle st. * Retun a poiter to the final string on success and NULL on error and the original string remain intact */ const char * StringInsertCharStringPos( string_t st,char x,const char * y,size_t p ) ; /* * Insert character x infront of every character y in a string handled by handle st. * Retun a poiter to the final string on success and NULL on error and the original string remain intact */ const char * StringInsertCharChar( string_t st,char x,char y ) ; /* * Crop off the first x elements and the last y elements from the string handled by handle st * * Return a pointer to the cropped string on success and NULL on error and the original string remain intact. * NULL is also returned if cropping will result in less that zero characters in the string */ const char * StringCrop( string_t st,size_t x,size_t y ) ; /* * getchar() until a newline or EOF character is reached and put the characters to a string_t object * The function basically get its content from the terminal ( stdin ) . * NULL is returned if sufficient memory can not be optained to hold terminal content. */ string_t StringGetFromTerminal( void ) ; /* * getchar() of upto s characters or until a newline or EOF character is reached and put the characters to a string_t object * The function basically get its content from the terminal ( stdin ) . * NULL is returned if sufficient memory can not be optained to hold terminal content. */ string_t StringGetFromTerminal_1( size_t s ) ; /* * Turn echo off and get string from the terminal. * This function is ideal for reading passphrases from the terminal. * 1 is returned when character echoing can not be turned off. * 2 is returned if sufficient memory can not be optained to hold terminal content. * 0 is returned on success. */ int StringSilentlyGetFromTerminal( string_t * ) ; /* * Turn echo off and get a string of upto s characters from the terminal. * This function is ideal for reading passphrases from the terminal. * 1 is returned when character echoing can not be turned off. * 2 is returned if sufficient memory can not be optained to hold terminal content. * 0 is returned on success. */ int StringSilentlyGetFromTerminal_1( string_t *,size_t s ) ; /* * Open a file given by path and return a string_t handle * * NULL is returned if the file could not be opened for reading or could not get sufficient memory to hold the file. */ string_t StringGetFromFile( const char * path ) ; /* * constract a string_t object with size random characters read from "/dev/urandom. * StringVoid is returned on error. */ string_t StringRandomString( size_t size ) ; /* * Open a file given by path and return a string_t handle through agrument st with the content of the file . * return value: 0 - opefation succeeded. * 1 - path is invalid. * 2 - could not open file for reading. * 3 - could not allocate memory to host file content */ int StringGetFromFile_1( string_t * st,const char * path ) ; /* * Open a file given by path and return a string_t handle through agrument st with the content of the file . * Start reading the file from offset byte and read length bytes. * return value: 0 - opefation succeeded. * 1 - path is invalid. * 2 - could not open file for reading. * 3 - could not allocate memory to host file content */ int StringGetFromFile_3( string_t * st,const char * path,size_t offset,size_t length ) ; /* * Open a file given by path and return a string_t handle with hhe content of the file . * return value through status: * 0 - opefation succeeded. * 1 - path is invalid. * 2 - could not open file for reading. * 3 - could not allocate memory to host file content * * This function does the same thing the previous one does,the different is how return values are returned. */ string_t StringGetFromFile_2( const char * path,int * status ) ; /* * reads a maximum of "length" bytes from a file given by "path" argument starting at "offset" offset * and then lock the memory buffer. * return values: * 0 - success * 1 - file operation failed * 2 - memory operation failed * * The mlock()ed string object will be returned through str argument * negative value of length means reads the entire file content * * warning memory may or may not lock */ int StringGetFromFileMemoryLocked( string_t * str,const char * path,size_t offset,ssize_t length ) ; /* * White the string managed by handle st to a file given by path and return the number of bytes written. * */ #define CREATE 1 /*if the file does not exist,create it,if the file exist,trancate it*/ #define APPEND 2 /* if the file exist,append it*/ void StringWriteToFile( string_t st,const char * path,int mode ) ; /* * Open a virtual file given by path return a string_t handle with the content of the file. * Virtual files are like those in /proc,you cab read stuff from them but their sizes are always zero */ string_t StringGetFromVirtualFile( const char * path ) ; /* * below two functions creates a hash of the string using junkin's one at a time hash algorithm */ u_int32_t StringJenkinsOneAtATimeHash( const char * key ) ; u_int32_t StringJenkinsOneAtATimeHash_1( string_t ) ; /* * a few convenient "safe" functions */ /* * why doesnt free() take const void * ???? */ static __inline__ void StringFree( const void * str ) { free( ( void * )str ) ; } /* * safely do free( *dev ) followed by *dev = NULL * this function hence should take only a double pointer. * ie * char * e = malloc(sizeof(char)) ; * ..; * StringFree_1(&e); */ static __inline__ void StringFree_1( const void * str ) { char ** c ; if( str != NULL ){ c = ( char ** ) str ; free( *c ) ; *c = NULL ; } } static __inline__ size_t StringSize( const char * str ) { if( str == NULL ){ return 0 ; }else{ return strlen( str ) ; } } static __inline__ int StringsAreEqual( const char * x,const char * y ) { if( x == NULL || y == NULL ){ return 0 ; }else{ return strcmp( x,y ) == 0 ; } } static __inline__ int StringHasNothing( const char * x ) { return x != NULL && *x == '\0' ; } static __inline__ int StringsAreNotEqual( const char * x,const char * y ) { if( x == NULL || y == NULL ){ return 1 ; }else{ return strcmp( x,y ) != 0 ; } } static __inline__ int StringPrefixMatch( const char * x,const char * y,size_t z ) { if( x == NULL || y == NULL ){ return 0 ; }else{ return strncmp( x,y,z ) == 0 ; } } /* * returns true if a atleast one cstring in the series starts with x * NOTE:The series must be NULL terminated. */ int StringAtLeastOnePrefixMatch( const char * x,... ) __attribute__ ( ( sentinel ) ) ; /* * returns true if atleast one cstring is a component of x * NOTE:The series must be NULL terminated. */ int StringHasAtLeastOneComponent_1( const char * x,... ) __attribute__ ( ( sentinel ) ) ; /* * returns true if atleast one cstring is a component of a string managed by object st * NOTE:The series must be NULL terminated. */ int StringHasAtLeastOneComponent( string_t st,... ) __attribute__ ( ( sentinel ) ) ; static __inline__ int StringPrefixEqual( const char * x,const char * y ) { if( x == NULL || y == NULL ){ return 0 ; }else{ return strncmp( x,y,strlen( y ) ) == 0 ; } } static __inline__ int StringPrefixNotEqual( const char * x,const char * y ) { if( x == NULL || y == NULL ){ return 0 ; }else{ return strncmp( x,y,strlen( y ) ) != 0 ; } } static __inline__ ssize_t StringHasComponent_1( const char * x,const char * y ) { char * e ; if( x == NULL || y == NULL ){ return -1 ; }else{ e = strstr( x,y ) ; if( e == NULL ){ return -1 ; }else{ return e - x ; } } } static __inline__ size_t StringCharCount( const char * x,char y ) { size_t s = 0 ; char m ; if( x != NULL ){ while( 1 ){ m = *x ; x++ ; if( m == y ){ s++ ; }else if( m == '\0' ){ break ; } } } return s ; } static __inline__ int StringHasComponent( const char * x,const char * y ) { if( x == NULL || y == NULL ){ return 0 ; }else{ return strstr( x,y ) != NULL ; } } static __inline__ int StringHasNoComponent( const char * x,const char * y ) { if( x == NULL || y == NULL ){ return 0 ; }else{ return strstr( x,y ) == NULL ; } } static __inline__ ssize_t StringLastIndexOfChar_1( const char * str,char s ) { const char * c ; if( str == NULL ){ return -1 ; }else{ c = strrchr( str,s ) ; if( c == NULL ){ return -1 ; }else{ return c - str ; } } } static __inline__ ssize_t StringFirstIndexOfChar_1( const char * str,char s ) { if( str == NULL ){ return -1 ; }else{ return strchr( str,s ) - str ; } } static __inline__ const char ** StringPointer( string_t st ) { return ( const char ** ) st ; } static __inline__ const char * StringContent( string_t st ) { const char ** e = StringPointer( st ) ; if( e == NULL ){ return NULL ; }else{ return *e ; } } #ifdef __cplusplus } #endif #endif zuluCrypt-6.2.0/zuluCrypt-cli/utility/string/StringList.c000066400000000000000000000575331425361753700236370ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "StringList.h" /* * buffer size will grow exponentially by a multiple of this number */ #define FACTOR 2 /* * initial buffer size */ #define INIT_SIZE 8 struct StringListType { size_t size ; /* size of the array*/ size_t length ; /* size of the buffer of thr array */ string_t * stp ; /* pointer to String_t array */ }; struct StringType { char * string ; size_t size ; size_t length ; int owned ; }; static void _f( void ) { } static void ( *_memory_error )( void ) = _f ; void StringListExitOnMemoryExaustion( void ( *f )( void ) ) { _memory_error = f ; } static void * _StringListError( void ) { _memory_error() ; return NULL ; } void StringListForEach( stringList_t stl,void (*fct)( string_t ) ) { size_t i ; size_t j ; string_t * q ; string_t p ; if( stl != StringListVoid ){ j = stl->size ; q = stl->stp ; for( i = 0 ; i < j ; i++ ){ p = *( q + i ) ; if( p != StringVoid ){ fct( p ) ; } } } } void StringListForEach_1( stringList_t stl,void (*fct)( string_t,void * ),void * arg ) { size_t i ; size_t j ; string_t * q ; string_t p ; if( stl != StringListVoid ){ j = stl->size ; q = stl->stp ; for( i = 0 ; i < j ; i++ ){ p = *( q + i ) ; if( p != StringVoid ){ fct( p,arg ) ; } } } } void StringListForEachString( stringList_t stl,void (*fct)( const char * ) ) { size_t i ; size_t j ; string_t * q ; string_t p ; if( stl != StringListVoid ){ j = stl->size ; q = stl->stp ; for( i = 0 ; i < j ; i++ ){ p = *( q + i ) ; if( p != StringVoid ){ fct( p->string ) ; } } } } void StringListForEachString_1( stringList_t stl,void (*fct)( const char *,void * ),void * arg ) { size_t i ; size_t j ; string_t * q ; string_t p ; if( stl != StringListVoid ){ j = stl->size ; q = stl->stp ; for( i = 0 ; i < j ; i++ ){ p = *( q + i ) ; if( p!= StringVoid ){ fct( p->string,arg ) ; } } } } static inline string_t * __ExpandMemory( stringList_t stl ) { string_t * p ; if( stl->size >= stl->length ){ stl->length = stl->length * FACTOR ; p = realloc( stl->stp,sizeof( string_t ) * ( stl->length ) ) ; if( p == NULL ){ return _StringListError() ; }else{ return p ; } }else{ return stl->stp ; } } stringList_t StringList( const char * cstring ) { stringList_t stl ; if( cstring == NULL ){ return StringListVoid ; } stl = malloc( sizeof( struct StringListType ) ) ; if( stl == NULL ){ return _StringListError() ; } stl->stp = malloc( sizeof( string_t ) * INIT_SIZE ) ; if( stl->stp == NULL ){ free( stl ) ; return _StringListError() ; } stl->stp[0] = String( cstring ) ; if( stl->stp[0] == StringVoid ){ free( stl->stp ) ; free( stl ) ; return _StringListError() ; }else{ stl->stp[0]->owned = 1 ; stl->size = 1 ; stl->length = INIT_SIZE ; return stl ; } } StringListIterator StringListBegin( stringList_t stl ) { if( stl == StringListVoid ){ return NULL ; }else{ return stl->stp ; } } StringListIterator StringListEnd( stringList_t stl ) { if( stl == StringListVoid ){ return NULL ; }else{ return stl->stp + stl->size ; } } void StringListGetIterators( stringList_t stl,StringListIterator * begin,StringListIterator * end ) { if( stl == StringListVoid ){ *begin = NULL ; *end = NULL ; }else{ *begin = stl->stp; *end = stl->stp + stl->size ; } } string_t * StringListAssign( stringList_t stl ) { string_t * p ; if( stl == StringListVoid ){ return NULL ; } p = __ExpandMemory( stl ) ; if( p == NULL ){ return _StringListError() ; }else{ stl->stp = p ; stl->stp[ stl->size ] = StringVoid ; p = &stl->stp[ stl->size ] ; stl->size = stl->size + 1 ; return p ; } } string_t * StringListArray( stringList_t * stz,size_t arraySize ) { stringList_t stl = malloc( sizeof( struct StringListType ) ) ; if( stl == NULL ){ return _StringListError() ; } stl->stp = malloc( sizeof( string_t ) * arraySize ) ; if( stl->stp == NULL ){ free( stl ) ; return _StringListError() ; } stl->size = arraySize ; stl->length = arraySize ; memset( stl->stp,'\0',sizeof( string_t ) * arraySize ) ; *stz = stl ; return stl->stp ; } string_t StringListAssignString( stringList_t stl,string_t st ) { string_t * p ; if( stl == StringListVoid ){ return st ; } p = __ExpandMemory( stl ) ; if( p == NULL ){ return _StringListError() ; }else{ stl->stp = p ; if( st != NULL ){ st->owned = 1 ; } stl->stp[ stl->size ] = st ; stl->size = stl->size + 1 ; return st ; } } stringList_t StringListInit( void ) { stringList_t stl = malloc( sizeof( struct StringListType ) ) ; if( stl == NULL ){ return _StringListError() ; } stl->stp = malloc( sizeof( string_t ) * INIT_SIZE ) ; if( stl->stp == NULL ){ free( stl ) ; return _StringListError() ; }else{ stl->size = 0 ; stl->length = INIT_SIZE ; return stl ; } } stringList_t StringListWithSize( char ** c, size_t s,size_t t ) { stringList_t stl ; if( c == NULL ){ return StringListVoid ; } stl = malloc( sizeof( struct StringListType ) ) ; if( stl == NULL ){ return _StringListError() ; } stl->stp = malloc( sizeof( string_t ) * INIT_SIZE ) ; if( stl->stp == NULL ){ free( stl ) ; return _StringListError() ; } stl->stp[0] = StringInheritWithSize( c,s,t ) ; if( stl->stp[0] == StringVoid ){ free( stl->stp ) ; free( stl ) ; return _StringListError() ; }else{ stl->stp[0]->owned = 1 ; stl->size = 1 ; stl->length = INIT_SIZE ; return stl ; } } stringList_t StringListAppendWithSize( stringList_t stl,char ** c, size_t s,size_t l ) { string_t * p ; string_t q ; if( stl == StringListVoid ){ return StringListWithSize( c,s,l ) ; } q = StringInheritWithSize( c,s,l ) ; if( q == StringVoid ){ return stl ; } p = __ExpandMemory( stl ) ; if( p == NULL ){ StringDelete( &q ) ; return _StringListError() ; }else{ stl->stp = p ; q->owned = 1 ; stl->stp[ stl->size ] = q ; stl->size = stl->size + 1 ; return stl ; } } stringList_t StringListAppendSize( stringList_t stl,const char * cstring,size_t len ) { stringList_t p ; char * c ; if( cstring == NULL ){ return stl ; } c = malloc( sizeof( char ) * ( len + 1 ) ) ; if( c == NULL ){ return _StringListError() ; } memcpy( c,cstring,len ) ; *( c + len ) = '\0' ; p = StringListAppendWithSize( stl,&c,len,len + 1 ) ; if( p == StringListVoid ){ free( c ) ; return _StringListError() ; }else{ return p ; } } stringList_t StringListAppendList( stringList_t p,stringList_t q ) { size_t j ; size_t i ; string_t * z ; string_t k ; if( q == StringListVoid ){ return p ; } if( p == StringListVoid ){ return StringListCopy( q ) ; } j = StringListSize( q ) ; z = q->stp ; for( i = 0 ; i < j ; i++ ){ k = *( z + i ) ; if( k != StringVoid ){ StringListAppendSize( p,k->string,k->size ) ; } } return p ; } stringList_t StringListAppendString( stringList_t stl,string_t st ) { if( st == StringVoid ){ return stl ; }else{ return StringListAppendSize( stl,st->string,st->size ) ; } } stringList_t StringListSplit( const char * cstring,char splitter ) { const char * b = cstring ; char * d ; char * e ; char s[ 2 ] ; size_t sp_len = sizeof( char ) ; size_t len ; stringList_t stl = StringListVoid ; stringList_t stx ; if( cstring == NULL ){ return StringListVoid ; } s[ 1 ] = '\0' ; s[ 0 ] = splitter ; while( 1 ){ d = strstr( b,s ) ; if( d == NULL ){ if( *b != '\0' ){ if( b == cstring || *b != splitter ){ stl = StringListAppend( stl,b ) ; } } break ; }else{ len = d - b ; if( len > 0 ){ e = malloc( sizeof( char ) * ( len + 1 ) ) ; if( e == NULL ){ StringListDelete( &stl ) ; return _StringListError() ; } memcpy( e,b,len ) ; *( e + len ) = '\0' ; stx = StringListAppendWithSize( stl,&e,len,len + 1 ) ; if( stx == StringListVoid ){ StringListDelete( &stl ) ; free( e ) ; return _StringListError() ; }else{ stl = stx ; } } b = d + sp_len ; } } return stl ; } stringList_t StringListStringSplit( string_t st,char splitter ) { if( st == StringVoid ){ return StringListVoid ; }else{ return StringListSplit( st->string,splitter ) ; } } size_t StringListSize( stringList_t stl ) { if( stl == StringListVoid ){ return 0 ; }else{ return stl->size ; } } const char * StringListContentAt( stringList_t stl,size_t index ) { if( stl == StringListVoid ){ return NULL ; }else{ if( index >= stl->size ){ return NULL ; }else{ return stl->stp[ index ]->string ; } } } int StringListContentAtEqual( stringList_t stl,size_t index,const char * cstring ) { if( stl == StringListVoid || cstring == NULL ){ return 0 ; }else{ if( index >= stl->size ){ return 0 ; }else{ return strcmp( stl->stp[ index ]->string,cstring ) == 0 ; } } } const char * StringListContentAtLast( stringList_t stl ) { if( stl == StringListVoid ){ return NULL ; }else{ if( stl->size < 1 ){ return NULL ; }else{ return stl->stp[ stl->size - 1 ]->string ; } } } string_t StringListStringAtLast( stringList_t stl ) { if( stl == StringListVoid ){ return StringVoid ; }else{ if( stl->size < 1 ){ return StringVoid ; }else{ return stl->stp[ stl->size - 1 ] ; } } } stringList_t StringListInsertAt( stringList_t stl,const char * cstring,size_t index ) { string_t * p ; string_t q ; size_t size = sizeof( string_t ) ; if( stl == StringListVoid ){ return StringListVoid ; } if( cstring == NULL ){ return stl ; } if( index > stl->size ){ return stl ; } q = String( cstring ) ; if( q == StringVoid ){ return _StringListError() ; } p = __ExpandMemory( stl ) ; if( p == NULL ){ StringDelete( &q ) ; return _StringListError() ; }else{ stl->stp = p ; memmove( stl->stp + index + 1,stl->stp + index,size * ( stl->size - index ) ) ; q->owned = 1 ; stl->stp[index] = q ; stl->size = stl->size + 1 ; return stl ; } } static int _StringListStringInsertAt( stringList_t stl,string_t * st,size_t index ) { string_t * p ; size_t size = sizeof( string_t ) ; if( stl == StringListVoid ){ return 0 ; } if( index > stl->size ){ return 0 ; } p = __ExpandMemory( stl ) ; if( p == NULL ){ _StringListError() ; return 0 ; }else{ stl->stp = p ; memmove( stl->stp + index + 1,stl->stp + index,size * ( stl->size - index ) ) ; stl->stp[index] = *st ; if( stl->stp[index] != StringVoid ){ stl->stp[index]->owned = 1 ; } stl->size = stl->size + 1 ; return 1 ; } } static int _StringListString( string_t * st,stringList_t * r ) { stringList_t stl = malloc( sizeof( struct StringListType ) ) ; if( stl == NULL ){ _StringListError() ; return 0 ; } stl->stp = malloc( sizeof( string_t ) * INIT_SIZE ) ; if( stl->stp == NULL ){ free( stl ) ; _StringListError() ; return 0 ; } if( *st != StringVoid ){ stl->stp[ 0 ] = *st ; stl->stp[ 0 ]->owned = 1 ; }else{ stl->stp[ 0 ] = StringVoid ; } stl->size = 1 ; stl->length = INIT_SIZE ; *r = stl ; return 1 ; } stringList_t StringListString( string_t * st ) { stringList_t stl = StringListVoid ; if( st && *st ){ if( _StringListString( st,&stl ) ){ *st = StringVoid ; } } return stl ; } void StringListAppendString_1( stringList_t * stl,string_t * st ) { if( st && *st && stl ){ if( *stl == StringListVoid ){ if( _StringListString( st,stl ) ){ *st = StringVoid ; } }else{ if( _StringListStringInsertAt( *stl,st,( *stl )->size ) ){ *st = StringVoid ; } } } } stringList_t StringListStringInsertAt( stringList_t stl,string_t * st,size_t index ) { if( st && *st ){ if( _StringListStringInsertAt( stl,st,index ) ){ *st = StringVoid ; } } return stl ; } stringList_t StringListInsertAtSize( stringList_t stl,const char * cstring,size_t len,size_t index ) { char * c ; string_t * p ; string_t q ; size_t size = sizeof( string_t ) ; if( stl == StringListVoid || cstring == NULL ){ return stl ; } if( index > stl->size ){ return stl ; } c = malloc( sizeof( char ) * ( len + 1 ) ) ; if( c == NULL ){ return _StringListError() ; } memcpy( c,cstring,len ); *( c + len ) = '\0' ; q = StringInheritWithSize( &c,len,len + 1 ) ; if( q == StringVoid ){ free( c ) ; return _StringListError() ; } p = __ExpandMemory( stl ) ; if( p == NULL ){ StringDelete( &q ) ; return _StringListError() ; }else{ stl->stp = p ; memmove( stl->stp + index + 1,stl->stp + index,size * ( stl->size - index ) ) ; q->owned = 1 ; stl->stp[index] = q ; stl->size = stl->size + 1 ; return stl ; } } stringList_t StringListPrependSize( stringList_t stl,const char * cstring,size_t len ) { char * c ; stringList_t p ; if( cstring == NULL ){ return stl ; } if( stl == StringListVoid ){ c = malloc( sizeof( char ) * ( len + 1 ) ) ; if( c == NULL ){ return _StringListError() ; } memcpy( c,cstring,len ) ; *( c + len ) = '\0' ; p = StringListWithSize( &c,len,len + 1 ) ; if( p == StringListVoid ){ free( c ) ; return _StringListError() ; }else{ return p ; } }else{ return StringListInsertAtSize( stl,cstring,len,0 ) ; } } stringList_t StringListPrepend( stringList_t stl,const char * cstring ) { if( stl == StringListVoid ){ return StringList( cstring ) ; }else{ return StringListInsertAt( stl,cstring,0 ) ; } } stringList_t StringListAppend( stringList_t stl,const char * cstring ) { string_t q ; if( stl == StringListVoid ){ return StringList( cstring ) ; } if( cstring == NULL ){ return stl ; } q = String( cstring ) ; if( q == StringVoid ){ return _StringListError() ; } stl->stp = __ExpandMemory( stl ) ; if( stl->stp == NULL ){ StringDelete( &q ) ; return _StringListError() ; }else{ q->owned = 1 ; stl->stp[ stl->size ] = q ; stl->size = stl->size + 1 ; return stl ; } } stringList_t StringListAppendIfAbsent( stringList_t stl,const char * cstring ) { if( stl == StringListVoid ){ return StringList( cstring ) ; }else{ if( StringListContains( stl,cstring ) == -1 ){ StringListAppend( stl,cstring ) ; } return stl ; } } ssize_t StringListContains( stringList_t stl,const char * cstring ) { size_t i ; size_t size ; string_t * k ; string_t e ; if( stl == StringListVoid || cstring == NULL ){ return -1 ; } size = stl->size ; k = stl->stp ; for( i = 0 ; i < size ; i++ ){ e = *( k + i ) ; if( e != StringVoid ){ if( strcmp( e->string,cstring ) == 0 ){ return i ; } } } return -1 ; } ssize_t StringListHasSequence( stringList_t stl,const char * str ) { size_t i ; size_t size ; string_t * k ; string_t e ; if( stl == StringListVoid || str == NULL ){ return -1 ; } size = stl->size ; k = stl->stp ; for( i = 0 ; i < size ; i++ ){ e = *( k + i ) ; if( e != StringVoid ){ if( strstr( e->string,str ) != NULL ){ return i ; } } } return -1 ; } string_t StringListHasSequence_1( stringList_t stl,const char * str ) { ssize_t e = StringListHasSequence( stl,str ) ; if( e == -1 ){ return StringVoid ; }else{ return *( stl->stp + e ) ; } } ssize_t StringListHasStartSequence( stringList_t stl,const char * str ) { size_t i ; size_t size ; string_t * k ; string_t e ; size_t len ; if( stl == StringListVoid || str == NULL ){ return -1 ; } len = strlen( str ) ; size = stl->size ; k = stl->stp ; for( i = 0 ; i < size ; i++ ){ e = *( k + i ) ; if( e != StringVoid ){ if( strncmp( e->string,str,len ) == 0 ){ return i ; } } } return -1 ; } string_t StringListHasStartSequence_1( stringList_t stl,const char * str ) { ssize_t e = StringListHasStartSequence( stl,str ) ; if( e == -1 ){ return StringVoid ; }else{ return *( stl->stp + e ) ; } } const char ** StringListStringArray( stringList_t stl ) { size_t i ; size_t j ; const char ** q ; string_t * p ; string_t z ; if( stl == StringListVoid ){ q = malloc( sizeof( char * ) ) ; if( q == NULL ){ return _StringListError() ; }else{ *q = NULL ; } }else{ j = stl->size ; p = stl->stp ; q = malloc( sizeof( char * ) * ( j + 1 ) ) ; if( q == NULL ){ return _StringListError() ; } *( q + j ) = NULL ; for( i = 0 ; i < j ; i++ ){ z = *( p + i ) ; if( z != StringVoid ){ *( q + i ) = z->string ; }else{ *( q + i ) = NULL ; } } } return q ; } void StringListStringArray_1( char * const ** buffer,size_t * size ,stringList_t stl ) { size_t i ; size_t j ; string_t * p ; string_t z ; char ** e ; if( buffer == NULL || size == NULL || stl == StringListVoid ){ return ; } e = ( char ** ) *buffer ; j = stl->size ; p = stl->stp ; if( *size < j ){ e = realloc( e,sizeof( char * ) * ( j + 1 ) ) ; if( e == NULL ){ _StringListError() ; *size = 0 ; }else{ *size = j ; *( e + j ) = NULL ; } } for( i = 0 ; i < j ; i++ ){ z = *( p + i ) ; if( z != StringVoid ){ *( e + i ) = z->string ; }else{ *( e + i ) = NULL ; } } *buffer = e ; } size_t StringListRemoveIfStringStartsWith( stringList_t stl,const char * str ) { string_t z ; string_t * it ; string_t * end ; string_t * result ; size_t count = 0 ; size_t len ; if( stl == StringListVoid || str == NULL ){ return 0 ; } it = stl->stp ; end = it + stl->size ; result = it ; count = 0 ; len = strlen( str ) ; while( it != end ){ z = *it ; it++ ; if( z != StringVoid ){ if( strncmp( z->string,str,len ) == 0 ){ free( z->string ) ; free( z ) ; count++ ; stl->size-- ; }else{ *result = z ; result++ ; } }else{ *result = z ; result++ ; } } return count ; } size_t StringListRemoveIfPresent_1( stringList_t stl,string_t st ) { return StringListRemoveIfPresent( stl,st->string ) ; } size_t StringListRemoveIfPresent( stringList_t stl,const char * str ) { string_t z ; string_t * it ; string_t * end ; string_t * result ; size_t count = 0 ; if( stl == StringListVoid || str == NULL ){ return 0 ; } it = stl->stp ; end = it + stl->size ; result = it ; count = 0 ; while( it != end ){ z = *it ; it++ ; if( z != StringVoid ){ if( strcmp( z->string,str ) == 0 ){ free( z->string ) ; free( z ) ; count++ ; stl->size-- ; }else{ *result = z ; result++ ; } }else{ *result = z ; result++ ; } } return count ; } size_t StringListRemoveIfStringContains( stringList_t stl,const char * str ) { string_t z ; string_t * it ; string_t * end ; string_t * result ; size_t count = 0 ; if( stl == StringListVoid || str == NULL ){ return 0 ; } it = stl->stp ; end = it + stl->size ; result = it ; count = 0 ; while( it != end ){ z = *it ; it++ ; if( z != StringVoid ){ if( strstr( z->string,str ) != NULL ){ free( z->string ) ; free( z ) ; count++ ; stl->size-- ; }else{ *result = z ; result++ ; } }else{ *result = z ; result++ ; } } return count ; } stringList_t StringListRemoveAt( stringList_t stl, size_t index ) { size_t size ; if( stl == StringListVoid ){ return StringListVoid ; } if( index >= stl->size ){ return stl ; } size = sizeof( string_t ) ; if( stl->stp[index] != StringVoid ){ stl->stp[index]->owned = 0 ; } StringDelete( &stl->stp[index] ) ; memmove( stl->stp + index,stl->stp + index + 1,size * ( stl->size - 1 - index ) ) ; stl->size = stl->size - 1 ; return stl ; } void StringListRemoveAt_1( stringList_t stl,StringListIterator at,StringListIterator * end ) { StringListRemoveAt( stl,at - stl->stp ) ; *end = *end - 1 ; } string_t StringListDetachAt( stringList_t stl, size_t index ) { string_t st; size_t size ; if( stl == StringListVoid ){ return StringVoid ; } if( index >= stl->size ){ return StringVoid ; } st = stl->stp[index] ; size = sizeof( string_t ) ; memmove( stl->stp + index,stl->stp + index + 1,size * ( stl->size - 1 - index ) ) ; stl->size = stl->size - 1 ; if( st != StringVoid ){ st->owned = 0 ; } return st ; } ssize_t StringListRemoveString( stringList_t stl,const char * cstring ) { ssize_t index = StringListContains( stl,cstring ) ; if( index == -1 ){ return -1 ; }else{ StringListRemoveAt( stl,index ) ; return index ; } } string_t StringListStringAt( stringList_t stl,size_t index ) { if( stl == StringListVoid ){ return StringVoid ; }else{ if( index >= stl->size ){ return StringVoid ; }else{ return stl->stp[index] ; } } } void StringListDelete( stringList_t * stl ) { size_t i ; stringList_t stx ; size_t size ; string_t * k ; string_t e ; if( stl == NULL ){ return ; } if( *stl == StringListVoid ){ return ; } stx = *stl ; size = stx->size ; *stl = StringListVoid ; k = stx->stp ; for( i = 0 ; i < size ; i++ ){ e = *( k + i ) ; if( e != StringVoid ){ free( e->string ) ; free( e ) ; } } free( stx->stp ) ; free( stx ); } void StringListClearDelete( stringList_t * stl ) { size_t i ; stringList_t stx ; size_t size ; string_t * k ; string_t e ; if( stl == NULL ){ return ; } if( *stl == StringListVoid ){ return ; } stx = *stl ; size = stx->size ; *stl = StringListVoid ; k = stx->stp ; for( i = 0 ; i < size ; i++ ){ e = *( k + i ) ; if( e != StringVoid ){ memset( e->string,'\0',e->length ) ; free( e->string ) ; free( e ) ; } } free( stx->stp ) ; free( stx ); } void StringListMultipleDelete( stringList_t * stl,... ) { stringList_t * entry ; va_list list ; va_start( list,stl ) ; StringListDelete( stl ) ; while( 1 ){ entry = va_arg( list,stringList_t * ) ; if( entry == NULL ){ break ; } StringListDelete( entry ) ; } va_end( list ) ; } stringList_t StringListCopy( stringList_t stl ) { size_t i ; size_t j ; string_t * st ; string_t * xt ; string_t st_1 ; stringList_t stx ; if( stl == StringListVoid ){ return StringListVoid ; } j = stl->size ; stx = malloc( sizeof( struct StringListType ) ) ; if( stx == NULL ){ return _StringListError() ; } stx->stp = malloc( sizeof( string_t ) * j ) ; if( stx->stp == NULL ){ free( stx ) ; return _StringListError() ; } stx->size = stl->size ; xt = stx->stp ; st = stl->stp ; for( i = 0 ; i < j ; i++ ){ st_1 = *( st + i ) ; if( st_1 == StringVoid ){ xt[ i ] = StringVoid ; }else{ xt[ i ] = StringWithSize( st_1->string,st_1->size ) ; xt[ i ]->owned = 1 ; } } return stx ; } string_t StringListCopyStringAt( stringList_t stl,size_t pos ) { if( stl == StringListVoid ){ return StringVoid ; } if( pos >= stl->size ){ return StringVoid ; } return StringCopy( *( stl->stp + pos ) ) ; } stringList_t StringListSwap( stringList_t stl, size_t x,size_t y ) { string_t p ; if( stl == StringListVoid || x >= stl->size || y >= stl->size ){ return stl ; }else{ p = stl->stp[ x ] ; stl->stp[ x ] = stl->stp[ y ] ; stl->stp[ y ] = p ; return stl ; } } void StringListPrintAt( stringList_t stl,size_t index ) { if( stl != StringListVoid ){ if( index < stl->size ){ printf("%s",stl->stp[ index ]->string ) ; } } } void StringListPrintLineAt( stringList_t stl,size_t index ) { if( stl != StringListVoid ){ if( index < stl->size ){ printf("%s\n",stl->stp[ index ]->string ) ; } } } void StringListPrintList( stringList_t stl ) { size_t i ; size_t j ; string_t * p ; string_t q ; if( stl == StringListVoid ){ return ; } j = stl->size ; p = stl->stp ; for( i = 0 ; i < j ; i++ ){ q = *( p + i ) ; if( q != StringVoid ){ printf("%s\n",q->string ) ; } } } zuluCrypt-6.2.0/zuluCrypt-cli/utility/string/StringList.h000066400000000000000000000374621425361753700236430ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef STRINGLISTTYPE #define STRINGLISTTYPE #ifdef __cplusplus extern "C" { #endif #include "String.h" #include /* * stringList_t is a type to be used as a handle with these functions * * this library implements a an array of strings_t type dynamically and add other functionality * */ typedef struct StringListType * stringList_t ; /* * create a custom type to represent a stringList_t pointing to NULL while hiding the pointer nature of stringList_t * string_t is an opaque handle and NULL assignment "gives unnecessary info" about its nature. */ #define StringListVoid ( ( stringList_t ) 0 ) /* * an STL style iterator type */ typedef string_t * StringListIterator ; /* * returns a pointer to the memory block occupying the first element on the list */ StringListIterator StringListBegin( stringList_t ) ; /* * returns a pointer to a memory block past the end of the array,STL style */ StringListIterator StringListEnd( stringList_t ) ; /* * set iterator begin and iterator end */ void StringListGetIterators( stringList_t,StringListIterator * begin,StringListIterator * end ) ; /* * call a function with a signature void foo( string_t ) on each entry in the list */ void StringListForEach( stringList_t stl,void (*)( string_t ) ) ; /* * call a function with a signature void foo( string_t,void * ) on each entry in the list * The third argument will be passed on to the function specified in the second argument */ void StringListForEach_1( stringList_t stl,void (*)( string_t,void * ),void * ) ; /* * call a function with a signature void foo( const char *,void * ) on each entry in the list * The third argument will be passed on to the function specified in the second argument */ void StringListForEachString_1( stringList_t stl,void (*)( const char *,void * ),void * ) ; /* * call a function with a signature void foo( const char * ) on each entry in the list */ void StringListForEachString( stringList_t stl,void (*)( const char * ) ) ; /* * Takes a pointer to a function to be called when memory allocation can not take place * ie if the system has run out of memory and malloc() or realloc() has failed. * This function is optional and "StringListVoid" will be returned on memory exaustion if the function * isnt set. */ void StringListExitOnMemoryExaustion( void (*)( void ) ) ; /* * create stringlist handle with a C string. All stringlist operations should happen through this handle */ stringList_t StringList( const char * cstring ) ; /* * create stringlist handle with a string_t. All stringlist operations should happen through this handle * this function will take ownership of st,invalidating the handle after auto deleting its contents */ stringList_t StringListString( string_t * ) ; /* * create a stringList_t object with empty content */ stringList_t StringListInit( void ) ; /* * Create a StringList object with arraySize string_t "slots" and expose them for easier assignment of multiple string_t objects. * * example use case * stringList_t stl ; * string_t * x = StringListArray( &stl,3 ) ; * x[0] = String( "abc" ) ; * x[1] = String( "def" ) ; * x[2] = String( "ghi" ) ; * ... * ... * NOTE:This is a dangerous function as it does not guard against StringVoid. * Assign StringVoid and segfault will surely happen sooner or later. */ string_t * StringListArray( stringList_t *,size_t arraySize ) ; /* * Return the number of elements in the list */ size_t StringListSize( stringList_t stl ) ; /* * create a stringlist from splitted cstring using splitter as a splitting trigger. */ stringList_t StringListSplit( const char * cstring,char splitter ) ; /* * add a new spot at the end of stringList_t object and return its position. * * eg usage: * string_t * p = StringListAssign( stl ) ; * *p = String( "abc" ) ; * * another way of doing the same thing: * string_t p = StringListAssignString( stl,String( "abc" ) ) ; * NOTE:This is a dangerous function as it does not guard against StringVoid. * Assign StringVoid and segfault will surely happen sooner or later. */ string_t * StringListAssign( stringList_t ) ; /* * add a string_t objest to the end of stringList_t object * string_t object passed is returned on success,StringVoid is return otherwise */ string_t StringListAssignString( stringList_t,string_t ) ; /* * create a stringlist from string_t using splitter as a splitting trigger. */ stringList_t StringListStringSplit( string_t st,char splitter ) ; /* * return a string_t element at position index. * First element is at position 0. */ string_t StringListStringAt( stringList_t stl,size_t index ) ; static __inline__ string_t StringListStringAtFirstPlace( stringList_t stl ) { return StringListStringAt(stl,0 ) ; } static __inline__ string_t StringListStringAtSecondPlace( stringList_t stl ) { return StringListStringAt(stl,1 ) ; } /* * return a pointer to a string at position index. * First element is at position 0. * */ const char * StringListContentAt( stringList_t stl,size_t index ) ; static __inline__ const char * StringListContentAtFirstPlace( stringList_t stl ) { return StringListContentAt( stl,0 ) ; } static __inline__ const char * StringListContentAtSecondPlace( stringList_t stl ) { return StringListContentAt( stl,1 ) ; } static __inline__ const char * StringListContentAtThirdPlace( stringList_t stl ) { return StringListContentAt( stl,2 ) ; } /* * strcmp() a strinf at index with cstring */ int StringListContentAtEqual( stringList_t stl,size_t index,const char * cstring ) ; /* * printf() string content at a given index */ void StringListPrintAt( stringList_t stl,size_t index ) ; /* * printf() all elements in the list,one line per element */ void StringListPrintList( stringList_t stl ) ; /* * printf() with a new line string content at a given index */ void StringListPrintLineAt( stringList_t stl,size_t index ) ; /* * return a pointer to a string at the last elenent in the list. */ const char * StringListContentAtLast( stringList_t stl ) ; /* * return a string_t at the last elenent in the list. */ string_t StringListStringAtLast( stringList_t stl ) ; /* * return an index position of an element with cstring. * return -1 if there is no element in the list with the string. */ ssize_t StringListContains( stringList_t stl,const char * cstring ) ; /* * return 1 if the managed list has atleast one cstring entry */ static int StringListHasEntry( stringList_t stl,const char * cstring ) ; /* * return 1 if the managed list has no cstring entry */ static int StringListHasNoEntry( stringList_t stl,const char * cstring ) ; /* * return an index position of the first string_t object in the stringList_t object with a character * sequence str ; * return -1 if no such sequence exist */ ssize_t StringListHasSequence( stringList_t stl,const char * str ) ; /* * return the first string_t object in the stringList_t object with a character * sequence str ; * return StringVoid if no such sequence exist */ string_t StringListHasSequence_1( stringList_t stl,const char * str ) ; /* * return an index position of the first string_t object in the stringList_t object with a character * sequence that starts with str ; * return -1 if no such sequence exist */ ssize_t StringListHasStartSequence( stringList_t stl,const char * str ) ; /* * return the first string_t object in the stringList_t object with a character * sequence that starts with str ; * return StringVoid if no such sequence exist */ string_t StringListHasStartSequence_1( stringList_t stl,const char * str ) ; /* * append an entry into the list. * if stl == NULL, then the function call is the same as "StringList( cstring )" */ stringList_t StringListAppend( stringList_t stl,const char * cstring ) ; /* * append an entry into the list if the entry is not already in the list * if stl == NULL, then the function call is the same as "StringList( cstring )" */ stringList_t StringListAppendIfAbsent( stringList_t stl,const char * cstring ) ; /* * append an entry into the list and take ownership of it. * if stl == NULL, then the function call is the same as "StringList( cstring )" */ void StringListAppendString_1( stringList_t * stl,string_t * ) ; /* * append an entry into the list. * if stl == NULL, then the function call is the same as "StringList( cstring )" */ stringList_t StringListAppendString( stringList_t stl,string_t ) ; /* * append an entry into the list by taking only len characters from the string. * if stl == NULL, then the function call is the same as "StringList( cstring )" */ stringList_t StringListAppendSize( stringList_t stl,const char * cstring,size_t len ) ; /* * Append a stringList_t on the second argument to stringList_t on the first argument * return the stringList_t on the first argument */ stringList_t StringListAppendList( stringList_t,stringList_t ) ; /* * prepend an entry into the list * if stl == NULL then the function is the same as "StringList( cstring )" */ stringList_t StringListPrepend( stringList_t stl,const char * cstring ) ; /* * prepend an entry into the list by taking len characters from the string. * if stl == NULL then the function is the same as "StringList( cstring )" */ stringList_t StringListPrependSize( stringList_t stl,const char * cstring,size_t len ) ; /* * insert an element as position index. * the first position is at position 0 * if index == size of the list,the operations will have the same effect as appending the entry to the end of the list */ stringList_t StringListInsertAt( stringList_t stl,const char * cstring,size_t index ) ; /* * insert string_t as position index. * the first position is at position 0 * * this function will take ownership of st,invalidating the handle after auto deleting its contents * * if index == size of the list,the operations will have the same effect as appending the entry to the end of the list */ stringList_t StringListStringInsertAt( stringList_t stl,string_t *,size_t index ) ; /* * insert an element as position index by taking only len characters from the string * the first position is at position 0 * if index == size of the list,the operations will have the same effect as appending the entry to the end of the list */ stringList_t StringListInsertAtSize( stringList_t stl,const char * cstring,size_t len, size_t index ) ; /* * remove an entry from the list bt deleting it * the first position is at position 0 */ stringList_t StringListRemoveAt( stringList_t stl, size_t index ) ; /* * Remove a string "at" iterator is pointing to,the end iterator will be adjusted to reflect * the removed item * NOTE:arguments are not checked for validity */ void StringListRemoveAt_1( stringList_t stl,StringListIterator at,StringListIterator * end ) ; /* * go through every string in the list and remove all strings that starts with str * returned value is the number of elements removed */ size_t StringListRemoveIfStringStartsWith( stringList_t stl,const char * str ) ; /* * go through every string in the list and remove all strings has str character sequence * returned value is the number of elements removed */ size_t StringListRemoveIfStringContains( stringList_t stl,const char * str ) ; /* * remove a string_t object from the managed list if it manages string str. * this function is to be used if there maybe multiple occurances of the string. * If there is atmost one entry,then StringListRemoveString() is a function to use. */ size_t StringListRemoveIfPresent( stringList_t stl,const char * str ) ; /* * remove a string_t object from the managed list if it is found. * this function is to be used if there maybe multiple occurances of the string. */ size_t StringListRemoveIfPresent_1( stringList_t stl,string_t st ) ; /* * remove an entry from the list at position index and "let it free",the detached entry is now a fully fledged string_t object. * the first position is at position 0 */ string_t StringListDetachAt( stringList_t stl, size_t index ) ; /* * remember to clean after yourself * when function return, stl will point to NULL */ void StringListDelete( stringList_t * stl ) ; /* * returns NULL terminated array of strings( char * argv[] ) composed of strings managed by the stringlist * NULL is returned on error. * NOTE: remember to free() the returned value but DONOT free its content. */ const char ** StringListStringArray( stringList_t ) ; /* * It does what the above does but it reuses the buffer and hence its better if the function is called * multiple times. * second argument will hold the size of the buffer without counting the NULL terminator * The two first arguments must be initilized to example values * NOTE: remember to free() the first argument but DONOT free its content. * Example usage * char * const * buffer = NULL ; * size_t buffer_size = 0 ; * stringList_t stl = StringList( "abc" ) ; * StringListStringArray_1( &buffer,&buffer_size,stl ) ; * puts( buffer[0] ) ; */ void StringListStringArray_1( char * const **,size_t *,stringList_t ) ; /* * remember to clean after yourself * overwite string objects as they are cleaned up */ void StringListClearDelete( stringList_t * stl ) ; /* * delete multiple stringList_t * objects. * NOTE; The last element on the argument list must be '\0' */ void StringListMultipleDelete( stringList_t * stl,... ) __attribute__ ( ( sentinel ) ) ; /* * find the first element with cstring and remove it and return the position of where the element was. * return -1 when there is no element in the list with cstring. * call the function repeatedly until you get -1 if elements can repeat. */ ssize_t StringListRemoveString( stringList_t stl,const char * cstring ) ; /* * add a cstring to the list and take it over( own it ) * cstring will be NULL on function return. * cstring must be created will malloc. * s is the size of the string * l is the size of the buffer holding the string */ stringList_t StringListAppendWithSize( stringList_t stl,char ** cstring,size_t s,size_t l ) ; /* * create a stringlist with cstring and take it over( own it ) * cstring will point to NULL on function return. * cstring must be created with malloc. * s is the size of the string * l is the size of the buffer holding the string */ stringList_t StringListWithSize( char ** cstring,size_t s,size_t l ) ; /* * returns a copy of a string list */ stringList_t StringListCopy( stringList_t stl ) ; /* * make a string_t copy of a string at position pos * first position is at pos = 0 */ string_t StringListCopyStringAt( stringList_t,size_t pos ) ; static __inline__ string_t StringListCopyStringAtFirstPlace( stringList_t stl ) { return StringListCopyStringAt( stl,0 ) ; } static __inline__ string_t StringListCopyStringAtSecondPlace( stringList_t stl ) { return StringListCopyStringAt( stl,1 ) ; } static __inline__ int StringListHasEntry( stringList_t stl,const char * cstring ) { return StringListContains( stl,cstring ) != -1 ; } static __inline__ int StringListHasNoEntry( stringList_t stl,const char * cstring ) { return StringListContains( stl,cstring ) == -1 ; } /* * move entry at position x to position y and entry at position y to position x * * first entry is at position 0. */ stringList_t StringListSwap( stringList_t stl, size_t x,size_t y ) ; #ifdef __cplusplus } #endif #endif zuluCrypt-6.2.0/zuluCrypt-gui.1000066400000000000000000000010061425361753700164370ustar00rootroot00000000000000 .TH zuluCrypt-gui 1 .br .SH NAME zuluCrypt-gui - Graphical front end for zuluCrypt-cli .br .SH SUMMARY zuluCrypt-gui is a GUI front end to zuluCrypt-cli .br copyright: 2011-2013 Ink Francis,mhogomchungu@gmail.com .br license : GPLv2+ .br options: .br -d path to where a volume to be auto unlocked/mounted is located .br -m tool to use to open a default file manager(default tool is xdg-open) .br -e start the application without showing the GUI .br .br .SH LAST EDIT Last change: Mon Apr 8 19:59:36 EDT 2013 zuluCrypt-6.2.0/zuluCrypt-gui/000077500000000000000000000000001425361753700163605ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluCrypt-gui/CMakeLists.txt000066400000000000000000000077011425361753700211250ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) add_definitions( -D_FILE_OFFSET_BITS=64 -Wextra -Wall -pedantic -I${PROJECT_BINARY_DIR}/zuluCrypt-gui/ ) include_directories( ${PROJECT_BINARY_DIR}/zuluCrypt-gui/ ) set( UI_FILES createfile.ui about.ui help.ui createvolume.ui luksdeletekey.ui password.ui zulucrypt.ui createkeyfile.ui luksaddkey.ui createvolume.ui cryptoinfo.ui warnwhenextendingcontainerfile.ui createvolumeinexistingfile.ui managevolumeheader.ui cryptfiles.ui createvolumedialog.ui managesystemvolumes.ui erasedevice.ui help.ui dialogok.ui filemanager.ui showluksslots.ui ) set( MOC_FILES cryptoinfo.h about.h dialogok.h utility.h createfile.h luksaddkey.h createkeyfile.h warnwhenextendingcontainerfile.h luksdeletekey.h createvolume.h createvolumeinexistingfile.h password_dialog.h zulucrypt.h help.h erasedevice.h managevolumeheader.h cryptfiles.h createvolumedialog.h managesystemvolumes.h about.h help.h filemanager.h showluksslots.h ) set( SRC about.cpp dialogok.cpp secrets.cpp createfile.cpp createvolume.cpp luksdeletekey.cpp createkeyfile.cpp luksaddkey.cpp main.cpp warnwhenextendingcontainerfile.cpp password_dialog.cpp createvolumeinexistingfile.cpp zulucrypt.cpp cryptoinfo.cpp erasedevice.cpp managevolumeheader.cpp cryptfiles.cpp createvolumedialog.cpp managesystemvolumes.cpp keystrength.cpp help.cpp about.cpp filemanager.cpp showluksslots.cpp ) Qt5_WRAP_UI( UI ${UI_FILES} ) Qt5_WRAP_CPP( MOC ${MOC_FILES} ) Qt5_ADD_RESOURCES( TRAY_RC_SRCS icon.qrc ) INCLUDE_DIRECTORIES( ${CMAKE_BINARY_DIR} ) add_executable( zuluCrypt-gui ${MOC} ${UI} ${SRC} ${TRAY_RC_SRCS} ) set_target_properties( zuluCrypt-gui PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( zuluCrypt-gui PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pedantic" ) if( WITH_PWQUALITY AND library_pwquality ) TARGET_LINK_LIBRARIES( zuluCrypt-gui lxqt-wallet ${Qt5Widgets_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Network_LIBRARIES} ${blkid} ${library_pwquality} ) else( WITH_PWQUALITY AND library_pwquality ) TARGET_LINK_LIBRARIES( zuluCrypt-gui lxqt-wallet ${Qt5Widgets_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Network_LIBRARIES} ${blkid} ${kwallet_library} ) endif( WITH_PWQUALITY AND library_pwquality ) target_link_libraries( zuluCrypt-gui sharedObject zuluCryptPluginManager ) install( TARGETS zuluCrypt-gui RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) install( FILES ${PROJECT_BINARY_DIR}/zuluCrypt.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications ) install( FILES zuluCrypt.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps ) install( FILES zuluCrypt.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons ) install( FILES zuluCrypt.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps ) install( FILES zuluCrypt.nicolas.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps ) install( FILES zuluCrypt.nicolas.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps ) install( FILES zuluCrypt.papirus.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps ) install( FILES zuluCrypt.papirus.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps ) install( FILES zuluCrypt.papirus.dark.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps ) install( FILES zuluCrypt.papirus.dark.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps ) #install (FILES zuluCrypt.png DESTINATION share/icons/hicolor/32x32/apps) # desktop file section file( WRITE ${PROJECT_BINARY_DIR}/zuluCrypt.desktop "[Desktop Entry] Comment[en_US]= Comment= Exec=${CMAKE_INSTALL_FULL_BINDIR}/zuluCrypt-gui -d %U GenericName[en_US]=Encrypted volumes manager GenericName=Encrypted volumes manager Icon=zuluCrypt Name[en_US]=ZuluCrypt Name=ZuluCrypt NoDisplay=false StartupNotify=true Terminal=false Type=Application MimeType=application/x-raw-disk-image; Categories=Security;Utility;Qt;X-MandrivaLinux-System-FileTools;\n") zuluCrypt-6.2.0/zuluCrypt-gui/TRANSLATIONS000066400000000000000000003561031425361753700202340ustar00rootroot00000000000000 CreateVolumeDialog warning!! yes no This operation will lead to permanent destrunction of all present data in /dev/sdc1. Are you sure you want to continue? This operation will lead to permanent destrunction of all present data in "%1". Are you sure you want to continue? It is advised to create encrypted containers over random data to prevent information leakage. Do you want to write random data to "%1" first before creating an encrypted container in it? You can stop the random data writing process anytime you want if it takes too long and you can no longer wait. DialogMsg Dialog &ok &yes &no text type cipher key size device loop offset size mode fs used unused used % active slots By default,volumes are mounted with "noexec" option and hence its not possible to run programs or scripts from them.To do so,create a group called "zulumount-exec" and add yourself to the group and volumes will start to be mounted with "exec" option and ability to runprograms or scripts from the volume will be enabled. "system volumes" are volumes that either udev has identify them as such if udev is enabled or have an entry in "/etc/fstab","/etc/crypttab" or "/etc/zuluCrypt-system". If you prefer for a device not to be considered a system device,start the tool from root account and then go to "menu->options->manage non system partitions" and add the device to the list and the device will stop being considered as "system". Alternatively,you can add yourself to group "zulucrypt" and all restrictions will be gone INFORMATION insufficient privilege to access a system device, only root user or members of group zulucrypt can do that insufficient privilege to access a system device in read/write mode, only root user or members of group zulucrypt-write can do that you do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again do not show this dialog again PasswordDialog open encrypted volume &open &cancel open the volume in &read only mode select mount point path open volume path &key &plugin key &from a key file open key file key mount name volume path checkvolumetype luks plain createfile create a container file file name file path file size open a folder dialog box &cancel % complete c&reate KB MB GB 1/2 create a container file ERROR! file name field is empty file path field is empty file size field is empty Illegal character in the file size field.Only digits are allowed file with the same name and at the destination folder already exist you dont seem to have writing access to the destination folder container file must be bigger than 3MB ERROR could not open cryptographic back end to generate random data terminating file creation process are you sure you want to stop file creation process? 2/2 write random data to a container file Select Path to where the file will be created createkeyfile create a key file keyfile name path to a folder to create a key in open a folder a key file will be created in c&reate &cancel keyfile path rng ERROR! the key name field is empth folder path to where the key will be created is empty file with the same name and at the destination folder already exist you dont seem to have writing access to the destination folder WARNING! process interrupted,key not fully generated SUCCESS! key file successfully created Select a folder to create a key file in createvolume create a new volume path to device c&reate &cancel key key from a keyfile open a key file repeat key volume type hidden key hidden key from keyfile volume size MB KB GB rng file system passphrase quality: 0/100 passphrase quality: %1/100 this tool expects to find file system creation tools at "%1/" and it can not find them. It is therefore not possible to create volumes using this tool. ERROR! path to file key file path keyfile volume path field is empty atleast one required field is empty illegal character detected in the hidden volume size field hidden passphrases do not match passphrases do not match volume created successfully creating a backup of the luks header is strongly advised. Please read documentation on why this is important. SUCCESS! presented file system is not supported,see documentation for more information insufficient privilege to open a system device in read/write mode, only root user or members of group zulucrypt-system can do that could not create an encrypted volume could not open volume for writing there seem to be an opened mapper associated with the device can not create a volume on a mounted device container file must be bigger than 3MB %1 not found insufficient memory to hold your response operation terminated per user request could not get passphrase in silent mode insufficient memory to hold the passphrase invalid path to key file could not get a key from a key file couldnt get enought memory to hold the key file could not get a key from a socket one or more required argument(s) for this operation is missing can not get passphrase in silent mode insufficient memory to hold passphrase could not find any partition with the presented UUID unrecognized ERROR! with status number %1 encountered cryptfiles destination path c&reate source path key key from a key file repeat key &cancel % complete create encrypted version of a file create decrypted version of an encrypted file ERROR! path to source field is empty invalid path to source file destination path already taken first key field is empty second key field is empty keys do not match invalid path to key file Select Path to put destination file select a file you want to encrypt zuluCrypt encrypted files ( *.zc ) ;; All Files ( * ) select a file you want to decrypt select a keyfile SUCCESS encrypted file created successfully decrypted file created successfully could not open keyfile for reading missing key source could not open encryption routines file or folder already exist at destination address invalid path to source could not resolve path to destination file required argument is missing insufficient privilege to create destination file presented key did not match the encryption key INFO! operation terminated per user request insufficient privilege to open source file for reading WARNING decrypted file created successfully but md5 checksum failed,file maybe corrupted cryptfilethread calculating md5sum creating encrypted container file copying data to the container file copying data from the container file cryptoinfo crypo info ok default options for plain volumes cipher: aes-cbc-essiv:sha256 keysize: 256 bits password hash: ripemd160 default creation options for luks volumes luks header hashing: sha1 cipher: aes-xts-plain64 default creation options for truecrypt volumes hash: ripemd160 erasedevice erase data on the device by writing random data over them path to device % completed &start &cancel The next dialog will write random data to a device leading to permanent loss of all contents on the device. Are you sure you want to continue? WARNING SUCCESS! data on the device successfully erased ERROR! could not create mapper could not resolve device path random data successfully written operation terminated per user choicer can not write on a device with opened mapper policy prevents non root user opening mapper on system partition device path is invalid passphrase file does not exist could not get enought memory to hold the key file insufficient privilege to open key file for reading this device appear to already be in use can not open a mapper on a mounted device could not write to the device device path field is empty invalid path to device Are you really sure you want to write random data to "%1" effectively destroying all contents in it? WARNING! enter path to volume to be erased select a non system partition to erase its contents kwalletconfig manage volumes in kwallet &add volume uuid comment key &delete do&ne repeat key ERROR atleast one required field is empty (comment field can be empty) passphrases do not match select a luks volume File does not appear to contain a luks volume <redacted> luksaddkey add a key to a luks volume volume path open file open partition key key from a key file open keyfile &add &cancel reenter key key already in the encrypted volume key to be added to the encrypted volume passphrase quality: 0/100 passphrase quality: %1/100 existing key file new key file encrypted volume path keyfile path ERROR! atleast one required field is empty keys do not match key added successfully. %1 / %2 slots are now in use key added successfully. SUCCESS! presented key does not match any key in the volume could not open luks volume volume is not a luks volume insufficient privilege to add a key to a system device, only root user or members of group "zulucrypt" can do that could not open volume in write mode all key slots are occupied, can not add any more keys can not get passphrase in silent mode insufficient memory to hold passphrase new passphrases do not match one or more required argument(s) for this operation is missing one or both keyfile(s) does not exist insufficient privilege to open key file for reading couldnt get enought memory to hold the key file could not get a key from a socket could not get elevated privilege,check binary permissions can not find a partition that match presented UUID device is not a luks device unrecognized ERROR! with status number %1 encountered luksdeletekey remove a key from a volume key existing key in the volume to delete existing key from a key file to delete open a keyfile &delete &cancel volume path open an encrypted file open an encrypted partition key keyfile path key file with a passphrase to delete ERROR! atleast one required field is empty volume is not a luks volume There is only one last key in the volume. Deleting it will make the volume unopenable and lost forever. Are you sure you want to delete this key? WARNING are you sure you want to delete a key from this volume? key removed successfully. key removed successfully. %1 / %2 slots are now in use SUCCESS! there is no key in the volume that match the presented key could not open the volume insufficient privilege to open a system device,only root user or members of group zulucrypt-system can do that could not open the volume in write mode insufficient memory to hold your response operation terminated per user request can not get passphrase in silent mode insufficient memory to hold passphrase one or more required argument(s) for this operation is missing keyfile does not exist could not get enough memory to open the key file insufficient privilege to open key file for reading could not get a key from a socket can not find a partition that match presented UUID unrecognized ERROR! with status number %1 encountered manageSystemVolumes manage system volumes &done add fi&le add dev&ice path to system volumes ERROR could not open "%1" for writing remove selected entry cancel are you sure you want to remove "%1" from the list? WARNING select path to system volume managedevicenames manage favorites &add device address mount point path open partition dialog open file dialog &done remove selected entry cancel ERROR! device address field is empty mount point path field is empty path to an encrypted file manageluksheader backup luks header backup name c&reate &cancel device path select a file with a luks backup header select a folder to store the header ERROR! atleast one required field is empty Are you sure you want to replace a header on device "%1" with a backup copy at "%2"? WARNING! select luks container you want to backup its header SUCCESS header saved successfully. if possible,store it securely. header restored successfully presented device is not a LUKS device failed to perform requested operation INFO! operation terminater per user request path to be used to create a back up file is occupied insufficient privilege to open backup header file for reading invalid path to back up header file insufficient privilege to create a backup header in a destination folder invalid path to device argument for path to a backup header file is missing only root user and "zulucrypt" members can restore and back up luks headers on system devices insufficient privilege to open device for writing could not resolve path to device backup file does not appear to contain luks header insufficient privilege to open device for reading device is not a luks device unrecognized ERROR! with status number %1 encountered openvolume select a partition to open partition size label type uuid use uuid &help use &uuid &cancel a list of all partitions on this system are displayed here. Double click an entry to use it you are not root user and hence only non system partition are displayed on this list. Please read documentation for more information on system/non system partitions. Double click an entry to use it you are a root user and all partitions are displayed. Double click an entry to use it info select a partition to create an encrypted volume in select an encrypted partition to open ERROR only cryto_LUKS volumes can be selected openvolumereadonly setting this option will cause the volume to open in read only mode info passwordDialog ERROR could not find any plugin installed cancel plugin path plugin name choose a module from the file system enter a module name to use to get passphrase select a key module enter a key key choose a key file from the file system enter a path to a keyfile location keyfile path Select a keyfile Select a key module Select Path to mount point folder Select encrypted volume atleast one required field is empty "/" character is not allowed in mount name field "zuluCrypt" wallet is not configured,go to: "menu->options->manage kwallet" to configure it and then add this volume first before continuing can store and retrieve passphrases only for LUKS volumes the volume does not appear to have an entry in the wallet warning could not open mount point because "%1" tool does not appear to be working correctly ERROR! An error has occured and the volume could not be opened failed to mount ntfs file system using ntfs-3g,is ntfs-3g package installed? there seem to be an open volume accociated with given address no file or device exist on given path volume could not be opened with the presented key insufficient privilege to mount the device with given options insufficient privilege to open device only root user can perform this operation -O and -m options can not be used together could not create mount point, invalid path or path already taken shared mount point path aleady taken there seem to be an opened mapper associated with the device could not get a passphrase from the module could not get passphrase in silent mode insufficient memory to hold passphrase one or more required argument(s) for this operation is missing invalid path to key file could not get enought memory to hold the key file insufficient privilege to open key file for reading could not get a passphrase through a local socket failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered could not create a lock on /etc/mtab unrecognized ERROR with status number %1 encountered zuluCrypt zuluCrypt Encrypted volume path Encrypted volume mount point path Type &open &create &help &luks o&ptions &favorites &zC encrypted container in a file Ctrl+Z encrypted container in a partition Ctrl+X Ctrl+A Ctrl+S about Ctrl+R add key Ctrl+U delete key Ctrl+W crypto info Ctrl+E keyfile Ctrl+D tray icon Ctrl+K select font Ctrl+L favorite volumes manage favorites select random number generator Ctrl+P close application Ctrl+C minimize Ctrl+T minimize to tray Ctrl+Y quit Ctrl+Q close all opened volumes Ctrl+G Ctrl+F erase data in a device Ctrl+N backup header Ctrl+B restore header permission Ctrl+I encrypt a file decrypt a file Ctrl+H luks header backup Ctrl+J manage system partitions manage volumes in wallet Ctrl+O use kde default wallet Ctrl+V manage non system partitions Ctrl+M info resetting font size to %1 because larger font sizes do not fit about zuluCrypt important information on luks header ERROR! volume is not open or was opened by a different user volume properties list is empty warning could not open mount point because "%1" tool does not appear to be working correctly close open folder properties remove key backup luks header add to favorite cancel close failed, volume is not open or was opened by a different user close failed, one or more files in the volume are in use. close failed, volume does not have an entry in /etc/mtab close failed, could not get a lock on /etc/mtab~ close failed, volume is unmounted but could not close mapper,advice to close it manually close failed, could not resolve full path of device close failed, shared mount point appear to be busy close failed, shared mount point appear to belong to a different user close failed, shared mount point appear to be in an ambiguous state,advice to unmount manually close failed, could not find any partition with the presented UUID unrecognized error with status number %1 encountered ERROR kwallet functionality doesnt seem to be enabled zuluCrypt-6.2.0/zuluCrypt-gui/about.cpp000066400000000000000000000115031425361753700201760ustar00rootroot00000000000000/* * * Copyright ( c ) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "about.h" #include "ui_about.h" #include #include #include #include "utility.h" #include "version.h" static QString e = R"R( gpg key finderpring: E3AF84691424AD00E099003502FC64E8DEBF43A8 The key can be retrieved with command: gpg --recv-keys 0x02FC64E8DEBF43A8 The key is below: -----BEGIN PGP PUBLIC KEY BLOCK----- mQINBFmVdDYBEAC/pVNcWOEw5PMLtGiCR9WhY5LOMnR7RlXX4l7JPTiYWGAq+WOV 3n6ueZ8TMsFxRl2TZoV7u1SyExP1RbBrtS2d8aQM/GmWFh1HSoUfiOwXqCFVTExC ORh5lgOTOWH/zkYLJksrcFhDyeip6Bjy368eFHkVRnSmYR5xj0UQpM0bsd3VGmsY 5YmGMudqAblutdME7DYX8E7tQ91JH8jTmtoLI99/1NVa28W75C0ixC+nu767rMFb eIEzer9eZSi3Eud2u9Cj3vVyTI9f7uWltpJ3V9RbpApdc4NFPCrqaJuXyooGUdfJ TPc2ofBkT/Oxyl2aNd5bl7Xexf1TprXRv5MN1FQ1pqYN8gjYWc/ZfVNQ/kR5kIx5 ZX1xMaDscyZZX96lP+xYVhfVSehFVDC2DtXPwbiQR8/EnyuRXUMnNWas0FUoZCKJ VCeYFpvHJUKdrvc6jc3jKM+8Mu9rrB7KvgqRb+MrjT0LKFK4N40xCJT0+evlDljA 5HmcEvwOTnBIy/JnqsjjCNCO80tlS4fuibBSv0z0MIiaggQHzsU+UcxrEDCSMaSM rVxfINXuOCEhS4Lw7Lwge28bYV1Sdvr6JJI3BC1mrX06l+FVm9ccOKAPMmcbyjMc 32cuJxWdaJdJsYKnR5+S11JrhjF24OsqCTQhAOF3EPPKEl7eo5/S//kTDQARAQAB tCdGcmFuY2lzIEJhbnlpa3dhIDxiYW55aWt3YWZiQGdtYWlsLmNvbT6JAjgEEwEC ACIFAlmVdDYCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEAL8ZOjev0Oo W/YP+wXokzRTzVMQOFENGuSAvC3ZvsVa6o2Pu9R/CoVFE5I7KIN6i8ZdECO3E0Bw 8VXXPmo/LB+/fCzeKBPqdEAHl1+q0OJU2peYfqHz/2MwZ9lQ29Oh503SmXg914oQ ChZQDEdLnaNIzs+2EOGO6XVvzB2Mnt161FdzvZt2xMrpxO4rFtjztwTuCEwwHjVS w/zAsWJ3X4NKhPbjwNM7PAF81hmVAh/ysr1yOCE8O9qr+QDMJRCe1IQayFFB9X6R K67q9k3brW6XvinzYn2fg36zwkuMcKsFZDy/OGpdkVYqRon74cliNmSdIz50S5Ph LQWfeblVSUfv+p0J1uXXSg3sTYh24cotWzn4/FlChBIaGVon0SQRIFVqGDxoK+nQ vlq5c8dLWn7Hg4oyOaECn0IsTIOHNzrA56yHuqtTOUe3aMhXMyInZ85LM3dYB58d Edbw58AWE0fEGsESbiaUKilZQ2hh19u8JsBwpxBTLYQTO0qem0LJxlDRP0PwApKN xXbdjFR4EgT6JED5bR7u2mGOA4IY0CPDGmecCNf4hFtHpwnfHt15n//3SjdaAbGV 9eu3i6xTlq41nKyWALPpRLgFXqLcJUiMVa+9OQ8vGSZlYxBOC9rRopL2qVyxzNhQ m9l+w2aDyauzVW2Kgeie6snxsFSD06B3PYdgYzcHI8Oc2RFzuQINBFmVdDYBEACW 0TiKpNsGnG9A2trMAiIW0K+jKd6pOs8JOphC4QPWnoDdD4Pdwka99LjOAPS6m1ok 81Wf5ogc8/czP6sYkzloFIpEEKI7LlsmBRXnlW9Gn6LKC6WAeDTLVXP0ZUIh5MsW DqvgpWQKjsV/p5RNubQuFS82JWutAyughz0CYwSSfHJBWxeDdDp3y9pVJKilucEp vB8axiDDiEPZkCaNGp3zUIiFJo0ndyCKyVUCO+HK22NCP5pkAOEZXbwCIDnL8GrG p/gwFreotBshaDbX+UCQfbkzZ5zPOFXOlpCQc7Omh1EWTX1ws9nUiBzutJOggdAZ UHr2drmRujIRhZlXwDGORqLYDNR8kNYeA6UrmZ5JhthI8vfdBEmC/WTPDIHvonpA 39V9n6LqSTc/+0fR9qe/qaliy9Nbr3q5hJXa75+bcP567dgNKhFvhUreWEwzPqaB NXO4xyG8HT2shH9DfFaE4rwYb+K0COo/9KyZD5QEvMnV7FEk+I8cliCU/NPYLSNp 9nRhopyAhqwvr/7fEJ/W7UhUcl4+aht4B6lWUHW+72Hvb5F/ehbKSthW0azzRjBJ nXTi9XrJFsNzzHHlNI/QJxAiAJ3Z2mKBS8iJ2RR2R3prGIocKu3e9hVM6HSfF4ZS curwmRejKHLrUs6kg22ZqBzvmPhg5W8rwIvsi2/2pwARAQABiQIfBBgBAgAJBQJZ lXQ2AhsMAAoJEAL8ZOjev0OoGWEP/3kvNrOz/+JW1SGQ4SrrL6dihIUhmdgdDBH0 9d+UX+70ao2hk0tv6lDARy8uf9tt4fJ75otRvYS3PR9Sn0PUohqen4+6OsfoydUX e9qz934jWHUv+QV6KhifC3qh3ECi2/ouRS0Mnxzd1CaD0np9d/fSt4porfUJ5ck1 IfSPu7TFnnBhk6xt0V/SGEspcTnDAiiDcY6agMbCPo7rXMNyGVgk/a6OsO2qQGX5 42Hp4dPTXSjy1JiZ1htRvoau8OSrfEsHjW+x0dz6fyByW5EfewZXmFCjM3w+G5bT 2yAL//AkBZlL7T7IIdqkA4pVFEwAn2V1Xs5hfDuoRTFT4WkIkhaDIhiQZk/lHAz8 aZPWktdHzAROXiQvLEX+L5mjXgO8hPud7yXZTRIpDPRdKMZA0XVTwee4LxX/VnfB cE2guccUEFD+kZiR3Dng91V9xZ/DIu98ZcAV46lYhK83Csr6XGOPdIoIdT/v/3gc wvtwg4b/D8c1TmXPISCIX/cBzT3al1xjOPGQ/v+XnqMafJI5MHnFUzoRleE6slVB MLTWZGcEfBcgMIzoSF+i4dqg1v3dv1pDx1X3IR0n7440uDV1XDt48j5Rv51O0GdP cv9jY9bZAbVaMUjF7dw/bsqgJ2HCJ33cf16GybRtozOE36YDB2omg58ngIrlmlea 9azeqex9 =L6yQ -----END PGP PUBLIC KEY BLOCK----- )R" ; about::about( QWidget * parent ) : QDialog( parent ), m_ui( new Ui::about ) { m_ui->setupUi( this ) ; m_ui->textEdit->setText( VERSION_STRING + e ) ; m_ui->textEdit->setFont( parent->font() ) ; this->setFixedSize( this->size() ) ; this->setWindowFlags( Qt::Window | Qt::Dialog ) ; this->setFont( parent->font() ) ; connect( m_ui->pushButton,SIGNAL( clicked( bool ) ),this,SLOT( pbClose() ) ) ; this->show() ; } about::~about() { delete m_ui ; } void about::pbClose() { this->hide() ; this->deleteLater() ; } void about::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbClose() ; } bool about::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->pbClose() ; } ) ; } zuluCrypt-6.2.0/zuluCrypt-gui/about.h000066400000000000000000000023611425361753700176450ustar00rootroot00000000000000/* * * Copyright ( c ) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ABOUT_H #define ABOUT_H #include #include class QCloseEvent ; class QEvent ; class QObject ; namespace Ui { class about; } class about : public QDialog { Q_OBJECT public: static void instance( QWidget * parent ) { new about( parent ) ; } explicit about( QWidget * parent ) ; ~about() ; private slots: void pbClose( void ) ; private: void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::about * m_ui ; }; #endif // ABOUT_H zuluCrypt-6.2.0/zuluCrypt-gui/about.ui000066400000000000000000000441641425361753700200420ustar00rootroot00000000000000 about 0 0 642 431 About 260 400 121 31 &Close 10 10 621 391 10 30 601 351 true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'monospace'; color:#000000; background-color:#ffffff;">Version  : 5.2.0 </span><span style=" font-family:'monospace';"><br />Copyright: 2011-2017 Francis Banyikwa,mhogomchungu@gmail.com <br />License  : GPLv2+</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'monospace';"><br />This program is free software: you can redistribute it and/or modify</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'monospace';">it under the terms of the GNU General Public License as published by</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'monospace';">the Free Software Foundation, either version 2 of the License, or</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'monospace';">( at your option ) any later version.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'monospace';"><br />My GPG</span><span style=" font-family:'Hack';"> key finderpring: E3AF84691424AD00E099003502FC64E8DEBF43A8</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack';"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">Get the key with command: gpg --recv-keys 0x02FC64E8DEBF43A8</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack';"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">The key is below:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack';"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">-----BEGIN PGP PUBLIC KEY BLOCK-----</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack';"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">mQINBFmVdDYBEAC/pVNcWOEw5PMLtGiCR9WhY5LOMnR7RlXX4l7JPTiYWGAq+WOV</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">3n6ueZ8TMsFxRl2TZoV7u1SyExP1RbBrtS2d8aQM/GmWFh1HSoUfiOwXqCFVTExC</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">ORh5lgOTOWH/zkYLJksrcFhDyeip6Bjy368eFHkVRnSmYR5xj0UQpM0bsd3VGmsY</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">5YmGMudqAblutdME7DYX8E7tQ91JH8jTmtoLI99/1NVa28W75C0ixC+nu767rMFb</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">eIEzer9eZSi3Eud2u9Cj3vVyTI9f7uWltpJ3V9RbpApdc4NFPCrqaJuXyooGUdfJ</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">TPc2ofBkT/Oxyl2aNd5bl7Xexf1TprXRv5MN1FQ1pqYN8gjYWc/ZfVNQ/kR5kIx5</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">ZX1xMaDscyZZX96lP+xYVhfVSehFVDC2DtXPwbiQR8/EnyuRXUMnNWas0FUoZCKJ</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">VCeYFpvHJUKdrvc6jc3jKM+8Mu9rrB7KvgqRb+MrjT0LKFK4N40xCJT0+evlDljA</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">5HmcEvwOTnBIy/JnqsjjCNCO80tlS4fuibBSv0z0MIiaggQHzsU+UcxrEDCSMaSM</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">rVxfINXuOCEhS4Lw7Lwge28bYV1Sdvr6JJI3BC1mrX06l+FVm9ccOKAPMmcbyjMc</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">32cuJxWdaJdJsYKnR5+S11JrhjF24OsqCTQhAOF3EPPKEl7eo5/S//kTDQARAQAB</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">tCdGcmFuY2lzIEJhbnlpa3dhIDxiYW55aWt3YWZiQGdtYWlsLmNvbT6JAjgEEwEC</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">ACIFAlmVdDYCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEAL8ZOjev0Oo</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">W/YP+wXokzRTzVMQOFENGuSAvC3ZvsVa6o2Pu9R/CoVFE5I7KIN6i8ZdECO3E0Bw</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">8VXXPmo/LB+/fCzeKBPqdEAHl1+q0OJU2peYfqHz/2MwZ9lQ29Oh503SmXg914oQ</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">ChZQDEdLnaNIzs+2EOGO6XVvzB2Mnt161FdzvZt2xMrpxO4rFtjztwTuCEwwHjVS</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">w/zAsWJ3X4NKhPbjwNM7PAF81hmVAh/ysr1yOCE8O9qr+QDMJRCe1IQayFFB9X6R</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">K67q9k3brW6XvinzYn2fg36zwkuMcKsFZDy/OGpdkVYqRon74cliNmSdIz50S5Ph</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">LQWfeblVSUfv+p0J1uXXSg3sTYh24cotWzn4/FlChBIaGVon0SQRIFVqGDxoK+nQ</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">vlq5c8dLWn7Hg4oyOaECn0IsTIOHNzrA56yHuqtTOUe3aMhXMyInZ85LM3dYB58d</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">Edbw58AWE0fEGsESbiaUKilZQ2hh19u8JsBwpxBTLYQTO0qem0LJxlDRP0PwApKN</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">xXbdjFR4EgT6JED5bR7u2mGOA4IY0CPDGmecCNf4hFtHpwnfHt15n//3SjdaAbGV</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">9eu3i6xTlq41nKyWALPpRLgFXqLcJUiMVa+9OQ8vGSZlYxBOC9rRopL2qVyxzNhQ</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">m9l+w2aDyauzVW2Kgeie6snxsFSD06B3PYdgYzcHI8Oc2RFzuQINBFmVdDYBEACW</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">0TiKpNsGnG9A2trMAiIW0K+jKd6pOs8JOphC4QPWnoDdD4Pdwka99LjOAPS6m1ok</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">81Wf5ogc8/czP6sYkzloFIpEEKI7LlsmBRXnlW9Gn6LKC6WAeDTLVXP0ZUIh5MsW</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">DqvgpWQKjsV/p5RNubQuFS82JWutAyughz0CYwSSfHJBWxeDdDp3y9pVJKilucEp</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">vB8axiDDiEPZkCaNGp3zUIiFJo0ndyCKyVUCO+HK22NCP5pkAOEZXbwCIDnL8GrG</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">p/gwFreotBshaDbX+UCQfbkzZ5zPOFXOlpCQc7Omh1EWTX1ws9nUiBzutJOggdAZ</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">UHr2drmRujIRhZlXwDGORqLYDNR8kNYeA6UrmZ5JhthI8vfdBEmC/WTPDIHvonpA</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">39V9n6LqSTc/+0fR9qe/qaliy9Nbr3q5hJXa75+bcP567dgNKhFvhUreWEwzPqaB</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">NXO4xyG8HT2shH9DfFaE4rwYb+K0COo/9KyZD5QEvMnV7FEk+I8cliCU/NPYLSNp</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">9nRhopyAhqwvr/7fEJ/W7UhUcl4+aht4B6lWUHW+72Hvb5F/ehbKSthW0azzRjBJ</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">nXTi9XrJFsNzzHHlNI/QJxAiAJ3Z2mKBS8iJ2RR2R3prGIocKu3e9hVM6HSfF4ZS</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">curwmRejKHLrUs6kg22ZqBzvmPhg5W8rwIvsi2/2pwARAQABiQIfBBgBAgAJBQJZ</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">lXQ2AhsMAAoJEAL8ZOjev0OoGWEP/3kvNrOz/+JW1SGQ4SrrL6dihIUhmdgdDBH0</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">9d+UX+70ao2hk0tv6lDARy8uf9tt4fJ75otRvYS3PR9Sn0PUohqen4+6OsfoydUX</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">e9qz934jWHUv+QV6KhifC3qh3ECi2/ouRS0Mnxzd1CaD0np9d/fSt4porfUJ5ck1</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">IfSPu7TFnnBhk6xt0V/SGEspcTnDAiiDcY6agMbCPo7rXMNyGVgk/a6OsO2qQGX5</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">42Hp4dPTXSjy1JiZ1htRvoau8OSrfEsHjW+x0dz6fyByW5EfewZXmFCjM3w+G5bT</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">2yAL//AkBZlL7T7IIdqkA4pVFEwAn2V1Xs5hfDuoRTFT4WkIkhaDIhiQZk/lHAz8</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">aZPWktdHzAROXiQvLEX+L5mjXgO8hPud7yXZTRIpDPRdKMZA0XVTwee4LxX/VnfB</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">cE2guccUEFD+kZiR3Dng91V9xZ/DIu98ZcAV46lYhK83Csr6XGOPdIoIdT/v/3gc</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">wvtwg4b/D8c1TmXPISCIX/cBzT3al1xjOPGQ/v+XnqMafJI5MHnFUzoRleE6slVB</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">MLTWZGcEfBcgMIzoSF+i4dqg1v3dv1pDx1X3IR0n7440uDV1XDt48j5Rv51O0GdP</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">cv9jY9bZAbVaMUjF7dw/bsqgJ2HCJ33cf16GybRtozOE36YDB2omg58ngIrlmlea</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">9azeqex9</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">=L6yQ</span></p> <p style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack';">-----END PGP PUBLIC KEY BLOCK-----</span></p></body></html> textEdit pushButton zuluCrypt-6.2.0/zuluCrypt-gui/createfile.cpp000066400000000000000000000256641425361753700212040ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "ui_createfile.h" #include "createfile.h" #include "utility.h" #include "../zuluCrypt-cli/constants.h" #include "dialogmsg.h" #include #include #include #include #include #include createfile::createfile( QWidget * parent,std::function< void( const QString& ) > f ) : QDialog( parent ),m_ui( new Ui::createfile ),m_function( std::move( f ) ) { m_ui->setupUi( this ) ; this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; m_label.setOptions( m_ui->label_6,m_ui->pushButton ) ; m_ui->progressBar->setMinimum( 0 ) ; m_ui->progressBar->setMaximum( 100 ) ; m_ui->progressBar->setValue( 0 ) ; m_ui->pbOpenFolder->setIcon( QIcon( ":/folder.png" ) ) ; connect( m_ui->checkBoxNoRandomData,SIGNAL( stateChanged( int ) ),this,SLOT( warnAboutRandomData( int ) ) ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->pbOpenFolder,SIGNAL( clicked() ),this,SLOT(pbOpenFolder() ) ) ; connect( m_ui->pbCreate,SIGNAL( clicked() ),this,SLOT( pbCreate() ) ) ; connect( m_ui->lineEditFileName,SIGNAL( textChanged( QString ) ),this,SLOT(fileTextChange( QString ) ) ) ; connect( this,SIGNAL( sendProgress( QString,QString,QString,QString,int ) ), this,SLOT( setProgress( QString,QString,QString,QString,int ) ) ) ; this->installEventFilter( this ) ; this->setWindowTitle( tr( "Create A Container File" ) ) ; m_running = false ; this->showUI() ; } bool createfile::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->pbCancel() ; } ) ; } void createfile::fileTextChange( QString txt ) { auto p = m_ui->lineEditFilePath->text() ; if( p.isEmpty() ){ auto x = utility::homePath() + "/" + txt.split( "/" ).last() ; m_ui->lineEditFilePath->setText( x ) ; return ; } int i = p.lastIndexOf( "/" ) ; if( i != -1 ){ p = p.mid( 0,i ) + "/" + txt.split( "/" ).last() ; m_ui->lineEditFilePath->setText( p ) ; } } void createfile::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbCancel() ; } void createfile::enableAll() { m_ui->lineEditFileName->setEnabled( true ) ; m_ui->lineEditFilePath->setEnabled( true ) ; m_ui->lineEditFileSize->setEnabled( true ) ; m_ui->pbOpenFolder->setEnabled( true ) ; m_ui->label->setEnabled( true ) ; m_ui->label_2->setEnabled( true ) ; m_ui->label_3->setEnabled( true ) ; m_ui->label_4->setEnabled( true ) ; m_ui->label_5->setEnabled( true ) ; m_ui->pbCreate->setEnabled( true ) ; m_ui->checkBoxNoRandomData->setEnabled( true ) ; } void createfile::disableAll() { m_ui->pbCreate->setEnabled( false ) ; m_ui->lineEditFileName->setEnabled( false ) ; m_ui->lineEditFilePath->setEnabled( false ) ; m_ui->lineEditFileSize->setEnabled( false ) ; m_ui->comboBox->setEnabled( false ) ; m_ui->pbOpenFolder->setEnabled( false ) ; m_ui->label->setEnabled( false ) ; m_ui->label_2->setEnabled( false ) ; m_ui->label_3->setEnabled( false ) ; m_ui->label_4->setEnabled( false ) ; m_ui->label_5->setEnabled( false ) ; m_ui->checkBoxNoRandomData->setEnabled( false ) ; } void createfile::showUI() { this->enableAll() ; m_ui->comboBox->setCurrentIndex( 1 ) ; m_ui->lineEditFileName->clear() ; m_ui->lineEditFilePath->setText( utility::homePath() + "/" ) ; m_ui->lineEditFileSize->clear() ; m_ui->progressBar->setValue( 0 ) ; m_ui->lineEditFileName->setFocus() ; this->show() ; } void createfile::warnAboutRandomData( int e ) { if( e == Qt::Checked ){ DialogMsg msg( this ) ; auto m = tr( "\nBy default,zuluCrypt creates a volume in a container file over randomly generated data \ to hide usage patterns of the container.\n\ \n\ This process takes time and it may take a very,very \ long time if the volume about to be created is large enough and this option exists to \ skip the process for the impatient among us but but it comes at a cost and the cost may be \ too high when it finally reveal itself while infront of an adversary when they look at \ the encrypted container and manage to derive meaning based on how the container looks from outside.\n\ \n\ If you know what you are doing,then continue by all means,if in doubt,my advise is to endure the \ process and be safer in the long run." ) ; msg.ShowUIInfo( tr( "INFO" ),false,m ) ; } } void createfile::pbCreate() { auto fileName = m_ui->lineEditFileName->text() ; auto filePath = m_ui->lineEditFilePath->text() ; auto fileSize = m_ui->lineEditFileSize->text() ; if( fileName.isEmpty()){ return m_label.show( tr( "File name field is empty" ) ) ; } if( filePath.isEmpty()){ return m_label.show( tr( "File path field is empty" ) ) ; } if( fileSize.isEmpty()){ return m_label.show( tr( "File size field is empty" ) ) ; } if( m_ui->checkBoxNoRandomData->isChecked() ){ auto e = DialogMsg( this ).ShowUIYesNoDefaultNo( tr( "WARNING" ),tr( "Are you really sure you do not want to create a more secured volume?" ) ) ; if( e != QMessageBox::Yes ){ return ; } } bool test ; fileSize.toInt( &test ) ; if( test == false ){ return m_label.show( tr( "Illegal character in the file size field.Only digits are allowed" ) ) ; } if( utility::pathExists( filePath ) ){ return m_label.show( tr( "File with the same name and at the destination folder already exist" ) ) ; } if( !utility::canCreateFile( filePath ) ){ m_label.show( tr( "You dont seem to have writing access to the destination folder" ) ) ; m_ui->lineEditFilePath->setFocus() ; return ; } qint64 size = 0 ; switch( m_ui ->comboBox->currentIndex() ){ case 0 :size = fileSize.toLongLong() * 1024 ; break ; case 1 :size = fileSize.toLongLong() * 1024 * 1024 ; break ; case 2 :size = fileSize.toLongLong() * 1024 * 1024 * 1024 ; break ; } if( size < 3145728 ){ return m_label.show( tr( "Container file must be bigger than 3MB" ) ) ; } this->disableAll() ; m_ui->progressBar->setValue( 0 ) ; m_exit = false ; if( m_ui->checkBoxNoRandomData->isChecked() ){ QFile file( filePath ) ; if( !file.open( QIODevice::WriteOnly ) ){ return m_label.show( tr( "Failed to create volume file" ) ) ; } utility::changePathOwner( file ) ; if( !file.resize( size ) ){ QFile::remove( filePath ) ; return m_label.show( tr( "Failed to create volume file" ) ) ; } file.close() ; m_function( filePath ) ; }else{ m_running = true ; if( utility::useDmCryptForRandomData() ){ if( utility::requireSystemPermissions( filePath ) ){ if( !utility::enablePolkit( utility::background_thread::False ) ){ return m_label.show( tr( "Failed to enable polkit support" ) ) ; } } QFile file( filePath ) ; if( !file.open( QIODevice::WriteOnly ) ){ return m_label.show( tr( "Failed to create volume file" ) ) ; } utility::changePathOwner( file ) ; if( !file.resize( size ) ){ QFile::remove( filePath ) ; return m_label.show( tr( "Failed to create volume file" ) ) ; } file.close() ; utility::progress update( 1500,[ this ]( const utility::progress::result& m ){ emit sendProgress( m.current_speed, m.average_speed, m.eta, m.total_time, m.percentage_done ) ; } ) ; int r = utility::clearVolume( filePath,&m_exit,0,update.updater_quint() ).await() ; if( r == 5 ){ m_label.show( tr( "Operation terminated per user choice" ) ) ; QFile::remove( filePath ) ; }else if( r == 0 ){ m_function( filePath ) ; }else{ m_label.show( tr( "Could not open cryptographic back end to generate random data" ) ) ; QFile::remove( filePath ) ; } }else{ this->createFile( filePath,size ) ; } m_running = false ; } this->HideUI() ; } void createfile::createFile( const QString& filePath,qint64 size ) { enum class result{ success,deviceFail,cancelled,fileFail } ; utility::progress update( 1500,[ this ]( const utility::progress::result& m ){ emit sendProgress( m.current_speed, m.average_speed, m.eta, m.total_time, m.percentage_done ) ; } ) ; auto s = Task::await( [ & ]{ auto rd = utility::RandomDataSource::get() ; if( !rd->open() ){ return result::deviceFail ; } QFile file( filePath ) ; if( !file.open( QIODevice::WriteOnly ) ){ return result::fileFail ; } auto function = update.updater_qint() ; std::array< char,1024 > buffer ; qint64 size_written = 0 ; while( size_written < size ){ if( m_exit ){ return result::cancelled ; }else{ auto s = rd->getData( buffer.data(),buffer.size() ) ; auto m = file.write( buffer.data(),s ) ; if( m == -1 ){ //WTF!! } file.flush() ; size_written += m ; function( size,size_written ) ; } } file.resize( size ) ; return result::success ; } ) ; switch( s ) { case result::success : m_function( filePath ) ; break ; case result::fileFail : m_label.show( tr( "Failed to create volume file" ) ) ; break ; case result::deviceFail : m_label.show( tr( "Could not open cryptographic back end to generate random data" ) ) ; break ; case result::cancelled : m_label.show( tr( "Operation terminated per user choice" ) ) ; break ; } } void createfile::pbCancel() { if( m_running ){ auto x = tr( "Terminating file creation process" ) ; auto y = tr( "Are you sure you want to stop file creation process?" ) ; DialogMsg msg( this ) ; if( msg.ShowUIYesNoDefaultNo( x,y ) == QMessageBox::Yes ){ m_exit = true ; } }else{ this->HideUI() ; } } void createfile::HideUI() { this->hide() ; this->deleteLater() ; } void createfile::setProgress( QString cs,QString av,QString eta,QString tt,int st ) { Q_UNUSED( cs ) Q_UNUSED( tt ) QString a = tr( "Average Speed:" ) + " " + av ; QString b = tr( "ETA:" ) + " " + eta ; this->setWindowTitle( a + " : " + b ) ; m_ui->progressBar->setValue( st ) ; } void createfile::pbOpenFolder() { auto p = tr( "Select Path to where the file will be created" ) ; auto q = utility::homePath() ; auto x = QFileDialog::getExistingDirectory( this,p,q,QFileDialog::ShowDirsOnly ) ; while( true ){ if( x.endsWith( '/' ) ){ x.truncate( x.length() - 1 ) ; }else{ break ; } } if( !x.isEmpty() ){ x = x + "/" + m_ui->lineEditFilePath->text().split( "/" ).last() ; m_ui->lineEditFilePath->setText( x ) ; } } createfile::~createfile() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/createfile.h000066400000000000000000000037311425361753700206400ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef CREATEFILE_H #define CREATEFILE_H #include #include "utility.h" class DialogMsg ; class QPushButton ; class FileTask ; class QCloseEvent ; class createfile ; namespace Ui { class createfile ; } class createfile : public QDialog { Q_OBJECT public: static createfile& instance( QWidget * parent,std::function< void( const QString& ) > f ) { return *( new createfile( parent,std::move( f ) ) ) ; } explicit createfile( QWidget *,std::function< void( const QString& ) > ) ; ~createfile() ; signals : void sendProgress( QString,QString,QString,QString,int ) ; public slots: void warnAboutRandomData( int ) ; void HideUI( void ) ; void showUI( void ) ; void pbOpenFolder( void ) ; void pbCancel( void ) ; void pbCreate( void ) ; private slots: void setProgress( QString,QString,QString,QString,int ) ; void fileTextChange( QString ) ; private: void createFile( const QString&,qint64 ) ; void enableAll( void ) ; void disableAll( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::createfile * m_ui ; std::atomic_bool m_exit ; bool m_running ; std::function< void( const QString& ) > m_function ; utility::label m_label ; }; #endif // CREATEFILE_H zuluCrypt-6.2.0/zuluCrypt-gui/createfile.ui000066400000000000000000000147511425361753700210320ustar00rootroot00000000000000 createfile Qt::ApplicationModal 0 0 521 225 Create A Container File 120 10 281 31 10 10 101 31 File Name Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 120 40 281 31 10 40 101 31 File Path Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 10 140 101 31 File Size Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 120 140 113 31 120 170 281 21 24 400 40 31 31 open a folder dialog box 260 190 111 31 &Cancel true false 10 160 101 41 % Complete Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 150 190 111 31 C&reate true true 230 140 51 31 true KB MB GB 120 70 21 71 150 70 251 71 Do Not Write Random Data To Container(STRONGLY discouraged) true 0 0 521 221 true TextLabel Qt::AlignCenter true 200 190 121 33 &OK lineEditFileName lineEditFilePath pbOpenFolder lineEditFileSize comboBox pbCreate pbCancel zuluCrypt-6.2.0/zuluCrypt-gui/createkeyfile.cpp000066400000000000000000000130041425361753700216760ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "createkeyfile.h" #include "ui_createkeyfile.h" #include "utility.h" #include "../zuluCrypt-cli/constants.h" #include #include #include #include #include #include #include #include "utility.h" #include "dialogmsg.h" #include #include #include #include #include createkeyfile::createkeyfile( QWidget * parent ) : QDialog( parent ),m_ui( new Ui::createkeyfile ) { m_ui->setupUi( this ) ; this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; m_ui->pbOpenFolder->setIcon( QIcon( ":/folder.png" ) ) ; connect( m_ui->pbCreate,SIGNAL( clicked() ),this,SLOT( pbCreate() ) ) ; connect( m_ui->pbOpenFolder,SIGNAL( clicked() ),this,SLOT( pbOpenFolder() ) ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->lineEditFileName,SIGNAL( textChanged( QString ) ),this,SLOT( keyTextChange( QString ) ) ) ; this->installEventFilter( this ) ; m_running = false ; m_label.setOptions( m_ui->label_3,m_ui->pushButton ) ; this->ShowUI() ; } bool createkeyfile::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void createkeyfile::keyTextChange( QString txt ) { auto p = m_ui->lineEditPath->text() ; if( p.isEmpty() ){ auto x = utility::homePath() + "/" + txt.split( "/" ).last() ; m_ui->lineEditPath->setText( x ) ; }else{ int i = p.lastIndexOf( "/" ) ; if( i != -1 ){ p = p.mid( 0,i ) + "/" + txt.split( "/" ).last() ; m_ui->lineEditPath->setText( p ) ; } } } void createkeyfile::HideUI() { this->hide() ; this->deleteLater() ; } void createkeyfile::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbCancel() ; } void createkeyfile::ShowUI() { m_ui->lineEditFileName->clear() ; m_ui->lineEditPath->setText( utility::homePath() + "/" ) ; m_ui->comboBoxRNG->setCurrentIndex( 0 ) ; this->show() ; } void createkeyfile::pbCancel() { if( m_running ){ m_stop = true ; }else{ this->HideUI() ; } } void createkeyfile::enableAll() { m_ui->label->setEnabled( true ) ; m_ui->label_2->setEnabled( true ) ; m_ui->lineEditFileName->setEnabled( true ) ; m_ui->lineEditPath->setEnabled( true ) ; m_ui->pbCreate->setEnabled( true ) ; m_ui->pbOpenFolder->setEnabled( true ) ; m_ui->labelRNG->setEnabled( true ) ; m_ui->comboBoxRNG->setEnabled( true ) ; } void createkeyfile::disableAll() { m_ui->label->setEnabled( false ) ; m_ui->label_2->setEnabled( false ) ; m_ui->lineEditFileName->setEnabled( false ) ; m_ui->lineEditPath->setEnabled( false ) ; m_ui->pbCreate->setEnabled( false ) ; m_ui->pbOpenFolder->setEnabled( false ) ; m_ui->labelRNG->setEnabled( false ) ; m_ui->comboBoxRNG->setEnabled( false ) ; } void createkeyfile::pbCreate() { auto fileName = m_ui->lineEditFileName->text() ; auto path = m_ui->lineEditPath->text() ; if( fileName.isEmpty() ){ return m_label.show( tr( "The key name field is empty" ) ) ; } if( path.isEmpty() ){ return m_label.show( tr( "Folder path to where the key will be created is empty" ) ) ; } if( utility::pathExists( path ) ){ return m_label.show( tr( "File with the same name and at the destination folder already exist" ) ) ; } if( !utility::canCreateFile( path ) ){ m_label.show( tr( "You dont seem to have writing access to the destination folder" ) ) ; m_ui->lineEditPath->setFocus() ; return ; } this->disableAll() ; m_stop = false ; m_running = true ; auto _getRNGSource = [ this ](){ if( m_ui->comboBoxRNG->currentIndex() == 0 ){ return "/dev/urandom" ; }else{ return "/dev/random" ; } } ; Task::await( [ & ](){ utility::fileHandle source ; if( !source.open( _getRNGSource() ) ){ m_stop = true ; }else{ utility::fileHandle sink ; if( !sink.open( path,false ) ){ m_stop = true ; }else{ utility::changePathOwner( sink ) ; for( int i = 0 ; i < 64 ; i++ ){ if( m_stop ){ break ; }else{ sink.writeChar( source.getChar() ) ; } } } } } ) ; m_running = false ; if( m_stop ){ m_label.show( tr( "Process interrupted,key not fully generated" ) ) ; this->enableAll() ; }else{ m_label.show( tr( "KeyFile successfully created" ) ) ; this->HideUI() ; } } void createkeyfile::pbOpenFolder() { auto p = tr( "Select A Folder To Create A Key File In" ) ; auto q = utility::homePath() ; auto x = QFileDialog::getExistingDirectory( this,p,q,QFileDialog::ShowDirsOnly ) ; while( true ){ if( x.endsWith( '/' ) ){ x.truncate( x.length() - 1 ) ; }else{ break ; } } if( !x.isEmpty() ){ x = x + "/" + m_ui->lineEditPath->text().split( "/" ).last() ; m_ui->lineEditPath->setText( x ) ; } } createkeyfile::~createkeyfile() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/createkeyfile.h000066400000000000000000000032421425361753700213460ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef CREATEKEYFILE_H #define CREATEKEYFILE_H #include #include #include "utility.h" class QWidget ; class keyFileTask ; class QCloseEvent ; namespace Ui { class createkeyfile ; } class createkeyfile : public QDialog { Q_OBJECT public: static createkeyfile& instance( QWidget * parent ) { return *( new createkeyfile( parent ) ) ; } explicit createkeyfile( QWidget * parent = 0 ) ; ~createkeyfile() ; signals: void HideUISignal( void ) ; public slots: void ShowUI( void ) ; void HideUI( void ) ; private slots: void pbCancel( void ) ; void pbCreate( void ) ; void pbOpenFolder( void ) ; void keyTextChange( QString ) ; private: void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; void disableAll( void ) ; void enableAll( void ) ; Ui::createkeyfile * m_ui ; bool m_running ; bool m_stop ; utility::label m_label ; }; #endif // CREATEKEYFILE_H zuluCrypt-6.2.0/zuluCrypt-gui/createkeyfile.ui000066400000000000000000000116031425361753700215340ustar00rootroot00000000000000 createkeyfile Qt::ApplicationModal 0 0 551 133 Create A KeyFile 120 10 311 31 10 10 101 31 Keyfile Name Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 120 40 311 31 path to a folder to create a key in 430 40 31 31 open a folder a key file will be created in 200 100 81 31 C&reate true true 280 100 81 31 &Cancel true false 10 40 101 31 KeyFile Path Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 10 70 101 31 RNG Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 120 70 161 31 /dev/urandom /dev/random 0 0 551 131 true TextLabel Qt::AlignCenter true 220 100 111 33 &OK lineEditFileName lineEditPath pbOpenFolder comboBoxRNG pbCreate pbCancel zuluCrypt-6.2.0/zuluCrypt-gui/createvolume.cpp000066400000000000000000001164101425361753700215620ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "utility.h" #include "createvolume.h" #include "ui_createvolume.h" #include #include #include #include #include #include #include #include #include "task.hpp" #include "utility.h" #include "erasedevice.h" #include "createvolumedialog.h" #include "dialogmsg.h" #include "tcrypt.h" #include #include "plugin.h" #include #include "../zuluCrypt-cli/constants.h" createvolume::createvolume( QWidget * parent ) : QDialog( parent ),m_ui( new Ui::createvolume ) { m_ui->setupUi( this ) ; this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; m_ui->lineEditVolumePath->setEnabled( false ) ; m_ui->lineEditPassphrase1->setFocus() ; m_isWindowClosable = true ; m_warned = false ; m_ui->lineEditIterationNumber->setVisible( false ) ; m_ui->labelIterationNumber->setVisible( false ) ; m_ui->groupBoxLUKS2Options->setVisible( false ) ; m_ui->labelLUKS2Options->setVisible( false ) ; connect( m_ui->pbLuks2Set,&QPushButton::clicked,[ this ](){ m_ui->groupBoxLUKS2Options->setVisible( false ) ; m_ui->labelLUKS2Options->setVisible( false ) ; } ) ; connect( m_ui->pbLUKS2Options,&QPushButton::clicked,[ this ](){ m_showingLuks2AdvanceOptions = true ; m_ui->groupBoxLUKS2Options->setVisible( true ) ; m_ui->labelLUKS2Options->setVisible( true ) ; } ) ; connect( m_ui->pbLuks2Cancel,&QPushButton::clicked,[ this ](){ this->luks2Cancel() ; } ) ; auto m = static_cast< void ( QComboBox::* )( int ) >( &QComboBox::currentIndexChanged ) ; connect( m_ui->cbLuks2Pbkdf,m,[ this ]( int s ){ if( s == 2 ){ m_ui->lineEditLuks2MaxMemory->clear() ; m_ui->lineEditLuks2ParallelThreads->clear() ; m_ui->lineEditLuks2MaxMemory->setEnabled( false ) ; m_ui->lineEditLuks2ParallelThreads->setEnabled( false ) ; }else{ m_ui->lineEditLuks2MaxMemory->setEnabled( true ) ; m_ui->lineEditLuks2ParallelThreads->setEnabled( true ) ; } } ) ; #ifdef CRYPT_LUKS2 m_ui->cbLuks2AllowDiscard->setEnabled( true ) ; #else m_ui->cbLuks2AllowDiscard->setEnabled( false ) ; #endif connect( m_ui->pbOpenKeyFile,SIGNAL( clicked() ),this,SLOT( pbOpenKeyFile() ) ) ; connect( m_ui->pbCreate,SIGNAL( clicked() ),this,SLOT( pbCreateClicked() ) ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancelClicked() ) ) ; connect( m_ui->cbNormalVolume,SIGNAL( activated( int ) ),this,SLOT( cbNormalVolume( int ) ) ) ; connect( m_ui->cbHiddenVolume,SIGNAL( activated( int ) ),this,SLOT( cbHiddenVolume( int ) ) ) ; connect( m_ui->comboBoxVolumeType,SIGNAL( currentIndexChanged( int ) ),this,SLOT( volumeType( int ) ) ) ; connect( m_ui->lineEditPassphrase1,SIGNAL( textChanged( QString ) ),this,SLOT( keyChanged_0( QString ) ) ) ; connect( m_ui->lineEditHiddenKey,SIGNAL( textChanged( QString ) ),this,SLOT( keyChanged_1( QString ) ) ) ; connect( m_ui->pbHiddenKeyFile,SIGNAL( clicked() ),this,SLOT( pbOpenHiddenKeyFile() ) ) ; connect( m_ui->comboBoxVolumeType,SIGNAL( activated( int ) ),this,SLOT( setOptions( int ) ) ) ; this->installEventFilter( this ) ; m_ui->labelvolumeOptions->setVisible( false ) ; auto a = tr( "Options are separated by a \".\" character.\n\n" ) ; auto b = tr( "Multiple algorithms are separated by \":\" character.\n\n" ) ; auto c = tr( "Options are in a format of \"algorithm.cipher mode.key size in bits.hash\"\n\n") ; auto d = tr( "Default option is the first entry on the list" ) ; m_ui->comboBoxOptions->setToolTip( a + b + c + d ) ; m_ui->cbNormalVolume->addItem( tr( "Key" ) ) ; m_ui->cbNormalVolume->addItem( tr( "KeyFile" ) ) ; m_ui->cbNormalVolume->addItem( tr( "Key+KeyFile" ) ) ; m_ui->cbNormalVolume->addItem( tr( "YubiKey Challenge/Response" ) ) ; m_ui->cbHiddenVolume->addItem( tr( "Key" ) ) ; m_ui->cbHiddenVolume->addItem( tr( "KeyFile" ) ) ; m_ui->cbHiddenVolume->addItem( tr( "Key+KeyFile" ) ) ; m_ui->cbHiddenVolume->addItem( tr( "YubiKey Challenge/Response" ) ) ; m_veraCryptWarning.setWarningLabel( m_ui->veraCryptWarning ) ; /* * for simplicity's sake,lets only show most popular file systems. */ m_ui->comboBoxFS->addItems( utility::supportedFileSystems() ) ; m_ui->comboBoxVolumeType->clear() ; m_ui->comboBoxVolumeType->addItem( tr( "PLAIN dm-crypt" ) ) ; m_ui->comboBoxVolumeType->addItem( tr( "PLAIN dm-crypt with offset" ) ) ; #ifdef CRYPT_LUKS2 m_ui->comboBoxVolumeType->addItem( tr( "LUKS1" ) ) ; m_ui->comboBoxVolumeType->addItem( tr( "LUKS1+External Header" ) ) ; m_ui->comboBoxVolumeType->addItem( tr( "LUKS2" ) ) ; m_ui->comboBoxVolumeType->addItem( tr( "LUKS2+External Header" ) ) ; #else m_ui->comboBoxVolumeType->addItem( tr( "LUKS" ) ) ; m_ui->comboBoxVolumeType->addItem( tr( "LUKS+External Header" ) ) ; #endif m_ui->comboBoxVolumeType->addItem( tr( "Normal TrueCrypt" ) ) ; m_ui->comboBoxVolumeType->addItem( tr( "Normal+Hidden TrueCrypt" ) ) ; m_ui->comboBoxVolumeType->addItem( tr( "Normal VeraCrypt" ) ) ; m_ui->comboBoxVolumeType->addItem( tr( "Normal+Hidden VeraCrypt" ) ) ; #ifdef CRYPT_LUKS2 m_ui->comboBoxVolumeType->setCurrentIndex( int( createvolume::luks2 ) ) ; #else m_ui->comboBoxVolumeType->setCurrentIndex( int( createvolume::luks ) ) ; #endif m_ui->comboBoxHiddenSize->setCurrentIndex( 2 ) ; this->setOptions( 1 ) ; } void createvolume::keyChanged_0( QString key ) { if( m_keyStrength.canCheckQuality() ){ if( m_ui->cbNormalVolume->currentIndex() == 0 ){ return this->keyChanged( true,key ) ; } } this->keyChanged( false,QString() ) ; } void createvolume::keyChanged_1( QString key ) { if( m_keyStrength.canCheckQuality() ){ if( m_ui->cbHiddenVolume->currentIndex() == 0 ){ return this->keyChanged( true,key ) ; } } this->keyChanged( false,QString() ) ; } void createvolume::keyChanged( bool check,const QString& key ) { if( check ){ int st = m_keyStrength.quality( key ) ; if( st < 0 ){ this->setWindowTitle( tr( "Passphrase Quality: 0%" ) ) ; }else{ this->setWindowTitle( tr( "Passphrase Quality: %1%" ).arg( QString::number( st ) ) ) ; } }else{ this->setWindowTitle( tr( "Create A New Volume" ) ) ; } } bool createvolume::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void createvolume::volumeType( int s ) { m_ui->cbNormalVolume->clear() ; m_ui->cbHiddenVolume->clear() ; m_ui->cbNormalVolume->addItem( tr( "Key" ) ) ; m_ui->cbNormalVolume->addItem( tr( "KeyFile" ) ) ; m_ui->cbNormalVolume->addItem( tr( "Key+KeyFile" ) ) ; m_ui->cbNormalVolume->addItem( tr( "YubiKey Challenge/Response" ) ) ; m_ui->cbHiddenVolume->addItem( tr( "Key" ) ) ; m_ui->cbHiddenVolume->addItem( tr( "KeyFile" ) ) ; m_ui->cbHiddenVolume->addItem( tr( "Key+KeyFile" ) ) ; m_ui->cbHiddenVolume->addItem( tr( "YubiKey Challenge/Response" ) ) ; auto _enableHidden = [ this ](){ m_ui->lineEditHiddenKey->setEnabled( true ) ; m_ui->lineEditHiddenKey1->setEnabled( true ) ; m_ui->lineEditHiddenSize->setEnabled( true ) ; m_ui->pbHiddenKeyFile->setEnabled( true ) ; m_ui->comboBoxHiddenSize->setEnabled( true ) ; m_ui->cbHiddenVolume->setEnabled( true ) ; m_ui->label->setEnabled( true ) ; m_ui->labelHidden->setEnabled( true ) ; m_ui->label_2Hidden->setEnabled( true ) ; } ; auto _disableHidden = [ this ](){ m_ui->lineEditHiddenKey->clear() ; m_ui->lineEditHiddenKey1->clear() ; m_ui->lineEditHiddenSize->clear() ; m_ui->lineEditHiddenKey->setEnabled( false ) ; m_ui->lineEditHiddenKey1->setEnabled( false ) ; m_ui->pbHiddenKeyFile->setEnabled( false ) ; m_ui->comboBoxHiddenSize->setEnabled( false ) ; m_ui->cbHiddenVolume->setEnabled( false ) ; m_ui->labelHidden->setEnabled( false ) ; m_ui->label_2Hidden->setEnabled( false ) ; auto e = m_ui->comboBoxVolumeType->currentIndex() == createvolume::plain_with_offset ; m_ui->label->setEnabled( e ) ; m_ui->lineEditHiddenSize->setEnabled( e ) ; m_ui->comboBoxHiddenSize->setEnabled( e ) ; } ; auto type = createvolume::createVolumeType( s ) ; switch( type ){ case createvolume::luks : case createvolume::luks_external_header : #ifdef CRYPT_LUKS2 case createvolume::luks2 : case createvolume::luks2_external_header : #endif m_ui->comboBoxRNG->setEnabled( true ) ; m_ui->label_2->setEnabled( false ) ; m_ui->lineEditPIM->setEnabled( false ) ; _disableHidden() ; break ; case createvolume::plain : case createvolume::plain_with_offset : m_ui->comboBoxRNG->setEnabled( false ) ; m_ui->label_2->setEnabled( false ) ; m_ui->lineEditPIM->setEnabled( false ) ; _disableHidden() ; break ; case createvolume::normal_truecrypt : m_ui->comboBoxRNG->setEnabled( true ) ; m_ui->cbNormalVolume->addItem( tr( "TrueCrypt Keys" ) ) ; m_ui->label_2->setEnabled( false ) ; m_ui->lineEditPIM->setEnabled( false ) ; _disableHidden() ; break ; case createvolume::normal_veracrypt : m_ui->comboBoxRNG->setEnabled( true ) ; m_ui->cbNormalVolume->addItem( tr( "VeraCrypt Keys" ) ) ; m_ui->label_2->setEnabled( true ) ; m_ui->lineEditPIM->setEnabled( true ) ; _disableHidden() ; break ; case createvolume::normal_and_hidden_truecrypt : m_ui->comboBoxRNG->setEnabled( true ) ; m_ui->cbHiddenVolume->setCurrentIndex( 0 ) ; m_ui->cbHiddenVolume->addItem( tr( "TrueCrypt Keys" ) ) ; m_ui->cbNormalVolume->addItem( tr( "TrueCrypt Keys" ) ) ; m_ui->label_2->setEnabled( false ) ; m_ui->lineEditPIM->setEnabled( false ) ; this->cbHiddenVolume( 0 ) ; _enableHidden() ; break ; case createvolume::normal_and_hidden_veracrypt : m_ui->comboBoxRNG->setEnabled( true ) ; m_ui->cbHiddenVolume->setCurrentIndex( 0 ) ; m_ui->cbHiddenVolume->addItem( tr( "VeraCrypt Keys" ) ) ; m_ui->cbNormalVolume->addItem( tr( "VeraCrypt Keys" ) ) ; m_ui->label_2->setEnabled( true ) ; m_ui->lineEditPIM->setEnabled( true ) ; this->cbHiddenVolume( 0 ) ; _enableHidden() ; break ; } if( type == createvolume::plain_with_offset ){ m_ui->label->setText( tr( "Volume Offset" ) ) ; }else{ m_ui->label->setText( tr( "Volume Size" ) ) ; } } void createvolume::closeEvent( QCloseEvent * e ) { e->ignore() ; if( m_showingLuks2AdvanceOptions ){ this->luks2Cancel() ; }else{ if( m_isWindowClosable ){ this->pbCancelClicked() ; } } } void createvolume::ShowPartition( QString volume ) { this->ShowUI( tr( "Path To Device" ),volume ) ; } void createvolume::ShowFile( QString volume ) { this->ShowUI( tr( "Path To File" ),volume ) ; } void createvolume::eraseDataPartition() { auto path = m_ui->lineEditVolumePath->text() ; if( path.startsWith( "/dev/" ) ){ createVolumeDialog::instance( path,this,[ this ]( int r ){ if( r == 0 ){ this->HideUI() ; }else if( r == 1 ){ }else if( r == 2 ){ erasedevice::instance( this ).ShowUI( m_ui->lineEditVolumePath->text() ) ; } } ) ; } } void createvolume::setOptions( int e ) { auto options = m_ui->comboBoxOptions ; options->clear() ; /* * constructed structure format is: algorithm.cipher mode.key size in bits.hash function. * examples structures : * "aes.cbc-essiv:256.256.ripemd160" * "aes.xts-plain64.256.sha1" * "serpent:twofish:aes.xts-plain64.256.sha1" */ /* * we only support whirlpool if the user has libgcrypt >= 1.6.1 and cryptsetup >= 1.6.4 * read section 8.3 of the following link for more info: * https://code.google.com/p/cryptsetup/wiki/FrequentlyAskedQuestions * */ bool supportWhirlpool = utility::userHasGoodVersionOfWhirlpool() ; Q_UNUSED( e ) auto _plain_dmcrypt = [ this ](){ auto type = m_ui->comboBoxVolumeType->currentIndex() ; return type == createvolume::plain || type == createvolume::plain_with_offset ; } ; auto _luks = [ this ](){ auto type = m_ui->comboBoxVolumeType->currentIndex() ; #ifdef CRYPT_LUKS2 return type == createvolume::luks || type == createvolume::luks_external_header || type == createvolume::luks2_external_header || type == createvolume::luks2 ; #else return type == createvolume::luks || type == createvolume::luks_external_header ; #endif } ; auto luksSelected = _luks() ; #ifdef CRYPT_LUKS2 auto type = m_ui->comboBoxVolumeType->currentIndex() ; m_ui->pbLUKS2Options->setEnabled( type == createvolume::luks2_external_header || type == createvolume::luks2 ) ; #else m_ui->pbLUKS2Options->setEnabled( false ) ; #endif if( _plain_dmcrypt() ){ /* * crypto options for plain dm-crypt volumes */ auto s = utility::plainDmCryptOptions() ; if( s.isEmpty() ){ options->addItem( "aes.cbc-essiv:256.256.ripemd160" ) ; }else{ options->addItems( s ) ; } }else if( luksSelected ){ /* * cryto options for LUKS volumes. */ auto _add_options = [ & ]( const std::initializer_list& list ){ auto _add_option = [ & ]( const QString& algo,const QString& keySize ){ options->addItem( algo + ".xts-plain64." + keySize + ".sha256" ) ; options->addItem( algo + ".xts-plain64." + keySize + ".sha512" ) ; options->addItem( algo + ".xts-plain64." + keySize + ".sha1" ) ; options->addItem( algo + ".xts-plain64." + keySize + ".ripemd160" ) ; if( supportWhirlpool ){ options->addItem( algo + ".xts-plain64." + keySize + ".whirlpool" ) ; } } ; for( const auto& it : list ){ _add_option( it,"512" ) ; } for( const auto& it : list ){ _add_option( it,"256" ) ; } } ; _add_options( { "aes","serpent","twofish" } ) ; }else{ /* * crypto options for TrueCrypt and VeraCrypt volumes */ auto _add_options = [ & ]( const std::initializer_list& list ){ auto _veraCryptVolume = [ & ](){ using cv = createvolume ; auto e = cv::createVolumeType( m_ui->comboBoxVolumeType->currentIndex() ) ; return e == cv::normal_veracrypt || e == cv::normal_and_hidden_veracrypt ; } ; auto _add_option = [ & ]( const QString& algo ){ if( _veraCryptVolume() ){ options->addItem( algo + ".xts-plain64.256.sha512" ) ; options->addItem( algo + ".xts-plain64.256.ripemd160" ) ; }else{ options->addItem( algo + ".xts-plain64.256.ripemd160" ) ; options->addItem( algo + ".xts-plain64.256.sha512" ) ; } if( supportWhirlpool ){ options->addItem( algo + ".xts-plain64.256.whirlpool" ) ; } } ; for( const auto& it : list ){ _add_option( it ) ; } } ; _add_options( { "aes", "serpent", "twofish", "aes:serpent", "twofish:aes", "serpent:twofish", "aes:twofish:serpent", "serpent:twofish:aes" } ) ; } } void createvolume::ShowUI( const QString& l,const QString& v ) { this->enableAll() ; m_ui->labelVolumePath->setText( l ) ; m_ui->lineEditVolumePath->setText( v ) ; m_ui->pbOpenKeyFile->setEnabled( false ) ; m_ui->lineEditVolumePath->setEnabled( false ) ; this->cbNormalVolume( 0 ) ; m_ui->lineEditPassphrase1->setFocus() ; m_ui->comboBoxFS->setCurrentIndex( 0 ) ; m_ui->comboBoxRNG->setCurrentIndex( 0 ) ; m_ui->labelRepeatPassPhrase->setEnabled( true ) ; m_created = false ; this->show() ; this->eraseDataPartition() ; } void createvolume::pbOpenKeyFile() { auto Z = QFileDialog::getOpenFileName( this,tr( "Keyfile Path" ),utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->lineEditPassphrase1->setText( Z ) ; } } void createvolume::pbOpenHiddenKeyFile() { auto Z = QFileDialog::getOpenFileName( this,tr( "Keyfile Path" ),utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->lineEditHiddenKey->setText( Z ) ; } } void createvolume::pbCancelClicked() { #if 0 if( m_created == false ){ auto s = m_ui->lineEditVolumePath->text() ; if( !s.startsWith( "/dev/" ) ){ if( utility::loopDevicePath( s ).isEmpty() ){ QFile::remove( s ) ; } } } #endif this->HideUI() ; } void createvolume::tcryptGui( bool e ) { m_normalVolume = e ; //this->disableAll() ; tcrypt::instance( this,true,[ this ]( const QString& key,const QStringList& keyFiles ){ //this->enableAll() ; if( m_normalVolume ){ m_key = key ; m_keyFiles = keyFiles ; }else{ m_hiddenKey = key ; m_hiddenKeyFiles = keyFiles ; } },[ this ](){ //this->enableAll() ; bool x = m_ui->cbNormalVolume->currentIndex() == createvolume::normal_truecrypt ; bool y = m_ui->cbNormalVolume->currentIndex() == createvolume::normal_veracrypt ; if( x || y ){ m_ui->pbOpenKeyFile->setEnabled( false ) ; m_ui->lineEditPassphrase1->setEnabled( false ) ; } if( m_normalVolume ){ m_key.clear() ; m_keyFiles.clear() ; }else{ m_hiddenKey.clear() ; m_hiddenKeyFiles.clear() ; } } ) ; } void createvolume::luks2Cancel() { m_showingLuks2AdvanceOptions = false ; m_ui->groupBoxLUKS2Options->setVisible( false ) ; m_ui->labelLUKS2Options->setVisible( false ) ; m_ui->lineEditLuks2ForcedIteration->clear() ; m_ui->lineEditLuks2UnlockingTime->clear() ; m_ui->lineEditLuks2ParallelThreads->clear() ; m_ui->lineEditLuks2MaxMemory->clear() ; m_ui->lineLEdituks2Label->clear() ; m_ui->lineEditLuks2SubSystem->clear() ; m_ui->cbLuks2Pbkdf->setCurrentIndex( 0 ) ; m_ui->cbLuks2AllowDiscard->setChecked( false ) ; } void createvolume::cbNormalVolume( int r ) { this->setWindowTitle( tr( "Create A New Volume" ) ) ; auto _set_key_ui = [ this ](){ m_ui->pbOpenKeyFile->setEnabled( false ) ; m_ui->lineEditPassPhrase2->setEnabled( true ) ; m_ui->lineEditPassphrase1->setEnabled( true ) ; m_ui->lineEditPassphrase1->clear() ; m_ui->lineEditPassPhrase2->clear() ; m_ui->lineEditPassphrase1->setEchoMode( QLineEdit::Password ) ; m_ui->lineEditPassPhrase2->setEchoMode( QLineEdit::Password ) ; m_ui->labelPassPhrase->setText( tr( "Password" ) ) ; m_ui->labelRepeatPassPhrase->setEnabled( true ) ; m_ui->pbOpenKeyFile->setIcon( QIcon( ":/passphrase.png" ) ) ; } ; if( r == 0 ){ _set_key_ui() ; }else if( r == 1 ){ m_ui->pbOpenKeyFile->setEnabled( true ) ; m_ui->lineEditPassphrase1->clear() ; m_ui->lineEditPassPhrase2->clear() ; m_ui->lineEditPassphrase1->setEchoMode( QLineEdit::Normal ) ; m_ui->lineEditPassPhrase2->setEnabled( false ) ; m_ui->labelPassPhrase->setText( tr( "KeyFile" ) ) ; m_ui->labelRepeatPassPhrase->setEnabled( false ) ; m_ui->pbOpenKeyFile->setIcon( QIcon( ":/keyfile.png" ) ) ; }else if( r == 2 ){ _set_key_ui() ; m_ui->lineEditPassphrase1->setEnabled( false ) ; m_ui->lineEditPassPhrase2->setEnabled( false ) ; plugin::instance( this,plugins::plugin::hmac_key,[ this ]( const QString& key ){ m_key = key ; m_ui->lineEditPassphrase1->setText( m_key ) ; m_ui->lineEditPassPhrase2->setText( m_key ) ; if( key.isEmpty() ){ m_ui->cbNormalVolume->setCurrentIndex( 0 ) ; this->cbNormalVolume( 0 ) ; }else{ if( m_keyStrength.canCheckQuality() ){ this->setWindowTitle( tr( "Passphrase Quality: 100%" ) ) ; } } } ) ; }else if( r == 3 ){ _set_key_ui() ; }else{ m_ui->pbOpenKeyFile->setEnabled( false ) ; m_ui->lineEditPassphrase1->clear() ; m_ui->lineEditPassPhrase2->clear() ; m_ui->lineEditPassphrase1->setEchoMode( QLineEdit::Normal ) ; m_ui->lineEditPassPhrase2->setEnabled( false ) ; m_ui->lineEditPassphrase1->setEnabled( false ) ; m_ui->lineEditPassphrase1->setText( QString() ) ; m_ui->lineEditPassPhrase2->setText( QString() ) ; m_ui->labelPassPhrase->setText( tr( "Keys" ) ) ; m_ui->labelRepeatPassPhrase->setEnabled( false ) ; m_ui->pbOpenKeyFile->setIcon( QIcon( ":/passphrase.png" ) ) ; this->tcryptGui( true ) ; } } void createvolume::cbHiddenVolume( int r ) { this->setWindowTitle( tr( "Create A New Volume" ) ) ; auto _set_key_ui = [ this ](){ m_ui->pbHiddenKeyFile->setEnabled( false ) ; m_ui->lineEditHiddenKey1->setEnabled( true ) ; m_ui->lineEditHiddenKey->setEnabled( true ) ; m_ui->lineEditHiddenKey->clear() ; m_ui->lineEditHiddenKey1->clear() ; m_ui->lineEditHiddenKey->setEchoMode( QLineEdit::Password ) ; m_ui->lineEditHiddenKey1->setEchoMode( QLineEdit::Password ) ; m_ui->labelHidden->setText( tr( "Password" ) ) ; m_ui->pbHiddenKeyFile->setIcon( QIcon( ":/passphrase.png" ) ) ; } ; if( r == 0 ){ _set_key_ui() ; }else if( r == 1 ){ m_ui->pbHiddenKeyFile->setEnabled( true ) ; m_ui->lineEditHiddenKey->clear() ; m_ui->lineEditHiddenKey1->clear() ; m_ui->lineEditHiddenKey->setEchoMode( QLineEdit::Normal ) ; m_ui->lineEditHiddenKey->setEnabled( true ) ; m_ui->lineEditHiddenKey1->setEnabled( false ) ; m_ui->labelHidden->setText( tr( "KeyFile" ) ) ; m_ui->pbHiddenKeyFile->setIcon( QIcon( ":/keyfile.png" ) ) ; }else if( r == 2 ){ _set_key_ui() ; m_ui->lineEditHiddenKey->setEnabled( false ) ; m_ui->lineEditHiddenKey1->setEnabled( false ) ; plugin::instance( this,plugins::plugin::hmac_key,[ this ]( const QString& key ){ m_hiddenKey = key ; m_ui->lineEditHiddenKey->setText( m_hiddenKey ) ; m_ui->lineEditHiddenKey1->setText( m_hiddenKey ) ; if( key.isEmpty() ){ m_ui->cbHiddenVolume->setCurrentIndex( 0 ) ; this->cbHiddenVolume( 0 ) ; }else{ if( m_keyStrength.canCheckQuality() ){ this->setWindowTitle( tr( "Passphrase Quality: 100%" ) ) ; } } } ) ; } else if( r == 3 ){ _set_key_ui() ; }else{ m_ui->pbHiddenKeyFile->setEnabled( false ) ; m_ui->lineEditHiddenKey->clear() ; m_ui->lineEditHiddenKey1->clear() ; m_ui->lineEditHiddenKey->setEchoMode( QLineEdit::Normal ) ; m_ui->lineEditHiddenKey1->setEnabled( false ) ; m_ui->lineEditHiddenKey->setEnabled( false ) ; m_ui->lineEditHiddenKey->setText( QString() ) ; m_ui->lineEditHiddenKey1->setText( QString() ) ; m_ui->labelHidden->setText( tr( "Keys" ) ) ; m_ui->pbHiddenKeyFile->setIcon( QIcon( ":/passphrase.png" ) ) ; this->tcryptGui( false ) ; } } void createvolume::HideUI() { this->hide() ; this->deleteLater() ; } void createvolume::enableAll() { m_ui->lineEditIterationNumber->setEnabled( true ) ; m_ui->labelIterationNumber->setEnabled( true ) ; auto enable = m_ui->comboBoxVolumeType->currentText().contains( "VeraCrypt" ) ; m_ui->label_2->setEnabled( enable ) ; m_ui->lineEditPIM->setEnabled( enable ) ; m_ui->labelPassPhrase->setEnabled( true ) ; m_ui->labelVolumePath->setEnabled( true ) ; m_ui->labelRepeatPassPhrase->setEnabled( true ) ; m_ui->lineEditPassphrase1->setEnabled( true ) ; if( m_ui->cbNormalVolume->currentIndex() == 0 || m_ui->cbNormalVolume->currentIndex() == 3 ){ m_ui->lineEditPassPhrase2->setEnabled( true ) ; } //m_ui->lineEditVolumePath->setEnabled( true ) ; m_ui->pbCancel->setEnabled( true ) ; m_ui->pbCreate->setEnabled( true ) ; m_ui->pbOpenKeyFile->setEnabled( true ) ; m_ui->labelfs->setEnabled( true ) ; m_ui->labelvolumetype->setEnabled( true ) ; m_ui->labelrng->setEnabled( true ) ; m_ui->comboBoxFS->setEnabled( true ) ; m_ui->comboBoxVolumeType->setEnabled( true ) ; m_ui->cbNormalVolume->setEnabled( true ) ; m_ui->labelvolumeOptions->setEnabled( true ) ; m_ui->comboBoxOptions->setEnabled( true ) ; auto e = m_ui->comboBoxVolumeType->currentIndex() ; if( e != createvolume::plain ){ m_ui->comboBoxRNG->setEnabled( true ) ; } if( e == createvolume::plain_with_offset ){ m_ui->lineEditHiddenSize->setEnabled( true ) ; m_ui->label->setEnabled( true ) ; m_ui->comboBoxHiddenSize->setEnabled( true ) ; }else if( e == createvolume::normal_and_hidden_truecrypt || e == createvolume::normal_and_hidden_veracrypt ){ m_ui->lineEditHiddenSize->setEnabled( true ) ; m_ui->label->setEnabled( true ) ; m_ui->comboBoxHiddenSize->setEnabled( true ) ; m_ui->cbHiddenVolume->setEnabled( true ) ; m_ui->pbHiddenKeyFile->setEnabled( true ) ; m_ui->cbHiddenVolume->setEnabled( true ) ; m_ui->labelHidden->setEnabled( true ) ; m_ui->label_2Hidden->setEnabled( true ) ; m_ui->lineEditHiddenKey->setEnabled( true ) ; m_ui->lineEditHiddenKey1->setEnabled( true ) ; m_ui->pbHiddenKeyFile->setEnabled( m_ui->cbHiddenVolume->currentIndex() == 1 ) ; m_ui->lineEditHiddenKey1->setEnabled( m_ui->cbHiddenVolume->currentIndex() != 1 ) ; } if( m_ui->comboBoxVolumeType->currentText().startsWith( "LUKS2" ) ){ m_ui->pbLUKS2Options->setEnabled( true ) ; } } void createvolume::disableAll() { m_ui->pbLUKS2Options->setEnabled( false ) ; m_ui->lineEditIterationNumber->setEnabled( false ) ; m_ui->labelIterationNumber->setEnabled( false ) ; m_ui->label_2->setEnabled( false ) ; m_ui->lineEditPIM->setEnabled( false ) ; m_ui->labelPassPhrase->setEnabled( false ) ; m_ui->labelVolumePath->setEnabled( false ) ; m_ui->labelRepeatPassPhrase->setEnabled( false ) ; m_ui->lineEditPassphrase1->setEnabled( false ) ; m_ui->lineEditPassPhrase2->setEnabled( false ) ; m_ui->lineEditVolumePath->setEnabled( false ) ; m_ui->pbCancel->setEnabled( false ) ; m_ui->pbCreate->setEnabled( false ) ; m_ui->pbOpenKeyFile->setEnabled( false ) ; m_ui->labelfs->setEnabled( false ) ; m_ui->labelrng->setEnabled( false ) ; m_ui->labelvolumetype->setEnabled( false ) ; m_ui->comboBoxFS->setEnabled( false ) ; m_ui->comboBoxVolumeType->setEnabled( false ) ; m_ui->comboBoxRNG->setEnabled( false ) ; m_ui->cbNormalVolume->setEnabled( false ) ; m_ui->labelvolumeOptions->setEnabled( false ) ; m_ui->comboBoxOptions->setEnabled( false ) ; m_ui->lineEditHiddenSize->setEnabled( false ) ; m_ui->label->setEnabled( false ) ; m_ui->comboBoxHiddenSize->setEnabled( false ) ; m_ui->labelHidden->setEnabled( false ) ; m_ui->label_2Hidden->setEnabled( false ) ; m_ui->lineEditHiddenKey->setEnabled( false ) ; m_ui->lineEditHiddenKey1->setEnabled( false ) ; m_ui->cbHiddenVolume->setEnabled( false ) ; m_ui->pbHiddenKeyFile->setEnabled( false ) ; } void createvolume::pbCreateClicked() { DialogMsg msg( this ) ; auto volumePath = m_ui->lineEditVolumePath->text() ; auto passphrase_1 = m_ui->lineEditPassphrase1->text() ; auto passphrase_2 = m_ui->lineEditPassPhrase2->text() ; this->disableAll() ; utility2::raii raii( [ this ](){ this->enableAll() ; } ) ; if( utility::requireSystemPermissions( volumePath ) ){ if( !utility::enablePolkit( utility::background_thread::False ) ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Failed to enable polkit support" ) ) ; } } createvolume::createVolumeType type = createvolume::createVolumeType( m_ui->comboBoxVolumeType->currentIndex() ) ; if( volumePath.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Volume path field is empty" ) ) ; } if( type == createvolume::plain_with_offset ){ if( m_ui->lineEditHiddenSize->text().isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; } } if( type == createvolume::normal_and_hidden_truecrypt || type == createvolume::normal_and_hidden_veracrypt ){ auto x = m_ui->lineEditHiddenSize->text() ; if( x.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; } bool ok ; x.toUInt( &ok ) ; if( !ok ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Illegal character detected in the hidden volume size field" ) ) ; } if( m_ui->cbHiddenVolume->currentIndex() < 3 ){ if( m_ui->cbHiddenVolume->currentIndex() == 0 ){ if( m_ui->lineEditHiddenKey->text() != m_ui->lineEditHiddenKey1->text() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Hidden passphrases do not match" ) ) ; } }else if( m_ui->cbHiddenVolume->currentIndex() == 1 ){ if( m_ui->lineEditHiddenKey->text().isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; } } } if( !m_ui->comboBoxFS->currentText().contains( "fat" ) && m_warned == false ){ m_warned = true ; return msg.ShowUIOK( tr( "WARNING" ),tr( "It is best to create a hidden volume with vfat/fat file system." ) ) ; } } QString source ; int r = m_ui->cbNormalVolume->currentIndex() ; if( r == 0 ){ if( passphrase_1 != passphrase_2 ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Passphrases do not match" ) ) ; }else{ source = "-f" ; passphrase_1 = utility::keyPath() + "-2" ; auto key = m_ui->lineEditPassphrase1->text() ; utility::keySend( passphrase_1,key ) ; } }else if( r == 1 ){ if( passphrase_1.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; }else{ source = "-f" ; passphrase_1 = utility::resolvePath( passphrase_1 ).replace( "\"","\"\"\"" ) ; } }else if( r == 2 ){ source = "-f" ; passphrase_1 = utility::keyPath() + "-2" ; utility::keySend( passphrase_1,m_key ) ; }else if( r == 3 ){ if( passphrase_1.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; } if( passphrase_1 != passphrase_2 ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Passphrases do not match" ) ) ; } auto m = utility::yubiKey( passphrase_1 ) ; if( m.has_value() ){ source = "-f" ; passphrase_1 = utility::keyPath() + "-2" ; utility::keySend( passphrase_1,m.value() ) ; }else{ return msg.ShowUIOK( tr( "ERROR" ),tr( "Failed To Locate Or Run Yubikey's \"ykchalresp\" Program." ) ) ; } } switch( type ){ case createvolume::luks : case createvolume::luks_external_header : m_volumeType = "luks" ; break ; #ifdef CRYPT_LUKS2 case createvolume::luks2 : case createvolume::luks2_external_header : m_volumeType = "luks2" ; break ; #endif case createvolume::plain : case createvolume::plain_with_offset : m_volumeType = "plain" ; break ; case createvolume::normal_truecrypt : case createvolume::normal_and_hidden_truecrypt : m_volumeType = "tcrypt" ; break ; case createvolume::normal_veracrypt : case createvolume::normal_and_hidden_veracrypt : m_volumeType = "vcrypt" ; break ; default: m_volumeType = "luks" ; } QString g ; switch( m_ui->comboBoxRNG->currentIndex() ){ case 0 : g = "/dev/urandom" ; break ; case 1 : g = "/dev/random" ; break ; default: g = "/dev/urandom" ; } g += "." + m_ui->comboBoxOptions->currentText() ; if( type == createvolume::plain_with_offset ){ g += "." + m_ui->lineEditHiddenSize->text() ; switch( m_ui->comboBoxHiddenSize->currentIndex() ){ case 0 : g += "b" ; break ; case 1 : g += "k" ; break ; case 2 : g += "m" ; break ; case 3 : g += "g" ; break ; } }else if( type == createvolume::plain ){ g += ".0" ; }else if( type == createvolume::normal_veracrypt || type == createvolume::normal_and_hidden_veracrypt ){ auto e = m_ui->lineEditPIM->text() ; if( !e.isEmpty() ){ g += "." + e ; } }else{ auto forcedIterations = m_ui->lineEditLuks2ForcedIteration->text() ; auto unlockingTime = m_ui->lineEditLuks2UnlockingTime->text() ; auto maxThreads = m_ui->lineEditLuks2ParallelThreads->text() ; auto maxMemory = m_ui->lineEditLuks2MaxMemory->text() ; auto label = m_ui->lineLEdituks2Label->text() ; auto subsystem = m_ui->lineEditLuks2SubSystem->text() ; auto pbkdf = m_ui->cbLuks2Pbkdf->currentText() ; QString integrity = "null" ; if( label.isEmpty() ){ label = "null" ; } if( subsystem.isEmpty() ){ subsystem = "null" ; } if( unlockingTime.isEmpty() ){ unlockingTime = "-1" ; } if( forcedIterations.isEmpty() ){ forcedIterations = "-1" ; } if( maxThreads.isEmpty() ){ maxThreads = "-1" ; } if( maxMemory.isEmpty() ){ maxMemory = "-1" ; } auto allowDiscard = [ this ](){ if( m_ui->cbLuks2AllowDiscard->isChecked() ){ return "1" ; }else{ return "0" ; } }() ; QString m = ".%1.%2.%3.%4.%5.%6.%7.%8.%9" ; g += m.arg( unlockingTime,forcedIterations,integrity,pbkdf,maxMemory,maxThreads,label,subsystem,allowDiscard ) ; } volumePath.replace( "\"","\"\"\"" ) ; auto a = QString( ZULUCRYPTzuluCrypt ) ; auto b = volumePath ; auto c = m_ui->comboBoxFS->currentText() ; auto d = m_volumeType ; auto e = source ; auto f = passphrase_1 ; QString exe ; if( type == createvolume::normal_and_hidden_truecrypt || type == createvolume::normal_and_hidden_veracrypt ){ auto x = m_ui->lineEditHiddenKey->text() ; QString y ; auto k = m_ui->cbHiddenVolume->currentIndex() ; if( k == 0 ){ if( x != m_ui->lineEditHiddenKey1->text() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Passphrases do not match" ) ) ; } y = utility::keyPath() + "-1" ; utility::keySend( y,x ) ; }else if( k == 1 ){ y = utility::resolvePath( x ).replace( "\"","\"\"\"" ) ; }else if( k == 2 ){ y = utility::keyPath() + "-1" ; utility::keySend( y,m_hiddenKey ) ; }else if( k == 3 ){ if( x.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; } if( x != m_ui->lineEditHiddenKey1->text() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Passphrases do not match" ) ) ; } auto m = utility::yubiKey( x ) ; if( m.has_value() ){ y = utility::keyPath() + "-1" ; utility::keySend( y,m.value() ) ; }else{ return msg.ShowUIOK( tr( "ERROR" ),tr( "Failed To Locate Or Run Yubikey's \"ykchalresp\" Program." ) ) ; } } auto r = m_ui->lineEditHiddenSize->text().toULongLong() ; switch( m_ui->comboBoxHiddenSize->currentIndex() ){ case 0 : ; break ; case 1 : r *= 1024 ; break ; case 2 : r *= 1024 * 1024 ; break ; case 3 : r *= 1024 * 1024 * 1024 ; break ; } QString z = QString::number( r ) ; const auto arg = "%1 -c -k -d \"%2\" -z %3 -t %4 %5 \"%6\" -g %7 -e %8 -u \"%9\"" ; exe = QString( arg ).arg( a,b,c,d,e,f,g,z,y ) ; }else{ const auto arg = "%1 -c -k -d \"%2\" -z %3 -t %4 %5 \"%6\" -g %7" ; exe = QString( arg ).arg( a,b,c,d,e,f,g ) ; } for( const auto& it : m_keyFiles ){ auto e = it ; e.replace( "\"","\"\"\"" ) ; exe += " -F \"" + e + "\"" ; } for( const auto& it : m_hiddenKeyFiles ){ auto e = it ; e.replace( "\"","\"\"\"" ) ; exe += " -V \"" + e + "\"" ; } if( type == createvolume::normal_veracrypt || type == createvolume::normal_and_hidden_veracrypt ){ m_veraCryptWarning.show( tr( "Please be patient as creating a VeraCrypt volume may take a very long time.\n\n" ) ) ; } m_isWindowClosable = false ; raii.cancel() ; #ifdef CRYPT_LUKS2 if( type == createvolume::luks_external_header || type == createvolume::luks2_external_header ){ #else if( type == createvolume::luks_external_header ){ #endif this->taskFinished_1( utility::Task::run( utility::appendUserUID( exe ) ).await() ) ; }else{ this->taskFinished( utility::Task::run( utility::appendUserUID( exe ) ).await() ) ; } } void createvolume::taskFinished_1( const utility::Task& e ) { if( e.exitCode() != 0 ){ this->taskFinished( e ) ; }else{ auto volumePath = m_ui->lineEditVolumePath->text() ; volumePath.replace( "\"","\"\"\"" ) ; auto backUp = utility::homePath() + "/" + volumePath.split( '/' ).last() + ".volumeHeaderBackUp" ; auto e = "%1 -B -d \"%2\" -z \"%3\"" ; auto exe = QString( e ).arg( ZULUCRYPTzuluCrypt,volumePath,backUp ) ; DialogMsg msg( this ) ; if( utility::exec( exe ).await() != 0 ){ msg.ShowUIOK( tr( "WARNING!" ),tr( "Volume created successfully but failed to create an external header" ) ) ; }else{ std::atomic_bool exit( false ) ; auto function = []( quint64 size,quint64 offset ){ Q_UNUSED( size ) Q_UNUSED( offset ) } ; auto s = quint64( QFileInfo( backUp ).size() ) ; if( utility::clearVolume( volumePath, &exit, s != 0 ? s : 2 * 1024 * 1024, function ).await() == 0 ){ msg.ShowUIOK( tr( "SUCCESS!" ),tr( "Luks volume created successfully." ) ) ; }else{ msg.ShowUIOK( tr( "WARNING!" ),tr( "Luks volume created successfully,external header created successfully but failed to erase header on the device" ) ) ; } } this->HideUI() ; } } void createvolume::taskFinished( const utility::Task& e ) { DialogMsg msg( this ) ; m_veraCryptWarning.stopTimer() ; m_isWindowClosable = true ; auto x = tr( "Volume created successfully." ) ; if( utility::containsAtleastOne( m_volumeType,"luks","tcrypt","vcrypt" ) ){ x += tr( "\nCreating a backup of the \"%1\" volume header is strongly advised.\nPlease read documentation on why this is important." ).arg( m_volumeType ) ; } auto _err = [ & ](){ return tr( "Failed to create a volume" ) + "\n\n" + e.stdError() ; } ; switch ( e.exitCode() ){ case 0 : msg.ShowUIOK( tr( "SUCCESS!" ),x ) ; return this->HideUI() ; case 1 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Presented file system is not supported,see documentation for more information" ) ) ; break ; case 2 : msg.ShowUIOK( tr( "ERROR!" ),tr( "insufficient privilege to open a system device in read/write mode,\n\ only root user or members of group zulucrypt can do that" ) ) ; break ; case 3 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Could not create an encrypted volume" ) ) ; break ; case 4 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Could not open volume for writing" ) ) ; break ; case 5 : msg.ShowUIOK( tr( "ERROR!" ),tr( "There seem to be an opened mapper associated with the device" ) ) ; break ; case 6 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Can not create a volume on a mounted device" ) ) ; break ; case 7 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Container file must be bigger than 3MB" ) ) ; break ; case 8 : msg.ShowUIOK( tr( "ERROR!" ),tr( "%1 not found" ).arg( ZULUCRYPTmkfs ) ) ; break ; case 9 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Insufficient memory to hold your response" ) ) ; break ; case 10: msg.ShowUIOK( tr( "ERROR!" ),tr( "Operation terminated per user request" ) ) ; break ; case 11: msg.ShowUIOK( tr( "ERROR!" ),tr( "Could not get passphrase in silent mode" ) ) ; break ; case 12: msg.ShowUIOK( tr( "ERROR!" ),tr( "Insufficient memory to hold the passphrase" ) ) ; break ; case 13: msg.ShowUIOK( tr( "ERROR!" ),tr( "Passphrases do not match" ) ) ; break ; case 14: msg.ShowUIOK( tr( "ERROR!" ),tr( "Invalid path to key file" ) ) ; break ; case 15: msg.ShowUIOK( tr( "ERROR!" ),tr( "Could not get a key from a key file" ) ) ; break ; case 16: msg.ShowUIOK( tr( "ERROR!" ),tr( "Couldnt get enought memory to hold the key file" ) ) ; break ; case 17: msg.ShowUIOK( tr( "ERROR!" ),tr( "Could not get a key from a socket" ) ) ; break ; case 18: msg.ShowUIOK( tr( "ERROR!" ),tr( "One or more required argument(s) for this operation is missing" ) ) ; break ; case 19: msg.ShowUIOK( tr( "ERROR!" ),tr( "Can not get passphrase in silent mode" ) ) ; break ; case 20: msg.ShowUIOK( tr( "ERROR!" ),tr( "Insufficient memory to hold passphrase" ) ) ; break ; case 21: msg.ShowUIOK( tr( "ERROR!" ),tr( "Passphrases do not match") ) ; break ; case 22: msg.ShowUIOK( tr( "ERROR!" ),_err() ) ; break ; case 23: msg.ShowUIOK( tr( "ERROR!" ),tr( "Wrong argument detected for tcrypt volume" ) ) ; break ; case 110:msg.ShowUIOK( tr( "ERROR!" ),tr( "Could not find any partition with the presented UUID" ) ) ; break ; default: msg.ShowUIOK( tr( "ERROR!" ),tr( "Error Code: %1\n--\nStdOut: %2\n--\nStdError: %3").arg( QString::number( e.exitCode() ),QString( e.stdError() ),QString( e.stdOut() ) ) ) ; } m_veraCryptWarning.hide() ; this->enableAll() ; } createvolume::~createvolume() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/createvolume.h000066400000000000000000000056041425361753700212310ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef CREATEPARTITION_H #define CREATEPARTITION_H #include #include #include #include "utility.h" class QCloseEvent ; /* * this header is created at config time */ #include "keystrength.h" #include namespace Ui { class createvolume; } class createvolume : public QDialog { Q_OBJECT public: typedef enum{ plain, plain_with_offset, luks, luks_external_header, #ifdef CRYPT_LUKS2 luks2, luks2_external_header, #endif normal_truecrypt, normal_and_hidden_truecrypt, normal_veracrypt, normal_and_hidden_veracrypt }createVolumeType ; static createvolume& instance( QWidget * parent ) { return *( new createvolume( parent ) ) ; } explicit createvolume( QWidget * parent = 0 ) ; ~createvolume() ; signals: void CreateVolume( QString fileSystem,QString containterType,QString volumePath,QString passphrase,bool passphraseFromFile ) ; void HideUISignal( void ) ; public slots: void ShowPartition( QString volume ) ; void ShowFile( QString volume ) ; void HideUI( void ) ; private slots: void keyChanged_0( QString ) ; void keyChanged_1( QString ) ; void pbCreateClicked( void ) ; void pbCancelClicked( void ) ; void cbNormalVolume( int ) ; void cbHiddenVolume( int ) ; void pbOpenKeyFile( void ) ; void pbOpenHiddenKeyFile( void ) ; void volumeType( int ) ; void setOptions( int ) ; void tcryptGui( bool ) ; private: void luks2Cancel() ; void taskFinished( const utility::Task& ) ; void taskFinished_1( const utility::Task& ) ; void keyChanged( bool,const QString& ) ; void eraseDataPartition( void ) ; void enableAll( void ) ; void disableAll( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; void ShowUI( const QString&,const QString& ) ; bool m_created ; Ui::createvolume * m_ui ; bool m_isWindowClosable ; bool m_showingLuks2AdvanceOptions = false ; keystrength m_keyStrength ; QString m_volumeType ; bool m_warned ; QString m_key ; QStringList m_keyFiles ; QString m_hiddenKey ; QStringList m_hiddenKeyFiles ; bool m_normalVolume ; utility::veraCryptWarning m_veraCryptWarning ; }; #endif // CREATEPARTITION_H zuluCrypt-6.2.0/zuluCrypt-gui/createvolume.ui000066400000000000000000000520631425361753700214200ustar00rootroot00000000000000 createvolume Qt::ApplicationModal 0 0 560 432 true Create A New Volume 130 10 301 31 0 10 121 31 Path to Device Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 150 400 131 31 C&reate true true 280 400 131 31 &Cancel false 0 40 561 91 130 30 301 31 430 30 31 31 open a key file 0 30 121 31 Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 130 60 301 31 0 60 121 31 Repeat Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 130 0 301 31 130 370 151 31 false 130 130 301 31 Qt::LeftToRight plain luks 430 130 31 31 Advanced LUKS2 Options 280 370 151 31 /dev/urandom /dev/random 30 130 91 31 Volume Type Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 0 190 551 121 130 30 301 31 0 30 121 31 Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 0 60 121 31 Repeat Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 130 60 301 31 430 30 31 31 0 90 121 31 Volume Size Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 130 90 151 31 280 90 151 31 Bytes KiloBytes MegaBytes GigaBytes 130 0 301 31 10 0 111 31 Iteration Time (milliseconds) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 130 0 301 31 30 160 501 31 Qt::LeftToRight 20 370 81 31 Volume Options Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 130 340 151 31 File System Qt::AlignCenter 280 340 151 31 random number generator RNG Qt::AlignCenter 130 310 301 29 QLineEdit::Password 10 310 111 31 PIM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 0 0 561 431 true TextLabel Qt::AlignCenter true 2 6 561 421 true 0 0 561 441 30 10 491 51 Advanced Luks2 Options Qt::AlignCenter true 280 390 141 33 Set 20 60 251 31 Label Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 20 100 251 31 Sub System Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 100 320 171 31 Pbkdf Type Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 280 320 121 31 argon2id argon2i pbkdf2 20 140 251 31 Max Memory (KB) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 20 180 251 31 Parallel Threads Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 280 180 121 31 280 140 121 31 280 100 121 31 280 60 121 31 20 280 251 31 Unlocking Time Cost(Milliseconds) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 280 280 121 31 280 360 121 21 20 350 251 41 Allow Discard(TRIM) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 10 210 261 71 Forced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 280 230 121 31 140 390 141 33 Cancel lineEditVolumePath cbNormalVolume pbOpenKeyFile lineEditPassphrase1 lineEditPassPhrase2 comboBoxVolumeType comboBoxOptions cbHiddenVolume pbHiddenKeyFile lineEditHiddenKey lineEditHiddenKey1 lineEditHiddenSize comboBoxHiddenSize lineEditPIM comboBoxFS pbCreate comboBoxRNG pbCancel zuluCrypt-6.2.0/zuluCrypt-gui/createvolumedialog.cpp000066400000000000000000000051451425361753700227440ustar00rootroot00000000000000/* * * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "createvolumedialog.h" #include "ui_createvolumedialog.h" #include "utility.h" createVolumeDialog::createVolumeDialog( const QString& path,QWidget * parent,std::function< void( int ) > f ) : QDialog( parent ),m_ui( new Ui::createVolumeDialog ),m_path( path ),m_function( std::move( f ) ) { m_ui->setupUi( this ) ; this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; m_opt_count = 0 ; m_ui->pbNo->setFocus() ; connect( m_ui->pbYes,SIGNAL( clicked() ),this,SLOT( pbYes() ) ) ; connect( m_ui->pbNo,SIGNAL( clicked() ),this,SLOT( pbNo() ) ) ; this->ShowUI() ; } void createVolumeDialog::ShowUI() { auto msg = tr( "This operation will lead to permanent destrunction \ of all present data in \"%1\".\n\nAre you sure you want to continue?" ).arg( m_path ) ; m_ui->label_1->setText( msg ) ; this->show() ; } void createVolumeDialog::pbNo() { if( m_opt_count == 0 ){ m_opt = 0 ; }else{ m_opt = 1 ; } this->hide() ; this->deleteLater() ; } void createVolumeDialog::closeEvent( QCloseEvent * e ) { e->ignore() ; } void createVolumeDialog::pbYes() { m_ui->pbYes->setEnabled( false ) ; m_ui->pbNo->setEnabled( false ) ; m_ui->pbNo->setFocus() ; if( m_opt_count == 1 ){ m_opt = 2 ; this->hide() ; this->deleteLater() ; }else{ m_opt_count = 1 ; QString msg = tr( "It is advised to create encrypted containers over random data to prevent information leakage.\n\n\ Do you want to write random data to \"%1\" first before creating an encrypted container in it?\n\n\ You can stop the random data writing process anytime you want if \ it takes too long and you can no longer wait.\n\n" ).arg( m_path ) ; m_ui->label_1->setText( msg ) ; utility::Task::suspend( 2 ) ; m_ui->pbYes->setEnabled( true ) ; m_ui->pbNo->setEnabled( true ) ; } } createVolumeDialog::~createVolumeDialog() { m_function( m_opt ) ; delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/createvolumedialog.h000066400000000000000000000031271425361753700224070ustar00rootroot00000000000000/* * * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef createVolumeDialog_H #define createVolumeDialog_H #include #include #include #include #include namespace Ui { class createVolumeDialog ; } class createVolumeDialog : public QDialog { Q_OBJECT public: static createVolumeDialog& instance( const QString& path,QWidget * parent,std::function< void( int ) > f ) { return *( new createVolumeDialog( path,parent,std::move( f ) ) ) ; } explicit createVolumeDialog( const QString& path,QWidget * parent,std::function< void( int ) > ) ; ~createVolumeDialog() ; private slots: void pbYes( void ) ; void pbNo( void ) ; private: void closeEvent( QCloseEvent * ) ; void ShowUI( void ) ; Ui::createVolumeDialog * m_ui ; int m_opt ; int m_opt_count ; QString m_path ; std::function< void( int ) > m_function ; }; #endif // createVolumeDialog_H zuluCrypt-6.2.0/zuluCrypt-gui/createvolumedialog.ui000066400000000000000000000030371425361753700225750ustar00rootroot00000000000000 createVolumeDialog Qt::ApplicationModal 0 0 500 243 Warning!! 160 210 91 31 &Yes 250 210 91 31 &No 10 10 481 201 This operation will lead to permanent destrunction of all present data in /dev/sdc1. Are you sure you want to continue? Qt::AlignCenter true zuluCrypt-6.2.0/zuluCrypt-gui/createvolumeinexistingfile.cpp000066400000000000000000000200521425361753700245200ustar00rootroot00000000000000/* * * Copyright ( c ) 2019 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "createvolumeinexistingfile.h" #include "ui_createvolumeinexistingfile.h" #include "utility.h" #include "bin_path.h" #include "dialogmsg.h" #include struct Unit{ static const qint64 GB = 1024 * 1024 * 1024 ; static const qint64 MB = 1024 * 1024 ; static const qint64 KB = 1024 ; }; static std::pair< qint64,QString > _offset( qint64 s,qint64 Unit,const char * unit ) { Task::await( [ & ](){ while( s % Unit != 0 ){ s++ ; } } ) ; auto m = s / Unit ; return { s,QString::number( m ) + unit } ; } static std::pair< qint64,QString > _volumeOffset( qint64 s ) { if( s >= Unit::GB ){ return _offset( s,Unit::GB,"g" ) ; }else if( s >= Unit::MB ){ return _offset( s,Unit::MB,"m" ) ; }else if( s >= Unit::KB ){ return _offset( s,Unit::KB,"k" ) ; }else{ return { s,QString::number( s ) + "b" } ; } } class createHiddenVolume { public: enum class openStatus{ FailedToGetRandomData,FailedToOpenDevice,Success } ; createHiddenVolume( const QString& file ) : m_file( file ), m_randomData( utility::RandomDataSource::get( utility::RandomDataSource::types::urandom ) ) { } openStatus open() { if( m_randomData->open() ){ m_file.open( QIODevice::WriteOnly | QIODevice::Append ) ; if( m_file.isOpen() ){ return openStatus::Success ; }else{ return openStatus::FailedToOpenDevice ; } }else{ return openStatus::FailedToGetRandomData ; } } template< typename Function > bool resize( qint64 containerSize,qint64 offSet,Function function ) { std::array< char,1024 > buffer ; qint64 size_written = 0 ; containerSize = containerSize + offSet - m_file.size() ; utility::progress update( 1500,std::move( function ) ) ; auto pgr = update.updater_qint() ; Task::await( [ & ](){ while( true ){ m_randomData->getData( buffer.data(),buffer.size() ) ; auto s = m_file.write( buffer.data(),buffer.size() ) ; if( s == -1 ){ //WTF!! } m_file.flush() ; size_written += s ; pgr( containerSize,size_written ) ; /* * This simple test makes sure the end result is atleast as big as we expect it * to be. It may be bigger and this is a feature since the final size may not * be a multiple of 512. */ if( size_written >= containerSize ){ break ; } } } ) ; m_file.close() ; return true ; } bool createVolume( const QString& key, const QString& volumePath, const QString& enc, const QString& offset ) { auto path = volumePath ; path.replace( "\"","\"\"\"" ) ; auto keyPath = utility::keyPath() ; utility::keySend( keyPath,key ) ; QString exe = "%1 -c -k -d \"%2\" -z ext4 -t plain -f %3 -g /dev/urandom.%4.%5b" ; exe = exe.arg( ZULUCRYPTzuluCrypt,path,keyPath,enc,offset ) ; return utility::Task::run( utility::appendUserUID( exe ) ).await().success() ; } private: QFile m_file ; std::unique_ptr< utility::RandomDataSource > m_randomData ; }; createVolumeInExistingFIle::createVolumeInExistingFIle( QWidget * parent ) : QDialog( parent ), m_ui( new Ui::createVolumeInExistingFIle ) { m_ui->setupUi( this ) ; m_ui->lineEditPassword->setMaxLength( 32767 ) ; m_warning = tr( "Extending A Host File Size." ) ; this->setFixedSize( this->size() ) ; m_ui->pbSetFile->setIcon( QIcon( ":/file.png" ) ) ; this->displayWarning( false ) ; connect( m_ui->cbShowPassword,&QCheckBox::stateChanged,[ this ]( int s ){ if( s == Qt::Checked ){ m_ui->lineEditPassword->setEchoMode( QLineEdit::Normal ) ; }else{ m_ui->lineEditPassword->setEchoMode( QLineEdit::Password ) ; } } ) ; connect( m_ui->pbSetFile,&QPushButton::clicked,[ this ](){ auto e = QFileDialog::getOpenFileName( this,tr( "Enter Path To Existing File" ),utility::homePath() ) ; if( !e.isEmpty() ){ m_ui->lineEditVolumePath->setText( e ) ; this->disableAll() ; m_volumeOffset = _volumeOffset( QFile( e ).size() ) ; m_ui->lineEditVolumeOffset->setText( m_volumeOffset.second ) ; this->enableAll() ; } } ) ; connect( m_ui->pbCancel,&QPushButton::clicked,[ this ](){ this->Hide() ; } ) ; connect( m_ui->pbCreate,&QPushButton::clicked,[ this ](){ this->create() ; } ) ; auto s = utility::plainDmCryptOptions() ; if( s.isEmpty() ){ m_ui->cbVolumeProperties->addItem( "aes.cbc-essiv:256.256.ripemd160" ) ; }else{ m_ui->cbVolumeProperties->addItems( s ) ; } this->show() ; } createVolumeInExistingFIle::~createVolumeInExistingFIle() { delete m_ui ; } void createVolumeInExistingFIle::updateProgress( QString cs,QString av,QString eta,QString tt,int s ) { Q_UNUSED( cs ) Q_UNUSED( tt ) QString a = tr( "Average Speed:" ) + " " + av + "\n" ; QString b = tr( "ETA:" ) + " " + eta + "\n" ; QString c = tr( "Percentage Completed: %1%" ).arg( QString::number( s ) ) ; m_ui->labelWarning->setText( m_warning + "\n\n" + a + b + c ) ; } void createVolumeInExistingFIle::enableAll() { m_ui->frame->setEnabled( true ) ; } void createVolumeInExistingFIle::disableAll() { m_ui->frame->setEnabled( false ) ; } void createVolumeInExistingFIle::displayWarning( bool e ) { m_ui->labelWarning->setVisible( e ) ; } void createVolumeInExistingFIle::create() { auto volumePath = m_ui->lineEditVolumePath->text() ; auto containersize = m_ui->lineEditContainerSize->text() ; auto key = m_ui->lineEditPassword->text() ; auto volumeOffset = m_ui->lineEditVolumeOffset->text() ; if( volumePath.isEmpty() || containersize.isEmpty() || key.isEmpty() || volumeOffset.isEmpty() ){ return DialogMsg( this ).ShowUIOK( tr( "ERROR" ),tr( "AtLeast One Required Field Is Empty" ) ) ; } createHiddenVolume volume( volumePath ) ; bool ok ; auto containerSize = containersize.toLongLong( &ok ) * 1024 * 1024 ; if( !ok ){ return DialogMsg( this ).ShowUIOK( tr( "ERROR" ),tr( "Illegal Character Found In The Container Size Field" ) ) ; } auto status = volume.open() ; if( status == createHiddenVolume::openStatus::FailedToOpenDevice ){ return DialogMsg( this ).ShowUIOK( tr( "ERROR" ),tr( "Failed To Open File In Write Mode" ) ) ; }else if( status == createHiddenVolume::openStatus::FailedToGetRandomData ){ return DialogMsg( this ).ShowUIOK( tr( "ERROR" ),tr( "Failed To Open \"/dev/urandom\" Device In Read Mode" ) ) ; } this->displayWarning( true ) ; volume.resize( containerSize,m_volumeOffset.first,[ this ]( const utility::progress::result& m ){ QMetaObject::invokeMethod( this, "updateProgress", Q_ARG( QString,m.current_speed ), Q_ARG( QString,m.average_speed ), Q_ARG( QString,m.eta ), Q_ARG( QString,m.total_time ), Q_ARG( int,m.percentage_done ) ) ; } ) ; auto enc = m_ui->cbVolumeProperties->currentText() ; auto offSet = QString::number( m_volumeOffset.first ) ; m_ui->labelWarning->setText( tr( "Creating A Plain DM-Crypt Volume" ) ) ; if( volume.createVolume( key,volumePath,enc,offSet ) ){ m_ui->labelWarning->setText( tr( "Volume Created Successfully" ) ) ; }else{ m_ui->labelWarning->setText( tr( "Failed To Create A Volume" ) ) ; } utility::Task::suspend( 2 ) ; this->Hide() ; } void createVolumeInExistingFIle::Hide() { this->hide() ; this->deleteLater() ; } void createVolumeInExistingFIle::closeEvent( QCloseEvent * e ) { e->ignore() ; this->Hide() ; } bool createVolumeInExistingFIle::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->Hide() ; } ) ; } zuluCrypt-6.2.0/zuluCrypt-gui/createvolumeinexistingfile.h000066400000000000000000000031161425361753700241670ustar00rootroot00000000000000/* * * Copyright ( c ) 2019 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef CREATEVOLUMEINEXISTINGFILE_H #define CREATEVOLUMEINEXISTINGFILE_H #include #include namespace Ui { class createVolumeInExistingFIle; } class createVolumeInExistingFIle : public QDialog { Q_OBJECT public: static void instance( QWidget * parent ) { new createVolumeInExistingFIle( parent ) ; } explicit createVolumeInExistingFIle( QWidget * parent ) ; ~createVolumeInExistingFIle(); private slots : void updateProgress( QString,QString,QString,QString,int ) ; private: void enableAll() ; void disableAll() ; void displayWarning( bool ) ; void create() ; void Hide() ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; QString m_warning ; std::pair< qint64,QString > m_volumeOffset ; Ui::createVolumeInExistingFIle * m_ui ; }; #endif // CREATEVOLUMEINEXISTINGFILE_H zuluCrypt-6.2.0/zuluCrypt-gui/createvolumeinexistingfile.ui000066400000000000000000000164421425361753700243630ustar00rootroot00000000000000 createVolumeInExistingFIle 0 0 643 326 Create Volume In Existing File 10 10 621 311 QFrame::StyledPanel QFrame::Raised 0 70 171 51 Select Cover File (Video files like mp4 and mkv) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 180 80 261 31 440 80 31 31 0 160 171 31 Container Size (MB) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 180 160 131 31 0 240 171 31 Volume Properties Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 180 240 261 31 310 280 121 31 &Cancel 190 280 121 31 C&reate 0 120 171 31 Volume OffSet (Auto calculated) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 10 10 601 61 QFrame::StyledPanel QFrame::Raised 0 0 601 61 Create A Plain dm-crypt Container Hidden Inside Cover File (Steganography) Qt::AlignCenter true 180 120 131 31 true 0 200 171 31 Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 180 200 261 31 QLineEdit::Password 440 200 21 31 -10 -10 641 321 true TextLabel Qt::AlignCenter true lineEditVolumePath pbSetFile lineEditVolumeOffset lineEditContainerSize lineEditPassword cbShowPassword cbVolumeProperties pbCreate pbCancel zuluCrypt-6.2.0/zuluCrypt-gui/cryptfiles.cpp000066400000000000000000000353411425361753700212560ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "cryptfiles.h" #include "utility.h" #include "../zuluCrypt-cli/constants.h" #include #include #include #include #include #include #include #include #include #include #include "ui_cryptfiles.h" #include "utility.h" #include "openvolume.h" #include "dialogmsg.h" #include "lxqtwallet.h" #include "plugin.h" cryptfiles::cryptfiles( QWidget * parent ) :QDialog( parent ),m_ui( new Ui::cryptfiles ) { m_ui->setupUi( this ) ; this->setFont( parent->font() ) ; this->setFixedSize( this->size() ) ; m_ui->progressBar->setMinimum( 0 ) ; m_ui->progressBar->setMaximum( 100 ) ; m_ui->progressBar->setValue( 0 ) ; m_ui->pbOpenFolder->setIcon( QIcon( ":/folder.png" ) ) ; m_ui->pushButtonFile->setIcon( QIcon( ":/file.png" ) ) ; connect( m_ui->pbCreate,SIGNAL( clicked() ),this,SLOT( pbCreate() ) ) ; connect( m_ui->pushButtonFile,SIGNAL( clicked() ),this,SLOT( pbOpenFile() ) ) ; connect( m_ui->pbOpenFolder,SIGNAL( clicked() ),this,SLOT( pbOpenFolder() ) ) ; connect( m_ui->comboBox,SIGNAL( activated( int ) ),this,SLOT( cbChanged( int ) ) ) ; connect( m_ui->lineEditSourcePath,SIGNAL( textChanged( QString ) ),this,SLOT( sourceTextChanged( QString ) ) ) ; connect( m_ui->pushButtonKeyFile,SIGNAL( clicked() ),this,SLOT( pbKeyFile() ) ) ; connect( m_ui->pushButtonCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( this,SIGNAL( progressUpdate( int ) ),this,SLOT( progressBarUpdate( int ) ) ) ; this->cbChanged( 0 ) ; m_OperationInProgress = false ; m_label.setOptions( m_ui->label,m_ui->pushButton ) ; m_ui->lineEditPass_2->setEchoMode( QLineEdit::Password ) ; m_ui->lineEditSourcePath->setFocus() ; m_ui->lineEditDestinationPath->setText( QString() ) ; m_ui->lineEditDestinationPath->setEnabled( false ) ; m_ui->lineEditSourcePath->setEnabled( false ) ; this->installEventFilter( this ) ; } bool cryptfiles::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void cryptfiles::sourceTextChanged( QString source ) { QString dest ; if( m_operation == "-E" ){ dest = source.split( "/" ).last() + ".zC" ; }else{ dest = source.split( "/" ).last() ; } auto p = m_ui->lineEditDestinationPath->text().split( "/" ) ; auto size = p.size() ; QString path ; for( int i = 0 ; i < size - 1 ; i++ ){ path += p.at( i ) + "/" ; } path += dest ; if( m_operation == "-D" ){ if( path.endsWith( ".zc" ) || path.endsWith( ".zC" ) ){ path = path.mid( 0,path.size() - 3 ) ; } } m_ui->lineEditDestinationPath->setText( path ) ; } QString cryptfiles::destinationPath( const QString& e ) { if( e.isEmpty() ){ return utility::homePath() + "/" ; }else{ int r = e.lastIndexOf( '/' ) ; if( r == -1 ){ return utility::homePath() + "/" ; }else{ auto x = e ; x.truncate( r ) ; return x + "/" ; } } } void cryptfiles::encrypt() { m_operation = "-E" ; this->setWindowTitle( tr( "Create An Encrypted Version Of A File" ) ) ; this->show() ; } void cryptfiles::decrypt() { m_operation = "-D" ; m_ui->labelKey2->setEnabled( false ) ; m_ui->lineEditPass_2->setEnabled( false ) ; this->setWindowTitle( tr( "Create A Decrypted Version Of An encrypted File" ) ) ; this->show() ; } void cryptfiles::decrypt( const QString& e ) { m_ui->lineEditSourcePath->setText( e ) ; m_operation = "-D" ; m_ui->labelKey2->setEnabled( false ) ; m_ui->lineEditPass_2->setEnabled( false ) ; m_ui->lineEditDestinationPath->setText( this->destinationPath( e ) ) ; this->sourceTextChanged( e ) ; this->setWindowTitle( tr( "Create A Decrypted Version Of An encrypted File" ) ) ; this->show() ; } void cryptfiles::closeEvent( QCloseEvent * e ) { e->ignore() ; this->HideUI() ; } void cryptfiles::pbCancel() { this->HideUI() ; } void cryptfiles::HideUI() { this->hide() ; this->deleteLater() ; } void cryptfiles::enableAll() { if( m_operation == "-E" ){ m_ui->labelKey2->setEnabled( true ) ; m_ui->lineEditPass_2->setEnabled( true ) ; } m_ui->labelKey->setEnabled( true ) ; m_ui->lineEditPass_1->setEnabled( true ) ; m_ui->labelDestinationPath->setEnabled( true ) ; m_ui->labelSourcePath->setEnabled( true ) ; m_ui->pbCreate->setEnabled( true ) ; m_ui->pbOpenFolder->setEnabled( true ) ; m_ui->pushButtonFile->setEnabled( true ) ; m_ui->pushButtonCancel->setEnabled( true ) ; m_ui->comboBox->setEnabled( true ) ; m_ui->labelProgressBar->setEnabled( true ) ; } void cryptfiles::disableAll() { m_ui->lineEditPass_1->setEnabled( false ) ; m_ui->lineEditPass_2->setEnabled( false ) ; m_ui->labelKey2->setEnabled( false ) ; m_ui->labelKey->setEnabled( false ) ; m_ui->labelDestinationPath->setEnabled( false ) ; m_ui->labelSourcePath->setEnabled( false ) ; m_ui->lineEditDestinationPath->setEnabled( false ) ; m_ui->lineEditSourcePath->setEnabled( false ) ; m_ui->pbCreate->setEnabled( false ) ; m_ui->pbOpenFolder->setEnabled( false ) ; m_ui->pushButtonFile->setEnabled( false ) ; m_ui->comboBox->setEnabled( false ) ; m_ui->labelProgressBar->setEnabled( false ) ; m_ui->pushButtonCancel->setEnabled( false ) ; } void cryptfiles::pbCreate() { auto source = utility::resolvePath( m_ui->lineEditSourcePath->text() ) ; if( source.isEmpty() ){ return m_label.show( tr( "Path to source field is empty" ) ) ; } auto dest = utility::resolvePath( m_ui->lineEditDestinationPath->text() ) ; if( !utility::pathExists( source ) ){ return m_label.show( tr( "Invalid path to source file" ) ) ; } if( utility::pathExists( dest ) ){ return m_label.show( tr( "Destination path already taken" ) ) ; } if( !utility::canCreateFile( dest ) ){ return m_label.show( tr( "You dont seem to have writing access to the destination folder" ) ) ; } auto key_1 = m_ui->lineEditPass_1->text() ; auto key_2 = m_ui->lineEditPass_2->text() ; QString keySource ; if( m_ui->comboBox->currentIndex() == 1 ){ if( utility::pathExists( key_1 ) ){ keySource = "-f" ; }else{ return m_label.show( tr( "Invalid path to key file" ) ) ; } }else{ keySource = "-p" ; if( key_1.isEmpty() ){ return m_label.show( tr( "First key field is empty" ) ) ; } if( m_operation == "-E" ){ if( key_2.isEmpty() ){ return m_label.show( tr( "Second key field is empty" ) ) ; } if( key_1 != key_2 ){ return m_label.show( tr( "Keys do not match" ) ) ; } } } this->disableAll() ; if( m_operation == "-D" && source.endsWith( ".zc" ) ){ return m_label.show( tr( "These very old encrypted files are no longer supported" ) ) ; }else{ #define _constPtr toLatin1().constData() bool e = m_operation == "-E" ; if( keySource == "-f" ){ QFile f( key_1 ) ; f.open( QIODevice::ReadOnly ) ; auto r = f.readAll() ; this->cryptFile( source._constPtr,dest._constPtr,r.constData(),r.size(),e ) ; }else{ this->cryptFile( source._constPtr,dest._constPtr,key_1._constPtr,key_1.size(),e ) ; } } } void cryptfiles::cryptFile( const char * s,const char * d,const char * k,unsigned long l,bool encrypt ) { using function_t = std::function< int( int ) > ; function_t foo = [ this ]( int e ){ emit progressUpdate( e ) ; return 0 ; } ; auto f = reinterpret_cast< void * >( &foo ) ; auto u = []( int e,void * f ) { auto function = reinterpret_cast< function_t * >( f ) ; return ( *function )( e ) ; } ; auto r = Task::await( [ & ]{ auto r = u_int32_t( l ) ; if( encrypt ){ return lxqt_wallet_create_encrypted_file( k,r,s,d,u,f ) ; }else{ return lxqt_wallet_create_decrypted_file( k,r,s,d,u,f ) ; } } ) ; if( r == lxqt_wallet_wrong_password ){ this->taskFinished( cryptfiles::wrongKey ) ; }else if( r == lxqt_wallet_no_error ){ if( m_ui->progressBar->value() == 100 ){ utility::changePathOwner( d ) ; if( encrypt ){ this->taskFinished( cryptfiles::encryptSuccess ) ; }else{ this->taskFinished( cryptfiles::decryptSuccess ) ; } }else{ this->taskFinished( cryptfiles::quit ) ; } }else{ /* * we shouldnt get here and we return a bogus return value for lack of better * alternative */ this->taskFinished( cryptfiles::openMapperReadFail ) ; } } void cryptfiles::disableCancel() { m_ui->pushButtonCancel->setEnabled( false ) ; } void cryptfiles::enableCancel() { m_ui->pushButtonCancel->setEnabled( true ) ; } void cryptfiles::titleUpdate( QString title ) { this->setWindowTitle( title ) ; } void cryptfiles::progressBarUpdate( int i ) { m_ui->progressBar->setValue( i ) ; } void cryptfiles::pbOpenFolder( void ) { QString p = tr( "Select Path to put destination file" ) ; QString x = QFileDialog::getExistingDirectory( this,p,utility::homePath(), QFileDialog::ShowDirsOnly ) ; while( true ){ if( x.endsWith( '/' ) ){ x.truncate( x.length() - 1 ) ; }else{ break ; } } if( x.isEmpty() ){ x = utility::homePath() ; } QString path ; if( m_operation == "-E" ){ path = x + "/" + m_ui->lineEditSourcePath->text().split( "/" ).last() + ".zC" ; }else{ path = x + "/" + m_ui->lineEditSourcePath->text().split( "/" ).last() ; path.chop( 3 ) ; } m_ui->lineEditDestinationPath->setText( path ) ; if( m_ui->lineEditSourcePath->text().isEmpty() ){ m_ui->lineEditSourcePath->setFocus() ; }else{ m_ui->pbCreate->setFocus() ; } } void cryptfiles::cbChanged( int r ) { auto _key_ui = [ this ](){ m_ui->lineEditPass_1->setToolTip( tr( "Enter A Key" ) ) ; m_ui->pushButtonKeyFile->setIcon( QIcon( ":/passphrase.png" ) ) ; m_ui->pushButtonKeyFile->setEnabled( false ) ; m_ui->lineEditPass_1->clear() ; m_ui->lineEditPass_2->clear() ; m_ui->lineEditPass_1->setEchoMode( QLineEdit::Password ) ; m_ui->lineEditPass_1->setFocus() ; m_ui->labelKey->setText( tr( "Key" ) ) ; m_ui->labelKey2->setText( tr( "Repeat Key" ) ) ; m_ui->lineEditPass_1->setEnabled( true ) ; if( m_operation == "-E" ){ m_ui->labelKey2->setEnabled( true ) ; m_ui->lineEditPass_2->setEnabled( true ) ; } } ; if( r == 0 ){ _key_ui() ; }else if( r == 1 ){ m_ui->lineEditPass_1->setToolTip( tr( "Enter A Path To A Keyfile Location" ) ) ; m_ui->labelKey->setText( tr( "keyfile path" ) ) ; m_ui->pushButtonKeyFile->setIcon( QIcon( ":/keyfile.png" ) ) ; m_ui->lineEditPass_1->setEnabled( true ) ; m_ui->lineEditPass_2->setEnabled( false ) ; m_ui->pushButtonKeyFile->setEnabled( true ) ; m_ui->labelKey2->setEnabled( false ) ; m_ui->lineEditPass_1->clear() ; m_ui->lineEditPass_2->clear() ; m_ui->lineEditPass_1->setEchoMode( QLineEdit::Normal ) ; m_ui->lineEditPass_1->setFocus() ; }else{ _key_ui() ; m_ui->lineEditPass_1->setEnabled( false ) ; m_ui->lineEditPass_2->setEnabled( false ) ; plugin::instance( this,plugins::plugin::hmac_key,[ this ]( const QString& key ){ m_ui->lineEditPass_1->setText( key ) ; m_ui->lineEditPass_2->setText( key ) ; if( key.isEmpty() ){ m_ui->comboBox->setCurrentIndex( 0 ) ; this->cbChanged( 0 ) ; } },tr( "Generate a key made up of a passphrase and a keyfile" ) ) ; } } void cryptfiles::pbOpenFile() { QString Z ; if( m_operation == "-E" ){ Z = QFileDialog::getOpenFileName( this,tr( "Select A File You Want To Encrypt" ),utility::homePath() ) ; }else{ auto x = tr( "zuluCrypt encrypted files ( *.zc ) ;; All Files ( * )" ) ; Z = QFileDialog::getOpenFileName( this,tr( "Select A File You Want To Decrypt" ),utility::homePath(),x ) ; } m_ui->lineEditSourcePath->setText( Z ) ; m_ui->lineEditDestinationPath->setText( this->destinationPath( Z ) ) ; this->sourceTextChanged( Z ) ; m_ui->lineEditPass_1->setFocus() ; } void cryptfiles::pbKeyFile() { auto e = QFileDialog::getOpenFileName( this,tr( "Select A Keyfile" ),utility::homePath() ) ; m_ui->lineEditPass_1->setText( e ) ; if( m_ui->lineEditSourcePath->text().isEmpty() ){ m_ui->lineEditSourcePath->setFocus() ; }else{ m_ui->pbCreate->setFocus() ; } } void cryptfiles::taskFinished( int st ) { DialogMsg msg( this ) ; m_OperationInProgress = false ; cryptfiles::status status = cryptfiles::status( st ) ; switch( status ){ case cryptfiles::encryptSuccess : m_label.show( tr( "Encrypted file created successfully" ) ) ; return this->HideUI() ; case cryptfiles::md5Pass : case cryptfiles::decryptSuccess : m_label.show( tr( "Decrypted file created successfully" ) ) ; return this->HideUI() ; case cryptfiles::openKeyFileReadFail : m_label.show( tr( "Could not open keyfile for reading" ) ) ; break ; case cryptfiles::openMapperFail : m_label.show( tr( "Could not open encryption routines" ) ) ; break ; case cryptfiles::destinationFileExists : m_label.show( tr( "File or folder already exist at destination address" ) ) ; break ; case cryptfiles::OpenDestinationFail : case cryptfiles::createFileFail : m_label.show( tr( "Insufficient privilege to create destination file" ) ) ; break ; case cryptfiles::wrongKey : m_label.show( tr( "Presented key did not match the encryption key" ) ) ; break ; case cryptfiles::quit : m_label.show( tr( "Operation terminated per user request" ) ) ; return this->HideUI() ; case cryptfiles::OpenSourceFail : m_label.show( tr( "Insufficient privilege to open source file for reading" ) ) ; break ; case cryptfiles::md5Fail : m_label.show( tr( "Decrypted file created successfully but md5 checksum failed,file maybe corrupted" ) ) ; return this->HideUI() ; case cryptfiles::openMapperReadFail : m_label.show( tr( "Could not open reading encryption routines" ) ) ; break ; case cryptfiles::openMapperWriteFail : m_label.show( tr( "Could not open writing encryption routines" ) ) ; break ; case cryptfiles::closeMapperFail : m_label.show( tr( "Failed to close encryption routine" ) ) ; break ; case cryptfiles::unset : case cryptfiles::success : case cryptfiles::QProcessFail : break ; } this->enableAll() ; if( status == cryptfiles::wrongKey ){ m_ui->lineEditPass_1->clear() ; m_ui->lineEditPass_1->setFocus() ; } } cryptfiles::~cryptfiles() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/cryptfiles.h000066400000000000000000000047701425361753700207250ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef CRYPTFILES_H #define CRYPTFILES_H #include #include #include "utility.h" class QWidget ; class QCloseEvent ; class cryptfiles ; namespace Ui { class cryptfiles ; } class cryptfiles : public QDialog { Q_OBJECT public: typedef enum{ unset, quit, success, openMapperReadFail, openMapperWriteFail, openMapperFail, closeMapperFail, openKeyFileReadFail, QProcessFail, md5Fail, md5Pass, wrongKey, encryptSuccess, decryptSuccess, destinationFileExists, createFileFail, OpenSourceFail, OpenDestinationFail }status; static cryptfiles& instance( QWidget * parent = 0 ) { return *( new cryptfiles( parent ) ) ; } explicit cryptfiles( QWidget * parent = 0 ) ; ~cryptfiles() ; signals: void HideUISignal( void ) ; void progressUpdate( int ) ; public slots: void encrypt( void ) ; void decrypt( void ) ; void decrypt( const QString& ) ; void enableCancel( void ) ; void disableCancel( void ) ; private slots: void pbCancel( void ) ; void pbCreate( void ) ; void pbOpenFile( void ) ; void pbKeyFile( void ) ; void pbOpenFolder( void ) ; void cbChanged( int ) ; void sourceTextChanged( QString ) ; void taskFinished( int ) ; void progressBarUpdate( int ) ; void titleUpdate( QString ) ; private: void cryptFile( const char *,const char *,const char *,unsigned long,bool ) ; void HideUI( void ) ; void headerBackUp( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; void disableAll( void ) ; void enableAll( void ) ; QString destinationPath( const QString& e = QString() ) ; Ui::cryptfiles * m_ui ; QString m_path ; bool m_OperationInProgress ; QString m_operation ; cryptfiles * m_task ; utility::label m_label ; }; #endif // CREATEKEYFILE_H zuluCrypt-6.2.0/zuluCrypt-gui/cryptfiles.ui000066400000000000000000000163331425361753700211110ustar00rootroot00000000000000 cryptfiles Qt::ApplicationModal 0 0 552 212 120 40 311 31 10 40 101 31 Destination Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 430 40 31 31 200 180 81 31 C&reate true true 10 10 101 31 Source Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 120 10 311 31 430 10 31 31 120 70 311 31 0 0 311 31 Password KeyFile Key+KeyFile 120 100 311 31 430 100 31 31 10 100 101 31 Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 120 130 311 31 10 130 101 31 Repeat Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 280 180 75 31 &Cancel 120 160 311 21 24 10 149 101 41 % Complete Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 0 0 551 211 true TextLabel Qt::AlignCenter true 230 170 90 33 &OK lineEditSourcePath pushButtonFile lineEditDestinationPath pbOpenFolder comboBox pushButtonKeyFile lineEditPass_1 lineEditPass_2 pbCreate pushButtonCancel zuluCrypt-6.2.0/zuluCrypt-gui/cryptoinfo.cpp000066400000000000000000000041631425361753700212640ustar00rootroot00000000000000/* * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "cryptoinfo.h" #include "ui_cryptoinfo.h" #include #include cryptoinfo::cryptoinfo( QWidget * parent,QString path,QString msg ) : QWidget( parent ),m_ui( new Ui::cryptoinfo ),m_path( path ),m_msg( msg ) { m_ui->setupUi( this ) ; if( !m_msg.isEmpty() ){ m_ui->label->setText( m_msg ) ; } this->setFixedSize( this->size() ) ; this->setWindowFlags( Qt::Window | Qt::Dialog ) ; this->setFont( parent->font() ) ; m_ui->checkBox->setChecked( false ) ; connect( m_ui->pbOK,SIGNAL( clicked() ),this,SLOT( pbOK() ) ) ; connect( m_ui->checkBox,SIGNAL( clicked( bool ) ),this,SLOT( checkBoxChecked( bool ) ) ) ; this->installEventFilter( this ) ; this->Show() ; } bool cryptoinfo::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void cryptoinfo::closeEvent( QCloseEvent * e ) { e->ignore() ; this->HideUI() ; } void cryptoinfo::HideUI() { this->hide() ; this->deleteLater() ; } void cryptoinfo::pbOK() { this->HideUI() ; } void cryptoinfo::Show() { if( utility::pathExists( m_path ) ){ this->deleteLater() ; }else{ this->show() ; } } void cryptoinfo::checkBoxChecked( bool checked ) { QFile f( m_path ) ; if( checked ){ f.open( QIODevice::WriteOnly | QIODevice::Truncate ) ; }else{ f.remove() ; } } cryptoinfo::~cryptoinfo() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/cryptoinfo.h000066400000000000000000000030111425361753700207200ustar00rootroot00000000000000/* * * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef CRYPTOINFO_H #define CRYPTOINFO_H #include #include #include #include "utility.h" class QCloseEvent ; namespace Ui { class cryptoinfo ; } class cryptoinfo : public QWidget { Q_OBJECT public: static cryptoinfo& instance( QWidget * parent,QString path,QString msg ) { return *( new cryptoinfo( parent,path,msg ) ) ; } cryptoinfo( QWidget * parent,QString path,QString msg ) ; ~cryptoinfo() ; signals: void closeUISignal( void ) ; private slots: void pbOK( void ) ; void checkBoxChecked( bool ) ; private: void Show( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; void HideUI( void ) ; Ui::cryptoinfo * m_ui ; QString m_path ; QString m_msg ; }; #endif // CRYPTOINFO_H zuluCrypt-6.2.0/zuluCrypt-gui/cryptoinfo.ui000066400000000000000000000034671425361753700211250ustar00rootroot00000000000000 cryptoinfo Qt::ApplicationModal 0 0 553 292 Greetings 230 260 101 31 Ok 20 0 511 221 Please consult "menu->help->open zuluCrypt.pdf" to get an introduction on zuluCrypt. Unity users,the menu is on the upper left corner of the screen when zuluCrypt has focus. Project's homepage is at: https://mhogomchungu.github.io/zuluCrypt Recommending reading FAQ page from the project's main page. Qt::PlainText Qt::AlignCenter true 150 220 391 41 Do not show this message again. zuluCrypt-6.2.0/zuluCrypt-gui/debugwindow.cpp000066400000000000000000000035421425361753700214060ustar00rootroot00000000000000/* * * Copyright (c) 2018 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "debugwindow.h" #include "ui_debugwindow.h" #include "utility.h" debugWindow::debugWindow( QWidget * parent ) : QWidget( parent ), m_ui( new Ui::debugWindow ) { m_ui->setupUi( this ) ; this->window()->setFixedSize( this->window()->size() ) ; m_ui->pbClose->setFocus() ; connect( m_ui->pbClear,&QPushButton::clicked,[ this ](){ m_ui->textEdit->setText( QString() ) ; } ) ; connect( m_ui->pbClose,&QPushButton::clicked,[ this ](){ this->Hide() ; } ) ; utility::setDebugWindow( this ) ; } debugWindow::~debugWindow() { delete m_ui ; } void debugWindow::Show() { this->show() ; } void debugWindow::Hide() { this->hide() ; } void debugWindow::UpdateOutPutSlot( const QString& e,bool s ) { if( this->isVisible() || s ){ auto s = m_ui->textEdit->toPlainText() ; m_ui->textEdit->setText( s + "\n" + e ) ; } } void debugWindow::UpdateOutPut( const QString& e,bool m ) { QMetaObject::invokeMethod( this, "UpdateOutPutSlot", Qt::QueuedConnection, Q_ARG( QString,e ), Q_ARG( bool,m ) ) ; } void debugWindow::closeEvent( QCloseEvent * e ) { e->ignore() ; this->hide() ; } zuluCrypt-6.2.0/zuluCrypt-gui/debugwindow.h000066400000000000000000000023721425361753700210530ustar00rootroot00000000000000/* * * Copyright (c) 2018 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef DEBUGWINDOW_H #define DEBUGWINDOW_H #include #include namespace Ui { class debugWindow; } class debugWindow : public QWidget { Q_OBJECT public: explicit debugWindow( QWidget * parent = nullptr ) ; ~debugWindow(); void Show() ; void Hide() ; void UpdateOutPut( const QString&,bool ) ; void closeEvent( QCloseEvent * ) ; private slots: void UpdateOutPutSlot( const QString&,bool ) ; private: Ui::debugWindow * m_ui ; }; #endif // DEBUGWINDOW_H zuluCrypt-6.2.0/zuluCrypt-gui/debugwindow.ui000066400000000000000000000025351425361753700212420ustar00rootroot00000000000000 debugWindow 0 0 659 465 zuluCrypt Debug Window 220 430 111 33 C&lear 330 430 111 33 &Close true true 10 10 641 421 true zuluCrypt-6.2.0/zuluCrypt-gui/dialogmsg.cpp000066400000000000000000000233621425361753700210400ustar00rootroot00000000000000/* * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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,see . */ #include "dialogmsg.h" #include "ui_dialogmsg.h" #include #include #include #include "../zuluCrypt-gui/utility.h" #include "dialogok.h" DialogMsg::DialogMsg( QWidget * parent ) : QDialog( parent ),m_ui( new Ui::DialogMsg ),m_parent( parent ) { m_ui->setupUi( this ) ; if( parent ){ this->setFont( parent->font() ) ; } connect( m_ui->pbNo,SIGNAL( clicked() ),this,SLOT( pbNo() ) ) ; connect( m_ui->pbYes,SIGNAL( clicked() ),this,SLOT( pbYes() ) ) ; connect( m_ui->pbOk,SIGNAL( clicked() ),this,SLOT( pbOK() ) ) ; this->installEventFilter( this ) ; } bool DialogMsg::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void DialogMsg::pbNo() { m_status = QMessageBox::No ; this->hide() ; } void DialogMsg::pbOK() { m_status = QMessageBox::Ok ; this->hide() ; } void DialogMsg::pbYes() { m_status = QMessageBox::Yes ; this->hide() ; } void DialogMsg::closeEvent( QCloseEvent * e ) { e->ignore() ; this->hide() ; } void DialogMsg::HideUI() { m_status = QMessageBox::NoButton ; this->hide() ; } void DialogMsg::ShowUI( const QString& title,const QString& msg ) { m_ui->label->setText( msg ) ; this->setWindowTitle( title ) ; this->show() ; this->exec() ; } void DialogMsg::ShowPermissionProblem( const QString& device ) { Q_UNUSED( device ) QString msg = tr( "\n\ \"system volumes\" are volumes that either udev has identify them as such if udev is enabled \ or have an entry in \"/etc/fstab\",\"/etc/crypttab\" or \"/etc/zuluCrypt/system_volumes.list\".\n\ \n\ If you prefer for a volume not to be considered a system volume,start the tool\ from root account and then go to \"menu->options->manage non system partitions\" \ and add the volume to the list and the volume will stop being considered as \"system\".\n\n\ Alternatively,you can add yourself to group \"zulucrypt\" and \"zulumount\" and all restrictions will go away." ) ; this->ShowUIInfo( tr( "INFORMATION" ),false,msg ) ; } void DialogMsg::ShowPermissionProblem( const QString& msg,const QString& device ) { QString msg1 ; if( device.startsWith( "/dev/" ) ){ if( msg == "reading" ){ msg1 = tr( "Insufficient privilege to access a system device,\nonly root user or members of group zulucrypt can do that" ) ; }else{ msg1 = tr( "Insufficient privilege to access a system device in read/write mode,\nonly root user or members of group zulucrypt-write can do that" ) ; } }else{ msg1 = tr( "You do not seem to have proper permissions to access the encrypted file in %1 mode,check file permissions and try again" ).arg( msg ) ; } this->ShowUIOK( tr( "INFORMATION"),msg1 ) ; } void DialogMsg::setDimentions( const QString& msg ) { this->setFixedSize( 372,146 ) ; m_ui->label->setGeometry( 10,10,351,91 ) ; m_ui->label->setFixedSize( m_ui->label->size() ) ; m_ui->pbOk->setGeometry( 150,110,75,31 ) ; m_ui->pbYes->setGeometry( 120,110,71,31 ) ; m_ui->pbNo->setGeometry( 190,110,75,31 ) ; return ; int len = msg.size() ; if( len <= 30 ){ this->setFixedSize( 270,90 ) ; m_ui->label->setGeometry( 10,10,251,31 ) ; m_ui->label->setFixedSize( m_ui->label->size() ) ; m_ui->pbOk->setGeometry( 100,50,75,31 ) ; m_ui->pbYes->setGeometry( 70,50,71,31 ) ; m_ui->pbNo->setGeometry( 140,50,75,31 ) ; }else if( len <= 130 ){ this->setFixedSize( 372,138 ) ; m_ui->label->setGeometry( 10,10,351,81 ) ; m_ui->label->setFixedSize( m_ui->label->size() ) ; m_ui->pbOk->setGeometry( 150,100,75,31 ) ; m_ui->pbYes->setGeometry( 120,100,71,31 ) ; m_ui->pbNo->setGeometry( 190,100,75,31 ) ; }else if( len > 130 ){ this->setFixedSize( 372,146 ) ; m_ui->label->setGeometry( 10,10,351,91 ) ; m_ui->label->setFixedSize( m_ui->label->size() ) ; m_ui->pbOk->setGeometry( 150,110,75,31 ) ; m_ui->pbYes->setGeometry( 120,110,71,31 ) ; m_ui->pbNo->setGeometry( 190,110,75,31 ) ; } } void DialogMsg::ShowLabels() { m_ui->labelType->setHidden( false ) ; m_ui->labelCipher->setHidden( false ) ; m_ui->labelKeySize->setHidden( false ) ; m_ui->labelDevice->setHidden( false ) ; m_ui->labelLoop->setHidden( false ) ; m_ui->labelOffset->setHidden( false ) ; m_ui->labelSize->setHidden( false ) ; m_ui->labelMode->setHidden( false ) ; m_ui->labelFs->setHidden( false ) ; m_ui->labelSize_2->setHidden( false ) ; m_ui->labelUsed->setHidden( false ) ; m_ui->labelUnused->setHidden( false ) ; m_ui->labelUsedPerc->setHidden( false ) ; m_ui->labelActiveSlots->setHidden( false ) ; } void DialogMsg::HideLabels() { m_ui->labelActiveSlots->setHidden( true ) ; m_ui->labelType->setHidden( true ) ; m_ui->labelCipher->setHidden( true ) ; m_ui->labelKeySize->setHidden( true ) ; m_ui->labelDevice->setHidden( true ) ; m_ui->labelLoop->setHidden( true ) ; m_ui->labelOffset->setHidden( true ) ; m_ui->labelSize->setHidden( true ) ; m_ui->labelMode->setHidden( true ) ; m_ui->labelFs->setHidden( true ) ; m_ui->labelSize_2->setHidden( true ) ; m_ui->labelUsed->setHidden( true ) ; m_ui->labelUnused->setHidden( true ) ; m_ui->labelUsedPerc->setHidden( true ) ; } void DialogMsg::ShowUIVolumeProperties( const QString& title,const QString& m ) { m_ui->pbYes->setHidden( true ) ; m_ui->pbNo->setHidden( true ) ; m_ui->pbOk->setHidden( false ) ; m_ui->label->setHidden( true ) ; QString msg = m ; msg.remove( " " ) ; auto stl = msg.split( "\n" ) ; if( stl.size() >= 14 ){ this->setFixedSize( this->size() ) ; auto _trancate_long_path = []( const QString& e )->QString{ const int len = 40 ; const int length = e.length() ; if( length <= len ){ return e ; }else{ return e.mid( 0,18 ) + "...." + e.mid( length - 18 ) ; } } ; auto _replace = [ & ]( int position,const char * txt,const QString& translated ){ auto e = stl.at( position ) ; e.replace( txt,translated ) ; return e ; } ; m_ui->labelType->setText( _replace( 0,"type:",tr( "type:" ) ) ) ; m_ui->labelCipher->setText( _replace( 1,"cipher:",tr( "cipher:" ) ) ) ; m_ui->labelKeySize->setText( _replace( 2,"keysize:",tr( "keysize:" ) ) ) ; m_ui->labelOffset->setText( _replace( 3,"offset:",tr( "offset:" ) ) ) ; m_ui->labelDevice->setText( _trancate_long_path( _replace( 4,"device:",tr( "device:" ) ) ) ) ; m_ui->labelLoop->setText( _trancate_long_path( _replace( 5,"loop:",tr( "loop:" ) ) ) ) ; m_ui->labelSize->setText( _replace( 6,"mode:",tr( "mode:" ) ) ) ; m_ui->labelMode->setText( _replace( 7,"active slots:",tr( "active slots:" ) ) ) ; m_ui->labelActiveSlots->setText( _replace( 8,"file system:",tr( "file system:" ) ) ) ; m_ui->labelFs->setText( _replace( 9,"total space:",tr( "total space:" ) ) ) ; m_ui->labelSize_2->setText( _replace( 10,"used space:",tr( "used space:" ) ) ) ; m_ui->labelUsed->setText( _replace( 11,"free space:",tr( "free space:" ) ) ) ; m_ui->labelUnused->setText( _replace( 12,"used%:",tr( "used%:" ) ) ) ; m_ui->labelUsedPerc->setText( _replace( 13,"UUID:",tr( "UUID:" ) ) ) ; //QString m = stl.at( 15 ) ; //m.replace( QString( "mount point2" ),QString( "public mount point" ) ) ; //m_ui->labelUsedPerc->setText( m ) ; this->ShowUI( title,msg ) ; } } void DialogMsg::ShowUIInfo( const QString& title,bool centered,const QString& msg ) { m_ui->pbYes->setHidden( true ) ; m_ui->pbNo->setHidden( true ) ; m_ui->pbOk->setHidden( false ) ; if( centered ){ m_ui->label->setAlignment( Qt::AlignHCenter|Qt::AlignVCenter ) ; }else{ m_ui->label->setAlignment( Qt::AlignLeft|Qt::AlignVCenter ) ; } this->setFixedSize( 562,338 ) ; m_ui->label->setGeometry( 20,10,531,271 ) ; m_ui->label->setFixedSize( m_ui->label->size() ) ; m_ui->pbOk->setGeometry( 240,290,81,31 ) ; this->HideLabels() ; this->ShowUI( title,msg ) ; } void DialogMsg::ShowUIOK( const QString& title,const QString& msg ) { dialogok( m_parent,false,false,title,msg ).Show() ; //m_ui->pbYes->setHidden( true ) ; //m_ui->pbNo->setHidden( true ) ; //m_ui->pbOk->setHidden( false ) ; //this->HideLabels() ; //this->setDimentions( msg ) ; //this->ShowUI( title,msg ) ; } void DialogMsg::SetUpButtons() { m_ui->pbYes->setHidden( false ) ; m_ui->pbNo->setHidden( false ) ; m_ui->pbOk->setHidden( true ) ; this->HideLabels() ; } QMessageBox::StandardButton DialogMsg::ShowUIYesNo( const QString& title,const QString& msg ) { return dialogok( m_parent,true,false,title,msg ).Show() ; } QMessageBox::StandardButton DialogMsg::ShowUIYesNoDefaultNo( const QString& title,const QString& msg ) { return dialogok( m_parent,true,true,title,msg ).Show() ; } bool DialogMsg::ShowUIOKDoNotShowOption( const QString& title,const QString& msg ) { QCheckBox checkBox( tr( "Do not show this dialog again" ),this ) ; this->setFixedSize( 270,110 ) ; checkBox.setGeometry( 30,40,251,31 ) ; m_ui->label->setGeometry( 10,10,251,31 ) ; m_ui->label->setFixedSize( m_ui->label->size() ) ; m_ui->pbOk->setGeometry( 100,70,75,31 ) ; m_ui->pbYes->setHidden( true ) ; m_ui->pbNo->setHidden( true ) ; m_ui->pbOk->setHidden( false ) ; this->HideLabels() ; this->ShowUI( title,msg ) ; return checkBox.isChecked() ; } DialogMsg::~DialogMsg() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/dialogmsg.h000066400000000000000000000041241425361753700205000ustar00rootroot00000000000000/* * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef DIALOGMSG_H #define DIALOGMSG_H #include #include #include "dialogok.h" class QWidget ; class QCloseEvent ; namespace Ui { class DialogMsg ; } class DialogMsg : public QDialog { Q_OBJECT public: explicit DialogMsg( QWidget * parent = 0 ) ; void ShowUIOK( const QString& title,const QString& msg ) ; QMessageBox::StandardButton ShowUIYesNo( const QString& title,const QString& msg ) ; QMessageBox::StandardButton ShowUIYesNoDefaultNo( const QString& title,const QString& msg ) ; void ShowUIInfo( const QString& title,bool,const QString& msg ) ; void ShowUIVolumeProperties( const QString& title,const QString& msg ) ; bool ShowUIOKDoNotShowOption( const QString& title,const QString& msg ) ; void ShowPermissionProblem( const QString& device ) ; void ShowPermissionProblem( const QString&,const QString& device ) ; void HideUI( void ) ; ~DialogMsg() ; private slots: void pbOK( void ) ; void pbYes( void ) ; void pbNo( void ) ; private: void SetUpButtons( void ) ; void ShowLabels( void ) ; void HideLabels( void ) ; void ShowUI( const QString& title,const QString& msg ) ; void setDimentions( const QString& msg ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::DialogMsg * m_ui ; QWidget * m_parent ; QMessageBox::StandardButton m_status ; }; #endif // DIALOGMSG_H zuluCrypt-6.2.0/zuluCrypt-gui/dialogmsg.ui000066400000000000000000000153111425361753700206660ustar00rootroot00000000000000 DialogMsg Qt::WindowModal 0 0 383 342 Dialog 150 310 81 31 &Ok 60 310 71 31 &Yes 260 310 75 31 &No 260 240 41 31 text Qt::PlainText Qt::AlignCenter true 0 20 381 21 type Qt::AlignCenter true 0 40 381 21 cipher Qt::AlignCenter 0 60 381 21 key size Qt::AlignCenter 0 100 381 21 device Qt::AlignCenter true 0 120 381 21 loop Qt::AlignCenter true 0 80 381 21 offset Qt::AlignCenter 0 140 381 21 size Qt::AlignCenter 0 160 381 21 mode Qt::AlignCenter 0 200 381 21 fs Qt::AlignCenter 0 220 381 21 size Qt::AlignCenter 0 240 381 20 used Qt::AlignCenter 0 260 381 20 unused Qt::AlignCenter 0 280 381 20 used % Qt::AlignCenter 0 180 381 20 active slots Qt::AlignCenter zuluCrypt-6.2.0/zuluCrypt-gui/dialogok.cpp000066400000000000000000000044501425361753700206600ustar00rootroot00000000000000/* * * Copyright ( c ) 2016 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "dialogok.h" #include "ui_dialogok.h" #include "utility.h" #include static QWidget * _setParent( QWidget * s ) { auto m = utility::mainWindowWidget() ; if( m != s ){ return m ; }else{ return s ; } } dialogok::dialogok( QWidget * parent,bool s,bool q,const QString& e,const QString& f ) : QDialog( _setParent( parent ) ),m_ui( new Ui::dialogok ), m_parent( parent ),m_mainWindow( utility::mainWindowWidget() ) { if( m_parent != m_mainWindow ){ m_parent->hide() ; } m_ui->setupUi( this ) ; m_ui->label->setText( f ) ; this->setWindowTitle( e ) ; this->setFixedSize( this->window()->size() ) ; connect( m_ui->pbOK,SIGNAL( clicked( bool ) ),this,SLOT( ok() ) ) ; connect( m_ui->pbNO,SIGNAL( clicked( bool ) ),this,SLOT( no() ) ) ; connect( m_ui->pbYES,SIGNAL( clicked( bool ) ),this,SLOT( yes() ) ) ; m_ui->pbNO->setVisible( s ) ; m_ui->pbYES->setVisible( s ) ; m_ui->pbOK->setVisible( !s ) ; if( s ){ if( q ){ m_ui->pbNO->setFocus() ; }else{ m_ui->pbYES->setFocus() ; } }else{ m_ui->pbOK->setFocus() ; } } void dialogok::ok() { m_buttonRole = QMessageBox::Ok ; this->done( 0 ) ; } void dialogok::yes() { m_buttonRole = QMessageBox::Yes ; this->done( 0 ) ; } void dialogok::no() { m_buttonRole = QMessageBox::No ; this->done( 0 ) ; } void dialogok::closeEvent( QCloseEvent * e ) { e->ignore() ; } dialogok::~dialogok() { delete m_ui ; } QMessageBox::StandardButton dialogok::Show() { this->show() ; this->exec() ; if( m_parent != m_mainWindow ){ m_parent->show() ; } return m_buttonRole ; } zuluCrypt-6.2.0/zuluCrypt-gui/dialogok.h000066400000000000000000000024761425361753700203330ustar00rootroot00000000000000/* * * Copyright ( c ) 2016 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef DIALOGOK_H #define DIALOGOK_H #include #include #include #include namespace Ui { class dialogok; } class dialogok : public QDialog { Q_OBJECT public: dialogok( QWidget * parent,bool,bool,const QString& title,const QString& msg ) ; ~dialogok() ; QMessageBox::StandardButton Show() ; private slots: void ok() ; void yes() ; void no() ; private: void closeEvent( QCloseEvent * ) ; Ui::dialogok * m_ui ; QMessageBox::StandardButton m_buttonRole ; QWidget * m_parent ; QWidget * m_mainWindow ; } ; #endif // DIALOGOK_H zuluCrypt-6.2.0/zuluCrypt-gui/dialogok.ui000066400000000000000000000036111425361753700205110ustar00rootroot00000000000000 dialogok Qt::ApplicationModal 0 0 502 235 Dialog true 200 200 101 31 &Ok 10 10 481 181 QFrame::NoFrame QFrame::Raised TextLabel Qt::AlignCenter true 150 200 101 31 &Yes 250 200 101 31 &No zuluCrypt-6.2.0/zuluCrypt-gui/erasedevice.cpp000066400000000000000000000172451425361753700213540ustar00rootroot00000000000000/* * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "erasedevice.h" #include "ui_erasedevice.h" #include #include #include #include #include "utility.h" #include "openvolume.h" #include "dialogmsg.h" #include "../zuluCrypt-cli/constants.h" erasedevice::erasedevice( QWidget * parent ) : QDialog( parent ),m_ui( new Ui::erasedevice ) { m_ui->setupUi( this ) ; m_label.setOptions( m_ui->label_2,m_ui->pushButton ) ; this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; m_ui->progressBar->setValue( 0 ) ; m_ui->progressBar->setMaximum( 100 ) ; m_ui->progressBar->setMinimum( 0 ) ; this->setWindowTitle( tr( "Write Random Data Over Existing Data" ) ) ; connect( m_ui->pushButtonFile,SIGNAL( clicked() ),this,SLOT( pbFile() ) ) ; connect( m_ui->pushButtonPartition,SIGNAL( clicked() ),this,SLOT( pbPartition() ) ) ; connect( m_ui->pushButtonStart,SIGNAL( clicked() ),this,SLOT( pbStart() ) ) ; connect( m_ui->pushButtonCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( this,SIGNAL( sendProgress( QString,QString,QString,QString,int ) ), this,SLOT( setProgress( QString,QString,QString,QString,int ) ) ) ; m_ui->pushButtonFile->setIcon( QIcon( ":/file.png" ) ) ; m_ui->pushButtonPartition->setIcon( QIcon( ":/partition.png" ) ) ; m_ui->lineEdit->setFocus() ; this->installEventFilter( this ) ; } bool erasedevice::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void erasedevice::ShowUI() { m_option = 0 ; DialogMsg msg( this ) ; auto x = tr ( "\ The next dialog will write random data to a device leading to permanent loss of all contents on the device.\n\n\ Are you sure you want to continue? " ) ; if( msg.ShowUIYesNoDefaultNo( tr( "WARNING" ),x ) == QMessageBox::Yes ){ this->show() ; }else{ this->HideUI() ; } } void erasedevice::ShowUI( const QString& path ) { m_option = 1 ; m_ui->lineEdit->setText( path ) ; this->show() ; this->pbStart() ; } void erasedevice::taskResult( int st ) { this->setWindowTitle( tr( "Write Random Data Over Existing Data" ) ) ; DialogMsg msg( this ) ; switch( st ){ case 0: m_ui->progressBar->setValue( 100 ) ; { QString a = tr( "Average Speed:" ) + " " + m_average_speed + "\n" ; QString b = tr( "Total Time:" ) + " " + m_total_time + "\n\n" ; m_label.show( a + b + tr( "Data on the device successfully erased" ) ) ; } break ; case 1: m_label.show( tr( "Could not create mapper" ) ) ;break ; case 2: m_label.show( tr( "Could not resolve device path" ) ) ;break ; case 3: m_label.show( tr( "Random data successfully written" ) ) ;break ; //case 4: msg.ShowUIOK( tr( "ERROR!" ),tr( "User chose not to proceed" ) ) ;break ; case 5: m_label.show( tr( "Operation terminated per user choice" ) ) ;break ; case 6: m_label.show( tr( "Can not write on a device with opened mapper" ) ) ;break ; case 7: m_label.show( tr( "Policy prevents non root user opening mapper on system partition" ) );break; case 8: msg.ShowPermissionProblem( "Writing",m_ui->lineEdit->text() ) ;break ; case 9: m_label.show( tr( "Device path is invalid" ) ) ;break ; case 10:m_label.show( tr( "Passphrase file does not exist" ) ) ;break ; case 11:m_label.show( tr( "Could not get enought memory to hold the key file" ) ) ;break ; case 12:m_label.show( tr( "Insufficient privilege to open key file for reading" ) ) ;break ; case 13:m_label.show( tr( "This device appear to already be in use" ) ) ;break ; case 14:m_label.show( tr( "Can not open a mapper on a mounted device" ) ) ;break ; default:m_label.show( tr( "Could not write to the device" ) ) ; } this->HideUI() ; } void erasedevice::HideUI() { this->hide() ; this->deleteLater() ; } void erasedevice::pbStart() { auto path = m_ui->lineEdit->text() ; DialogMsg msg( this ) ; if( path.isEmpty() ){ return m_label.show( tr( "Device path field is empty" ) ) ; } path = utility::resolvePath( path ) ; if( !utility::pathExists( path ) ){ return m_label.show( tr( "Invalid path to device" ) ) ; } if( m_option == 0 ){ QString x = tr( "\ Are you really sure you want to write random data to \"%1\" effectively destroying all contents in it?" ).arg( path ) ; if( msg.ShowUIYesNoDefaultNo( tr( "WARNING!" ),x ) == QMessageBox::No ){ return ; } } if( utility::requireSystemPermissions( path ) ){ if( !utility::enablePolkit( utility::background_thread::False ) ){ return m_label.show( tr( "Failed to enable polkit support" ) ) ; } } this->setWindowTitle( tr( "Writing Random Data Over Existing Data" ) ) ; this->disableAll() ; m_exit = false ; m_running = true ; utility::progress update( 1500,[ this ]( const utility::progress::result& m ){ emit sendProgress( m.current_speed, m.average_speed, m.eta, m.total_time, m.percentage_done ) ; } ) ; auto r = utility::clearVolume( path,&m_exit,0,update.updater_quint() ).await() ; m_running = false ; this->taskResult( r ) ; } void erasedevice::enableAll() { m_ui->label->setEnabled( true ) ; m_ui->labelPath->setEnabled( true ) ; m_ui->lineEdit->setEnabled( true ) ; m_ui->pushButtonCancel->setEnabled( true ) ; m_ui->pushButtonFile->setEnabled( true ) ; m_ui->pushButtonPartition->setEnabled( true ) ; m_ui->pushButtonStart->setEnabled( true ) ; m_ui->label_3->setEnabled( true ) ; m_ui->label_4->setEnabled( true ) ; m_ui->labelAverageSpeed->setEnabled( true ) ; m_ui->labelETA->setEnabled( true ) ; } void erasedevice::disableAll() { m_ui->label->setEnabled( false ) ; m_ui->labelPath->setEnabled( false ) ; m_ui->lineEdit->setEnabled( false ) ; //m_ui->pushButtonCancel->setEnabled( false ) ; //need this one enabled m_ui->pushButtonFile->setEnabled( false ) ; m_ui->pushButtonPartition->setEnabled( false ) ; m_ui->pushButtonStart->setEnabled( false ) ; m_ui->label_3->setEnabled( false ) ; m_ui->label_4->setEnabled( false ) ; m_ui->labelAverageSpeed->setEnabled( false ) ; m_ui->labelETA->setEnabled( false ) ; } void erasedevice::setProgress( QString cs,QString av,QString eta,QString tt,int st ) { Q_UNUSED( cs ) m_ui->labelAverageSpeed->setText( av ) ; m_ui->labelETA->setText( eta ) ; m_ui->progressBar->setValue( st ) ; m_average_speed = av ; m_total_time = tt ; } void erasedevice::pbCancel() { if( m_running ){ m_exit = true ; }else{ this->HideUI() ; } } void erasedevice::pbFile() { auto Z = QFileDialog::getOpenFileName( this,tr( "Enter Path To Volume To Be Erased" ),utility::homePath() ) ; m_ui->lineEdit->setText( Z ) ; } void erasedevice::pbPartition() { auto e = tr( "Select A Non System Partition To Erase Its Contents" ) ; openvolume::instance( this,false ).partitionList( e," -N",[ this ]( const QString& e ){ this->setPath( e ) ; } ) ; } void erasedevice::setPath( QString p ) { m_ui->lineEdit->setText( p ) ; } void erasedevice::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbCancel() ; } erasedevice::~erasedevice() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/erasedevice.h000066400000000000000000000036271425361753700210200ustar00rootroot00000000000000/* * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ERASEDEVICE_H #define ERASEDEVICE_H #include #include #include #include "utility.h" class QCloseEvent ; class EraseTask ; class QWidget ; namespace Ui { class erasedevice ; } class erasedevice : public QDialog { Q_OBJECT public: static erasedevice& instance( QWidget * parent ) { return *( new erasedevice( parent ) ) ; } explicit erasedevice( QWidget * parent = 0 ) ; ~erasedevice() ; void ShowUI( void ) ; void ShowUI( const QString& ) ; void HideUI( void ) ; signals: void complete( QString ) ; void sendProgress( QString,QString,QString,QString,int ) ; private slots: void enableAll( void ) ; void disableAll( void ) ; void pbStart( void ) ; void pbCancel( void ) ; void pbFile( void ) ; void pbPartition( void ) ; void setProgress( QString,QString,QString,QString,int ) ; void setPath( QString ) ; void taskResult( int ) ; private: void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::erasedevice * m_ui ; int m_option ; std::atomic_bool m_exit ; bool m_running ; utility::label m_label ; QString m_total_time ; QString m_average_speed ; }; #endif // ERASEDEVICE_H zuluCrypt-6.2.0/zuluCrypt-gui/erasedevice.ui000066400000000000000000000124221425361753700211770ustar00rootroot00000000000000 erasedevice Qt::ApplicationModal 0 0 532 175 Erase Data On The Device By Writing Random Data Over Them 10 20 101 31 Path to Device Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 410 20 31 31 440 20 31 31 10 110 101 31 % Completed Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 120 110 291 31 24 190 140 81 31 &Start true 270 140 81 31 &Cancel true false 120 20 291 31 10 50 101 31 Average Speed Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 10 86 101 21 ETA Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 120 50 291 31 N/A 120 80 291 31 N/A true 0 0 531 171 true TextLabel Qt::AlignCenter 220 140 90 33 &OK zuluCrypt-6.2.0/zuluCrypt-gui/executablesearchpaths.cpp000066400000000000000000000017761425361753700234460ustar00rootroot00000000000000/* * * Copyright ( c ) 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "executablesearchpaths.h" QStringList executableSearchPaths::values() { return { "/usr/local/bin/", "/usr/local/sbin/", "/usr/bin/", "/usr/sbin/", "/bin/", "/sbin/", "/opt/local/bin/", "/opt/local/sbin/", "/opt/bin/", "/opt/sbin/" } ; } zuluCrypt-6.2.0/zuluCrypt-gui/executablesearchpaths.h000066400000000000000000000016171425361753700231050ustar00rootroot00000000000000/* * * Copyright ( c ) 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef EXECUTABLESEARCHPATH_H #define EXECUTABLESEARCHPATH_H #include namespace executableSearchPaths { QStringList values() ; } #endif zuluCrypt-6.2.0/zuluCrypt-gui/favorites.cpp000066400000000000000000000176601425361753700211000ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "favorites.h" #include "utility.h" #include #include #include #include static QByteArray _sha256( const QString& e ) { return QCryptographicHash::hash( e.toUtf8(),QCryptographicHash::Sha256 ).toHex() ; } static utility2::result< QString > _config_path() { auto m = [](){ auto& settings = utility::settingsObject() ; if( !settings.contains( "ConfigLocation" ) ){ auto m = QStandardPaths::standardLocations( QStandardPaths::ConfigLocation ) ; if( !m.isEmpty() ){ settings.setValue( "ConfigLocation",m.first() + "/zuluCrypt/" ) ; }else{ //TODO: what to do here??? } } return settings.value( "ConfigLocation" ).toString() ; }() ; m += "/favorites/" ; if( utility::pathExists( m ) ){ return m ; }else{ if( QDir().mkpath( m ) ){ return m ; }else{ return {} ; } } } static QString _create_path( const QString& m,const favorites::entry& e ) { auto a = utility::split( e.volumePath,'@' ).last() ; a = utility::split( a,'/' ).last() ; a.replace( ":","" ) ; auto b = a + e.mountPointPath ; return m + a + "-" + _sha256( b ) + ".json" ; } static QString _create_entry_path( const favorites::entry& e ) { auto s = _config_path() ; if( s.has_value() ){ return _create_path( s.value(),e ) ; }else{ return {} ; } } static utility2::result< favorites::entry > _favorites( const QString& path ) { SirikaliJson json( QFile( path ),[]( const QString& e ){ Q_UNUSED( e ) } ) ; favorites::entry m ; if( json.passed() ){ m.internalConfigPath = QDir( path ).absolutePath() ; m.mountPointPath = json.getString( "mountPointPath" ) ; m.preMountCommand = json.getString( "preMountCommand" ) ; m.postMountCommand = json.getString( "postMountCommand" ) ; m.preUnmountCommand = json.getString( "preUnmountCommand" ) ; m.postUnmountCommand = json.getString( "postUnmountCommand" ) ; m.mountOptions = json.getString( "mountOptions" ) ; m.password = json.getByteArray( "password" ) ; m.volumePath = json.getString( "volumePath" ) ; favorites::triState::readTriState( json,m.readOnlyMode,"mountReadOnly" ) ; favorites::triState::readTriState( json,m.autoMount,"autoMountVolume" ) ; return m ; }else{ return {} ; } } favorites::favorites() { auto& settings = utility::settingsObject() ; if( settings.contains( "Favotites" ) ){ QStringList l ; for( const auto& it : settings.value( "Favotites" ).toStringList() ){ favorites::entry e ; auto s = [ & ](){ if( it.startsWith( "/dev/disk/by-id" ) ){ auto a = utility::deviceIDToPartitionID( it ) ; return utility::split( a,'\t' ) ; }else{ return utility::split( it,'\t' ) ; } }() ; e.volumePath = s.at( 0 ) ; e.mountPointPath = s.at( 1 ) ; this->add( e ) ; } settings.remove( "Favotites" ) ; } this->reload() ; } void favorites::reload() { m_favorites.clear() ; const auto m = _config_path() ; if( m.has_value() ){ const auto& a = m.value() ; const auto s = QDir( a ).entryList( QDir::Filter::Files | QDir::Filter::Hidden ) ; for( const auto& it : s ){ auto m = _favorites( a + it ) ; if( m.has_value() ){ m_favorites.emplace_back( std::move( m.RValue() ) ) ; } } }else{ utility::debug() << "Failed To Get Favorites List" ; } } favorites::error favorites::add( const favorites::entry& e ) { auto m = _config_path() ; if( !m.has_value() ){ utility::debug() << "Failed To Get Favorites Path" ; return error::FAILED_TO_CREATE_ENTRY ; } auto a = _create_path( m.value(),e ) ; SirikaliJson json( []( const QString& e ){ Q_UNUSED( e ) } ) ; json[ "volumePath" ] = e.volumePath ; json[ "mountPointPath" ] = e.mountPointPath ; json[ "mountOptions" ] = e.mountOptions ; json[ "preMountCommand" ] = e.preMountCommand ; json[ "postMountCommand" ] = e.postMountCommand ; json[ "preUnmountCommand" ] = e.preUnmountCommand ; json[ "postUnmountCommand" ] = e.postUnmountCommand ; json[ "password" ] = e.password ; favorites::triState::writeTriState( json,e.readOnlyMode,"mountReadOnly" ) ; favorites::triState::writeTriState( json,e.autoMount,"autoMountVolume" ) ; if( utility::pathExists( a ) ){ utility::debug() << "Favorite Entry Already Exist" ; return error::ENTRY_ALREADY_EXISTS ; }else{ if( json.passed() && json.toFile( a ) ){ while( true ){ if( utility::pathExists( a ) ){ break ; }else{ utility::debug() << "Waiting for a file to show up to the file system" ; utility::Task::suspendForOneSecond() ; } } this->reload() ; return error::SUCCESS ; }else{ utility::debug() << "Failed To Create Favorite Entry" ; return error::FAILED_TO_CREATE_ENTRY ; } } } utility2::result_ref< const favorites::entry& > favorites::readFavoriteByPath( const QString& configPath ) const { auto path = QDir( configPath ).absolutePath() ; for( const auto& it : m_favorites ){ if( it.internalConfigPath == path ){ return it ; } } return {} ; } utility2::result< favorites::entry > favorites::readFavoriteByFileSystemPath( const QString& path ) const { return _favorites( path ) ; } utility2::result_ref< const favorites::entry& > favorites::readFavorite( int position ) { return this->readFavorite( static_cast< size_t >( position ) ) ; } utility2::result_ref< const favorites::entry& > favorites::readFavorite( size_t position ) { if( position < m_favorites.size() ){ return m_favorites[ position ] ; }else{ return {} ; } } utility2::result_ref< const favorites::entry& > favorites::readFavorite( const QString& volumePath, const QString& mountPath ) const { if( mountPath.isEmpty() ){ for( const auto& it : m_favorites ){ if( it.volumePath == volumePath ){ return it ; } } }else{ for( const auto& it : m_favorites ){ if( it.volumePath == volumePath && it.mountPointPath == mountPath ){ return it ; } } } return {} ; } void favorites::replaceFavorite( const favorites::entry& old,const favorites::entry& New ) { this->removeFavoriteEntry( old ) ; this->add( New ) ; } template< typename Function > static bool _remove( const favorites::entry& e,Function function ) { auto s = function( e ) ; if( !s.isEmpty() && utility::pathExists( s ) ){ return QFile::remove( s ) ; }else{ return false ; } } void favorites::removeFavoriteEntry( const favorites::entry& e ) { if( _remove( e,_create_entry_path ) ){ this->reload() ; }else if( _remove( e,_create_entry_path ) ){ this->reload() ; }else{ utility::debug() << "Failed To Remove Favorite Entry: " + e.volumePath ; } } favorites::entry::entry() { } favorites::entry::entry( const QString& e,const QString& mountPath ) : volumePath( e ),mountPointPath( mountPath ) { } void favorites::volEntry::setAutoMount( bool s ) { auto m = m_tmpFavorite.get() ; if( m ){ utility::debug() << "Changing a setting of a temporary favorite: " + m->volumePath ; m->autoMount = s ; }else{ QString aa = "Creating a copy of a favorite at: %1\nto change a setting" ; utility::debug() << aa.arg( m_favorite->volumePath ) ; auto a = *m_favorite ; a.autoMount = s ; m_favorite = this->entry( std::move( a ) ) ; } } zuluCrypt-6.2.0/zuluCrypt-gui/favorites.h000066400000000000000000000150601425361753700205350ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef FAVORITES_H #define FAVORITES_H #include #include #include #include "utility.h" #include "json_parser.hpp" class favorites { public: class triState{ public: triState() : m_state( triState::STATES::UNDEFINED ) { } triState( bool e ) : m_state( e ? STATES::TRUE : STATES::FALSE ) { } void operator=( bool e ) { if( e ){ m_state = STATES::TRUE ; }else{ m_state = STATES::FALSE ; } } void toggle() { if( m_state == STATES::TRUE ){ m_state = STATES::FALSE ; }else if( m_state == STATES::FALSE ){ m_state = STATES::TRUE ; } } bool undefined() const { return m_state == STATES::UNDEFINED ; } bool defined() const { return !this->undefined() ; } operator bool() const { return this->True() ; } bool True() const { return m_state == STATES::TRUE ; } bool False() const { return m_state != STATES::TRUE ; } static void writeTriState( SirikaliJson& json, const favorites::triState& state, const char * entry ) { if( state.defined() ){ if( state.True() ){ json[ entry ] = "true" ; }else{ json[ entry ] = "false" ; } }else{ json[ entry ] = "" ; } } static void readTriState( SirikaliJson& json, favorites::triState& state, const char * entry ) { auto s = json.getString( entry ) ; if( !s.isEmpty() ){ state = s == "true" ? true : false ; } } private: enum class STATES{ UNDEFINED,TRUE,FALSE } m_state ; }; struct entry { static const favorites::entry& empty() { static favorites::entry s ; return s ; } entry() ; entry( const QString& volumePath,const QString& mountPath = QString() ) ; QString volumePath ; QString mountPointPath ; QString mountOptions ; QString preMountCommand ; QString postMountCommand ; QString preUnmountCommand ; QString postUnmountCommand ; QString internalConfigPath ; QByteArray password ; favorites::triState readOnlyMode ; favorites::triState autoMount ; }; static favorites& instance() { static favorites m ; return m ; } class volEntry{ public: volEntry() : m_favorite( std::addressof( favorites::entry::empty() ) ) { } volEntry( const QString& e ) : m_favorite( this->entry( e ) ) { } template< typename P > volEntry( favorites::entry&& e,P&& p ) : m_favorite( this->entry( std::move( e ) ) ), m_password( std::forward< P >( p ) ) { } volEntry( favorites::entry&& e ) : m_favorite( this->entry( std::move( e ) ) ), m_password( std::move( m_favorite->password ) ) { } volEntry( const favorites::entry& e ) : m_favorite( std::addressof( e ) ), m_password( e.password ) { } template< typename P > volEntry( const favorites::entry& e,P&& s ) : m_favorite( std::addressof( e ) ), m_password( std::forward< P >( s ) ) { } const favorites::entry& favorite() const { return *m_favorite ; } const QByteArray& password() const { return m_password ; } template< typename T > void setPassword( T&& e ) { m_password = std::forward< T >( e ) ; } void setAutoMount( bool s ) ; private: const favorites::entry * entry( favorites::entry&& e ) { utility::debug() << "Favorites managing temporary entry: " + e.volumePath ; m_tmpFavorite = std::make_unique< favorites::entry >( std::move( e ) ) ; return m_tmpFavorite.get() ; } std::unique_ptr< favorites::entry > m_tmpFavorite ; const favorites::entry * m_favorite ; QByteArray m_password ; static favorites::entry m_static_favorite_entry ; }; using volumeList = std::vector< volEntry > ; enum class error{ ENTRY_ALREADY_EXISTS,FAILED_TO_CREATE_ENTRY,SUCCESS } ; error add( const favorites::entry& ) ; void replaceFavorite( const favorites::entry&, const favorites::entry& ) ; void removeFavoriteEntry( const favorites::entry& ) ; template< typename Function, Task::detail::has_bool_return_type< Function,const favorites::entry& > = 0 > bool entries( Function&& function ) const { for( const auto& it : m_favorites ){ if( function( it ) ){ return true ; } } return false ; } template< typename Function, Task::detail::has_bool_return_type< Function,size_t,const favorites::entry& > = 0 > bool entries( Function&& function ) const { for( size_t it = 0 ; it < m_favorites.size() ; it++ ){ if( function( it,m_favorites[ it ] ) ){ return true ; } } return false ; } template< typename Function, typename NotFoundFunction, Task::detail::has_bool_return_type< Function,const favorites::entry& > = 0 > void entries( Function&& function,NotFoundFunction&& notFound ) const { if( !entries( std::forward( function ) ) ){ notFound() ; } } template< typename Function, Task::detail::has_void_return_type< Function,const favorites::entry& > = 0 > void entries( Function&& function ) const { for( const auto& it : m_favorites ){ function( it ) ; } } template< typename Function, Task::detail::has_void_return_type< Function,size_t,const favorites::entry& > = 0 > void entries( Function&& function ) const { for( size_t it = 0 ; it < m_favorites.size() ; it++ ){ function( it,m_favorites[ it ] ) ; } } utility2::result_ref< const favorites::entry& > readFavoriteByPath( const QString& configPath ) const ; utility2::result< favorites::entry > readFavoriteByFileSystemPath( const QString& configPath ) const ; utility2::result_ref< const favorites::entry& > readFavorite( int position ) ; utility2::result_ref< const favorites::entry& > readFavorite( size_t position ) ; utility2::result_ref< const favorites::entry& > readFavorite( const QString& volumePath, const QString& mountPath = QString() ) const ; favorites() ; private: void reload() ; std::vector< favorites::entry > m_favorites ; }; #endif // FAVORITES_H zuluCrypt-6.2.0/zuluCrypt-gui/favorites2.cpp000066400000000000000000000436221425361753700211570ustar00rootroot00000000000000/* * * Copyright (c) 2019 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "favorites2.h" #include "ui_favorites2.h" #include "tablewidget.h" #include "utility.h" #include "dialogmsg.h" #include "openvolume.h" #include #define COMMENT "-zuluCrypt_Comment_ID" Task::future< void >& favorites2::deleteKey( secrets::wallet& wallet,const QString& id ) { return Task::run( [ &wallet,id ](){ wallet->deleteKey( id ) ; } ) ; } Task::future< bool >& favorites2::addKey( secrets::wallet& wallet, const QString& id, const QString& key ) { return Task::run( [ &wallet,id,key ](){ if( wallet->addKey( id,key ) ){ return true ; }else{ utility::debug() << "Failed To Add Key To Wallet" ; return false ; } } ) ; } favorites2::favorites2( QWidget * parent, secrets& wallet, std::function< void() > function ) : QDialog ( parent ), m_ui( new Ui::favorites2 ), m_secrets( wallet ), m_settings(), m_function( std::move( function ) ) { m_ui->setupUi( this ) ; this->installEventFilter( this ) ; this->setFont( parent->font() ) ; this->setFixedSize( this->size() ) ; m_ui->tableWidget->horizontalHeader()->setStretchLastSection( true ) ; m_ui->tableWidget->setMouseTracking( true ) ; m_ui->tableWidgetWallet->horizontalHeader()->setStretchLastSection( true ) ; m_ui->tableWidgetWallet->setMouseTracking( true ) ; m_ui->tableWidgetWallet->setContextMenuPolicy( Qt::CustomContextMenu ) ; m_ui->tableWidget->setContextMenuPolicy( Qt::CustomContextMenu ) ; m_ui->tableWidget->setColumnWidth( 0,400 ) ; connect( m_ui->tableWidget,&QTableWidget::customContextMenuRequested,[ this ]( QPoint s ){ Q_UNUSED( s ) auto item = m_ui->tableWidget->currentItem() ; if( item ){ QMenu m ; auto ac = m.addAction( tr( "Remove" ) ) ; connect( ac,&QAction::triggered,[ this ](){ this->removeEntryFromFavoriteList() ; } ) ; m.exec( QCursor::pos() ) ; } } ) ; connect( m_ui->tableWidgetWallet,&QTableWidget::customContextMenuRequested,[ this ]( QPoint s ){ Q_UNUSED( s ) auto item = m_ui->tableWidgetWallet->currentItem() ; if( item ){ this->showContextMenu( item,true ) ; } } ) ; connect( m_ui->tableWidgetWallet,&QTableWidget::currentItemChanged,[]( QTableWidgetItem * c,QTableWidgetItem * p ){ tablewidget::selectRow( c,p ) ; } ) ; m_ui->tableWidgetWallet->setContextMenuPolicy( Qt::CustomContextMenu ) ; m_ui->pbFile->setIcon( QIcon( ":/file.png" ) ) ; m_ui->pbPartition->setIcon( QIcon( ":/partition.png" ) ) ; m_ui->pbFolder->setIcon( QIcon( ":/folder.png" ) ) ; connect( m_ui->pbVolumePathFromFileSystem,&QPushButton::clicked,[ this ](){ auto e = this->getExistingFile( tr( "Path To An Encrypted Volume" ) ) ; if( !e.isEmpty() ){ m_ui->lineEditVolumePath->setText( utility::pathToUUID( e ) ) ; } } ) ; connect( m_ui->pbFolder,&QPushButton::clicked,[ this ](){ auto e = this->getExistingFolder( tr( "Path To An Encrypted Volume" ) ) ; if( !e.isEmpty() ){ m_ui->lineEditVolumeID->setText( e ) ; auto a = utility::split( e,'/' ).last() ; m_ui->lineEditMountPath->setText( a ) ; } } ) ; connect( m_ui->pbFile,&QPushButton::clicked,[ this ](){ auto e = this->getExistingFile( tr( "Path To An Encrypted Volume" ) ) ; if( !e.isEmpty() ){ m_ui->lineEditVolumeID->setText( e ) ; auto a = utility::split( e,'/' ).last() ; m_ui->lineEditMountPath->setText( a ) ; } } ) ; connect( m_ui->pbAdd,&QPushButton::clicked,[ this ](){ favorites::entry e ; e.volumePath = m_ui->lineEditVolumeID->text() ; e.mountPointPath = m_ui->lineEditMountPath->text() ; e.mountOptions = m_ui->lineEditMountOptions->text() ; if( !e.volumePath.isEmpty() && !e.mountPointPath.isEmpty() ){ favorites::instance().add( e ) ; this->showUpdatedEntry( e ) ; m_ui->lineEditVolumeID->clear() ; m_ui->lineEditMountPath->clear() ; m_ui->lineEditMountOptions->clear() ; } } ) ; connect( m_ui->pbPartition,&QPushButton::clicked,[ this ](){ openvolume::instance( this,true ).ShowAllPartitions( [ this ]( const QString& e ){ m_ui->lineEditVolumeID->setText( e ) ; auto a = utility::split( m_ui->lineEditVolumeID->text(),'/' ).last() ; m_ui->lineEditMountPath->setText( a ) ; } ) ; } ) ; connect( m_ui->tabWidget,&QTabWidget::currentChanged,[ this ]( int index ){ this->tabChanged( index ) ; } ) ; connect( m_ui->pbAddKeyToWallet,&QPushButton::clicked,[ this ](){ this->addkeyToWallet() ; } ) ; connect( &m_volPathFav,&QMenu::triggered,[ this ]( QAction * ac ){ m_ui->lineEditVolumePath->setText( ac->objectName() ) ; } ) ; connect( m_ui->pbVolumePathFromFavorites,&QPushButton::clicked,[ this ](){ m_volPathFav.exec() ; } ) ; using bk = LXQt::Wallet::BackEnd ; m_ui->rbNone->setEnabled( true ) ; auto _set_supported = []( QRadioButton * rb,LXQt::Wallet::BackEnd e ){ rb->setEnabled( LXQt::Wallet::backEndIsSupported( e ) ) ; } ; _set_supported( m_ui->rbInternalWallet,bk::internal ) ; _set_supported( m_ui->rbKWallet,bk::kwallet ) ; _set_supported( m_ui->rbLibSecret,bk::libsecret ) ; auto walletBk = m_settings.autoMountBackEnd() ; if( walletBk == bk::internal ){ m_ui->label_22->setEnabled( true ) ; m_ui->pbChangeWalletPassword->setEnabled( [](){ auto a = utility::walletName() ; auto b = utility::applicationName() ; return LXQt::Wallet::walletExists( LXQt::Wallet::BackEnd::internal,a,b ) ; }() ) ; m_ui->label_22->setText( tr( "Change Internal Wallet Password" ) ) ; m_ui->rbInternalWallet->setChecked( true ) ; }else if( walletBk == bk::libsecret ){ m_ui->label_22->setEnabled( false ) ; m_ui->pbChangeWalletPassword->setEnabled( false ) ; m_ui->label_22->setText( tr( "Not Applicable" ) ) ; m_ui->rbLibSecret->setChecked( true ) ; }else if( walletBk == bk::kwallet ){ m_ui->label_22->setEnabled( false ) ; m_ui->pbChangeWalletPassword->setEnabled( false ) ; m_ui->label_22->setText( tr( "Not Applicable" ) ) ; m_ui->rbKWallet->setChecked( true ) ; }else{ m_ui->rbNone->setChecked( true ) ; this->nobackendSet() ; } connect( m_ui->rbInternalWallet,&QRadioButton::toggled,[ this ]( bool e ){ if( e ){ m_ui->label_22->setText( tr( "Change Internal Wallet Password" ) ) ; m_ui->label_22->setEnabled( true ) ; m_ui->pbChangeWalletPassword->setEnabled( true ) ; this->walletBkChanged( bk::internal ) ; m_settings.autoMountBackEnd( bk::internal ) ; m_ui->pbChangeWalletPassword->setEnabled( [](){ auto a = utility::walletName() ; auto b = utility::applicationName() ; return LXQt::Wallet::walletExists( LXQt::Wallet::BackEnd::internal,a,b ) ; }() ) ; } } ) ; connect( m_ui->rbKWallet,&QRadioButton::toggled,[ this ]( bool e ){ if( e ){ m_ui->label_22->setText( tr( "Not Applicable" ) ) ; m_ui->label_22->setEnabled( false ) ; m_ui->pbChangeWalletPassword->setEnabled( false ) ; this->walletBkChanged( bk::kwallet ) ; m_settings.autoMountBackEnd( bk::kwallet ) ; } } ) ; connect( m_ui->rbLibSecret,&QRadioButton::toggled,[ this ]( bool e ){ if( e ){ m_ui->label_22->setText( tr( "Not Applicable" ) ) ; m_ui->label_22->setEnabled( false ) ; m_ui->pbChangeWalletPassword->setEnabled( false ) ; this->walletBkChanged( bk::libsecret ) ; m_settings.autoMountBackEnd( bk::libsecret ) ; } } ) ; connect( m_ui->rbNone,&QRadioButton::toggled,[ this ]( bool e ){ if( e ){ this->nobackendSet() ; } } ) ; connect( m_ui->pbClose,&QPushButton::clicked,[ this ](){ this->HideUI() ; } ) ; connect( m_ui->pbClose_2,&QPushButton::clicked,[ this ](){ this->HideUI() ; } ) ; connect( m_ui->tableWidget,&QTableWidget::itemClicked,[]( QTableWidgetItem * item ){ Q_UNUSED( item ) } ) ; connect( m_ui->tableWidget,&QTableWidget::currentItemChanged,[]( QTableWidgetItem * x,QTableWidgetItem * y ){ tablewidget::selectRow( x,y ) ; } ) ; m_ui->labelPassword->setVisible( false ) ; m_ui->pbVisiblePassword->setVisible( false ) ; connect( m_ui->pbVisiblePassword,&QPushButton::clicked,[ this ](){ m_ui->labelPassword->clear() ; m_ui->labelPassword->setVisible( false ) ; m_ui->pbVisiblePassword->setVisible( false ) ; } ) ; m_ui->cbShowPassword->setChecked( true ) ; m_ui->lineEditPassword->setEchoMode( QLineEdit::Password ) ; connect( m_ui->cbShowPassword,&QCheckBox::stateChanged,[ this ]( int s ){ if( s ){ m_ui->lineEditPassword->setEchoMode( QLineEdit::Password ) ; }else{ m_ui->lineEditPassword->setEchoMode( QLineEdit::Normal ) ; } } ) ; connect( m_ui->pbChangeWalletPassword,&QPushButton::clicked,[ this ](){ auto a = utility::walletName() ; auto b = utility::applicationName() ; if( m_ui->rbInternalWallet->isChecked() ){ this->hide() ; m_secrets.changeInternalWalletPassword( a,b,[ this ]( bool s ){ if( s ){ this->walletBkChanged( LXQt::Wallet::BackEnd::internal ) ; } this->show() ; } ) ; } } ) ; this->updateVolumeList( 0 ) ; this->addAction( [ this ](){ auto ac = new QAction( this ) ; ac->setShortcuts( { Qt::Key_Enter,Qt::Key_Return,Qt::Key_Menu } ) ; connect( ac,&QAction::triggered,[ this ](){ this->shortcutPressed() ; } ) ; return ac ; }() ) ; this->ShowUI() ; } favorites2::~favorites2() { delete m_ui ; } void favorites2::nobackendSet() { m_ui->label_22->setText( tr( "Not Applicable" ) ) ; m_ui->label_22->setEnabled( false ) ; m_ui->pbChangeWalletPassword->setEnabled( false ) ; this->setControlsAvailability( false,true ) ; m_settings.autoMountBackEnd( settings::walletBackEnd() ) ; } void favorites2::setCommand( QLineEdit * lineEdit ) { auto path = this->getExistingFile( tr( "Select A Command Executable" ) ) ; if( !path.isEmpty() ){ lineEdit->setText( path ) ; } } void favorites2::addkeyToWallet() { auto a = m_ui->lineEditVolumePath->text() ; auto b = m_ui->lineEditPassword->text() ; if( a.isEmpty() || b.isEmpty() ){ m_ui->labelPassword->setText( tr( "Atleast One Required Field Is Empty" ) ) ; m_ui->labelPassword->setVisible( true ) ; m_ui->pbVisiblePassword->setVisible( true ) ; return ; } m_ui->pbAddKeyToWallet->setEnabled( false ) ; m_ui->tableWidgetWallet->setEnabled( false ) ; m_ui->pbAddKeyToWallet->setEnabled( false ) ; favorites2::addKey( m_wallet.get(),a,b ).then( [ this,a ]( bool s ){ m_ui->tableWidgetWallet->setEnabled( true ) ; m_ui->pbAddKeyToWallet->setEnabled( true ) ; if( s ){ tablewidget::addRow( m_ui->tableWidgetWallet,{ a } ) ; m_ui->lineEditPassword->clear() ; m_ui->lineEditPassword->setEchoMode( QLineEdit::Password ) ; m_ui->lineEditVolumePath->clear() ; m_ui->lineEditVolumePath->setFocus() ; } m_ui->pbAddKeyToWallet->setEnabled( true ) ; } ) ; } void favorites2::deleteKeyFromWallet( const QString& id ) { m_ui->tableWidgetWallet->setEnabled( false ) ; m_ui->pbAddKeyToWallet->setEnabled( false ) ; favorites2::deleteKey( m_wallet.get(),id ).await() ; m_ui->pbAddKeyToWallet->setEnabled( true ) ; m_ui->tableWidgetWallet->setEnabled( true ) ; } QStringList favorites2::readAllKeys() { QStringList a ; const auto s = Task::await( [ & ](){ return m_wallet->readAllKeys() ; } ) ; for( const auto& it : s ){ if( !it.endsWith( COMMENT ) ){ a.append( it ) ; } } return a ; } void favorites2::showContextMenu( QTableWidgetItem * item,bool itemClicked ) { QMenu m ; connect( m.addAction( tr( "Delete Entry" ) ),&QAction::triggered,[ this ](){ auto table = m_ui->tableWidgetWallet ; auto row = table->currentRow() ; if( row != -1 ){ auto a = table->item( row,0 )->text() ; this->deleteKeyFromWallet( a ) ; tablewidget::deleteRow( table,row ) ; } } ) ; connect( m.addAction( tr( "Show Password" ) ),&QAction::triggered,[ this ](){ auto table = m_ui->tableWidgetWallet ; auto row = table->currentRow() ; if( row != -1 ){ auto a = Task::await( [ & ]()->QString{ return m_wallet->readValue( table->item( row,0 )->text() ) ; } ) ; if( !a.isEmpty() ){ auto e = QObject::tr( "The Password Is \"%1\"" ).arg( a ) ; m_ui->labelPassword->setText( e ) ; m_ui->labelPassword->setVisible( true ) ; m_ui->pbVisiblePassword->setVisible( true ) ; } } } ) ; m.addAction( tr( "Close Menu" ) ) ; m.setFont( this->font() ) ; if( itemClicked ){ m.exec( QCursor::pos() ) ; }else{ auto p = this->pos() ; auto x = p.x() + 100 + m_ui->tableWidgetWallet->columnWidth( 0 ) ; auto y = p.y() + 50 + m_ui->tableWidgetWallet->rowHeight( 0 ) * item->row() ; p.setX( x ) ; p.setY( y ) ; m.exec( p ) ; } } template< typename Function > static auto _hide_ui( Function hide,LXQt::Wallet::BackEnd bk ) { return [ hide = std::move( hide ),bk ](){ using w = LXQt::Wallet::BackEnd ; if( bk == w::internal || bk == w::windows_dpapi ){ hide() ; } } ; } void favorites2::walletBkChanged( LXQt::Wallet::BackEnd bk ) { this->setControlsAvailability( true,true ) ; m_wallet = m_secrets.walletBk( bk ) ; m_wallet.open( [ this ](){ for( const auto& it : this->readAllKeys() ){ tablewidget::addRow( m_ui->tableWidgetWallet,{ it } ) ; } },_hide_ui( [ this ](){ this->hide() ; },bk ),[ this ]( bool opened ){ if( opened ){ for( const auto& it : this->readAllKeys() ){ tablewidget::addRow( m_ui->tableWidgetWallet,{ it } ) ; } }else{ m_ui->lineEditVolumePath->clear() ; this->setControlsAvailability( false,true ) ; } this->show() ; } ) ; } void favorites2::setControlsAvailability( bool e,bool m ) { if( m ){ tablewidget::clearTable( m_ui->tableWidgetWallet ) ; } m_ui->label_21->setEnabled( e ) ; m_ui->label_23->setEnabled( e ) ; m_ui->tableWidgetWallet->setEnabled( e ) ; m_ui->pbAddKeyToWallet->setEnabled( e ) ; m_ui->lineEditVolumePath->setEnabled( e ) ; m_ui->lineEditPassword->setEnabled( e ) ; m_ui->pbVolumePathFromFavorites->setEnabled( e ) ; m_ui->cbShowPassword->setEnabled( e ) ; m_ui->pbVolumePathFromFileSystem->setEnabled( e ) ; } void favorites2::tabChanged( int index ) { if( index == 1 ){ auto walletBk = m_settings.autoMountBackEnd() ; if( walletBk.isValid() ){ this->walletBkChanged( walletBk.bk() ) ; } auto m = m_ui->pbVolumePathFromFavorites->menu() ; if( m ){ m->deleteLater() ; } if( m_ui->tableWidget->rowCount() ){ m = new QMenu( this ) ; for( const auto& it : tablewidget::columnEntries( m_ui->tableWidget,0 ) ){ m->addAction( it )->setObjectName( it ) ; } connect( m,&QMenu::triggered,[ this ]( QAction * ac ){ auto m = ac->objectName() ; m_ui->lineEditVolumePath->setText( utility::pathToUUID( m ) ) ; } ) ; m_ui->pbVolumePathFromFavorites->setMenu( m ) ; } } } template< typename M > static void _updateList( QTableWidget * table,const QFont& font,const M& m ) { tablewidget::clearTable( table ) ; favorites::instance().entries( [ & ]( size_t index,const favorites::entry& e ){ const auto& a = e.volumePath ; const auto& b = e.mountPointPath ; tablewidget::addRow( table,{ a,b },font ) ; tablewidget::setRowToolTip( table,static_cast< int >( index ),a ) ; } ) ; tablewidget::selectRow( table,m ) ; } void favorites2::updateVolumeList( const QString& volPath ) { _updateList( m_ui->tableWidget,this->font(),volPath ) ; } void favorites2::updateVolumeList( size_t row ) { _updateList( m_ui->tableWidget,this->font(),static_cast< int >( row ) ) ; } void favorites2::showUpdatedEntry( const favorites::entry& e ) { this->updateVolumeList( e.volumePath ) ; m_ui->tabWidget->setCurrentIndex( 0 ) ; } void favorites2::removeEntryFromFavoriteList() { auto table = m_ui->tableWidget ; if( table->rowCount() > 0 ){ auto row = table->currentRow() ; auto& favorites = favorites::instance() ; const auto& aa = favorites.readFavorite( row ) ; if( aa.has_value() ){ favorites::instance().removeFavoriteEntry( aa.value() ) ; this->updateVolumeList( 0 ) ; }else{ utility::debug() << "Warning: favorites2::removeEntryFromFavoriteList() out of range" ; } } } void favorites2::cancel() { this->HideUI() ; } void favorites2::currentItemChanged( QTableWidgetItem * current,QTableWidgetItem * previous ) { tablewidget::selectRow( current,previous ) ; } void favorites2::itemClicked( QTableWidgetItem * current,bool clicked ) { Q_UNUSED( current ) Q_UNUSED( clicked ) } void favorites2::itemClicked( QTableWidgetItem * current ) { this->itemClicked( current,true ) ; } void favorites2::shortcutPressed() { this->itemClicked( m_ui->tableWidget->currentItem(),false ) ; } void favorites2::devicePathTextChange( QString ) { } void favorites2::closeEvent( QCloseEvent * e ) { e->ignore() ; this->HideUI() ; } void favorites2::HideUI() { this->hide() ; m_function() ; this->deleteLater() ; } QString favorites2::getExistingFolder( const QString& r ) { auto e = QFileDialog::getExistingDirectory( this,r,QDir::homePath() ) ; while( true ){ if( e.endsWith( '/' ) ){ e.truncate( e.length() - 1 ) ; }else{ break ; } } return e ; } QString favorites2::getExistingFile( const QString& r ) { auto e = QFileDialog::getOpenFileName( this,r,QDir::homePath() ) ; while( true ){ if( e.endsWith( '/' ) ){ e.truncate( e.length() - 1 ) ; }else{ break ; } } return e ; } void favorites2::ShowUI() { m_ui->tabWidget->setCurrentIndex( 0 ) ; m_ui->tableWidget->setFocus() ; this->show() ; this->raise() ; this->activateWindow() ; } bool favorites2::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } zuluCrypt-6.2.0/zuluCrypt-gui/favorites2.h000066400000000000000000000144471425361753700206270ustar00rootroot00000000000000#ifndef FAVORITES2_H #define FAVORITES2_H /* * * Copyright (c) 2019 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include "utility.h" #include "favorites.h" #include "secrets.h" #include "utility2.h" #include #include namespace Ui { class favorites2; } class favorites2 : public QDialog { Q_OBJECT public: class settings{ public: class walletBackEnd { public: walletBackEnd( LXQt::Wallet::BackEnd s ) : m_valid( true ),m_storage( s ) { } walletBackEnd() : m_valid( false ) { } bool operator==( LXQt::Wallet::BackEnd s ) const { return m_valid && m_storage == s ; } bool operator==( const settings::walletBackEnd& other ) const { if( this->m_valid && other.m_valid ){ return this->m_storage == other.m_storage ; }else{ return false ; } } bool isValid() const { return m_valid ; } bool isInvalid() const { return !this->isValid() ; } LXQt::Wallet::BackEnd bk() const { return m_storage ; } private: bool m_valid ; LXQt::Wallet::BackEnd m_storage ; }; settings() : m_settings( utility::settingsObject() ) { } settings( QSettings& s ) : m_settings( s ) { } bool autoMountFavoritesOnStartUp() { if( m_settings.contains( "AutoMountFavoritesOnStartUp" ) ){ return m_settings.value( "AutoMountFavoritesOnStartUp" ).toBool() ; }else{ bool s = false ; settings::autoMountFavoritesOnStartUp( s ) ; return s ; } } void autoMountFavoritesOnStartUp( bool e ) { m_settings.setValue( "AutoMountFavoritesOnStartUp",e ) ; } void autoMountBackEnd( const settings::walletBackEnd& e ) { m_settings.setValue( "AutoMountPassWordBackEnd",[ & ]()->QString{ if( e.isInvalid() ){ return "none" ; }else if( e == LXQt::Wallet::BackEnd::internal ){ return "internal" ; }else if( e == LXQt::Wallet::BackEnd::libsecret ){ return "libsecret" ; }else if( e == LXQt::Wallet::BackEnd::kwallet ){ return "kwallet" ; }else if( e == LXQt::Wallet::BackEnd::osxkeychain ){ return "osxkeychain" ; }else if( e == LXQt::Wallet::BackEnd::windows_dpapi ){ return "windows_DPAPI" ; }else{ return "none" ; } }() ) ; } settings::walletBackEnd autoMountBackEnd() { if( m_settings.contains( "AutoMountPassWordBackEnd" ) ){ auto e = m_settings.value( "AutoMountPassWordBackEnd" ).toString() ; if( e == "libsecret" ){ return LXQt::Wallet::BackEnd::libsecret ; }else if( e == "kwallet" ){ return LXQt::Wallet::BackEnd::kwallet ; }else if( e == "internal" ){ return LXQt::Wallet::BackEnd::internal ; }else if( e == "osxkeychain" ){ return LXQt::Wallet::BackEnd::osxkeychain ; }else if( e == "windows_DPAPI" ){ return LXQt::Wallet::BackEnd::windows_dpapi ; }else{ return settings::walletBackEnd() ; } }else{ m_settings.setValue( "AutoMountPassWordBackEnd",QString( "none" ) ) ; return settings::walletBackEnd() ; } } private: QSettings& m_settings ; }; static Task::future< void >& deleteKey( secrets::wallet&,const QString& id ) ; static Task::future< bool >& addKey( secrets::wallet&, const QString& id, const QString& key ) ; static favorites2& instance( QWidget * parent, secrets& wallet, std::function< void() > function ) { return *( new favorites2( parent, wallet, std::move( function ) ) ) ; } favorites2( QWidget * parent, secrets& wallet, std::function< void() > function ) ; ~favorites2() ; private : void nobackendSet() ; void showContextMenu( QTableWidgetItem * item,bool itemClicked ) ; void addkeyToWallet() ; void deleteKeyFromWallet( const QString& ) ; void walletBkChanged( LXQt::Wallet::BackEnd ) ; void setControlsAvailability( bool,bool clearTable ) ; void tabChanged( int ) ; void updateVolumeList( const QString& ) ; void updateVolumeList( size_t ) ; void showUpdatedEntry( const favorites::entry& ) ; void setCommand( QLineEdit * ) ; void removeEntryFromFavoriteList( void ) ; void add( void ) ; void cancel( void ) ; void currentItemChanged( QTableWidgetItem * current,QTableWidgetItem * previous ) ; void itemClicked( QTableWidgetItem * current,bool ) ; void itemClicked( QTableWidgetItem * current ) ; void shortcutPressed( void ) ; void devicePathTextChange( QString ) ; void ShowUI() ; void HideUI( void ) ; QStringList readAllKeys() ; QString getExistingFile( const QString& ) ; QString getExistingFolder( const QString& ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::favorites2 * m_ui ; secrets& m_secrets ; QWidget * m_parentWidget ; QMenu m_volPathFav ; int m_editRow ; bool m_reverseMode = false ; bool m_volumeNeedNoPassword = false ; bool m_mountReadOnly = false ; bool m_editMode = false ; settings m_settings ; std::function< void() > m_function ; QString m_cipherPath ; class wallet{ public: void operator=( secrets::wallet s ) { m_w.reset( new w{ std::move( s ) } ) ; } LXQt::Wallet::Wallet * operator->() { return m_w.get()->wallet.operator->() ; } secrets::wallet& get() { return m_w.get()->wallet ; } template< typename ... Args > void open( Args&& ... args ) { m_w->wallet.open( std::forward< Args >( args ) ... ) ; } operator bool() { auto s = m_w.get() ; if( s == nullptr ){ return false ; }else{ return s->wallet.operator bool() ; } } private: struct w{ secrets::wallet wallet ; } ; std::unique_ptr< w > m_w = nullptr ; } m_wallet ; } ; #endif // FAVORITES2_H zuluCrypt-6.2.0/zuluCrypt-gui/favorites2.ui000066400000000000000000000325271425361753700210140ustar00rootroot00000000000000 favorites2 0 0 791 474 Favorites 10 10 771 461 0 Favorite List 10 0 741 301 QAbstractScrollArea::AdjustToContents QAbstractItemView::NoEditTriggers QAbstractItemView::NoSelection false 80 Volume ID AlignCenter Mount Point AlignCenter 190 390 181 33 Add 150 300 461 31 10 300 131 31 Add A volume Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 610 300 41 33 650 300 41 33 150 330 461 31 0 330 141 31 Mount Path Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 370 390 191 31 &Close 150 360 461 31 0 360 141 31 Mount Options Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 690 300 41 33 Manage Keys In Wallets 10 10 741 411 QFrame::StyledPanel QFrame::Raised 10 10 201 241 Set Default Wallet 20 90 161 41 Internal Wallet 20 140 161 41 Libsecret 20 190 161 41 KWallet 20 40 161 41 None 220 10 511 241 QAbstractItemView::NoEditTriggers QAbstractItemView::NoSelection Volume Path AlignCenter 260 248 421 31 Enter Volume Path Below Qt::AlignCenter 260 278 411 31 QLineEdit::Normal 260 308 421 31 Enter Password Below Qt::AlignCenter 260 338 411 31 QLineEdit::Password 280 370 181 31 Add 670 278 31 31 10 278 201 51 Change Internal Wallet Password Qt::AlignBottom|Qt::AlignHCenter true 10 340 201 31 670 338 31 31 460 370 181 31 &Close 120 60 531 241 true TextLabel Qt::AlignCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse 310 260 131 33 Ok 700 278 31 31 tabWidget pbClose tableWidget lineEditVolumePath lineEditPassword pbAddKeyToWallet rbNone rbInternalWallet rbLibSecret rbKWallet pbChangeWalletPassword tableWidgetWallet zuluCrypt-6.2.0/zuluCrypt-gui/file.png000066400000000000000000000262151425361753700200130ustar00rootroot00000000000000‰PNG  IHDR  Ûph IDATxœíݰÝu}ïû÷gí½W6;;!!á‡`áG±U‹ŽUàzlmO½ÇžéÅÞétÎt˜‰GÇ£ÇqÚ‡±ÁQˆHñÎ=wZÇŸ\‹b=È©£ØâÔRG!?™@PEHB~²Ù{}ï WcöN¾ßÏg­ïz£UU}âæ›o ŠÆÿu檪ªX¿~ý›6lØð½ªªþ¥ªª·=üŠÎÏ#äŠÒCfC€ÐWÖ¯_ÿ¦7þ(¥t{D¼²ô€Ñ©ªêëÖ­!@ß ô…-[¶œ½qãÆ/ÿ<<.,½`u"B„}O€PTUU±iÓ¦wNOO?PUÕï•Þ0àDÐ÷ÅlذañÆ¿\UÕ‡"b¼ô€–èDÄ'nºé¦?*=àPElذá”ҿ¦”<ëP¿NJé“"èG„ì6lØðš”Ò?GÄ¥·´X'"DÐwYmÚ´éwSJÿ?û©å4«Ÿ¼ñÆEÐ7Ùlܸñ5UU}>¥4Qz À餔DÐ7Yüü5wŠ€"DÐ7Û´iÓINçΈXXz À뤔>¹nݺÿ\z0ܪª*"âo#â´ÂSøÙOLÿôG>ò#@hÔæÍ›ß¾Õ.@ÿ褔DPŒ¡16lXkKïàWtRJŸ¾ñÆE¡1###ë"¢[z‡Ô‰d'@hÄ–-[Þ¯/½€#!@v„ÚUUÕ©ªÊ—^ †NUU"ÈF€P»Í›7¿%"V”ÞÀ¬=ÿݱÞRzÐ~„ZUU)¥÷–ÞÀœu"â³"hš¡V>øà%ñë¥wpTDÐ8B­z½ÞŸ”ÞÀ1éD„/Ç#@¨ÍC=4žRò€0øFC„  Ôæ¹çžû½ˆXXzµõÂt  „Ú¤”þCé Ôj´ªªOøÃ!@muº¬ôj7"¨¡[·n=9"V•Þ@#DPB-z½ÞËKo Q¾ ¨…¡½^oeé 4N„ÇL€P‹”Ò¹¥7…މ¡.g—@6£UU}úCúÐÿVz0xuñó?†ËhJé³"˜+B]Àð!Àœ ê"@†ÓhDˆ`Öp¬F#ÂkB€Y @º!B€Y @]ºñén¸A„‡%@€:‰àˆP7–š B€C @Sºñé믿þM¥‡ýC€Mꦔ>+B€ç  i"xrèFÄgo¸áCN€¹t«ª!0ä“!'@€ÜºUU}öúë¯cé!@~(¡[UÕm"†J!0„PR·ªªÛ®»î:CB€¥uSJ"†„ú!!@€~ÑM)Ývíµ×þÇÒC€æ ŸtSJŸ!Ð^è7"ZL€ý¨›Rúü?øA-#@€~Õ­ªJ„@Ë Ÿu{½ž @¿!Ð"Ý^¯÷ùk¯½ö÷JŽE7"n!0Ø0Hºqû_ÿõ_‹P4ÝN§#B`@ `uSJ"•$@€AÖM)Ý~íµ×þné!Àì`Ðu«ªúâ>ð@€mÐM)‰h @€m"B Ï  mDô1´Q7¥ôŵk׊è3h«nUU"úŒÚ¬ÛëõDô´>"@€aÐíõz·‹(O€Ãb¼×ëÝ~Í5׈(H€Ãd<¥tû>ð×—ÃJ€Ãf¼ªª/Š(C€ÃH„@!V"  À0!™†ÝxUU_|ÿûß/B 1ÞétDd @~f¼Óé|ñšk®!Ð ðÿ  ¿L„@ƒÀ¯¯ªêvõ ‡6!B ~àðDÔL€ÙDUU·¿ÿýïÿíÒC  À‹›H)}Q„À± ³#B `ö&"â‹kÖ¬!p”ÀÜL¤”D%0w"Ž’8:Ï¿&äß—ƒD€½‰ªª¾$B`öÀ±!0àØ‰˜%P‰ªª¾´fÍG @ê3"Ž@€Ôk""¾ôWõW—•ýH€Ôo"¥ôe¿J€4C„À!€æˆ8ˆhÖDJéËkÖ¬¹¬ôè y½^O„@€\D„Èi¢×ë}ù/ÿò//)=J yM¤”î! +Ÿah €2&"âÎ÷½ï}"„¡"@Ê™èt:"„¡"@Ê! Pžah€þ0‘R!´žè"„Ö ýåùoÑûÚÒC   ÿLTUu—¡@!´’è_UUÝõÞ÷¾W„Р¿Mt:;Em!@úߤ¡-À`!´‚“?ÿ‰é"„%@ËdUU"„%@a` €Á$BH`p‰Žl"„"@ßdUUw¾÷½ï}Mé!ðb@;LFÄ]"„~'@ÚC„Ð÷4`ff&Çcl/Ã5<"„¾&@ Ýnwa†ËìÎp ÓdDxM}I€@fffrÈ“®ÁàZè…éô#ÍX”á3\ƒÁ¶°ªª;ßóž÷ˆú†€TUÕø3 UUýkÓ× ¦”D}C€@3NÊp¯d¸í BèR:¯ék\}õÕ÷§”lú:´†¡/h@UUfºÎÍ9®CkˆŠ Ѐ”R–û±#ǵh…!B(F€@3^òw÷wM_äÊ+¯Ü×4}Zgaüì焼ºô†€†ìß¿ÿµ9®366öш¸/ǵh•…½^ï.Bnšó†¹òÊ+§SJoˆgr\VYØëõîz×»Þ%BÈF€@s~7×…®ºêªñ¿GD/×5i…NG„€æ¬ºõÖ[ÏÎu±«¯¾úŽ”ÒŸçº­²°ÓéÜõîw¿[„Ð8 ªªêM9¯÷¶·½íãUUý—ðLs·0"D Р”Ò©ª*ë5W¯^ý?ªªúˆx2ë…iBã4ëüüã—å¾èêÕ«¿ZUÕ+"âå¾6oaDÜõ®w½ëâÒCh'Í»ªÄEßþö·?²zõê߉ˆ?‰ˆŸ”ØÀÀZØétþQ„ÐÍ{Óºuë–•ºøêÕ«ÿ."^oˆ‡Kí`à,L)‰j'@ y£Ýn÷ÿ,9`õêÕS«W¯¾iÇŽ/Ÿý|’ÏDÄ®’› SJÿøîw¿[„P›Tzí°eË–mqÆÁ/´<Ü /÷«Çõó6ÇÕ{\?o›Ëqý¶gŽ›îõzüÅ_üÅæCÞ €[o½uôÀ¯éõz¯ˆWEÄ…qFDŒFôÕû®µÇõó¶ƒÞ¾;¥ô>øÁ~÷ÂŒ–ÃfÿþýñðÃÇž={bß¾}133‡ÿà°RÇõËŽ~?îXnßï÷­ŸÞW³9ndd$&&&bþüù±xñâH©ø¿¹v:µñŸJyÞ•W^9ÿôóÿ""âsŸû\çñÇ_6==½("ÆSJ‹žÿ½Ã½~ûôôô¬®Ÿë|Ïœ«Ã¯×›Ýw8>øö‡:ßÑÞ·Ãm;ÚóÍæ}Ô‡h ’¨…g@^ü¸­[·Æ7¿ùÍxøá‡gýàÔ£ÛíÆé§Ÿçž{nÌ›7ïÇäúøPUÕoýùŸÿù·f5 …µ ‡?nÿþýñ÷ÿ÷±eË–CžÈgdd$.¸à‚xéK_ú+¿—ëãCJiã¾}û~ãï|ç³³Ð"^„ zòÉ'ããÿ¸ø€>133?üáã¾ûî;æ/;ZUU­š˜˜X[äâ}@€@CöíÛŸúÔ§bçÎ¥§Ù¶m[<ðÀ%'ü×[o½õ²’J Ð;î¸#vìØQzp[¶l‰íÛ·—œð·7ÝtÓI%” @ [·nM›6•ž¼ˆûï¿¿ä—b166öùÏ}îsÝ"  Ѐ{î¹§ô`öíÛ>úhÉ —<õÔSÿOɹ ¨Ùó?ç …¿ +"âŠ[n¹å¿—‹šmÛ¶ÍÏù€òÓŸþ´ô„ˆˆµó7ó¶Ò#r P³Ý»w—žÌÁÔÔÔQÿ¤ì:UUµîæ›o~WéM P³½{÷–žÌÑJOˆˆˆ”ÒõûØÇ|9ÐjjæË¯€c´ö–[n¹qÍš5£¥‡4A€@Ÿ©ªjõÉ'Ÿ|×­·Þêç„­#@ ?ýû™™™ïÝrË-¿^z@ô¯—TUõí}ìcï\³fÇl |0€þ6^UÕ‡–,YòÍuëÖ­*=àX  ¯ît:ÿzóÍ7ÿ÷5kÖtK8ZÇxD¬=餓¶|ô£ýc_– "¸`ðœŸ8餓þuݺu¿[z À\øã0¸.J)ÝùÑ~ô‡)¥u£££ŸºòÊ+Ÿ)= àH<ƒï¢ªªþ¯©©©¯[·îºo¼qEéA‡ãhÅñîN§óîuëÖý ªªÏÏÌÌü¿ïxÇ;6–ð<íôëñë###×ÜtÓMSJ_­ªê›UU}ëíoû#¥ÇÃK€@û­ªªjUD¼-¥7Þxãö”Ò·ªªÚ[ªªÚÚëõ|Ç;Þ±=¥Tz+Ðr†Ï²ªªÞò‹oèt:qã7N}ä#y&"vEijUU=;ž?¦ªªCž¬×ëÍê¢ß>×ùf{þ¦Ï7›ûu¸k͹ær¾Ã9è:O\ýõoÕ áð¼îÏÿ[4—ü¬Él?¹Íu¾c½}]ç;Ô³KužëXÎ7ËÛùÒ=já»`٨ټyóJOæ¨Óñp‹¸P³ÉÉÉÒ€9H)ù‡€ŒÔ줓N*=˜ƒùóçöë騟švÚi1þüÒ3€YZºtié CE€@ÍRJqÁ”žÌBJ)Î8ãŒÒ3†Š\rÉ%ÑívKÏ^IJeËâøã/=`¨hÀääd\~ùå¥gG0oÞ¼¸ð KÏ:òªW½*^þò——žB§Ó‰ßüÍߌ‰‰‰ÒS†ŽýÁüA¼æ5¯)=øÝn7~ë·~+–,YRz ÀP-=Ú,¥¯ýëãÌ3ÏŒ»îº+vìØQz ­”R,_¾<.¸àÏ|$@ ƒ•+WÆŠ+býúõ±qãÆx衇â™gž)= Z¯ÓéÄÄÄD,[¶,N;í´X´hQTUUzÀP I§Ó‰ /¼0.¼ð¨ª*¦§§cïÞ½/|2tð'E‡û$i¶Ç½Øíæz¾£=n¶{†i_¿ÿ?›ë'èý²çàãFFFb||\pô…ŒŽŽÆ¢E‹^øu¿|Bî¸æëçms9®ßö €ÁàEè@6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À°™™™‰íÛ·ÇîÝ»ãÙgŸ}áíUUÍêöw´·›ëqM_g˜îGîCÎëíqN'æÍ›“““1þüY€æ ÈäñÇo}ë[±yóæ8pà@é90T,X§vZ¬\¹2:Oþ”$@ aSSSqçwÆ~ðƒ9ÿË2P={öĆ bëÖ­qÑEÅi§VzÀÐ Р={öÄ'?ùÉxüñÇKO"âÀñ½ï}/ž~úé8ÿüó#¥TzÀÐñ<44djj*>ñ‰OˆèC›7oŽÍ›7—ž0”4äK_úR<ñÄ¥g‡±aÆøéOZzÀÐ ЀG}4î¿ÿþÒ3€#¨ª*~ô£•ž0t4àßø†œÃxúé§cûöí¥g 5›ššŠ­[·–žÌ’ÈK€@Í~øá˜žž.=˜%¯ÕÈK€@ÍvïÞ]z0ˆ^¯WzÀÐ P³={ö”žÌÑJOj633Sz0G¾i@>ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² P³±±±Ò€9)=`h¨Ù‚ JOæ¨Ûí–ž04ÔlñâÅ¥'s011)¥Ò3††šqÆ1oÞ¼Ò3€Y:õÔSKO*jÖétâ‚ .(=˜¥åË——ž0T4à’K.‰ÑÑÑÒ3€±téÒ8ñÄKÏ*°hÑ¢xík_[zp£££qá…–ž0t4äÒK/U«V•žBJ)^ùÊWú®uhHJ)Þò–·ÄË^ö²ÒS€_022_|±Ÿâ‹Ô¡A£££ñæ7¿9N?ýôøú׿ûöí+= †Ú’%K⢋.Š… –ž0´dðŠW¼"~í×~-î»ï¾Ø´iSlÛ¶-ªª*= †B·ÛSO=5N;í´8å”SüÝ(L€@&Ýn7^ýêWÇ«_ýꘞžŽ½{÷ñ‘Ã}’tðÛg{Ül¯s¬×í÷£¾sõÓ}(yƒÝétb||ÜO9è3 ‰ã?>Ž?þøÞV÷'ŸŽëßãúyÛ\Žë·=Ç4äáEè@6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À0Ú¹sgìÙ³'öíÛUUò˜¹¾ýÅŽ;ÚÛ¹ný×mË}=ÖÛ»n\sX¯;66ccc1>>>«Ûõ ÉÓO?÷Þ{olذ!víÚUz1>>'œpB,]º4ÆÆÆJÏ¡ @ a½^/¾öµ¯Åw¾ó˜žž.=€_ðì³ÏÆc=ÿöoÿ§žzj,[¶,RJ¥gA« hÐþýûã¶Ûn‹­[·–žÀôz½xôÑGcÏž=±bÅŠõ)4ŋС!333ñ™Ï|F| Ý»wÇ–-[fýz`î4äÎ;ïŒmÛ¶•žÀíÙ³'yä‘Ò3 µ4à‰'žˆù—)=€£ôÄOÄþýûKÏ€V Ѐ»ï¾ÛÓ÷¬ªªØ¾}{éÐJj6==[¶l)=€c´k×®èõz¥g@ë¨ÙÃ?Ï=÷\é£^¯{÷î-=ZG€@Íž~úéÒ¨ÉJO€Ö P³={ö”ž@M¦¦¦JO€Ö P3?í =|C¨Ÿ² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€lÔltt´ôj’R*=ZG€@Í,XPz5év»¥'@ë¨Ù¢E‹JO &óæÍ+=ZG€@ÍÎ<óLÿbÐN'&''KÏ€Ö P³ÑÑÑX¹reé£N8!:Ÿ*AÝü­‚\z饴XJ)–-[Vz´’Ï K–,‰W½êU¥gp”N9å”/=ZI€@C~û·;Î:ë¬Ò3˜£… Æé§Ÿ^z´–†ŒŒŒÄýÑÅŠ+JO`–-ZçœsŽŸÿ  РyóæÅ[ßúÖ¸ì²Ë|g,€>ÖétbùòåqÎ9çÄÈÈHé9Ðj~d34,¥—^zi¼â¯ˆ{ï½76lØO=õTéYDÄqÇ'œpB,]º4FG}Z9ø›™LNNÆå—_—_~yìÞ½;ž~ú騷o_ÌÌÌòøªªæôö;îhoçºõ_·-÷õXoïºýqÍa¼nÄϾeúøøxŒÕí£'@ € Ä‚ ~ém³} uÜà×ÏÛær\¿íÄãúyÛ0äá5 @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À0šššŠ={öľ}ûbff&""ªªú¥cþõáÏ7ÛÛ;ßìÏ=¨š|_Íåºm8ß þùî÷óÊØØXŒÅÈÈȬoÔC€@&Ï>ûlÜwß}±~ýúؾ}ûœ(hÆääd,^¼8N>ùäèt|aä @ aUUŽ÷ÞßøÆ7bÿþý¥çð öîÝ{÷îíÛ·ÇòåËãä“OŽ”RéYÐj4==·ß~{<ðÀ¥§pÓÓÓ±mÛ¶Ø»woœuÖYž  hHUUqÛm·Å¦M›JO`–žz꩘™™‰sÎ9§ôh-y ¹ûî»ÅÀÚµkWlß¾½ô h- عsgÜsÏ=¥gp”{ì±8pà@éÐJp÷Ýw¿ðíu<½^ϳ Ð5›žžŽ7–žÀ1Ú¹s§o™  P³ÿøÇž¶h™™™Ø»woéÐ:j¶sçÎÒ¨‰P‚ú ¨Ùž={JO &SSS¥'@ë¨ÙsÏ=Wz5éõz¥'@ë d#@€l² @6ÈF€Ù d#@€l² @6ÈF€@ÍFGGKO &ŽO• nþVAÍ&''KO &þQ ê'@ fÇ|é ÔdÞ¼y¥'@ë¨Ù™gžé_ÌZ ÓéÄ‚ JÏ€Ö P³n·+V¬(=€ctüñÇ{ 4Àß*hÀ%—\)¥Ò38Ë–-+=ZI€@–-[/{ÙËJÏà(-Y²$&&&JÏ€V Ðßÿýß÷¯ghþüùqæ™g–ž­%@ Ä.n\ HIDAT!cccqÅWÄòåËKO`–&''cåÊ•^û ò· 499ú§_|±3€>–RŠSN9%V­Zccc¥ç@«ù^¡Ð°ÑÑÑxÃÞ¯|å+ãÛßþvlÚ´)žyæ™Ò³ˆŸ}Œ>á„âÔSOñññÒs`(ÈdÉ’%ñÆ7¾1ªªŠíÛ·ÇÞ½{cïÞ½/ü~UU³:ÏÁÇííæz\Óצûцûó:myËŸAºG:®ŸîÇØØXt»Ý˜˜˜xá»ÎõÏ>ptd–R:ä‹Ógû@ê¸Á?®Ÿ·Íå¸~Û3ˆÇõó¶a<ÈÃ¥Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€ÙŒ–ÃêÀñÌ3ϼð몪~é÷þõ\{±Û5uÝ£Ý3LûúýÿÙl÷õÛž~ê¸6þù”}ccc1222«=@½d233?úÑbãÆñÐCÅÔÔTéICmdd$.\‹/ŽO<±ô2xàâ«_ýjìÚµ«ô~nff&vîÜ;wüä'qúé§ÇâÅ‹KÏ‚Ö Р^¯_ùÊWâ»ßýné)ÁâÁŒ¥K—Æé§Ÿ)¥Ò“ µ4è _øBüð‡?,=€YzüñÇczz:Î>ûìÒS µ|,hÈ·¿ýmñ0€ž|òÉxì±ÇJÏ€Ö ЀݻwÇ×¾öµÒ38J>úh<÷Üs¥g@+ hÀ?ÿó?{à`½^/¶oß^z´’šUU÷ßé£;vÌùçâ/N€@Íy䑨¿é£éé騷o_éÐ:j¶cǎҨɳÏ>[z´ŽšíÞ½»ôj255Uz´Žšyñ9@{ôz½Ò u² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@ fŽ¿Vm‘R*=ZÇgJP³ÉÉÉ񬃯ØXé Ð:j¶páÂÒ¨I·Û-=ZG€@Í^ò’—ø2,€H)Å‚ JÏ€ÖñYÔl||<Î>ûìÒ38F .Œ‘‘‘Ò3 u4àu¯{]é £SO=µôh% 8óÌ3cÕªU¥gp”/^ì˯ !òæ7¿9N<ñÄÒ3˜£ñññ8묳JÏ€Ö ÐyóæÅÿñ‹€rÜqÇŹçžëµÐ  :á„âÏþìÏâüóÏ/=€±xñâ8ÿüócÞ¼y¥§@«–m7>>ø‡<òHÜsÏ=ñÐCÅôôtéYDD§Ó‰… ÆòåËcþüù¥çÀP ÉgœW\qELMMŶmÛb÷îݱgÏžb¤ªªY§Ôqý²£ß;–Û÷û}ë§÷U[Žó÷¯ÌŸ©”Rt»Ý˜7o^LNN¾ðåVÇz`vdÖívcÅŠ¿òöƒø÷@è¸Á?®Ÿ·Íå¸~Û3ˆÇõó¶a<ÈÃk@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l`6z¥Ð„ºì.=hÔÞÒhB]´›Çzj!@¨‹JÐb)¥]¥7Єºl-=hN¯×óXO-µH)m(½hŽÇzê"@¨Ëƒ¥ÍI)m.½v Ô¢ÓéÜWzМ^¯÷ÃÒhB-Î>ûì'"b}é@#î¿á†ž(=‚v ÔéîÒ€FÜ]zí!@¨MJéKoêç1ž: j322ò•ðó@ mvíß¿ÿ+¥GЄڜuÖYϦ”>WzP«Ï­[·nªôÚC€P·O”Ô§×ë}²ôÚE€P«+VüSDü ô ÷}èCú§Ò#hB­RJ‘Rú@é@-<¦S;BíV¬Xñ÷~Z* ¶ªª6Ο?ÿ ¥wÐ>„Ú¥”z½^ï=¥wG¯Óé¼gÍš5½Ò;hB#Î=÷Ü/TUå[öÀ`úŸ×]wÝ¥GÐN„ÆŒŽŽ^¾m –g;ÎÛK ½yéK_ú`UU¾ HUUÿíÚk¯}°ôÚK€Ð¨sÏ=÷#UUýCéÀ‹«ªêŽë¯¿þ£¥wÐn„F¥”¢ªª?‰ˆŸ”ÞÑ####Rzí'@hÜyç·£×ë½!"v•ÞÒ“###¿síµ×z¬¦q„,Î;ï¼ûSJ¿SUÕ3¥·¿ä™^¯÷ûk×®ÝXzÃA€ÍÊ•+¿ÿI„@ßx&"Þ|à 7|·ô†‡!«U«V}eddäòˆØQz ¹Nçß]wÝuÿ«ô†‹!»sÎ9ç;333¯‹ˆ‡Ko€!õp§ÓyÝÚµk=óAv„".¸à‚õóæÍûˆøBé-0d¾pàÀßX»víúÒCN£¥0¼Î:ë¬]UU½yÓ¦Mÿ5"ÖFÄxéMÐbÏTUõß®»îº•Âpó E¥”bÕªUI)~`!4㎑‘‘óÄýÀ3 ô…U«V=°aÆÿˆˆ‹Ê.€VøAJé}k×®ýŸ¥‡Àó}å¼óÎû‡ªªþaÓ¦Moìõz‹Ko€ASUÕw:Î5ƒ~$@è;)¥ˆˆ;"âŽõë׿<"þ”ÒUU\vô¯”Òã½^ï3Nço×®]ûƒÒ{àpRé0_ÿú×G—.]úÚªª.¯ªê²ˆxuüB@WUõKÇüëA8®Ÿ·9®ÞãúyÛ\Žë·=ƒx\?osÜ@ü˜ŠˆïFÄ×:Î×7mÚôO·Ýv[ï'€>"@H?þñÇŸ~úé•)¥•)¥U½^ïô”Ò¢^¯7Ïÿ÷+Žõ­ƒõz¿üqþX¬Žt«îáÎ?×ó ÓýhÃ}(yA|µá>ê:îÇìÎ?Ësí}þ¿^¯·+"¶¥”6OOOožššÚüáøÙY]ø¹ÿ‘iEtÄ\oIEND®B`‚zuluCrypt-6.2.0/zuluCrypt-gui/filemanager.cpp000066400000000000000000000032531425361753700213410ustar00rootroot00000000000000/* * * Copyright ( c ) 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "filemanager.h" #include "ui_filemanager.h" #include "utility.h" fileManager::fileManager( QWidget * parent,std::function< void( const QString& ) > s ) : QDialog( parent ), m_ui( new Ui::fileManager ),m_function( std::move( s ) ) { m_ui->setupUi( this ) ; connect( m_ui->pushButton,SIGNAL( clicked( bool ) ),this,SLOT( set() ) ) ; this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; m_ui->label->setText( tr( "Enter Below The Name Of The Application You Want To Be Used To Open Mount Points." ) ) ; m_ui->lineEdit->setText( utility::fileManager() ) ; this->show() ; } fileManager::~fileManager() { delete m_ui ; } void fileManager::set() { auto e = m_ui->lineEdit->text() ; utility::setFileManager( e ) ; if( !e.isEmpty() ){ m_function( e ) ; } this->hide() ; this->deleteLater() ; } void fileManager::closeEvent( QCloseEvent * e ) { e->ignore() ; this->hide() ; this->deleteLater() ; } zuluCrypt-6.2.0/zuluCrypt-gui/filemanager.h000066400000000000000000000025571425361753700210140ustar00rootroot00000000000000/* * * Copyright ( c ) 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef FILEMANAGER_H #define FILEMANAGER_H #include #include #include #include namespace Ui { class fileManager; } class fileManager : public QDialog { Q_OBJECT public: static void instance( QWidget * w,std::function< void( const QString& ) > s ) { new fileManager( w,std::move( s ) ) ; } explicit fileManager( QWidget * parent,std::function< void( const QString& ) > ) ; ~fileManager(); private slots: void set( void ) ; private: void closeEvent( QCloseEvent * ) ; Ui::fileManager * m_ui ; std::function< void( const QString& ) > m_function ; }; #endif // FILEMANAGER_H zuluCrypt-6.2.0/zuluCrypt-gui/filemanager.ui000066400000000000000000000024251425361753700211740ustar00rootroot00000000000000 fileManager 0 0 541 215 Set File Manager 10 10 521 141 TextLabel Qt::AlignCenter true 150 150 241 29 200 180 141 31 &Set zuluCrypt-6.2.0/zuluCrypt-gui/folder.png000066400000000000000000000026611425361753700203460ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÛNµ_¨1IDATXÃí—Ïk]EÇ?gî¼—ˆØÖj‰ZDP©]tç?P…ºRZ ºwãÎU…"è¿!‚ÐMb©+©ˆX¤Õ*T[±5©Mš&yMò’wï9.æÌ½“ÔBJ7<îܹgΜßó=óàA×Ož½oÙãœý×Ï€c'ϜߪëÃBE§Dç˜òþÒ©Gþ'y÷}óøQWjBP"P ÂÔ@ˆÍ˜¯¾¹¨UU‰J2.š*¶¿Ë޹ÁäPm·^þü£×¾ôõæ~[ei´‰“»•Ìîâà ‡Ä;A%§ˆ ¶&"xg~ÙšC•¥! zî»ß’m=aqiÄÊ­9šÓá…7¯¢§p&£9”’Þs$ý74ÀÀ9föìgßÞYZ˜àª¿^ú–S'޲6£;ÜOc±gç{3ÓÓ{ÿ3vz‘;+‹±3@cdme‰ž`åömÁ‰$e"æ¡ôór¨êÝsUË»²{ÏnÍ]á‘Ù§i&ãag@]×´Í$…«ª‘ýâ™Ç°rXaô‡™× hÔnU5¥í º~õ¦fö±±º:é ¯¯²1Zî¼Ûf@ŽPUŽsn2i•;ã¶Gj1œ-–XÈ#²ÉgNc ª¾²:zï¼X^^fþËL \:TA \ Ék“Èh½áÊõ QïÆ‰ì(¿ˆAaŽÎѹ«û·><}ícG´ A>ýþ/î‘^¨eme‹J”Ö”– ,KW‹ºÏß­:@+ÇúÚ¿¾Ñ¸ðÓmh·E4WB´<µÀ!ºD$ˆŠ˜rMPq$O½¤=¢%4÷KT¼Ú¢éJ§Õ¾®‘ôî$Õ?±ÿ¦@Œ=FÛH™F“.1™@¸­æ(Úb´_“Ç-¬–Ä`qUûŘtF­!ö!&£y«}”bLº+Óã£ÁµQí€SG¨\oD´ÐF‹L£=ÈÛ?p6·h`hºÄšZcÞéPð´Q;ϰÃZ³ÞYó º=ô¹@ :6=M®‚˜dÅR< à½T´7çÒæÖÚqe¥–1 6@\’i ô‹å:{œó-†f5e£TI :eK!S`!Ĩè•ù*ÉÅB“©ÍC1YçÒ<#"3>ÉF@ñªJÛ&ªT+¹Æ„Z`h¢f”´ý|@oD›ï95a{)çõ\Ò¢àªÊ!xÌP¦ ÅRpB&_qXNø6ЧÉO5š÷?\]àç_“{ȽZ©ì ') ’äURñN†ìä6–ðOîfÏ£³±ÇÍ%3WV,]—Ýæu>´²”Y é2§¦»À8Çb=AÙª[4Ä´¡ô¸è³*‰<2—%Ø5í7‹öÏVB®,@ÄÑ„€î©Ç8øì󨶵­)òµÂ@ŠÍ™óͨ Eº¬ÖKÙÜ5cQž-à]Åï­áoÞ^gvu“ZÛ®L|qï‹…c¾h@ª=º³ÌÀ*¨+M»àíï_^*nÜZÅG„ñdÌ–ö*I–Ob|«óÊÁ8¦Ã2˜R9Ázì˜ Þ*"ä,WÞÁ¦Ýgü°ró«K£Ç¥r‰±†ŒZ' %Ñr¦\j:¢ Æý»†°Y[ZÄ6}“Ÿ„Dtm4FÌýC3»÷_LÑzø™·qnphL×!UIª0<«Cq¶&DŠ ."– ‘€QE$µ'1]EqD¢ŽY¹ü1¼ôÿ˜¾Êÿƒ¿½%å¤ÙTbIEND®B`‚zuluCrypt-6.2.0/zuluCrypt-gui/help.cpp000066400000000000000000000041651425361753700200220ustar00rootroot00000000000000/* * * Copyright ( c ) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "help.h" #include "ui_help.h" #include #include #include #include "utility.h" #include "pdf_path.h" help::help( QWidget * parent,const QString& path ) : QDialog( parent ), m_ui( new Ui::help ), m_openPath( path ) { m_ui->setupUi( this ) ; this->setFixedSize( this->size() ) ; this->setWindowFlags( Qt::Window | Qt::Dialog ) ; this->setFont( parent->font() ) ; connect( m_ui->pushButton,SIGNAL( clicked( bool ) ),this,SLOT( pbClose() ) ) ; connect( m_ui->pushButton_2,SIGNAL( clicked( bool ) ),this,SLOT( pbOpenPDF() ) ) ; this->show() ; } help::~help() { delete m_ui ; } void help::pbClose() { this->hide() ; this->deleteLater() ; } void help::pbOpenPDF() { auto x = tr( "WARNING!" ) ; auto y = tr( "Failed to open zuluCrypt.pdf,make sure your system can open pdf files using \"%1\" tool and try again" ).arg( m_openPath ) ; QString e = PDF_PATH ; if( utility::pathExists( e ) ){ utility::openPath( e,m_openPath,this,x,y ) ; }else{ e += ".gz" ; if( utility::pathExists( e ) ){ utility::openPath( e,m_openPath,this,x,y ) ; }else{ utility::openPath( PDF_PATH,m_openPath,this,x,y ) ; } } } void help::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbClose() ; } bool help::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->pbClose() ; } ) ; } zuluCrypt-6.2.0/zuluCrypt-gui/help.h000066400000000000000000000025001425361753700174560ustar00rootroot00000000000000/* * * Copyright ( c ) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef HELP_H #define HELP_H #include #include class QCloseEvent ; class QEvent ; class QObject ; namespace Ui { class help; } class help : public QDialog { Q_OBJECT public: static void instance( QWidget * parent,const QString& path ) { new help( parent,path ) ; } explicit help( QWidget * parent,const QString& ) ; ~help() ; private slots: void pbClose( void ) ; void pbOpenPDF( void ) ; private: void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::help * m_ui ; QString m_openPath ; }; #endif // HELP_H zuluCrypt-6.2.0/zuluCrypt-gui/help.ui000066400000000000000000002140421425361753700176520ustar00rootroot00000000000000 help 0 0 821 562 Help 410 530 121 31 &Close 10 10 801 521 10 30 781 481 true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt;">ZuluCrypt is a simple, feature rich and powerful solution for hard drives encryption for linux.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt supports LUKS, TrueCrypt, VeraCrypt and PLAIN dm-crypt encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These supported encrypted volumes may resides in image files, hard drives and usb sticks, LVM</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volumes as well as in mdraid devices.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of encrypted volumes. Those that use what is commonly know as “a header†and</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">those that do not. TrueCrypt, VeraCry and LUKS volumes use a header. PLAIN dm-crypt volumes do</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">not use a header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a &quot;volume header&quot;.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage to it will makes it impossible to open the volume causing permanent loss of encrypted data.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">The damage to the header is usually caused by accidental formatting of the device or use of</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">some buggy partitioning tools or wrongly reassembled logical volumes.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible again after the header is restored if the header on the volume get corrupted.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack'; color:#008000;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are two kinds of header using encrypted volumes. Those that use an encrypted header and those</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">that do not. TrueCrypt and VeraCrypt use an encrypted header whereas LUKS does not. The use of non</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted header in LUKS makes it obvious to everybody that the volume is an encrypted LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may be problematic to some people. How big the problem may be depends on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">person and their use case for hard drive encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The use of encrypted header as in TrueCrypt or VeraCrypt volumes or no header at all as in PLAIN dm-</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">crypt volumes make these volumes indistinguishable from random noise and this may seem useful at a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">glance but its usefulness may not hold up against scrutiny as the likelihood of being believed that a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">100GB file made up of cryptographically sound random data is just a 100GB file made up of random</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data and not a container file for an encrypted volume is not very high.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With LUKS, TrueCrypt and VeraCrypt volumes, it is very important to have a volume header backup</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">since a valid header is required to unlock the volume. A corrupted or missing header will make the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume unusable causing the loss of all encrypted data.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">LUKS stands for “Linux Unified Key Setupâ€. It is a specification of how to store information necessary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to open a LUKS formatted encryption volume. LUKS encryption format is the standard format in linux</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and a recommended one if the encrypted volume is to be used among linux systems. TrueCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt volumes are better alternative if the encrypted volume is to be shared between linux,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">windows and OSX computers.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can create and open 5 types of encrypted volumes, LUKS, TrueCrypt, VeraCrypt,PLAIN</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dm-crypt and PLAIN dm-crypt volume at a none zero offset. PLAIN dmcrypt volume is a header less</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume and all necessary encryption information is provided by zuluCrypt when it creates or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open these volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; text-decoration: underline;">Pros and cons of the five volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt; text-decoration: underline;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It does not use a volume header and hence its not possible to “brick†the entire volume simply by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over writing a small part of it.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It does not use a header and hence its impossible to know if the volume is made up of only</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">cryptographically sound random data or if its an encrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It does not use a header and hence any tool that opens these volumes must provide the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options that were used when the volume was created. Different tools may use different encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">options making these encrypted volumes not very portable between applications or even between</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">different versions of the same application.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLAIN dm-crypt at a none zero offset.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This volume has the same pros and cons as those of a PLAIN dm-crypt volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional pro for this volume is that it can be places anywhere on the device making it possible</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to have this volume on top of any one of the other supported encrypted volume or on top of an</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">unencrypted volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For example, its possible to have an X MB drive that has unencrypted file system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">at the beginning of the device and a “PLAIN dm-crypt volume with an offset†somewhere towards the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">end of the device making it possible to use the drive as unencrypted volume and as encrypted volume</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">simultaneously depending on sensitivity of the data to be stored on the device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this volume type is to be used, preceding part of the drive should be formatted in “FAT†family of file systems.This volume types gives a “hidden volume†type functionality offered by TrueCrypt and VeraCrypt. When creating or unlocking this volume type, the starting offset of the volume will be asked and NOT the volume size as TrueCrypt and VeraCrypt does with the hidden volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above means, if you have a 100 MB drive and you want to create a 30MB “PLAIN dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume at a none zero offsetâ€, you will enter the starting offset of the volume as 70MB. In VeraCrypt or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt, you will enter the hidden volume size of 30MB. The starting offset and the size of the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hidden volume are related by a simple formula: starting offset(70MB) = device size(100MB) – hidden</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume size(30MB).</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TrueCrypt</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and hence its not possible to know if the volume is TrueCrypt formatted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume or if the volume is just made up of cryptographically sound random data.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Hidden volume. A TrueCrypt volume can have up to two different encrypted volumes. The first</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume is commonly know as “outer volume†and the second optional one is commonly known as</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“hidden volumeâ€.When a TrueCrypt volume is about to be opened, the user has an option to select</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">which one of the two to open by giving appropriate key.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It uses an encrypted header and it is not possible to open the volume without a valid header. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">use a TrueCrypt volume, make sure you have at least one backup of the volume header.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VeraCrypt</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VeraCrypt is an extension of TrueCrypt and it shares the same TrueCrypt’s pros and cons.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Pro for VeraCrypt over TrueCrypt.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. It requires stronger effort to unlock VeraCrypt volume and this makes them more secure over</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">TrueCrypt volumes.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Additional Cons for VeraCrypt over TrueCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It requires stronger effort to unlock a VeraCrypt volume and this increases the time it takes to unlock</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a VeraCrypt volume. How long it will take depends on the strength of the computer and it may vary</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from a few seconds to several minutes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">LUKS</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pro:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS volume can be opened with up to 8 different keys.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cons:</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. A LUKS header is stored unencrypted making it obvious the volume is LUKS formatted encrypted</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume and this may not be desirable under certain circumstances. It is possible to create a LUKS</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">volume with a detached header and zuluCrypt can open these volumes using “luks†plugin.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. It uses a header. As it is not possible to open a header using encrypted volume without its header, a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">corrupted LUKS header makes it impossible to open the volume. If you use a LUKS volume, make</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sure you have at least one backup of the volume header.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can do two types of encryption. It can do single file encryption/decryption or block device</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encryption.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">File encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can encrypt and decrypt individual files. This feature is useful when a user just wants to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt a single file and taking the route of creating an encrypted container file to host the file is seen</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as an unnecessary hassle. This functionality is akin to file encryption using gpg with a symmetric key.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">File encryption is done using libgcrypt as a cryptographic backend. Files are encrypted using 256 bit</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">AES in CBC mode. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The encryption key is derived from user pass phrase using pbkdf2 with 10,000</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">rounds of iterations and sha2 as a cryptographic hash function. The resulting encrypted file will have a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file size that equals (64 + 1024 * n) bytes where n is a number starting from zero.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted file:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;encrypt a file†to open a file encryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to store encrypted, enter the password to be used to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypt the file and then click “create†and the encrypted version of the file will be created at the path</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by “destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">To decrypt the file created with above steps:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to the menu and then click “zC-&gt;decrypt a file†to open a file decryption dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. At the dialog that will show up, click the button that is on the same line as “source path†text. A file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dialog will show up, select the file you want to decrypt, enter the password to be used to decrypt the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file and then click “create†and the decrypted version of the file will be created at the path given by</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“destination path†field.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Block device encryption.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A hard drive or a usb stick are two examples of block devices. A regular file can simulate a block</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">device through a use of devices known as “loop devicesâ€. These devices have a device path that starts</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">with “/dev/loopâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The infrastructure in the linux kernel that deal with block device encryption is called “dm-crypt†and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does its work through a process commonly known as OTF(on the file encryption). Dm-crypt devices</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">are represented by device addresses that starts with “/dev/dm-†and these paths are usually accessed</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">through their soft links that reside in “/dev/mapperâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Below is an example of steps taken in creating a 100MB encrypted container in a file and adding a file</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">in it to be stored securely.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Create a 100MB file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Attach a loop device to the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Create an OTF encryption mapper against the loop device.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Put a file system on the encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Mount the file system on the mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Copy The file to be stored securely to the file system through the mount point.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Unmount the file system.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Destroy the OTF encryption mapper.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Detach the loop device from the file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">10. Maintain the encrypted volume as a secure holder of files within it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All zuluCrypt does is provide a GUI to make it easy to do above specified tasks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With the above steps:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 1 deal with a path that look like “/home/ink/secret.imgâ€, this is a path to a regular file.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 2 converts “/home/ink/secret.img†file to something like “/dev/loop0†loop device path.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step 3 converts “/dev/loop0†loop device path to something like “/dev/mapper/secrets.imgâ€. Data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">written to “/dev/mapper/secrets.img†will get encrypted and then passed forward to “/dev/loop0†on its</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">way to “/home/ink/secret.imgâ€. When data is read from “/dev/mapper/secrets.imgâ€, the data will be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">read from “/dev/loop0†who in turn will read it from “/home/ink/secret.imgâ€, decrypted by dm-crypt</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then given to the reader. This process is called “on the fly encryption†because the encryption</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mapper does not store or hold on to data, it gets data and then encrypts or decrypts it depending on the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">direction of data flow and then passes it along.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in an image file.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a file†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Enter the name of the file to be used to hold the container in the “file name†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the size of the container in the “file size†field.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. Click “createâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Wait for the container file to be created and for the volume creation dialog to show up.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7. Enter the password to be used to create the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">8. Select the type of volume you want to create from the “volume type†list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">9. Click create to create the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to create an encrypted container in a partition.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;create-&gt;encrypted container in a hard drive†to open a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Click/double click on the hard drive you want to create a volume in and then advance to instruction</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">number 7 in the instruction list above. If the partition you want to put an encrypted container does not</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">show up on the list, then restart zuluCrypt from root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a file using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a file†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click the button to the right of “volume path†field and then browse to where</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the volume is and click it to open it. Alternatively, you can just drag the volume file on zuluCrypt to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">generate a password dialog prompt with the file path already filled in.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">How to open an encrypted container that reside in a partition using zuluCrypt.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Start zuluCrypt.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Go to “menu-&gt;open-&gt;encrypted container in a partition†to bring up a dialog window.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. On the dialog window, click/double click on the partition with an encrypted volume you want to</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">open.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Enter the volume key in the volume key field and then click “open†to open the volume.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With both two steps above, the volume will be opened and mounted at a path whose last component is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">given by the entry in the field “mount nameâ€. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When the volume is successfully opened, zuluCrypt will</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">automatically open the mount point path. To close the volume, click its entry on the zuluCrypt window</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">and then click “close†on the pop up window.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt can open an encrypted volume using keys derived from different sources. These sources</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">include, a pass phrase, a key file, a key retrieved from kwallet, a key retrieved from Gnome's libsecret,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">a key retrieved from an internal secure storage system, a key from gpg encrypted key file among other</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">sources.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a pass phrase volume key, make sure the key source option read “key†and then enter the pass</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phrase on the entry field at the bottom.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a keyfile as the source of volume key, click the option bar and then select “keyfile†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring a dialog box that will allow you to browse to where the key</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">file is.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To use a plugin as the source of volume key, click the option bar and then select “plugin†and then</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">press the button on the lower right to bring up a list of available plugins and then select the one you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want from the list.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Volume keys stored in kwallet, Gnome keyring or internal secure storage system plugins can be</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">managed by going to “menu-&gt;options-&gt;manage volumes in internal/kde/gnome walletâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Storage of keys in a gnome wallet/keyring seem most appropriate in a gnome session but this has some security repercussions, the keys are stored in the user keyring and this keyring gets unlocked when the user logs in. This means that once a user is logged in and the keyring is open, any application that runs in that user session can read those keys using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In a kde system, a kwallet secure storage system seem most appropriate but it suffers from the same</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">security problem the gnome secure storage system has, once the wallet is open, any application running in the user session can access it using public APIs exposed by the storage system.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The behaviors of the above secure storage systems is by design but this design may not be ideal for</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">some users under certain use cases. The internal secure storage system is powered by libgcrypt and it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">does not have the behavior of the above two systems. An unlocked internal secured storage system is</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">accessible only to the instance of zuluCrypt that unlocked it.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Favorites.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For convenience, most used volumes can be easily opened by adding them to the favorite list. Entries</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">on the list are added in the dialog window opened by clicking “menu-&gt;options-&gt;manage favoritesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Favorite entries are added by clicking the “favorite†entry on the menu.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Erase data in a device.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It is very important to create encrypted volume over cryptographically strong random data to make it</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">impossible to know what part of the encrypted volume has been used and what part has not. If the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">encrypted volume is created over predictable data patterns like on a device with only zeros in it,</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">forensic analysis may reveal how much and what part of the encrypted volume are in use.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When creating an encrypted container in a device, zuluCrypt offers an option to first write random data</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">over the device. This feature can be performed on other devices by activating it through “menu-&gt;erase</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">data in a deviceâ€. Random data are written to disk by opening a plain dm-crypt encryption mapper on</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">the device with a 64 byte random key and then blasting zeros on the device through the mapper. This</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">technique has proven to be faster compared to alternatives like writing random data on the device read</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from “/dev/urandomâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">System and non system volumes.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To enforce access controls on what user can access what block device and what they can do with the</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">access they have, zuluCrypt employes a concept of “system volumes†and “non system volumesâ€.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A system volume is defined as a volume that has an active entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/fstabâ€,â€/etc/crypptabâ€,“/etc/zuluCrypt/system_volumes.list†or if udev identify it as such if udev</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">is enabled. Ideally, all volumes inside the computer are to be considers system volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A non system volume is a volume that failed in the above considerations or if it has an entry in</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“/etc/zuluCrypt/non_system_volumes.listâ€. Ideally, these volumes are plug gable usb based hard drives</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">or usb sticks.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Partitions can be added or removed from the list of system or non system volumes simply by starting</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zuluCrypt from root's account and then going to “menu-&gt;options-&gt;manage system volumes/manage</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">non system volumes†and then adding the volume in the appropriate list.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Permissions.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluCrypt limits what a user can do on block devices through unix's group based permission system</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">using two groups, “zulucrypt†and “zulumountâ€.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, only a root user or a user who is a member of group</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">“zulucrypt†can create an encrypted volume in the device or taking/restoring volume headers. If you</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">want to create a volume in a device and the device does not show up on the list, restart zuluCrypt from</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">root's account and try again.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If a device is identified as a system device, zuluMount will mount it only if the user is root, is a</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">member of group “zulumount†or the device has an entry in “/etc/fstab†with either “user†or “usersâ€</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">mount options set.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ZuluMount.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount is a general purpose mounting tool that can open zuluCrypt supported encrypted volumes</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">as well as non encrypted volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also auto detect plugged in devices and auto mount them.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ZuluMount can also unlock encfs volumes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2015-2017 Francis Banyikwa, mhogomchungu@gmail.com</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> 290 530 121 33 Open &PDF textEdit pushButton zuluCrypt-6.2.0/zuluCrypt-gui/icon.qrc000066400000000000000000000004211425361753700200140ustar00rootroot00000000000000 zuluCrypt.png keyfile.png folder.png partition.png file.png passphrase.png module.png zuluCrypt-6.2.0/zuluCrypt-gui/json_parser.hpp000066400000000000000000000135061425361753700214230ustar00rootroot00000000000000/* * * Copyright ( c ) 2019 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef JSON_H #define JSON_H #include #include #include #include #include #include class SirikaliJson { public: using function = std::function< void( const QString& ) > ; SirikaliJson( function log = []( const QString& e ){ Q_UNUSED( e ) } ) : m_log( std::move( log ) ) { } SirikaliJson( const QByteArray& e,function log = []( const QString& e ){ Q_UNUSED( e ) } ) : m_log( std::move( log ) ) { this->getData( e ) ; } SirikaliJson( const QString& e,function log = []( const QString& e ){ Q_UNUSED( e ) } ) : m_log( std::move( log ) ) { this->getData( e.toUtf8() ) ; } SirikaliJson( QFile&& e,function log = []( const QString& e ){ Q_UNUSED( e ) } ) : m_log( std::move( log ) ) { this->getData( e ) ; } SirikaliJson( QFile& e,function log = []( const QString& e ){ Q_UNUSED( e ) } ) : m_log( std::move( log ) ) { this->getData( e ) ; } std::vector< int > getIntVector( const char * key ) const { auto s = m_json.value( key ) ; if( s.isArray() ){ std::vector< int > m ; const auto arr = s.toArray() ; for( const auto& it : arr ){ m.emplace_back( it.toInt() ) ; } return m ; }else{ return {} ; } } QStringList getStringList( const char * key ) const { auto s = m_json.value( key ) ; if( s.isArray() ){ QStringList m ; const auto arr = s.toArray() ; for( const auto& it : arr ){ m.append( it.toString() ) ; } return m ; }else{ return {} ; } } QString getString( const char * key,const QString& defaultValue ) const { return m_json.value( key ).toString( defaultValue ) ; } QString getString( const char * key ) const { return m_json.value( key ).toString() ; } QByteArray getByteArray( const char * key,const QByteArray& defaultValue ) const { return this->getString( key,defaultValue ).toUtf8() ; } QByteArray getByteArray( const char * key ) const { return this->getString( key ).toUtf8() ; } bool getBool( const char * key,bool s = false ) const { return m_json.value( key ).toBool( s ) ; } int getInterger( const char * key,int s = 0 ) const { return m_json.value( key ).toInt( s ) ; } double getDouble( const char * key,double s = 0.0 ) const { return m_json.value( key ).toDouble( s ) ; } QStringList getTags( const char * tag ) { QStringList s ; const QJsonArray arr = m_doc.array() ; for( const auto& it : arr ){ if( it.isObject() ){ auto value = it.toObject().value( tag ) ; if( value.isString() ){ s.append( value.toString() ) ; } } } return s ; } SirikaliJson& operator[]( const char * key ) { m_key = key ; return *this ; } void operator=( const char * value ) { m_json.insert( m_key,value ) ; } void operator=( const QString& value ) { m_json.insert( m_key,value ) ; } void operator=( bool value ) { m_json.insert( m_key,value ) ; } void operator=( const QByteArray& value ) { m_json.insert( m_key,QString( value ) ) ; } void operator=( const std::vector< int >& value ) { QJsonArray arr ; for( const auto& it : value ){ arr.append( it ) ; } m_json.insert( m_key,arr ) ; } void operator=( int value ) { m_json.insert( m_key,QString( value ) ) ; } void operator=( const QStringList& value ) { QJsonArray arr ; for( const auto& it : value ){ arr.append( it ) ; } m_json.insert( m_key,arr ) ; } bool toFile( const QString& path ) const { QFile file( path ) ; if( file.open( QIODevice::WriteOnly ) ){ file.write( this->structure() ) ; return true ; }else{ return false ; } } QByteArray structure() const { return QJsonDocument( m_json ).toJson( QJsonDocument::JsonFormat::Indented ) ; } bool passed() const { return m_passed ; } bool failed() const { return !this->passed() ; } private: void logException( const QString& e ) const { if( m_fileName.isEmpty() ){ QString m = "Error, Malformed Json Structure Encountered" ; m_log( m + "\n\n" + e ) ; }else{ QString m = QString( "Error, Malformed Json Structure Encountered in File: %1" ).arg( m_fileName ) ; m_log( m + "\n\n" + e ) ; } } void getData( QFile& f ) { m_fileName = f.fileName() ; if( !f.isOpen() ){ if( !f.open( QIODevice::ReadOnly ) ){ m_passed = false ; m_log( QString( "Error, Failed To Open File For Reading: %1" ).arg( m_fileName ) ) ; return ; } } this->getData( f.readAll() ) ; } void getData( const QByteArray& e ) { QJsonParseError error ; m_doc = QJsonDocument::fromJson( e,&error ) ; if( error.error == QJsonParseError::NoError ){ if( m_doc.isObject() ){ m_json = m_doc.object() ; }else{ m_passed = false ; this->logException( "Error Reason: Expected an object and got something else" ) ; } }else{ m_passed = false ; this->logException( "Error Reason: " + error.errorString() ) ; } } QString m_fileName ; bool m_passed = true ; std::function< void( const QString& ) > m_log = []( const QString& e ){ Q_UNUSED( e ) } ; const char * m_key ; QJsonObject m_json ; QJsonDocument m_doc ; }; #endif //JSON_H zuluCrypt-6.2.0/zuluCrypt-gui/keyfile-1.png000066400000000000000000000036141425361753700206600ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎébKGDÿÿÿ ½§“ pHYs¯¯^‘tIMEÚ ÷Ææë IDATXí—]h\ÇÇsï{W»+YÚ]}X’%Û)vâš’8µ yP ”Ò<…×ÐBí§búJk§¥PBÉCiñKÓCêÚPhÒ`h)¡-Ôýql7õ‡lË–¥H+íJ»{¿ïÜéÃ]m%[–T·.sïÌΞÿœùŸÿ™´­R©÷ÿ›‰5ïú±°¿¿²Z­¶6šxDÿ?¬õ÷M‡Ï­uj­yÏÔ––BdË!²B€ÖYŸad3Ò4kÛß©ÈS½tš°aqåÊú™››Ã–ÇqXY^&_(Ë僀J¥B£årò]ºr’]£9¼ FõîL „!=ÝÝHÛÞ„À‚‰‰‰NDÆÇÆ:¡†Ñ!cÆÃ”]†ÉØpžßŸ{Ô¨&N÷³”Ëe†0¥$]%ìv" $޳ ÕÞ?Ñfþjf¬šR Ë$_´ðš‹È‚C"ºpr†eÖë¹³tûe{¿ ÓDJÙé“Rv2Ų,,ËBë'ßE¡§ we)%‰Îxbš&†iþ'u·Š€‚‹~ˆ%%;wî¤^«‘jeY„aˆ”’ÞÞ^¤”ÌÌÌÐ××G,Þû+õ˜Ùk0þ³°$˜žÞEWW޳µÀNh­u†%€?;ý–>ø™Ãн}ƒúßü–¾zõšv]WÇq¬ƒ XUÂÏo×u¹yó&®ë244D³Ù¤Õj‘Ëå0 ß÷Éçó,..£££LMM‘&!½=Ù*‹Ise™¹¹YŠÅ½½½!6ŒÂ†B´ÿ~,ËZG²UulµZ …uDŸ~å+¼XýOê¡1Å݇9ÿ›IªŒíehçN=<< ødaaáÑJx§îéc^Ò7]íµš:I­”ÒI’h×uuÇ:ˆc=ñ¢þçoèé»wõ…¿þm3‘L§ï܉Û~©¿¿ßÜ’ãÁ£Ù×kÆ)I:£1†å©¥bDw7±ÖÔoÜ êûÙ‘7 ÑZgÄ Z­–n4¼ôòË_.‹¿«V«jË,@´Ïš«5ߟ…k?G'bþT? M­Û·8vŒê{ïáºnG’$! C|ß×Q‰¯?~¬V«½S«Õ’m¥a†¡-8i ùQÐ)´Á0ð£1î¾ùcºöì!cr{÷²|þ<´ÏQxžŽ¢H|õèÑã—/_>[¯×“GUÀ‡ODZ£E LC ÒˆpøKØ÷þ€.ì"72ÀîW_%p]Âf“î矧”¥Qáyž6LSœüΉï^ü裟zž§6+ÁEàvC±à§üñ^È‹1o^÷(”öBí*Tž%B”ç¡ãÒåûˆ¶`y­–6-Süòì[¯¿ýëw¿¿•ó #0V08ý\w¦Á©à¹AI£_@« ³×«Oš¦äóy-m[œxíÄ÷Μ9û:nç÷€HiâtµAîý ý©W@%뜫4%N†‡‡u³±,N~ûµ“gΜý Ø¦mÌ@ ‘«ã/¶§z¡”"IR¥ô'Ÿ{žxâëµÚÒOþçòÅâ?+n89UŠ(Šê£cc'ÇùEÅÉc_¥Ëår÷ÒÒÒS[\Ïõsp¿¯¯ï^½^Oy û7ÉK1¯õƒ IEND®B`‚zuluCrypt-6.2.0/zuluCrypt-gui/keyfile.png000066400000000000000000000262151425361753700205240ustar00rootroot00000000000000‰PNG  IHDR  Ûph IDATxœíݰÝu}ïû÷gí½W6;;!!á‡`áG±U‹ŽUàzlmO½ÇžéÅÞétÎt˜‰GÇ£ÇqÚ‡±ÁQˆHñÎ=wZÇŸ\‹b=È©£ØâÔRG!?™@PEHB~²Ù{}ï WcöN¾ßÏg­ïz£UU}âæ›o ŠÆÿu檪ªX¿~ý›6lØð½ªªþ¥ªª·=üŠÎÏ#äŠÒCfC€ÐWÖ¯_ÿ¦7þ(¥t{D¼²ô€Ñ©ªêëÖ­!@ß ô…-[¶œ½qãÆ/ÿ<<.,½`u"B„}O€PTUU±iÓ¦wNOO?PUÕï•Þ0àDÐ÷ÅlذañÆ¿\UÕ‡"b¼ô€–èDÄ'nºé¦?*=àPElذá”ҿ¦”<ëP¿NJé“"èG„ì6lØðš”Ò?GÄ¥·´X'"DÐwYmÚ´éwSJÿ?û©å4«Ÿ¼ñÆEÐ7Ùlܸñ5UU}>¥4Qz À餔DÐ7Yüü5wŠ€"DÐ7Û´iÓINçΈXXz À뤔>¹nݺÿ\z0ܪª*"âo#â´ÂSøÙOLÿôG>ò#@hÔæÍ›ß¾Õ.@ÿ褔DPŒ¡16lXkKïàWtRJŸ¾ñÆE¡1###ë"¢[z‡Ô‰d'@hÄ–-[Þ¯/½€#!@v„ÚUUÕ©ªÊ—^ †NUU"ÈF€P»Í›7¿%"V”ÞÀ¬=ÿݱÞRzÐ~„ZUU)¥÷–ÞÀœu"â³"hš¡V>øà%ñë¥wpTDÐ8B­z½ÞŸ”ÞÀ1éD„/Ç#@¨ÍC=4žRò€0øFC„  Ôæ¹çžû½ˆXXzµõÂt  „Ú¤”þCé Ôj´ªªOøÃ!@muº¬ôj7"¨¡[·n=9"V•Þ@#DPB-z½ÞËKo Q¾ ¨…¡½^oeé 4N„ÇL€P‹”Ò¹¥7…މ¡.g—@6£UU}úCúÐÿVz0xuñó?†ËhJé³"˜+B]Àð!Àœ ê"@†ÓhDˆ`Öp¬F#ÂkB€Y @º!B€Y @]ºñén¸A„‡%@€:‰àˆP7–š B€C @Sºñé믿þM¥‡ýC€Mꦔ>+B€ç  i"xrèFÄgo¸áCN€¹t«ª!0ä“!'@€ÜºUU}öúë¯cé!@~(¡[UÕm"†J!0„PR·ªªÛ®»î:CB€¥uSJ"†„ú!!@€~ÑM)Ývíµ×þÇÒC€æ ŸtSJŸ!Ð^è7"ZL€ý¨›Rúü?øA-#@€~Õ­ªJ„@Ë Ÿu{½ž @¿!Ð"Ý^¯÷ùk¯½ö÷JŽE7"n!0Ø0Hºqû_ÿõ_‹P4ÝN§#B`@ `uSJ"•$@€AÖM)Ý~íµ×þné!Àì`Ðu«ªúâ>ð@€mÐM)‰h @€m"B Ï  mDô1´Q7¥ôŵk׊è3h«nUU"úŒÚ¬ÛëõDô´>"@€aÐíõz·‹(O€Ãb¼×ëÝ~Í5׈(H€Ãd<¥tû>ð×—ÃJ€Ãf¼ªª/Š(C€ÃH„@!V"  À0!™†ÝxUU_|ÿûß/B 1ÞétDd @~f¼Óé|ñšk®!Ð ðÿ  ¿L„@ƒÀ¯¯ªêvõ ‡6!B ~àðDÔL€ÙDUU·¿ÿýïÿíÒC  À‹›H)}Q„À± ³#B `ö&"â‹kÖ¬!p”ÀÜL¤”D%0w"Ž’8:Ï¿&äß—ƒD€½‰ªª¾$B`öÀ±!0àØ‰˜%P‰ªª¾´fÍG @ê3"Ž@€Ôk""¾ôWõW—•ýH€Ôo"¥ôe¿J€4C„À!€æˆ8ˆhÖDJéËkÖ¬¹¬ôè y½^O„@€\D„Èi¢×ë}ù/ÿò//)=J yM¤”î! +Ÿah €2&"âÎ÷½ï}"„¡"@Ê™èt:"„¡"@Ê! Pžah€þ0‘R!´žè"„Ö ýåùoÑûÚÒC   ÿLTUu—¡@!´’è_UUÝõÞ÷¾W„Р¿Mt:;Em!@úߤ¡-À`!´‚“?ÿ‰é"„%@ËdUU"„%@a` €Á$BH`p‰Žl"„"@ßdUUw¾÷½ï}Mé!ðb@;LFÄ]"„~'@ÚC„Ð÷4`ff&Çcl/Ã5<"„¾&@ Ýnwa†ËìÎp ÓdDxM}I€@fffrÈ“®ÁàZè…éô#ÍX”á3\ƒÁ¶°ªª;ßóž÷ˆú†€TUÕø3 UUýkÓ× ¦”D}C€@3NÊp¯d¸í BèR:¯ék\}õÕ÷§”lú:´†¡/h@UUfºÎÍ9®CkˆŠ Ѐ”R–û±#ǵh…!B(F€@3^òw÷wM_äÊ+¯Ü×4}Zgaüì焼ºô†€†ìß¿ÿµ9®366öш¸/ǵh•…½^ï.Bnšó†¹òÊ+§SJoˆgr\VYØëõîz×»Þ%BÈF€@s~7×…®ºêªñ¿GD/×5i…NG„€æ¬ºõÖ[ÏÎu±«¯¾úŽ”ÒŸçº­²°ÓéÜõîw¿[„Ð8 ªªêM9¯÷¶·½íãUUý—ðLs·0"D Р”Ò©ª*ë5W¯^ý?ªªúˆx2ë…iBã4ëüüã—å¾èêÕ«¿ZUÕ+"âå¾6oaDÜõ®w½ëâÒCh'Í»ªÄEßþö·?²zõê߉ˆ?‰ˆŸ”ØÀÀZØétþQ„ÐÍ{Óºuë–•ºøêÕ«ÿ."^oˆ‡Kí`à,L)‰j'@ y£Ýn÷ÿ,9`õêÕS«W¯¾iÇŽ/Ÿý|’ÏDÄ®’› SJÿøîw¿[„P›Tzí°eË–mqÆÁ/´<Ü /÷«Çõó6ÇÕ{\?o›Ëqý¶gŽ›îõzüÅ_üÅæCÞ €[o½uôÀ¯éõz¯ˆWEÄ…qFDŒFôÕû®µÇõó¶ƒÞ¾;¥ô>øÁ~÷ÂŒ–ÃfÿþýñðÃÇž={bß¾}133‡ÿà°RÇõËŽ~?îXnßï÷­ŸÞW³9ndd$&&&bþüù±xñâH©ø¿¹v:µñŸJyÞ•W^9ÿôóÿ""âsŸû\çñÇ_6==½("ÆSJ‹žÿ½Ã½~ûôôô¬®Ÿë|Ïœ«Ã¯×›Ýw8>øö‡:ßÑÞ·Ãm;ÚóÍæ}Ô‡h ’¨…g@^ü¸­[·Æ7¿ùÍxøá‡gýàÔ£ÛíÆé§Ÿçž{nÌ›7ïÇäúøPUÕoýùŸÿù·f5 …µ ‡?nÿþýñ÷ÿ÷±eË–CžÈgdd$.¸à‚xéK_ú+¿—ëãCJiã¾}û~ãï|ç³³Ð"^„ zòÉ'ããÿ¸ø€>133?üáã¾ûî;æ/;ZUU­š˜˜X[äâ}@€@CöíÛŸúÔ§bçÎ¥§Ù¶m[<ðÀ%'ü×[o½õ²’J Ð;î¸#vìØQzp[¶l‰íÛ·—œð·7ÝtÓI%” @ [·nM›6•ž¼ˆûï¿¿ä—b166öùÏ}îsÝ"  Ѐ{î¹§ô`öíÛ>úhÉ —<õÔSÿOɹ ¨Ùó?ç …¿ +"âŠ[n¹å¿—‹šmÛ¶ÍÏù€òÓŸþ´ô„ˆˆµó7ó¶Ò#r P³Ý»w—žÌÁÔÔÔQÿ¤ì:UUµîæ›o~WéM P³½{÷–žÌÑJOˆˆˆ”ÒõûØÇ|9ÐjjæË¯€c´ö–[n¹qÍš5£¥‡4A€@Ÿ©ªjõÉ'Ÿ|×­·Þêç„­#@ ?ýû™™™ïÝrË-¿^z@ô¯—TUõí}ìcï\³fÇl |0€þ6^UÕ‡–,YòÍuëÖ­*=àX  ¯ît:ÿzóÍ7ÿ÷5kÖtK8ZÇxD¬=餓¶|ô£ýc_– "¸`ðœŸ8餓þuݺu¿[z À\øã0¸.J)ÝùÑ~ô‡)¥u£££ŸºòÊ+Ÿ)= àH<ƒï¢ªªþ¯©©©¯[·îºo¼qEéA‡ãhÅñîN§óîuëÖý ªªÏÏÌÌü¿ïxÇ;6–ð<íôëñë###×ÜtÓMSJ_­ªê›UU}ëíoû#¥ÇÃK€@û­ªªjUD¼-¥7Þxãö”Ò·ªªÚ[ªªÚÚëõ|Ç;Þ±=¥Tz+Ðr†Ï²ªªÞò‹oèt:qã7N}ä#y&"vEijUU=;ž?¦ªªCž¬×ëÍê¢ß>×ùf{þ¦Ï7›ûu¸k͹ær¾Ã9è:O\ýõoÕ áð¼îÏÿ[4—ü¬Él?¹Íu¾c½}]ç;Ô³KužëXÎ7ËÛùÒ=já»`٨ټyóJOæ¨Óñp‹¸P³ÉÉÉÒ€9H)ù‡€ŒÔ줓N*=˜ƒùóçöë騟švÚi1þüÒ3€YZºtié CE€@ÍRJqÁ”žÌBJ)Î8ãŒÒ3†Š\rÉ%ÑívKÏ^IJeËâøã/=`¨hÀääd\~ùå¥gG0oÞ¼¸ð KÏ:òªW½*^þò——žB§Ó‰ßüÍߌ‰‰‰ÒS†ŽýÁüA¼æ5¯)=øÝn7~ë·~+–,YRz ÀP-=Ú,¥¯ýëãÌ3ÏŒ»îº+vìØQz ­”R,_¾<.¸àÏ|$@ ƒ•+WÆŠ+býúõ±qãÆx衇â™gž)= Z¯ÓéÄÄÄD,[¶,N;í´X´hQTUUzÀP I§Ó‰ /¼0.¼ð¨ª*¦§§cïÞ½/|2tð'E‡û$i¶Ç½Øíæz¾£=n¶{†i_¿ÿ?›ë'èý²çàãFFFb||\pô…ŒŽŽÆ¢E‹^øu¿|Bî¸æëçms9®ßö €ÁàEè@6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À°™™™‰íÛ·ÇîÝ»ãÙgŸ}áíUUÍêöw´·›ëqM_g˜îGîCÎëíqN'æÍ›“““1þüY€æ ÈäñÇo}ë[±yóæ8pà@é90T,X§vZ¬\¹2:Oþ”$@ aSSSqçwÆ~ðƒ9ÿË2P={öĆ bëÖ­qÑEÅi§VzÀÐ Р={öÄ'?ùÉxüñÇKO"âÀñ½ï}/ž~úé8ÿüó#¥TzÀÐñ<44djj*>ñ‰OˆèC›7oŽÍ›7—ž0”4äK_úR<ñÄ¥g‡±aÆøéOZzÀÐ ЀG}4î¿ÿþÒ3€#¨ª*~ô£•ž0t4àßø†œÃxúé§cûöí¥g 5›ššŠ­[·–žÌ’ÈK€@Í~øá˜žž.=˜%¯ÕÈK€@ÍvïÞ]z0ˆ^¯WzÀÐ P³={ö”žÌÑJOj633Sz0G¾i@>ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² P³±±±Ò€9)=`h¨Ù‚ JOæ¨Ûí–ž04ÔlñâÅ¥'s011)¥Ò3††šqÆ1oÞ¼Ò3€Y:õÔSKO*jÖétâ‚ .(=˜¥åË——ž0T4à’K.‰ÑÑÑÒ3€±téÒ8ñÄKÏ*°hÑ¢xík_[zp£££qá…–ž0t4äÒK/U«V•žBJ)^ùÊWú®uhHJ)Þò–·ÄË^ö²ÒS€_022_|±Ÿâ‹Ô¡A£££ñæ7¿9N?ýôøú׿ûöí+= †Ú’%K⢋.Š… –ž0´dðŠW¼"~í×~-î»ï¾Ø´iSlÛ¶-ªª*= †B·ÛSO=5N;í´8å”SüÝ(L€@&Ýn7^ýêWÇ«_ýꘞžŽ½{÷ñ‘Ã}’tðÛg{Ül¯s¬×í÷£¾sõÓ}(yƒÝétb||ÜO9è3 ‰ã?>Ž?þøÞV÷'ŸŽëßãúyÛ\Žë·=Ç4äáEè@6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À0Ú¹sgìÙ³'öíÛUUò˜¹¾ýÅŽ;ÚÛ¹ný×mË}=ÖÛ»n\sX¯;66ccc1>>>«Ûõ ÉÓO?÷Þ{olذ!víÚUz1>>'œpB,]º4ÆÆÆJÏ¡ @ a½^/¾öµ¯Åw¾ó˜žž.=€_ðì³ÏÆc=ÿöoÿ§žzj,[¶,RJ¥gA« hÐþýûã¶Ûn‹­[·–žÀôz½xôÑGcÏž=±bÅŠõ)4ŋС!333ñ™Ï|F| Ý»wÇ–-[fýz`î4äÎ;ïŒmÛ¶•žÀíÙ³'yä‘Ò3 µ4à‰'žˆù—)=€£ôÄOÄþýûKÏ€V Ѐ»ï¾ÛÓ÷¬ªªØ¾}{éÐJj6==[¶l)=€c´k×®èõz¥g@ë¨ÙÃ?Ï=÷\é£^¯{÷î-=ZG€@Íž~úéÒ¨ÉJO€Ö P³={ö”ž@M¦¦¦JO€Ö P3?í =|C¨Ÿ² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€lÔltt´ôj’R*=ZG€@Í,XPz5év»¥'@ë¨Ù¢E‹JO &óæÍ+=ZG€@ÍÎ<óLÿbÐN'&''KÏ€Ö P³ÑÑÑX¹reé£N8!:Ÿ*AÝü­‚\z饴XJ)–-[Vz´’Ï K–,‰W½êU¥gp”N9å”/=ZI€@C~û·;Î:ë¬Ò3˜£… Æé§Ÿ^z´–†ŒŒŒÄýÑÅŠ+JO`–-ZçœsŽŸÿ  РyóæÅ[ßúÖ¸ì²Ë|g,€>ÖétbùòåqÎ9çÄÈÈHé9Ðj~d34,¥—^zi¼â¯ˆ{ï½76lØO=õTéYDÄqÇ'œpB,]º4FG}Z9ø›™LNNÆå—_—_~yìÞ½;ž~ú騷o_ÌÌÌòøªªæôö;îhoçºõ_·-÷õXoïºýqÍa¼nÄϾeúøøxŒÕí£'@ € Ä‚ ~ém³} uÜà×ÏÛær\¿íÄãúyÛ0äá5 @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À0šššŠ={öľ}ûbff&""ªªú¥cþõáÏ7ÛÛ;ßìÏ=¨š|_Íåºm8ß þùî÷óÊØØXŒÅÈÈȬoÔC€@&Ï>ûlÜwß}±~ýúؾ}ûœ(hÆääd,^¼8N>ùäèt|aä @ aUUŽ÷ÞßøÆ7bÿþý¥çð öîÝ{÷îíÛ·ÇòåËãä“OŽ”RéYÐj4==·ß~{<ðÀ¥§pÓÓÓ±mÛ¶Ø»woœuÖYž  hHUUqÛm·Å¦M›JO`–žz꩘™™‰sÎ9§ôh-y ¹ûî»ÅÀÚµkWlß¾½ô h- عsgÜsÏ=¥gp”{ì±8pà@éÐJp÷Ýw¿ðíu<½^ϳ Ð5›žžŽ7–žÀ1Ú¹s§o™  P³ÿøÇž¶h™™™Ø»woéÐ:j¶sçÎÒ¨‰P‚ú ¨Ùž={JO &SSS¥'@ë¨ÙsÏ=Wz5éõz¥'@ë d#@€l² @6ÈF€Ù d#@€l² @6ÈF€@ÍFGGKO &ŽO• nþVAÍ&''KO &þQ ê'@ fÇ|é ÔdÞ¼y¥'@ë¨Ù™gžé_ÌZ ÓéÄ‚ JÏ€Ö P³n·+V¬(=€ctüñÇ{ 4Àß*hÀ%—\)¥Ò38Ë–-+=ZI€@–-[/{ÙËJÏà(-Y²$&&&JÏ€V Ðßÿýß÷¯ghþüùqæ™g–ž­%@ Ä.n\ HIDAT!cccqÅWÄòåËKO`–&''cåÊ•^û ò· 499ú§_|±3€>–RŠSN9%V­Zccc¥ç@«ù^¡Ð°ÑÑÑxÃÞ¯|å+ãÛßþvlÚ´)žyæ™Ò³ˆŸ}Œ>á„âÔSOñññÒs`(ÈdÉ’%ñÆ7¾1ªªŠíÛ·ÇÞ½{cïÞ½/ü~UU³:ÏÁÇííæz\Óצûцûó:myËŸAºG:®ŸîÇØØXt»Ý˜˜˜xá»ÎõÏ>ptd–R:ä‹Ógû@ê¸Á?®Ÿ·Íå¸~Û3ˆÇõó¶a<ÈÃ¥Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€ÙŒ–ÃêÀñÌ3ϼð몪~é÷þõ\{±Û5uÝ£Ý3LûúýÿÙl÷õÛž~ê¸6þù”}ccc1222«=@½d233?úÑbãÆñÐCÅÔÔTéICmdd$.\‹/ŽO<±ô2xàâ«_ýjìÚµ«ô~nff&vîÜ;wüä'qúé§ÇâÅ‹KÏ‚Ö Р^¯_ùÊWâ»ßýné)ÁâÁŒ¥K—Æé§Ÿ)¥Ò“ µ4è _øBüð‡?,=€YzüñÇczz:Î>ûìÒS µ|,hÈ·¿ýmñ0€ž|òÉxì±ÇJÏ€Ö ЀݻwÇ×¾öµÒ38J>úh<÷Üs¥g@+ hÀ?ÿó?{à`½^/¶oß^z´’šUU÷ßé£;vÌùçâ/N€@Íy䑨¿é£éé騷o_éÐ:j¶cǎҨɳÏ>[z´ŽšíÞ½»ôj255Uz´Žšyñ9@{ôz½Ò u² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@ fŽ¿Vm‘R*=ZÇgJP³ÉÉÉ񬃯ØXé Ð:j¶páÂÒ¨I·Û-=ZG€@Í^ò’—ø2,€H)Å‚ JÏ€ÖñYÔl||<Î>ûìÒ38F .Œ‘‘‘Ò3 u4àu¯{]é £SO=µôh% 8óÌ3cÕªU¥gp”/^ì˯ !òæ7¿9N<ñÄÒ3˜£ñññ8묳JÏ€Ö ÐyóæÅÿñ‹€rÜqÇŹçžëµÐ  :á„âÏþìÏâüóÏ/=€±xñâ8ÿüócÞ¼y¥§@«–m7>>ø‡<òHÜsÏ=ñÐCÅôôtéYDD§Ó‰… ÆòåËcþüù¥çÀP ÉgœW\qELMMŶmÛb÷îݱgÏžb¤ªªY§Ôqý²£ß;–Û÷û}ë§÷U[Žó÷¯ÌŸ©”Rt»Ý˜7o^LNN¾ðåVÇz`vdÖívcÅŠ¿òöƒø÷@è¸Á?®Ÿ·Íå¸~Û3ˆÇõó¶a<ÈÃk@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l`6z¥Ð„ºì.=hÔÞÒhB]´›Çzj!@¨‹JÐb)¥]¥7Єºl-=hN¯×óXO-µH)m(½hŽÇzê"@¨Ëƒ¥ÍI)m.½v Ô¢ÓéÜWzМ^¯÷ÃÒhB-Î>ûì'"b}é@#î¿á†ž(=‚v ÔéîÒ€FÜ]zí!@¨MJéKoêç1ž: j322ò•ðó@ mvíß¿ÿ+¥GЄڜuÖYϦ”>WzP«Ï­[·nªôÚC€P·O”Ô§×ë}²ôÚE€P«+VüSDü ô ÷}èCú§Ò#hB­RJ‘Rú@é@-<¦S;BíV¬Xñ÷~Z* ¶ªª6Ο?ÿ ¥wÐ>„Ú¥”z½^ï=¥wG¯Óé¼gÍš5½Ò;hB#Î=÷Ü/TUå[öÀ`úŸ×]wÝ¥GÐN„ÆŒŽŽ^¾m –g;ÎÛK ½yéK_ú`UU¾ HUUÿíÚk¯}°ôÚK€Ð¨sÏ=÷#UUýCéÀ‹«ªêŽë¯¿þ£¥wÐn„F¥”¢ªª?‰ˆŸ”ÞÑ####Rzí'@hÜyç·£×ë½!"v•ÞÒ“###¿síµ×z¬¦q„,Î;ï¼ûSJ¿SUÕ3¥·¿ä™^¯÷ûk×®ÝXzÃA€ÍÊ•+¿ÿI„@ßx&"Þ|à 7|·ô†‡!«U«V}eddäòˆØQz ¹Nçß]wÝuÿ«ô†‹!»sÎ9ç;333¯‹ˆ‡Ko€!õp§ÓyÝÚµk=óAv„".¸à‚õóæÍûˆøBé-0d¾pàÀßX»víúÒCN£¥0¼Î:ë¬]UU½yÓ¦Mÿ5"ÖFÄxéMÐbÏTUõß®»îº•Âpó E¥”bÕªUI)~`!4㎑‘‘óÄýÀ3 ô…U«V=°aÆÿˆˆ‹Ê.€VøAJé}k×®ýŸ¥‡Àó}å¼óÎû‡ªªþaÓ¦Moìõz‹Ko€ASUÕw:Î5ƒ~$@è;)¥ˆˆ;"âŽõë׿<"þ”ÒUU\vô¯”Òã½^ï3Nço×®]ûƒÒ{àpRé0_ÿú×G—.]úÚªª.¯ªê²ˆxuüB@WUõKÇüëA8®Ÿ·9®ÞãúyÛ\Žë·=ƒx\?osÜ@ü˜ŠˆïFÄ×:Î×7mÚôO·Ýv[ï'€>"@H?þñÇŸ~úé•)¥•)¥U½^ïô”Ò¢^¯7Ïÿ÷+Žõ­ƒõz¿üqþX¬Žt«îáÎ?×ó ÓýhÃ}(yA|µá>ê:îÇìÎ?Ësí}þ¿^¯·+"¶¥”6OOOožššÚüáøÙY]ø¹ÿ‘iEtÄ\oIEND®B`‚zuluCrypt-6.2.0/zuluCrypt-gui/keystrength.cpp000066400000000000000000000013661425361753700214410ustar00rootroot00000000000000/* * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ zuluCrypt-6.2.0/zuluCrypt-gui/keystrength.h000066400000000000000000000026241425361753700211040ustar00rootroot00000000000000/* * * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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 */ #ifndef KEYSTRENGTH_H #define KEYSTRENGTH_H #include #include "can_build_pwquality.h" #if BUILD_PWQUALITY class keystrength { public: keystrength() : m_handle( pwquality_default_settings() ) { } ~keystrength() { pwquality_free_settings( m_handle ) ; } int quality( const QString& e ) { return pwquality_check( m_handle,e.toLatin1().constData(), nullptr,nullptr,nullptr ) ; } bool canCheckQuality() { return true ; } private: pwquality_settings_t * m_handle ; }; #else class keystrength { public: keystrength() { } ~keystrength() { } int quality( const QString& e ) { Q_UNUSED( e ) ; return -1 ; } bool canCheckQuality() { return false ; } private: }; #endif #endif // KEYSTRENGTH_H zuluCrypt-6.2.0/zuluCrypt-gui/luksaddkey.cpp000066400000000000000000000540141425361753700212300ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "ui_luksaddkey.h" #include "luksaddkey.h" #include "../zuluCrypt-cli/constants.h" #include "zulucrypt.h" #include "utility.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "openvolume.h" #include "task.hpp" #include "dialogmsg.h" #include "plugin.h" #include "utility.h" luksaddkey::luksaddkey( QWidget * parent ) : QDialog( parent ) { m_ui = new Ui::luksaddkey() ; m_ui->setupUi( this ) ; m_label.setOptions( m_ui->label_5,m_ui->pushButton ) ; m_isWindowClosable = true ; m_ui->textEditPathToVolume->setText( QString() ) ; m_ui->textEditExistingPassphrase->setEchoMode( QLineEdit::Password ) ; m_ui->textEditPassphraseToAdd->setEchoMode( QLineEdit::Password ) ; this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; m_ui->lineEditPIM->setEnabled( false ) ; m_ui->label_4->setEnabled( false ) ; m_ui->groupBoxLUKS2Options->setVisible( false ) ; m_ui->labelAdvanceLuks2Options->setVisible( false ) ; connect( m_ui->pbLuks2Set,&QPushButton::clicked,[ this ](){ m_ui->groupBoxLUKS2Options->setVisible( false ) ; m_ui->labelAdvanceLuks2Options->setVisible( false ) ; } ) ; connect( m_ui->pushButtonLuks2AdvancedOptions,&QPushButton::clicked,[ this ](){ m_showingLuks2AdvanceOptions = true ; m_ui->groupBoxLUKS2Options->setVisible( true ) ; m_ui->labelAdvanceLuks2Options->setVisible( true ) ; } ) ; connect( m_ui->pbLuks2Cancel,&QPushButton::clicked,[ this ](){ this->luks2Cancel() ; } ) ; auto m = static_cast< void ( QComboBox::* )( int ) >( &QComboBox::currentIndexChanged ) ; connect( m_ui->cbLuks2Pbkdf,m,[ this ]( int s ){ if( s == 2 ){ m_ui->lineEditLuks2MaxMemory->clear() ; m_ui->lineEditLuks2ParallelThreads->clear() ; m_ui->lineEditLuks2MaxMemory->setEnabled( false ) ; m_ui->lineEditLuks2ParallelThreads->setEnabled( false ) ; }else{ m_ui->lineEditLuks2MaxMemory->setEnabled( true ) ; m_ui->lineEditLuks2ParallelThreads->setEnabled( true ) ; } } ) ; connect( m_ui->cbVolumeType,SIGNAL( activated( int ) ),this,SLOT( cbVolumeType( int ) ) ) ; connect( m_ui->pushButtonOpenFile,SIGNAL( clicked() ),this,SLOT( pbOpenFile() ) ) ; connect( m_ui->pushButtonOpenExistingKeyFile,SIGNAL( clicked() ),this,SLOT( pbOpenExisitingKeyFile() ) ) ; connect( m_ui->pushButtonOpenNewKeyFile,SIGNAL( clicked() ),this,SLOT( pbOpenNewKeyFile() ) ) ; connect( m_ui->pushButtonOpenPartition,SIGNAL( clicked() ),this,SLOT( pbOpenPartition( void ) ) ) ; connect( m_ui->pushButtonAdd,SIGNAL( clicked() ),this,SLOT( pbAdd() ) ) ; connect( m_ui->pushButtonCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; if( m_ui->cbNewKey->currentIndex() == 0 && m_keystrength.canCheckQuality() ){ connect( m_ui->textEditPassphraseToAdd,SIGNAL( textChanged( QString ) ),this,SLOT( keyChanged_0( QString ) ) ) ; }else{ connect( m_ui->textEditPassphraseToAdd,SIGNAL( textChanged( QString ) ),this,SLOT( keyChanged_1( QString ) ) ) ; } connect( m_ui->cbExistingKey,SIGNAL( activated( int ) ),this,SLOT( cbExistingKey( int ) ) ) ; connect( m_ui->cbNewKey,SIGNAL( activated( int ) ),this,SLOT( cbNewKey( int ) ) ) ; m_ui->lineEditReEnterPassphrase->setEchoMode( QLineEdit::Password ) ; m_ui->pushButtonOpenExistingKeyFile->setEnabled( false ) ; m_ui->pushButtonOpenNewKeyFile->setEnabled( false ) ; m_ui->pushButtonOpenPartition->setIcon( QIcon( ":/partition.png" ) ) ; m_ui->pushButtonOpenFile->setIcon( QIcon( ":/file.png" ) ) ; this->cbExistingKey( 0 ) ; this->cbNewKey( 0 ) ; this->cbVolumeType( 0 ) ; m_veraCryptWarning.setWarningLabel( m_ui->label_5 ) ; this->installEventFilter( this ) ; } bool luksaddkey::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void luksaddkey::keyChanged_1( QString key ) { Q_UNUSED( key ) this->setWindowTitle( tr( "Add A Key To A Volume" ) ) ; } void luksaddkey::keyChanged_0( QString key ) { auto st = m_keystrength.quality( key ) ; if( st < 0 ){ this->setWindowTitle( tr( "Passphrase Quality: 0%" ) ) ; }else{ this->setWindowTitle( tr( "Passphrase Quality: %1%" ).arg( QString::number( st ) ) ) ; } } void luksaddkey::closeEvent( QCloseEvent * e ) { e->ignore() ; if( m_isWindowClosable ){ this->HideUI() ; } } void luksaddkey::ShowUI( const QString& path ) { m_ui->textEditPathToVolume->setText( path ) ; this->ShowUI() ; } void luksaddkey::ShowUI( const QString& path,const QString& slot,std::function< void() > onExit ) { m_ui->textEditPathToVolume->setText( path ) ; m_ui->lineEditPIM->setText( slot ) ; m_onExit = std::move( onExit ) ; this->ShowUI() ; } void luksaddkey::ShowUI() { this->setFieldFocus() ; this->show() ; } void luksaddkey::setFieldFocus() { if( m_ui->textEditPathToVolume->text().isEmpty() ){ m_ui->textEditPathToVolume->setFocus() ; }else if( m_ui->textEditExistingPassphrase->text().isEmpty() ){ m_ui->textEditExistingPassphrase->setFocus() ; }else if( m_ui->textEditPassphraseToAdd->text().isEmpty() ){ m_ui->textEditPassphraseToAdd->setFocus() ; }else if( m_ui->cbNewKey->currentIndex() == 0 ){ if( m_ui->lineEditReEnterPassphrase->text().isEmpty() ){ m_ui->lineEditReEnterPassphrase->setFocus() ; }else{ m_ui->pushButtonAdd->setFocus() ; } }else{ m_ui->pushButtonAdd->setFocus() ; } } void luksaddkey::HideUI() { this->hide() ; m_onExit() ; this->deleteLater() ; } void luksaddkey::cbVolumeType( int e ) { if( e == 0 ){ /* * LUKS volume */ m_ui->lineEditPIM->setEnabled( false ) ; m_ui->label_4->setEnabled( false ) ; m_ui->lineEditPIM->setEnabled( false ) ; m_ui->lineEditPIM->setEchoMode( QLineEdit::Normal ) ; m_ui->pushButtonLuks2AdvancedOptions->setEnabled( true ) ; }else if( e == 1 ){ /* * TrueCrypt */ m_ui->lineEditPIM->setEnabled( false ) ; m_ui->label_4->setEnabled( false ) ; m_ui->lineEditPIM->setEnabled( false ) ; m_ui->pushButtonLuks2AdvancedOptions->setEnabled( false ) ; }else{ /* * VeraCrypt */ m_ui->lineEditPIM->setEnabled( true ) ; m_ui->label_4->setEnabled( true ) ; m_ui->lineEditPIM->setEnabled( true ) ; m_ui->lineEditPIM->setEchoMode( QLineEdit::Password ) ; m_ui->label_4->setText( tr( "PIM" ) ) ; m_ui->pushButtonLuks2AdvancedOptions->setEnabled( false ) ; } } void luksaddkey::cbExistingKey( int e ) { m_yubikeyExistingKey = false ; auto _key_ui = [ this ](){ m_ui->textEditExistingPassphrase->setToolTip( tr( "Enter A Key" ) ) ; m_ui->textEditExistingPassphrase->setEchoMode( QLineEdit::Password ) ; m_ui->pushButtonOpenExistingKeyFile->setEnabled( false ) ; m_ui->labelExistingPassphrase->setText( tr( "Password" ) ) ; m_ui->textEditExistingPassphrase->clear() ; m_ui->pushButtonOpenExistingKeyFile->setIcon( QIcon( ":/passphrase.png" ) ) ; m_ui->textEditExistingPassphrase->setFocus() ; m_ui->textEditExistingPassphrase->setEnabled( true ) ; } ; if( e == 0 ){ _key_ui() ; }else if( e == 1 ){ m_ui->textEditExistingPassphrase->setToolTip( tr( "Enter a path to a keyfile location" ) ) ; m_ui->textEditExistingPassphrase->setEchoMode( QLineEdit::Normal ) ; m_ui->pushButtonOpenExistingKeyFile->setEnabled( true ) ; m_ui->labelExistingPassphrase->setText( tr( "KeyFile Path" ) ) ; m_ui->textEditExistingPassphrase->clear() ; m_ui->pushButtonOpenExistingKeyFile->setIcon( QIcon( ":/keyfile.png" ) ) ; m_ui->textEditExistingPassphrase->setFocus() ; m_ui->textEditExistingPassphrase->setEnabled( true ) ; }else if( e == 2 ){ _key_ui() ; m_ui->textEditExistingPassphrase->setEnabled( false ) ; plugin::instance( this,plugins::plugin::hmac_key,[ this ]( const QString& key ){ m_ui->textEditExistingPassphrase->setText( key ) ; if( key.isEmpty() ){ m_ui->cbExistingKey->setCurrentIndex( 0 ) ; this->cbExistingKey( 0 ) ; } } ) ; }else{ _key_ui() ; m_yubikeyExistingKey = true ; } } void luksaddkey::cbNewKey( int e ) { m_yubekeyNewKey = false ; auto _key_ui = [ this ](){ m_ui->textEditPassphraseToAdd->setToolTip( tr( "Enter a key" ) ) ; m_ui->textEditPassphraseToAdd->setEchoMode( QLineEdit::Password ) ; m_ui->pushButtonOpenNewKeyFile->setEnabled( false ) ; m_ui->labelNewPassphrase->setText( tr( "Password" ) ) ; m_ui->textEditPassphraseToAdd->clear() ; m_ui->lineEditReEnterPassphrase->clear() ; m_ui->lineEditReEnterPassphrase->setEnabled( true ) ; m_ui->labelReEnterPassphrase->setEnabled( true ) ; m_ui->pushButtonOpenNewKeyFile->setIcon( QIcon( ":/passphrase.png" ) ) ; m_ui->textEditPassphraseToAdd->setFocus() ; m_ui->textEditPassphraseToAdd->setEnabled( true ) ; } ; if( e == 0 ){ _key_ui() ; }else if( e == 1 ){ m_ui->textEditPassphraseToAdd->clear() ; m_ui->lineEditReEnterPassphrase->clear() ; m_ui->textEditPassphraseToAdd->setToolTip( tr( "Enter a path to a keyfile location" ) ) ; m_ui->textEditPassphraseToAdd->setEchoMode( QLineEdit::Normal ) ; m_ui->pushButtonOpenNewKeyFile->setEnabled( true ) ; m_ui->labelNewPassphrase->setText( tr( "KeyFile path" ) ) ; m_ui->lineEditReEnterPassphrase->setEnabled( false ) ; m_ui->labelReEnterPassphrase->setEnabled( false ) ; m_ui->pushButtonOpenNewKeyFile->setIcon( QIcon( ":/keyfile.png" ) ) ; m_ui->textEditPassphraseToAdd->setFocus() ; m_ui->textEditPassphraseToAdd->setEnabled( true ) ; }else if( e == 2 ){ _key_ui() ; m_ui->textEditPassphraseToAdd->setEnabled( false ) ; m_ui->lineEditReEnterPassphrase->setEnabled( false ) ; plugin::instance( this,plugins::plugin::hmac_key,[ this ]( const QString& key ){ m_ui->textEditPassphraseToAdd->setText( key ) ; m_ui->lineEditReEnterPassphrase->setText( key ) ; if( key.isEmpty() ){ m_ui->cbNewKey->setCurrentIndex( 0 ) ; this->cbNewKey( 0 ) ; }else{ if( m_keystrength.canCheckQuality() ){ this->setWindowTitle( tr( "Passphrase Quality: 100%" ) ) ; } } } ) ; }else{ m_yubekeyNewKey = true ; m_ui->lineEditReEnterPassphrase->setEnabled( false ) ; m_ui->lineEditReEnterPassphrase->clear() ; m_ui->textEditPassphraseToAdd->clear() ; m_ui->textEditPassphraseToAdd->setEchoMode( QLineEdit::Password ) ; } } void luksaddkey::pbOpenExisitingKeyFile( void ) { auto Z = QFileDialog::getOpenFileName( this,tr( "Existing KeyFile" ),utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->textEditExistingPassphrase->setText( Z ) ; } this->setFieldFocus() ; } void luksaddkey::pbOpenNewKeyFile( void ) { auto Z = QFileDialog::getOpenFileName( this,tr( "New KeyFile" ),utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->textEditPassphraseToAdd->setText( Z ) ; } this->setFieldFocus() ; } void luksaddkey::pbOpenFile( void ) { auto Z = QFileDialog::getOpenFileName( this,tr( "Encrypted Volume Path" ),utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->textEditPathToVolume->setText( Z ) ; } this->setFieldFocus() ; } void luksaddkey::pbOpenPartition( void ) { openvolume::instance( this,false ).showLuksOnly().ShowAllPartitions( [ this ]( const QString& e ){ this->setFieldFocus() ; this->ShowUI( e ) ; } ) ; } void luksaddkey::pbAdd( void ) { DialogMsg msg( this ) ; std::function< void() > sendNewKey = [](){} ; std::function< void() > sendExistingKey = [](){} ; this->disableAll() ; utility2::raii raii( [ this ](){ this->enableAll() ; } ) ; auto ExistingKey = m_ui->textEditExistingPassphrase->text() ; auto NewKey = m_ui->textEditPassphraseToAdd->text() ; auto NewKey_1 = m_ui->lineEditReEnterPassphrase->text() ; m_volumePath = m_ui->textEditPathToVolume->text() ; auto existingKeyIsKeyFile = m_ui->cbExistingKey->currentIndex() == 1 ; auto newKeyIsKeyFile = m_ui->cbNewKey->currentIndex() == 1 ; if( m_volumePath.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; } m_volumePath = utility::resolvePath( m_volumePath ) ; if( utility::requireSystemPermissions( m_volumePath ) ){ if( !utility::enablePolkit( utility::background_thread::False ) ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Failed to enable polkit support" ) ) ; } } if( existingKeyIsKeyFile ){ if( ExistingKey.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; } } if( newKeyIsKeyFile ){ if( NewKey.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; } }else{ if( !m_yubekeyNewKey ){ if( NewKey != NewKey_1 ){ msg.ShowUIOK( tr( "ERROR!" ),tr( "Keys do not match" ) ) ; m_ui->textEditPassphraseToAdd->clear() ; m_ui->lineEditReEnterPassphrase->clear() ; m_ui->textEditPassphraseToAdd->setFocus() ; return ; } } } QString existingPassType ; if( existingKeyIsKeyFile ){ ExistingKey = utility::resolvePath( ExistingKey ).replace( "\"","\"\"\"" ) ; existingPassType = "-u" ; }else{ auto k = m_ui->textEditExistingPassphrase->text() ; if( m_yubikeyExistingKey ){ auto m = utility::yubiKey( k ) ; if( m.has_value() ){ k = m.value() ; }else{ this->cbExistingKey( 0 ) ; return m_label.show( tr( "Failed To Locate Or Run Yubikey's \"ykchalresp\" Program." ) ) ; } } existingPassType = "-u" ; ExistingKey = utility::keyPath() + "-existingKey" ; sendExistingKey = [ = ](){ utility::keySend( ExistingKey,k ) ; } ; } QString newPassType ; if( newKeyIsKeyFile ){ NewKey = utility::resolvePath( NewKey ).replace( "\"","\"\"\"" ) ; newPassType = "-n" ; }else{ auto k = m_ui->textEditPassphraseToAdd->text() ; if( m_yubekeyNewKey ){ auto m = utility::yubiKey( k ) ; if( m.has_value() ){ k = m.value() ; }else{ this->cbNewKey( 0 ) ; return m_label.show( tr( "Failed To Locate Or Run Yubikey's \"ykchalresp\" Program." ) ) ; } } newPassType = "-n" ; NewKey = utility::keyPath() + "-newKey" ; sendNewKey = [ = ](){ utility::keySend( NewKey,k ) ; } ; } const QString& a = QString( ZULUCRYPTzuluCrypt ) ; QString b = m_volumePath ; b.replace( "\"","\"\"\"" ) ; const QString& c = existingPassType ; const QString& d = ExistingKey ; const QString& e = newPassType ; const QString& f = NewKey ; auto r = "%1 -a -d \"%2\" %3 \"%4\" %5 \"%6\"" ; auto exe = utility::appendUserUID( r ).arg( a,b,c,d,e,f ) ; if( m_ui->cbVolumeType->currentIndex() == 2 ){ exe += " -t vcrypt" ; auto e = m_ui->lineEditPIM->text() ; if( !e.isEmpty() ){ exe += "." + e ; } }else if( m_ui->cbVolumeType->currentIndex() == 0 ){ auto forcedIterations = m_ui->lineEditLuks2ForcedIteration->text() ; auto unlockingTime = m_ui->lineEditLuks2UnlockingTime->text() ; auto maxThreads = m_ui->lineEditLuks2ParallelThreads->text() ; auto maxMemory = m_ui->lineEditLuks2MaxMemory->text() ; auto keyslot = m_ui->lineEditLuks2KeySlot->text() ; auto pbkdf = m_ui->cbLuks2Pbkdf->currentText() ; if( unlockingTime.isEmpty() ){ unlockingTime = "-1" ; } if( forcedIterations.isEmpty() ){ forcedIterations = "-1" ; } if( maxThreads.isEmpty() ){ maxThreads = "-1" ; } if( maxMemory.isEmpty() ){ maxMemory = "-1" ; } if( keyslot.isEmpty() ){ keyslot = "-1" ; } QString opts = "%1.%2.%3.%4.%5.%6" ; exe += " -g " + opts.arg( unlockingTime,forcedIterations,pbkdf,maxMemory,maxThreads,keyslot) ; } m_isWindowClosable = false ; m_veraCryptWarning.show( m_ui->cbVolumeType->currentIndex() == 2 ) ; raii.cancel() ; sendNewKey() ; sendExistingKey() ; this->taskFinished( utility::Task::run( exe ).await() ) ; } void luksaddkey::keyAdded() { m_volumePath.replace( "\"","\"\"\"" ) ; auto l = utility::luksEmptySlots( m_volumePath ).await() ; QString success ; if( l.isEmpty() ){ m_label.show( tr( "Key added successfully." ) ) ; }else{ QString x = tr( "Key added successfully.\n%1 / %2 slots are now in use" ) ; m_label.show( x.arg( l.first() ).arg( l.at( 1 ) ) ) ; } this->HideUI() ; } void luksaddkey::taskFinished( const utility::Task& e ) { m_veraCryptWarning.stopTimer() ; m_isWindowClosable = true ; switch( e.exitCode() ){ case 0 : return this->keyAdded() ; case 1 : m_label.show( tr( "Presented key does not match any key in the volume" ) ) ; break ; case 2 : m_label.show( tr( "Could not open luks volume" ) ) ; break ; case 3 : m_label.show( tr( "Volume is not a luks volume" ) ) ; break ; case 4 : m_label.show( tr( "Insufficient privilege to add a key to a system device,\nonly root user or members of group \"zulucrypt\" can do that\n" ) ) ;break ; case 5 : m_label.show( tr( "Could not open volume in write mode" ) ) ; break ; case 6 : m_label.show( tr( "All key slots are occupied, can not add any more keys" ) ) ; break ; case 7 : m_label.show( tr( "Can not get passphrase in silent mode" ) ) ; break ; case 8 : m_label.show( tr( "Insufficient memory to hold passphrase" ) ) ; break ; case 9 : m_label.show( tr( "New passphrases do not match" ) ) ; break ; case 10 : m_label.show( tr( "One or more required argument(s) for this operation is missing" ) ) ; break ; case 11 : m_label.show( tr( "One or both keyfile(s) does not exist" ) ) ; break ; case 12 : m_label.show( tr( "Insufficient privilege to open key file for reading" ) ) ; break ; case 13 : m_label.show( tr( "Couldnt get enought memory to hold the key file" ) ) ; break ; case 14 : m_label.show( tr( "Could not get a key from a socket" ) ) ; break ; case 15 : m_label.show( tr( "Could not get elevated privilege,check binary permissions" ) ) ; break ; case 16 : m_label.show( tr( "Key slot already occupied" ) ) ; break ; case 17 : m_label.show( tr( "Failed to find empty key slot or key slot out of range" ) ) ; break ; case 110: m_label.show( tr( "Can not find a partition that match presented UUID" ) ) ; break ; case 113: m_label.show( tr( "Device is not a luks device" ) ) ; break ; default: m_label.show( tr( "Error Code: %1\n--\nStdOut: %2\n--\nStdError: %3").arg( QString::number( e.exitCode() ),QString( e.stdError() ),QString( e.stdOut() ) ) ) ; } m_veraCryptWarning.hide() ; this->enableAll() ; } void luksaddkey::disableAll() { m_ui->lineEditPIM->setEnabled( false ) ; m_ui->label_4->setEnabled( false ) ; m_ui->cbVolumeType->setEnabled( false ) ; m_ui->label_3->setEnabled( false ) ; m_ui->labelExistingPassphrase->setEnabled( false ) ; m_ui->labelLuksVolume->setEnabled( false ) ; m_ui->labelNewPassphrase->setEnabled( false ) ; m_ui->textEditExistingPassphrase->setEnabled( false ) ; m_ui->textEditPassphraseToAdd->setEnabled( false ) ; m_ui->textEditPathToVolume->setEnabled( false ) ; m_ui->lineEditReEnterPassphrase->setEnabled( false ) ; m_ui->labelNewPassphrase->setEnabled( false ) ; m_ui->lineEditReEnterPassphrase->setEnabled( false ) ; m_ui->pushButtonAdd->setEnabled( false ) ; m_ui->pushButtonCancel->setEnabled( false ) ; m_ui->pushButtonOpenExistingKeyFile->setEnabled( false ) ; m_ui->pushButtonOpenFile->setEnabled( false ) ; m_ui->pushButtonOpenNewKeyFile->setEnabled( false ) ; m_ui->pushButtonOpenPartition->setEnabled( false ) ; m_ui->labelReEnterPassphrase->setEnabled( false ) ; m_ui->label->setEnabled( false ) ; m_ui->label_2->setEnabled( false ) ; m_ui->cbNewKey->setEnabled( false ) ; m_ui->cbExistingKey->setEnabled( false ) ; m_ui->pushButtonLuks2AdvancedOptions->setEnabled( false ) ; } void luksaddkey::enableAll() { auto index = m_ui->cbVolumeType->currentIndex() ; m_ui->pushButtonLuks2AdvancedOptions->setEnabled( index == 0 ) ; m_ui->label_4->setEnabled( index == 2 ) ; m_ui->lineEditPIM->setEnabled( index == 2 ) ; m_ui->cbVolumeType->setEnabled( true ) ; m_ui->label_3->setEnabled( true ) ; m_ui->labelReEnterPassphrase->setEnabled( true ) ; m_ui->labelExistingPassphrase->setEnabled( true ) ; m_ui->labelLuksVolume->setEnabled( true ) ; m_ui->labelNewPassphrase->setEnabled( true ) ; m_ui->textEditExistingPassphrase->setEnabled( true ) ; m_ui->textEditPassphraseToAdd->setEnabled( true ) ; m_ui->textEditPathToVolume->setEnabled( true ) ; m_ui->labelNewPassphrase->setEnabled( true ) ; m_ui->pushButtonAdd->setEnabled( true ) ; m_ui->pushButtonCancel->setEnabled( true ) ; m_ui->pushButtonOpenExistingKeyFile->setEnabled( true ) ; m_ui->pushButtonOpenFile->setEnabled( true ) ; m_ui->pushButtonOpenNewKeyFile->setEnabled( true ) ; m_ui->pushButtonOpenPartition->setEnabled( true ) ; m_ui->lineEditPIM->setEnabled( true ) ; m_ui->cbNewKey->setEnabled( true ) ; m_ui->cbExistingKey->setEnabled( true ) ; index = m_ui->cbNewKey->currentIndex() ; if( index == 0 ){ m_ui->lineEditReEnterPassphrase->setEnabled( true ) ; }else if( index == 1 ){ m_ui->lineEditReEnterPassphrase->setEnabled( false ) ; }else if( index == 2 ){ m_ui->lineEditReEnterPassphrase->setEnabled( false ) ; m_ui->textEditPassphraseToAdd->setEnabled( false ) ; } m_ui->label->setEnabled( true ) ; m_ui->label_2->setEnabled( true ) ; } void luksaddkey::luks2Cancel() { m_showingLuks2AdvanceOptions = false ; m_ui->groupBoxLUKS2Options->setVisible( false ) ; m_ui->labelAdvanceLuks2Options->setVisible( false ) ; m_ui->lineEditLuks2ForcedIteration->clear() ; m_ui->lineEditLuks2UnlockingTime->clear() ; m_ui->lineEditLuks2ParallelThreads->clear() ; m_ui->lineEditLuks2MaxMemory->clear() ; m_ui->lineEditLuks2KeySlot->clear() ; m_ui->cbLuks2Pbkdf->setCurrentIndex( 0 ) ; } void luksaddkey::pbCancel( void ) { this->HideUI() ; } luksaddkey::~luksaddkey() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/luksaddkey.h000066400000000000000000000047241425361753700207000ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef luksaddkeySUI_H #define luksaddkeySUI_H #include #include #include #include "utility.h" #include "keystrength.h" namespace Ui { class luksaddkey ; } class QWidget ; class QCloseEvent ; class keystrength ; class luksaddkey : public QDialog { Q_OBJECT public: static luksaddkey& instance( QWidget * parent ) { return *( new luksaddkey( parent ) ) ; } explicit luksaddkey( QWidget * parent = 0 ) ; ~luksaddkey() ; signals : void clickedpbAdd( QString PathToVolume,bool keyfile,QString ExistingKey,bool newkeyfile,QString NewKey ) ; void pbOpenPartitionClicked( void ) ; public slots: void ShowUI( const QString& ) ; void ShowUI( const QString&,const QString&,std::function< void() > ) ; void ShowUI( void ) ; void HideUI( void ) ; private slots: void cbVolumeType( int ) ; void cbExistingKey( int ) ; void cbNewKey( int ) ; void keyChanged_0( QString ) ; void keyChanged_1( QString ) ; void pbOpenExisitingKeyFile( void ) ; void pbOpenNewKeyFile( void ) ; void pbOpenFile( void ) ; void pbOpenPartition( void ) ; void pbAdd( void ) ; void pbCancel( void ) ; void taskFinished( const utility::Task& ) ; void setFieldFocus( void ) ; private: void keyAdded( void ) ; void disableAll( void ) ; void enableAll( void ) ; void luks2Cancel() ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::luksaddkey * m_ui ; QString m_volumePath ; bool m_isWindowClosable ; bool m_yubikeyExistingKey ; bool m_yubekeyNewKey ; bool m_showingLuks2AdvanceOptions = false ; keystrength m_keystrength ; utility::veraCryptWarning m_veraCryptWarning ; utility::label m_label ; std::function< void() > m_onExit = [](){} ; }; #endif // luksaddkeySUI_H zuluCrypt-6.2.0/zuluCrypt-gui/luksaddkey.ui000066400000000000000000000421541425361753700210650ustar00rootroot00000000000000 luksaddkey Qt::ApplicationModal 0 0 602 342 true Add A Key To A Volume true 10 10 121 31 Volume Path Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 460 10 31 31 open file 490 10 31 31 open partition 190 310 111 31 &Add true true 300 310 111 31 &Cancel true false 140 10 321 31 50 40 501 31 Password Already In The Encrypted Volume Qt::AlignCenter 50 190 501 31 Password To Be Added To The Encrypted Volume Qt::AlignCenter true 140 280 321 31 10 280 121 31 Reenter Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 460 250 31 31 open keyfile true 140 250 321 31 10 250 121 31 Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 140 220 321 31 Password KeyFile Key+KeyFile YubiKey Challenge/Response 140 100 321 31 10 100 121 31 Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 460 100 31 31 open keyfile true 460 130 31 31 Advanced LUKS2 Options true 140 70 321 31 Password KeyFile Key+KeyFile YubiKey Challenge/Response 140 130 321 29 LUKS TrueCrypt VeraCrypt 10 130 121 31 Volume Type Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 140 160 321 29 QLineEdit::Password 10 150 121 51 PIM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 10 0 591 341 true TextLabel Qt::AlignCenter true 230 300 141 33 &OK 2 6 601 341 true 0 0 601 351 10 10 581 31 Advanced Luks2 Options Qt::AlignCenter true 290 300 141 33 Set 10 30 271 51 Key Slot Number To Add Key In Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 110 260 171 31 Pbkdf Type Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 290 260 121 31 argon2id argon2i pbkdf2 30 80 251 31 Max Memory (KB) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 30 120 251 31 Parallel Threads Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 290 120 121 31 290 80 121 31 290 40 121 31 10 210 271 51 Unlocking Time Cost(Milliseconds) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 290 220 121 31 10 150 271 71 Forced Iterations (Dangerous And Could Lead To Extremely Long Unlocking Time) Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 290 170 121 31 150 300 141 33 Cancel textEditPathToVolume pushButtonOpenFile pushButtonOpenPartition cbExistingKey textEditExistingPassphrase pushButtonOpenExistingKeyFile cbVolumeType lineEditPIM cbNewKey textEditPassphraseToAdd pushButtonOpenNewKeyFile lineEditReEnterPassphrase pushButtonAdd pushButtonCancel zuluCrypt-6.2.0/zuluCrypt-gui/luksdeletekey.cpp000066400000000000000000000261601425361753700217430ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "luksdeletekey.h" #include "zulucrypt.h" #include "../zuluCrypt-cli/constants.h" #include "utility.h" #include #include #include #include #include #include #include #include #include #include #include "openvolume.h" #include "ui_luksdeletekey.h" #include "task.hpp" #include "dialogmsg.h" #include "plugin.h" luksdeletekey::luksdeletekey( QWidget * parent ) : QDialog( parent ),m_ui( new Ui::luksdeletekey ) { m_isWindowClosable = true ; m_ui->setupUi( this ) ; m_label.setOptions( m_ui->label_2,m_ui->pushButton ) ; this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; m_ui->lineEditVolumePath->clear() ; connect( m_ui->pushButtonDelete,SIGNAL( clicked() ),this,SLOT( pbDelete() ) ) ; connect( m_ui->pushButtonCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->pushButtonOpenKeyFile,SIGNAL( clicked() ),this,SLOT( pbOpenKeyFile() ) ) ; connect( m_ui->pushButtonOpenVolume,SIGNAL( clicked() ),this,SLOT( pbOpenVolume() ) ) ; connect( m_ui->pushButtonOpenPartition,SIGNAL( clicked() ),this,SLOT( pbOpenPartition() ) ) ; connect( m_ui->cbKey,SIGNAL( activated( int ) ),this,SLOT( Key( int ) ) ) ; this->Key( 0 ) ; m_ui->cbKey->addItem( tr( "YubiKey Challenge/Response" ) ) ; auto m = tr( "zuluCrypt will have the same behavious as luksKillSlot if a key slot is given" ) ; auto n = tr( "zuluCrypt will have the same behavious as luksRemoveKey if a key slot is NOT given" ) ; m_ui->lineEditSlotNumber->setToolTip( m + "\n" + n ) ; this->installEventFilter( this ) ; } bool luksdeletekey::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void luksdeletekey::closeEvent( QCloseEvent * e ) { e->ignore() ; if( m_isWindowClosable ){ this->pbCancel() ; } } void luksdeletekey::Key( int e ) { auto _key_ui = [ this ](){ m_ui->lineEditPassphrase->setToolTip( tr( "Enter a key" ) ) ; m_ui->labelPassphrase->setText( tr( "Password" ) ) ; m_ui->lineEditPassphrase->setEchoMode( QLineEdit::Password ) ; m_ui->lineEditPassphrase->clear() ; m_ui->pushButtonOpenKeyFile->setEnabled( false ) ; m_ui->pushButtonOpenKeyFile->setIcon( QIcon( ":/passphrase.png" ) ) ; m_ui->lineEditPassphrase->setFocus() ; m_ui->lineEditPassphrase->setEnabled( true ) ; } ; if( e == 0 || e == 3 ){ _key_ui() ; }else if( e == 1 ){ m_ui->lineEditPassphrase->setToolTip( tr( "Enter a path to a keyfile location" ) ) ; m_ui->labelPassphrase->setText( tr( "KeyFile path" ) ) ; m_ui->lineEditPassphrase->setEchoMode( QLineEdit::Normal ) ; m_ui->lineEditPassphrase->clear() ; m_ui->pushButtonOpenKeyFile->setEnabled( true ) ; m_ui->pushButtonOpenKeyFile->setIcon( QIcon( ":/keyfile.png" ) ) ; m_ui->lineEditPassphrase->setEnabled( true ) ; }else{ _key_ui() ; m_ui->lineEditPassphrase->setEnabled( false ) ; plugin::instance( this,plugins::plugin::hmac_key,[ this ]( const QString& key ){ m_ui->lineEditPassphrase->setText( key ) ; if( key.isEmpty() ){ m_ui->cbKey->setCurrentIndex( 0 ) ; this->Key( 0 ) ; } } ) ; } } void luksdeletekey::pbOpenKeyFile() { auto Z = QFileDialog::getOpenFileName( this,tr( "Key File With A Passphrase To Delete" ),utility::homePath() ) ; m_ui->lineEditPassphrase->setText( Z ) ; if( m_ui->lineEditVolumePath->text().isEmpty() ){ m_ui->lineEditVolumePath->setFocus() ; }else{ m_ui->pushButtonDelete->setFocus() ; } } void luksdeletekey::ShowUI() { this->enableAll() ; m_ui->labelPassphrase->setText( tr( "Password" ) ) ; if( m_ui->lineEditVolumePath->text().isEmpty() ){ m_ui->lineEditVolumePath->setFocus() ; }else{ m_ui->lineEditPassphrase->setFocus() ; } m_ui->pushButtonOpenPartition->setIcon( QIcon( ":/partition.png" ) ) ; m_ui->pushButtonOpenVolume->setIcon( QIcon( ":/file.png" ) ) ; this->show() ; } void luksdeletekey::ShowUI( const QString& path ) { m_ui->lineEditVolumePath->setText( path ) ; this->ShowUI() ; } void luksdeletekey::ShowUI( const QString& path, const QString& slot, std::function< void() > onExit ) { m_ui->lineEditVolumePath->setText( path ) ; m_ui->lineEditSlotNumber->setText( slot ) ; m_onExit = std::move( onExit ) ; this->ShowUI() ; } void luksdeletekey::disableAll() { m_ui->label_3->setEnabled( false ) ; m_ui->lineEditSlotNumber->setEnabled( false ) ; m_ui->cbKey->setEnabled( false ) ; m_ui->label->setEnabled( false ) ; m_ui->labelPassphrase->setEnabled( false ) ; m_ui->lineEditPassphrase->setEnabled( false ) ; m_ui->lineEditVolumePath->setEnabled( false ) ; m_ui->pushButtonCancel->setEnabled( false ) ; m_ui->pushButtonDelete->setEnabled( false ) ; m_ui->pushButtonOpenKeyFile->setEnabled( false ) ; m_ui->pushButtonOpenPartition->setEnabled( false ) ; m_ui->pushButtonOpenVolume->setEnabled( false ) ; } void luksdeletekey::enableAll() { m_ui->label_3->setEnabled( true ) ; m_ui->lineEditSlotNumber->setEnabled( true ) ; m_ui->cbKey->setEnabled( true ) ; m_ui->label->setEnabled( true ) ; m_ui->labelPassphrase->setEnabled( true ) ; m_ui->lineEditPassphrase->setEnabled( true ) ; m_ui->lineEditVolumePath->setEnabled( true ) ; m_ui->pushButtonCancel->setEnabled( true ) ; m_ui->pushButtonDelete->setEnabled( true ) ; m_ui->pushButtonOpenPartition->setEnabled( true ) ; m_ui->pushButtonOpenVolume->setEnabled( true ) ; if( m_ui->cbKey->currentIndex() == 1 ){ m_ui->pushButtonOpenKeyFile->setEnabled( true ) ; } } void luksdeletekey::pbCancel() { this->HideUI() ; } void luksdeletekey::pbOpenPartition() { openvolume::instance( this,false ).showLuksOnly().ShowAllPartitions( [ this ]( const QString& e ){ this->ShowUI( e ) ; } ) ; } void luksdeletekey::pbDelete() { DialogMsg msg( this ) ; m_volumePath = utility::resolvePath( m_ui->lineEditVolumePath->text() ) ; this->disableAll() ; utility2::raii raii( [ this ](){ this->enableAll() ; } ) ; if( m_volumePath.isEmpty() ){ msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; }else{ if( utility::requireSystemPermissions( m_volumePath ) ){ if( !utility::enablePolkit( utility::background_thread::False ) ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Failed to enable polkit support" ) ) ; } } m_volumePath.replace( "\"","\"\"\"" ) ; raii.cancel() ; this->deleteKey( utility::luksEmptySlots( m_volumePath ).await() ) ; } } void luksdeletekey::deleteKey( const QStringList& l ) { if( l.isEmpty() ){ m_label.show( tr( "Volume is not a luks volume" ) ) ; return this->enableAll() ; }else if( l.first().toInt() == 1 ){ auto s = tr( "There is only one last key in the volume." ) ; s = s + tr( "\nDeleting it will make the volume unopenable and lost forever." ) ; s = s + tr( "\nAre you sure you want to delete this key?" ) ; if( DialogMsg( this ).ShowUIYesNoDefaultNo( tr( "WARNING" ),s ) == QMessageBox::No ){ return this->enableAll() ; } }else{ //auto s = tr( "Are you sure you want to delete a key from this volume?" ) ; //if( DialogMsg( this ).ShowUIYesNoDefaultNo( tr( "WARNING" ),s ) == QMessageBox::No ){ // return this->enableAll() ; //} } auto keyNumber = l.first().toInt() - 1 ; auto totalKeys = l.at( 1 ) ; QString keypath ; if( m_ui->cbKey->currentIndex() == 1 ){ keypath = utility::resolvePath( m_ui->lineEditPassphrase->text() ).replace( "\"","\"\"\"" ) ; }else{ keypath = utility::keyPath() ; auto key = m_ui->lineEditPassphrase->text() ; if( m_ui->cbKey->currentIndex() == 3 ){ auto m = utility::yubiKey( key ) ; if( m.has_value() ){ key = m.value() ; }else{ m_label.show( tr( "Failed To Locate Or Run Yubikey's \"ykchalresp\" Program." ) ) ; return this->enableAll() ; } } utility::keySend( keypath,key ) ; } auto r = "%1 -k -r -d \"%2\" -f \"%3\"" ; auto exe = utility::appendUserUID( r ).arg( ZULUCRYPTzuluCrypt,m_volumePath,keypath ) ; m_isWindowClosable = false ; auto slotNumber = m_ui->lineEditSlotNumber->text() ; if( !slotNumber.isEmpty() ){ exe += " -g " + slotNumber ; } auto e = utility::Task::run( exe ).await() ; m_isWindowClosable = true ; QString success ; switch( e.exitCode() ){ case 0 : success = tr( "Key removed successfully.\n%1 / %2 slots are now in use" ).arg( QString::number( keyNumber ) ).arg( totalKeys ) ; m_label.show( success ) ; return this->HideUI() ; case 2 : m_label.show( tr( "There is no key in the volume that match the presented key" ) ) ; break ; case 3 : m_label.show( tr( "Could not open the volume" ) ) ; break ; case 4 : m_label.show( tr( "Insufficient privilege to open a system device,\ only root user or members of group zulucrypt can do that" ) ) ; break ; case 5 : m_label.show( tr( "Could not open the volume in write mode" ) ) ; break ; case 6 : m_label.show( tr( "Insufficient memory to hold your response" ) ) ; break ; case 7 : m_label.show( tr( "Operation terminated per user request" ) ) ; break ; case 8 : m_label.show( tr( "Can not get passphrase in silent mode" ) ) ; break ; case 9 : m_label.show( tr( "Insufficient memory to hold passphrase" ) ) ; break ; case 10: m_label.show( tr( "One or more required argument(s) for this operation is missing" ) ) ; break ; case 11: m_label.show( tr( "Keyfile does not exist" ) ) ; break; case 12: m_label.show( tr( "Could not get enough memory to open the key file") ) ; break ; case 13: m_label.show( tr( "Insufficient privilege to open key file for reading" ) ) ; break ; case 14: m_label.show( tr( "Could not get a key from a socket" ) ) ; break ; case 110:m_label.show( tr( "Can not find a partition that match presented UUID" ) ) ; break ; default: m_label.show( tr( "Error Code: %1\n--\nStdOut: %2\n--\nStdError: %3").arg( QString::number( e.exitCode() ),QString( e.stdError() ),QString( e.stdOut() ) ) ) ; } this->enableAll() ; if( e.exitCode() == 2 ){ this->Key( 0 ) ; m_ui->cbKey->setCurrentIndex( 0 ) ; } } void luksdeletekey::pbOpenVolume() { auto Z = QFileDialog::getOpenFileName( this,tr( "Volume Path" ),utility::homePath() ) ; m_ui->lineEditVolumePath->setText( Z ) ; if( m_ui->lineEditPassphrase->text().isEmpty() ){ m_ui->lineEditPassphrase->setFocus() ; }else{ m_ui->pushButtonDelete->setFocus() ; } } void luksdeletekey::HideUI() { this->hide() ; m_onExit() ; this->deleteLater() ; } luksdeletekey::~luksdeletekey() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/luksdeletekey.h000066400000000000000000000040111425361753700213770ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef LUKSDELETEKEY_H #define LUKSDELETEKEY_H #include #include #include #include "utility.h" class QWidget ; namespace Ui { class luksdeletekey ; } class luksdeletekey : public QDialog { Q_OBJECT public: static luksdeletekey& instance( QWidget * parent ) { return *( new luksdeletekey( parent ) ) ; } explicit luksdeletekey( QWidget *parent = 0 ) ; ~luksdeletekey() ; signals: void pbDeleteClicked( QString volumePath,bool passPhraseIsFile,QString passPhrase ) ; void pbOpenPartitionClicked( void ) ; void HideUISignal( void ) ; public slots: void ShowUI( void ) ; void ShowUI( const QString& ) ; void ShowUI( const QString&,const QString&,std::function< void() > ) ; void HideUI( void ) ; private slots: void Key( int ) ; void pbOpenPartition( void ) ; void pbDelete( void ) ; void pbCancel( void ) ; void pbOpenKeyFile( void ) ; void pbOpenVolume( void ) ; void deleteKey( const QStringList& ) ; private: void disableAll( void ) ; void enableAll( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::luksdeletekey * m_ui ; QString m_volumePath ; utility::label m_label ; bool m_isWindowClosable ; std::function< void() > m_onExit = [](){} ; }; #endif // LUKSDELETEKEY_H zuluCrypt-6.2.0/zuluCrypt-gui/luksdeletekey.ui000066400000000000000000000143551425361753700216010ustar00rootroot00000000000000 luksdeletekey Qt::ApplicationModal 0 0 542 195 true Remove A Key From A Volume true 110 70 321 31 2 89 101 51 LUKS Slot Number Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 110 100 321 31 10 70 91 31 Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 430 70 31 31 open a keyfile true 180 160 91 31 &Delete true true 270 160 91 31 &Cancel true false 110 40 321 31 10 40 91 31 Volume Path Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 430 40 31 31 open an encrypted file true 460 40 31 31 open an encrypted partition true 110 130 321 31 Password KeyFile Key+KeyFIle 0 -10 541 201 true TextLabel Qt::AlignCenter true 220 160 101 33 &OK lineEditVolumePath pushButtonOpenVolume pushButtonOpenPartition lineEditPassphrase pushButtonOpenKeyFile cbKey pushButtonDelete pushButtonCancel zuluCrypt-6.2.0/zuluCrypt-gui/main.cpp000066400000000000000000000022071425361753700200110ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "zulucrypt.h" #include "utility.h" int main( int argc,char * argv[] ) { QSettings m( "zuluCrypt","zuluCrypt" ) ; utility::setSettingsObject( &m ) ; utility::setHDPI( "zuluCrypt" ) ; QApplication a( argc,argv ) ; return utility::startApplication( "zuluCrypt",[ & ](){ zuluCrypt e ; utility::startApplication( &e,"start" ) ; return a.exec() ; } ) ; } zuluCrypt-6.2.0/zuluCrypt-gui/managesystemvolumes.cpp000066400000000000000000000132531425361753700232000ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "managesystemvolumes.h" #include "ui_managesystemvolumes.h" #include #include #include #include #include #include #include #include #include #include #include #include "openvolume.h" #include "dialogmsg.h" #include "tablewidget.h" manageSystemVolumes::manageSystemVolumes( QWidget * parent,const char * s ) : QDialog( parent ),m_ui( new Ui::manageSystemVolumes ),m_path( s ) { m_ui->setupUi( this ) ; m_ui->tableWidget->setColumnWidth( 0,580 ) ; this->setFont( parent->font() ) ; this->setFixedSize( this->size() ) ; connect( m_ui->pbDone,SIGNAL( clicked() ),this,SLOT( pbDone() ) ) ; connect( m_ui->pbFile,SIGNAL( clicked() ),this,SLOT( pbFile() ) ) ; connect( m_ui->pbPartition,SIGNAL( clicked() ),this,SLOT( pbPartition() ) ) ; connect( m_ui->tableWidget,SIGNAL( currentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ),this, SLOT( currentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ) ) ; connect( m_ui->tableWidget,SIGNAL( itemClicked( QTableWidgetItem * ) ),this, SLOT( itemClicked( QTableWidgetItem * ) ) ) ; this->addAction( [ this ](){ auto ac = new QAction( this ) ; QList keys ; keys.append( Qt::Key_Enter ) ; keys.append( Qt::Key_Return ) ; keys.append( Qt::Key_Menu ) ; ac->setShortcuts( keys ) ; connect( ac,SIGNAL( triggered() ),this,SLOT( defaultButton() ) ) ; return ac ; }() ) ; this->installEventFilter( this ) ; this->readSystemPartitions() ; } bool manageSystemVolumes::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void manageSystemVolumes::defaultButton() { if( m_ui->pbDone->hasFocus() ){ this->pbDone() ; }else if( m_ui->pbFile->hasFocus() ){ this->pbFile() ; }else if( m_ui->pbPartition->hasFocus() ){ this->pbPartition() ; }else{ this->contextMenu() ; } } void manageSystemVolumes::currentItemChanged( QTableWidgetItem * current,QTableWidgetItem * previous ) { tablewidget::selectRow( current,previous ) ; } void manageSystemVolumes::readSystemPartitions() { auto e = utility::privilegedReadConfigFile( m_path ) ; m_read = e.first ; if( m_read ){ auto s = utility::split( e.second ) ; s.removeDuplicates() ; for( const auto& it : s ){ this->addItemsToTable( { it } ) ; } this->show() ; }else{ m_ui->pbFile->setEnabled( false ) ; m_ui->pbPartition->setEnabled( false ) ; m_ui->tableWidget->setEnabled( false ) ; } } void manageSystemVolumes::writeSystemPartitions() { if( m_read ){ auto table = m_ui->tableWidget ; int j = m_ui->tableWidget->rowCount() ; QByteArray s ; for( int i = 0 ; i < j ; i++ ){ s += table->item( i,0 )->text().toLatin1() + "\n" ; } utility::privilegedWriteConfigFile( s,m_path ) ; } } void manageSystemVolumes::itemClicked( QTableWidgetItem * current ) { this->itemClicked( current,true ) ; } void manageSystemVolumes::contextMenu() { this->itemClicked( m_ui->tableWidget->currentItem(),false ) ; } void manageSystemVolumes::itemClicked( QTableWidgetItem * current,bool clicked ) { if( current ){ tablewidget::selectRow( m_ui->tableWidget,current->row() ) ; QMenu m ; m.setFont( this->font() ) ; connect( m.addAction( tr( "Remove Selected Entry" ) ),SIGNAL( triggered() ),this,SLOT( removeCurrentRow() ) ) ; m.addSeparator() ; m.addAction( tr( "Cancel" ) ) ; if( clicked ){ m.exec( QCursor::pos() ) ; }else{ int x = m_ui->tableWidget->columnWidth( 0 ) / 2 ; int y = m_ui->tableWidget->rowHeight( current->row() ) * current->row() + 20 ; m.exec( m_ui->tableWidget->mapToGlobal( QPoint( x,y ) ) ) ; } } } void manageSystemVolumes::removeCurrentRow() { auto it = m_ui->tableWidget->currentItem() ; auto m = tr( "Are you sure you want to remove \n\"%1\"\n from the list?" ).arg( it->text() ) ; DialogMsg msg( this ) ; if( msg.ShowUIYesNoDefaultNo( tr( "WARNING"),m ) == QMessageBox::Yes ){ tablewidget::deleteRow( m_ui->tableWidget,it->row() ) ; } } void manageSystemVolumes::addItemsToTable( const QStringList& paths ) { if( !paths.isEmpty() ){ tablewidget::addRow( m_ui->tableWidget,paths ) ; } m_ui->tableWidget->setFocus() ; } void manageSystemVolumes::pbDone() { this->writeSystemPartitions() ; this->HideUI() ; } void manageSystemVolumes::pbFile() { auto e = QFileDialog::getOpenFileName( this,tr( "Select Path To System Volume" ),utility::homePath() ) ; this->addItemsToTable( { e } ) ; } void manageSystemVolumes::pbPartition() { openvolume::instance( this,true ).ShowAllPartitions( [ this ]( const QString& e ){ m_ui->tableWidget->setFocus() ; this->addItemsToTable( { e } ) ; } ) ; } void manageSystemVolumes::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbDone() ; } void manageSystemVolumes::HideUI() { this->hide() ; this->deleteLater() ; } manageSystemVolumes::~manageSystemVolumes() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/managesystemvolumes.h000066400000000000000000000037501425361753700226460ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef MANAGESYSTEMVOLUMES_H #define MANAGESYSTEMVOLUMES_H #include #include #include "utility.h" class QCloseEvent ; class QAction ; class QTableWidgetItem ; class QWidget ; namespace Ui { class manageSystemVolumes ; } class manageSystemVolumes : public QDialog { Q_OBJECT public: static void instance( QWidget * parent,const char * s ) { new manageSystemVolumes( parent,s ) ; } explicit manageSystemVolumes( QWidget * parent,const char * s ) ; ~manageSystemVolumes() ; void HideUI( void ) ; signals: void HideUISignal( void ) ; private slots: void defaultButton( void ) ; void pbDone( void ) ; void pbFile( void ) ; void pbPartition( void ) ; void currentItemChanged( QTableWidgetItem * current,QTableWidgetItem * previous ) ; void itemClicked( QTableWidgetItem * current,bool ) ; void itemClicked( QTableWidgetItem * current ) ; void removeCurrentRow( void ) ; void contextMenu( void ) ; private: void readSystemPartitions( void ) ; void writeSystemPartitions( void ) ; void addItemsToTable( const QStringList& ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::manageSystemVolumes * m_ui ; QString m_path ; bool m_read ; }; #endif // MANAGESYSTEMVOLUMES_H zuluCrypt-6.2.0/zuluCrypt-gui/managesystemvolumes.ui000066400000000000000000000053111425361753700230270ustar00rootroot00000000000000 manageSystemVolumes Qt::ApplicationModal 0 0 631 312 Manage System Volumes true 250 280 131 31 &Done false false 380 280 151 31 Add Fi&le false false 100 280 151 31 Add Dev&ice false false 10 10 611 271 QAbstractItemView::NoEditTriggers false false QAbstractItemView::NoSelection QAbstractItemView::SelectRows false Qt::NoPen Path To System Volumes zuluCrypt-6.2.0/zuluCrypt-gui/managevolumeheader.cpp000066400000000000000000000413011425361753700227140ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "managevolumeheader.h" #include "utility.h" #include "../zuluCrypt-cli/constants.h" #include #include #include #include #include #include #include #include "ui_managevolumeheader.h" #include "task.hpp" #include "utility.h" #include "openvolume.h" #include "dialogmsg.h" managevolumeheader::managevolumeheader( QWidget * parent ) : QDialog( parent ),m_ui( new Ui::managevolumeheader ) { m_ui->setupUi( this ) ; this->setFont( parent->font() ) ; this->setFixedSize( this->size() ) ; //m_ui->pbOpenFolder->setIcon( QIcon( QString( ":/folder.png" ) ) ) ; m_ui->pushButtonPartition->setIcon( QIcon( ":/partition.png" ) ) ; m_ui->pushButtonFile->setIcon( QIcon( ":/file.png" ) ) ; m_ui->lineEditDevicePath->setFocus() ; this->cbVolumeHeader( 0 ) ; connect( m_ui->cbVolumeType,SIGNAL( activated( int ) ),this,SLOT( cbVolumeType( int ) ) ); connect( m_ui->cbVolumeHeader,SIGNAL( activated( int ) ),this,SLOT( cbVolumeHeader( int ) ) ); connect( m_ui->pbCreate,SIGNAL( clicked() ),this,SLOT( pbCreate() ) ) ; connect( m_ui->pbOpenFolder,SIGNAL( clicked() ),this,SLOT( pbOpenLuksHeaderBackUp() ) ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->pushButtonFile,SIGNAL( clicked() ),this,SLOT( pbOpenFile() ) ) ; connect( m_ui->pushButtonPartition,SIGNAL( clicked() ),this,SLOT( pbOpenPartition() ) ) ; connect( m_ui->lineEditDevicePath,SIGNAL( textChanged( QString ) ),this,SLOT( backUpHeaderNameChange( QString ) ) ) ; connect( m_ui->cbKeySource,SIGNAL( activated( int ) ),this,SLOT( cbKeyType( int ) ) ) ; connect( m_ui->pBKeyFile,SIGNAL( clicked() ),this,SLOT( pbKeyFile() ) ) ; m_OperationInProgress = false ; m_veraCryptWarning.setWarningLabel( m_ui->labelVeraCryptWarning ) ; this->installEventFilter( this ) ; } bool managevolumeheader::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void managevolumeheader::cbKeyType( int e ) { if( e == 0 ){ m_ui->pBKeyFile->setEnabled( false ) ; m_ui->lineEditPassWord->setEchoMode( QLineEdit::Password ) ; }else{ m_ui->pBKeyFile->setEnabled( true ) ; m_ui->lineEditPassWord->setEchoMode( QLineEdit::Normal ) ; } m_ui->lineEditPassWord->clear() ; } void managevolumeheader::cbVolumeHeader( int e ) { bool enable = ( e != 0 ) ; m_ui->labelKeyType->setEnabled( enable ) ; m_ui->lineEditPassWord->clear() ; m_ui->pBKeyFile->setEnabled( enable ) ; m_ui->lineEditPassWord->setEnabled( enable ) ; m_ui->labelBackUpHeader->setEnabled( true ) ; m_ui->labelDevicePath->setEnabled( true ) ; m_ui->lineEditBackUpName->setEnabled( true ) ; m_ui->lineEditDevicePath->setEnabled( true ) ; m_ui->labelVolumeType->setEnabled( enable ) ; m_ui->cbVolumeType->setEnabled( enable ) ; m_ui->labelKeySource->setEnabled( enable ) ; m_ui->cbKeySource->setEnabled( enable ) ; auto index = m_ui->cbVolumeHeader->currentIndex() ; m_ui->labelPIM->setEnabled( index == 2 ) ; m_ui->lineEditPIM->setEnabled( index == 2 ) ; m_ui->cbKeySource->setEnabled( e != 0 ) ; m_ui->labelKeySource->setEnabled( e != 0 ) ; this->backUpHeaderNameChange( m_ui->lineEditDevicePath->text() ) ; } void managevolumeheader::cbVolumeType( int e ) { Q_UNUSED( e ) } void managevolumeheader::HideUI() { this->hide() ; this->deleteLater() ; } void managevolumeheader::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbCancel() ; } void managevolumeheader::ShowUI() { if( m_ui->lineEditDevicePath->text().isEmpty() ){ m_ui->lineEditDevicePath->setFocus() ; }else if( m_ui->lineEditBackUpName->text().isEmpty() ){ m_ui->lineEditBackUpName->setFocus() ; }else{ m_ui->pbCreate->setFocus() ; } this->show() ; } void managevolumeheader::restoreHeader() { m_operation = "restore" ; // m_ui->label->setText( tr( "Enter an existing key in the back up header file" ) ) ; this->setWindowTitle( tr( "Restore volume header" ) ) ; m_ui->labelBackUpHeader->setText( "Backup path" ) ; m_ui->pbCreate->setText( tr( "&Restore" ) ) ; this->ShowUI() ; } void managevolumeheader::headerBackUp() { m_operation = "backup" ; // m_ui->label->setText( tr( "Enter an existing key in the volume" ) ) ; this->setWindowTitle( tr( "Back up volume header" ) ) ; m_ui->labelBackUpHeader->setText( "Backup path" ) ; m_ui->pbCreate->setText( tr( "&Backup" ) ) ; this->ShowUI() ; } void managevolumeheader::backUpHeader() { this->headerBackUp() ; } void managevolumeheader::backUpHeader( QString device ) { m_ui->lineEditDevicePath->setText( device ) ; this->headerBackUp() ; } void managevolumeheader::backUpHeaderNameChange( QString name ) { if( m_operation == "restore" ){ return ; } if( !m_ui->lineEditDevicePath->text().isEmpty() ){ auto p = name.split( "/" ).last() ; if( p.isEmpty() ){ m_ui->lineEditBackUpName->clear() ; }else{ auto path = m_ui->lineEditBackUpName->text() ; if( path.isEmpty() ){ path = utility::homePath() + "/" ; } auto q = path.split( "/" ) ; path.clear() ; int j = q.size() - 1 ; for( int i = 0 ; i < j ; i++ ){ path += q.at( i ) + "/" ; } auto index = m_ui->cbVolumeHeader->currentIndex() ; if( index == 0 ){ path += p + ".luksVolumeHeaderBackUp" ; }else if( index == 1 ){ path += p + ".tcryptVolumeHeaderBackUp" ; }else{ path += p + ".vcryptVolumeHeaderBackUp" ; } m_ui->lineEditBackUpName->setText( path ) ; } } } void managevolumeheader::pbOpenLuksHeaderBackUp() { QString Z ; if( m_operation == "restore" ){ Z = QFileDialog::getOpenFileName( this,tr( "Select A File With A LUKS Backup Header" ),utility::homePath() ) ; if( Z.isEmpty() ){ return ; } }else{ Z = QFileDialog::getExistingDirectory( this,tr( "Select A Folder To Store The Header" ),utility::homePath(),QFileDialog::ShowDirsOnly ) ; if( Z.isEmpty() ){ return ; } while( true ){ if( Z.endsWith( '/' ) ){ Z.truncate( Z.length() - 1 ) ; }else{ break ; } } QString p = m_ui->lineEditDevicePath->text().split( "/" ).last() ; if( !p.isEmpty() ){ QString q = m_ui->lineEditBackUpName->text() ; if( q.isEmpty() ){ Z += "/" + p + ".volumeHeaderBackUp" ; }else{ q = q.split( "/" ).last() ; if( q.isEmpty() ){ Z += "/" + p + ".volumeHeaderBackUp" ; }else{ Z += "/" + q ; } } } } m_ui->lineEditBackUpName->setText( Z ) ; if( m_ui->lineEditDevicePath->text().isEmpty() ){ m_ui->lineEditDevicePath->setFocus() ; }else{ m_ui->pbCreate->setFocus() ; } } void managevolumeheader::pbCancel() { if( !m_OperationInProgress ){ this->HideUI() ; } } void managevolumeheader::enableAll() { m_ui->labelBackUpHeader->setEnabled( true ) ; m_ui->labelDevicePath->setEnabled( true ) ; m_ui->lineEditBackUpName->setEnabled( true ) ; m_ui->lineEditDevicePath->setEnabled( true ) ; m_ui->pbCancel->setEnabled( true ) ; m_ui->pbCreate->setEnabled( true ) ; m_ui->pbOpenFolder->setEnabled( true ) ; m_ui->pushButtonFile->setEnabled( true ) ; m_ui->pushButtonPartition->setEnabled( true ) ; m_ui->cbVolumeHeader->setEnabled( true ) ; auto index = m_ui->cbVolumeHeader->currentIndex() ; m_ui->labelPIM->setEnabled( index == 2 ) ; m_ui->lineEditPIM->setEnabled( index == 2 ) ; m_ui->labelKeyType->setEnabled( index != 0 ) ; m_ui->labelKeySource->setEnabled( index != 0 ) ; m_ui->cbKeySource->setEnabled( index != 0 ) ; m_ui->lineEditPassWord->setEnabled( index != 0 ) ; m_ui->labelVolumeType->setEnabled( index != 0 ) ; m_ui->cbVolumeType->setEnabled( index != 0 ) ; if( index != 0 ){ //m_ui->label->setEnabled( true ) ; if( m_ui->cbKeySource->currentIndex() == 1 ){ m_ui->pBKeyFile->setEnabled( true ) ; } } } void managevolumeheader::disableAll() { m_ui->labelKeyType->setEnabled( false ) ; m_ui->labelKeySource->setEnabled( false ) ; m_ui->cbKeySource->setEnabled( false ) ; m_ui->lineEditPassWord->setEnabled( false ) ; m_ui->labelVolumeType->setEnabled( false ) ; m_ui->cbVolumeType->setEnabled( false ) ; m_ui->labelBackUpHeader->setEnabled( false ) ; m_ui->labelDevicePath->setEnabled( false ) ; m_ui->lineEditBackUpName->setEnabled( false ) ; m_ui->lineEditDevicePath->setEnabled( false ) ; m_ui->pbCancel->setEnabled( false ) ; m_ui->pbCreate->setEnabled( false ) ; m_ui->pbOpenFolder->setEnabled( false ) ; m_ui->pushButtonFile->setEnabled( false ) ; m_ui->pushButtonPartition->setEnabled( false ) ; //m_ui->label->setEnabled( false ) ; m_ui->pBKeyFile->setEnabled( false ) ; m_ui->cbVolumeHeader->setEnabled( false ) ; m_ui->labelPIM->setEnabled( false ) ; m_ui->lineEditPIM->setEnabled( false ) ; } void managevolumeheader::pbCreate() { DialogMsg msg( this ) ; this->disableAll() ; utility2::raii raii( [ this ](){ this->enableAll() ; } ) ; if( m_ui->lineEditBackUpName->text().isEmpty() || m_ui->lineEditDevicePath->text().isEmpty() ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; } if( m_ui->lineEditPassWord->text().isEmpty() && m_ui->cbVolumeHeader->currentIndex() != 0 ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Atleast one required field is empty" ) ) ; } auto device = utility::resolvePath( m_ui->lineEditDevicePath->text() ) ; auto backUp = m_ui->lineEditBackUpName->text().replace( "\"","\"\"\"" ) ; QString exe ; if( utility::requireSystemPermissions( device ) ){ if( !utility::enablePolkit( utility::background_thread::False ) ){ return msg.ShowUIOK( tr( "ERROR!" ),tr( "Failed to enable polkit support" ) ) ; } } device.replace( "\"","\"\"\"" ) ; if( m_operation == "backup" ){ m_saveHeader = 1 ; if( m_ui->cbVolumeHeader->currentIndex() != 0 ){ if( m_ui->cbKeySource->currentIndex() == 0 ){ auto path = utility::keyPath() ; auto key = m_ui->lineEditPassWord->text() ; utility::keySend( path,key ) ; exe = QString( "%1 -B -d \"%2\" -z \"%3\" -f \"%4\"" ).arg( ZULUCRYPTzuluCrypt,device,backUp,path ) ; }else{ auto path = m_ui->lineEditPassWord->text() ; exe = QString( "%1 -B -d \"%2\" -z \"%3\" -f \"%4\"" ).arg( ZULUCRYPTzuluCrypt,device,backUp,path ) ; } if( m_ui->cbVolumeHeader->currentIndex() == 2 ){ auto e = m_ui->lineEditPIM->text() ; if( e.isEmpty() ){ exe += " -t vcrypt" ; }else{ exe += " -t vcrypt." + e ; } } }else{ exe = QString( "%1 -B -d \"%2\" -z \"%3\"" ).arg( ZULUCRYPTzuluCrypt,device,backUp ) ; } }else{ m_saveHeader = 0 ; auto x = m_ui->lineEditDevicePath->text() ; auto y = m_ui->lineEditBackUpName->text() ; auto warn = tr( "Are you sure you want to replace a header on device \"%1\" with a backup copy at \"%2\"?" ).arg( x ).arg( y ) ; if( msg.ShowUIYesNoDefaultNo( tr( "WARNING!" ),warn ) == QMessageBox::No ){ return ; } if( m_ui->cbVolumeHeader->currentIndex() != 0 ){ if( m_ui->cbKeySource->currentIndex() == 0 ){ auto path = utility::keyPath() ; auto key = m_ui->lineEditPassWord->text() ; utility::keySend( path,key ) ; exe = QString( "%1 -kR -d \"%2\" -z \"%3\" -f \"%4\"" ).arg( ZULUCRYPTzuluCrypt,device,backUp,path ) ; }else{ QString path = m_ui->lineEditPassWord->text() ; exe = QString( "%1 -kR -d \"%2\" -z \"%3\" -f \"%4\"" ).arg( ZULUCRYPTzuluCrypt,device,backUp,path ) ; } if( m_ui->cbVolumeHeader->currentIndex() == 2 ){ auto e = m_ui->lineEditPIM->text() ; if( e.isEmpty() ){ exe += " -t vcrypt" ; }else{ exe += " -t vcrypt." + e ; } } }else{ exe = QString( "%1 -kR -d \"%2\" -z \"%3\"" ).arg( ZULUCRYPTzuluCrypt,device,backUp ) ; } } /* * default to /dev/random as source of random data when managing a truecrypt header */ auto index = m_ui->cbVolumeType->currentIndex() ; if( index == 2 ){ exe += " -g /dev/urandom -e fde" ; }else if( index == 1 ){ exe += " -g /dev/urandom -e sys" ; } m_OperationInProgress = true ; m_veraCryptWarning.show( m_ui->cbVolumeHeader->currentIndex() == 2 ) ; raii.cancel() ; this->taskFinished( utility::exec( utility::appendUserUID( exe ) ).await() ) ; } void managevolumeheader::pbOpenPartition() { openvolume::instance( this,false ).ShowNonSystemPartitions( [ this ]( const QString& e ){ m_ui->lineEditDevicePath->setText( e ) ; if( m_ui->lineEditBackUpName->text().isEmpty() ){ m_ui->lineEditBackUpName->setFocus() ; }else{ m_ui->pbCreate->setFocus() ; } } ) ; } void managevolumeheader::pbOpenFile() { QString Z = QFileDialog::getOpenFileName( this,tr( "Select luks container you want to backup its header" ),utility::homePath() ) ; m_ui->lineEditDevicePath->setText( Z ) ; if( m_ui->lineEditBackUpName->text().isEmpty() ){ m_ui->lineEditBackUpName->setFocus() ; }else{ m_ui->pbCreate->setFocus() ; } } void managevolumeheader::pbKeyFile() { QString Z = QFileDialog::getOpenFileName( this,tr( "" ),utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->lineEditPassWord->setText( Z ) ; } } void managevolumeheader::success() { DialogMsg msg( this ) ; if( m_saveHeader ){ msg.ShowUIOK( tr( "SUCCESS" ),tr( "Header saved successfully.\nIf possible,store it securely." ) ) ; }else{ msg.ShowUIOK( tr( "SUCCESS" ),tr( "Header restored successfully" ) ) ; } return this->HideUI() ; } void managevolumeheader::taskFinished( int st ) { m_veraCryptWarning.stopTimer() ; m_OperationInProgress = false ; DialogMsg msg( this ) ; switch( st ){ case 0 : return this->success() ; case 1 : return this->success() ; case 2 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Presented device is not a LUKS device" ) ) ; break ; case 3 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Failed to perform requested operation" ) ) ; break ; case 4 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Failed to perform requested operation" ) ) ; break ; case 5 : msg.ShowUIOK( tr( "INFO!" ),tr( "Operation terminater per user request" ) ) ; break ; case 6 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Path to be used to create a back up file is occupied" ) ) ; break ; case 7 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Failed to perform requested operation" ) ) ; break ; case 8 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Insufficient privilege to open backup header file for reading" ) ) ; break ; case 9 : msg.ShowUIOK( tr( "ERROR!" ),tr( "Invalid path to back up header file" ) ) ; break ; case 10: msg.ShowUIOK( tr( "ERROR!" ),tr( "Insufficient privilege to create a backup header in a destination folder" )) ; break ; case 11: msg.ShowUIOK( tr( "ERROR!" ),tr( "Invalid path to device" ) ) ; break ; case 12: msg.ShowUIOK( tr( "ERROR!" ),tr( "Argument for path to a backup header file is missing" ) ) ; break ; case 13: msg.ShowUIOK( tr( "ERROR!" ),tr( "Argument for path to a backup header file is missing" ) ) ; break ; case 14: msg.ShowUIOK( tr( "ERROR!" ),tr( "Only root user and \"zulucrypt\" members can restore and back up luks headers on system devices" ) ) ; break ; case 15: msg.ShowUIOK( tr( "ERROR!" ),tr( "Insufficient privilege to open device for writing" ) ) ; break ; case 16: msg.ShowUIOK( tr( "ERROR!" ),tr( "Could not resolve path to device" ) ) ; break ; case 17: msg.ShowUIOK( tr( "ERROR!" ),tr( "Backup file does not appear to contain luks header" ) ) ; break ; case 18: msg.ShowUIOK( tr( "ERROR!" ),tr( "Insufficient privilege to open device for reading" ) ) ; break ; case 20:{ if( m_ui->cbVolumeHeader->currentIndex() != 0 ){ msg.ShowUIOK( tr( "ERROR!" ),tr( "Wrong password entered or volume is not a truecrypt volume" ) ) ; }else{ msg.ShowUIOK( tr( "ERROR!" ),tr( "Failed to perform requested operation on the LUKS volume" ) ) ; } } break ; case 21:{ if( m_ui->cbVolumeHeader->currentIndex() != 0 ){ msg.ShowUIOK( tr( "ERROR!" ),tr( "Wrong password entered or volume is not a veracrypt volume" ) ) ; }else{ msg.ShowUIOK( tr( "ERROR!" ),tr( "Failed to perform requested operation on the LUKS volume" ) ) ; } break ; } default: msg.ShowUIOK( tr( "ERROR!" ),tr( "Unrecognized ERROR! with status number %1 encountered" ).arg( st ) ) ; } m_veraCryptWarning.hide() ; this->enableAll() ; } managevolumeheader::~managevolumeheader() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/managevolumeheader.h000066400000000000000000000041601425361753700223630ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef managevolumeheader_H #define managevolumeheader_H #include #include #include "utility.h" class QWidget ; class QCloseEvent ; namespace Ui { class managevolumeheader; } class managevolumeheader : public QDialog { Q_OBJECT public: static managevolumeheader& instance ( QWidget * parent ) { return *( new managevolumeheader( parent ) ) ; } explicit managevolumeheader( QWidget * parent = 0 ) ; ~managevolumeheader() ; signals: void HideUISignal( void ) ; public slots: void ShowUI( void ) ; void HideUI( void ) ; void backUpHeader( void ) ; void backUpHeader( QString ) ; void restoreHeader( void ) ; private slots: void pbCancel( void ) ; void pbCreate( void ) ; void pbOpenLuksHeaderBackUp( void ) ; void taskFinished( int ) ; void pbOpenPartition( void ) ; void pbOpenFile( void ) ; void pbKeyFile( void ) ; void backUpHeaderNameChange( QString ) ; void cbKeyType( int ) ; void cbVolumeType( int ) ; void cbVolumeHeader( int ) ; private: void headerBackUp( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; void disableAll( void ) ; void enableAll( void ) ; void success( void ) ; Ui::managevolumeheader * m_ui ; QString m_path ; bool m_OperationInProgress ; QString m_operation ; int m_saveHeader ; utility::veraCryptWarning m_veraCryptWarning ; }; #endif // CREATEKEYFILE_H zuluCrypt-6.2.0/zuluCrypt-gui/managevolumeheader.ui000066400000000000000000000207001425361753700225470ustar00rootroot00000000000000 managevolumeheader Qt::ApplicationModal 0 0 561 306 Backup Volume Header 120 40 321 31 10 40 101 31 Backup Name Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 440 40 31 31 170 270 111 31 C&reate true true 280 270 111 31 &Cancel true false 10 10 101 31 Volume Path Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 120 10 321 31 440 10 31 31 470 10 31 31 120 150 321 31 Normal Volume Window System Volume Whole Drive Encrypted Volume 10 150 101 31 Volume Type Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 120 110 321 29 QLineEdit::Password 120 80 321 31 Manage A LUKS Header Manage A TrueCrypt Header Manage A VeraCrypt Header 40 110 71 31 PIM Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 120 230 321 31 QLineEdit::Password 440 230 31 31 120 190 321 31 Password KeyFile 10 190 101 31 Password Source Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 10 220 101 51 Outer Volume Password ONLY Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 10 0 541 301 true TextLabel Qt::AlignCenter true lineEditDevicePath pushButtonFile pushButtonPartition lineEditBackUpName pbOpenFolder cbVolumeHeader lineEditPIM cbVolumeType cbKeySource lineEditPassWord pBKeyFile pbCreate pbCancel zuluCrypt-6.2.0/zuluCrypt-gui/module.png000066400000000000000000000024421425361753700203550ustar00rootroot00000000000000‰PNG  IHDRójœ sRGB®Îé pHYs „ „ªâcytIMEÚ ®böc÷PLTE ooopst·¹»¯´·±¶¸¼¾¾´¹»¾Âͼ¾»¿ÂÂÆÈ†„„‰ˆˆŒkf‘j“l––——o›v›w!œw! †¥}¥§°¦¥¥©ƒ ª‹¯Ž¯“°—±±±²”²•³³³´“´—´µµ´µ¶µ·Ã¶·Ã¶¹Ä¶¹Å¶¹Æ···¸š¸› º¸¹ºÀÀ¼¦T¼¼Å¾©b¾ÃÅ¿¿À¿ÀÁÁÆÉÂÂÁÂÅÎÃÂÂÄÅÅÄÉÌÆÆÆÆÚ¾ÈÈÈÉÌÎÊÓÝËÌÌͶiͶjÍ·iηjθjÏÓÕѽ:ÒµÒÇXÓÝÛÕäÃÖ××Öäñ×¹×ÅbظظØÛÜÙµ0Ù½ÙÅ;Ûàçݽ(ÝÞÞÝàéÝæâÞ¹1ÞÊ6Þäçß¹1ߺ0ß»1ßÄ@ßáâßâàßäçßåèàâòàâóàäóàêãáãäáåôáåöâÝxâæ÷âçöâç÷âèêâëõâìõãÕMãå÷ãèéãòæäË]äåæäçøäíßåêìåêøåîùæëûè܇èíîèïáéêìéíïêÜPêíóêîðêñøêñÿëºëÕ@ëÖ?ëÖ@ëÛOëÜPëñÿëøÝìÒbìÖ@ìÝOìÝPìïñíÒbíÒcíÖ@í×Bíéíé€íðñíóùíùâîé€îðñîóùïðñïññïñöïòóïôùïõúðÆ ðõúðöúòæòôõòôöóæóç‘óôõóõöóö÷óøýóþÿôæ‘ôç‘ôõúôö÷ôöøõÇõöúõ÷øõûê÷Í÷ùù÷ùú÷ÿÿøÈøÊøÊ øËøÍùÊýÜþËÿÒÿÔÿÙÿÚÿß ÿáÿâÿå&ÿé0ÿê'ÿî ÿî(ÿï)ÿï,ÿô7ÿõ*ÿ÷;ÿÿÿ0&\)tRNS !$(,.16. */ #include "openvolume.h" #include #include #include "ui_openvolume.h" #include "task.hpp" #include #include #include #include #include #include #include #include #include #include "../zuluCrypt-cli/constants.h" #include "dialogmsg.h" #include "tablewidget.h" #include #include #define ALL_PARTITIONS 1 #define NON_SYSTEM_PARTITIONS 3 openvolume::openvolume( QWidget * parent,bool e ) : QDialog( parent ),m_ui( new Ui::openvolume() ),m_enableUUID( e ) { m_ui->setupUi( this ) ; m_ui->pbUUID->setEnabled( m_enableUUID ) ; this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; connect( m_ui->tableWidget,SIGNAL( itemDoubleClicked( QTableWidgetItem * ) ), this,SLOT( tableEntryDoubleClicked( QTableWidgetItem * ) ) ) ; connect( m_ui->tableWidget,SIGNAL( currentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ), this,SLOT( currentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ) ) ; connect( m_ui->pbHelp,SIGNAL( clicked() ),this,SLOT( pbHelp() ) ) ; connect( m_ui->pbUUID,SIGNAL( clicked() ),this,SLOT( pbUUID() ) ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->pbOpen,SIGNAL( clicked() ),this,SLOT( pbOpen() ) ) ; this->addAction( [ this ](){ auto ac = new QAction( this ) ; ac->setShortcuts( { Qt::Key_Enter,Qt::Key_Return } ) ; connect( ac,SIGNAL( triggered() ),this,SLOT( EnterKeyPressed() ) ) ; return ac ; }() ) ; auto tw = m_ui->tableWidget ; tw->setColumnWidth( 0,183 ) ; tw->setColumnWidth( 1,90 ) ; //tw->setColumnWidth( 2,110 ) ; tw->hideColumn( 2 ) ; tw->setColumnWidth( 3,90 ) ; tw->setColumnWidth( 4,309 ) ; for( int i = 0 ; i < 5 ; i++ ){ tw->horizontalHeaderItem( i )->setFont( this->font() ) ; } tw->horizontalHeader()->setVisible( true ) ; m_ui->checkBoxUUID->setVisible( false ) ; m_ui->pbHelp->setVisible( false ) ; this->installEventFilter( this ) ; this->disableAll() ; } bool openvolume::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } openvolume& openvolume::showEncryptedOnly() { m_showEncryptedOnly = true ; return *this ; } openvolume& openvolume::showLuksOnly() { m_showLuksOnly = true ; return *this ; } void openvolume::pbHelp() { DialogMsg msg( this ) ; QString m ; if( m_option == openvolume::allVolumes ){ m = tr( "A list of all partitions on this system are displayed here.\nDouble click an entry to use it" ) ; }else{ if( !utility::userIsRoot() ){ m = tr( "Restart the tool from root's account or after you have created and added yourself to group \"zulucrypt\" if the volume you want to use is not on the list." ) ; }else{ m = tr( "You are a root user and all partitions are displayed.\nDouble click an entry to use it" ) ; } } msg.ShowUIOK( tr( "INFO" ),m ) ; } void openvolume::pbUUID() { if( m_ui->pbUUID->isFlat() ){ m_ui->pbUUID->setFlat( false ) ; }else{ m_ui->pbUUID->setFlat( true ) ; } } void openvolume::pbCancel() { this->HideUI() ; } void openvolume::EnterKeyPressed() { auto tw = m_ui->tableWidget ; auto it = tw->currentItem() ; if( it ){ this->tableEntryDoubleClicked( tw->item( it->row(),0 ) ) ; } } void openvolume::currentItemChanged( QTableWidgetItem * current, QTableWidgetItem * previous ) { tablewidget::selectRow( current,previous ) ; } void openvolume::ShowNonSystemPartitions( std::function< void( const QString& ) > f ) { m_function = std::move( f ) ; this->partitionList( tr( "Select A Partition To Create An Encrypted Volume In" )," -N" ) ; } void openvolume::partitionList( const QString& p, const QString& q,std::function< void( const QString& )> f ) { m_function = std::move( f ) ; this->partitionList( p,q ) ; } openvolume& openvolume::setOnExit( std::function< void() > m ) { m_onExit = std::move( m ) ; return *this ; } void openvolume::ShowAllPartitions( std::function< void( const QString& ) > f ) { m_function = std::move( f ) ; this->partitionList( tr( "Select An Encrypted Partition To Open" )," -A" ) ; } void openvolume::allowLUKSOnly() { m_disableNonLUKS = true ; } void openvolume::partitionList( const QString& title,const QString& volumeType ) { this->setWindowTitle( title ) ; tablewidget::clearTable( m_ui->tableWidget ) ; m_ui->tableWidget->setEnabled( false ) ; this->show() ; if( volumeType == " -N" ){ m_option = openvolume::nonSystemVolumes ; }else if( volumeType == " -A" ){ m_option = openvolume::allVolumes ; }else if( volumeType == " -S" ){ m_option = openvolume::systemVolumes ; } QStringList r ; QStringList l ; Task::await( [ & ](){ l = utility::Task( QString( "%1 -AZ" ).arg( ZULUCRYPTzuluCrypt ) ).splitOutput( '\n' ) ; r = utility::Task( QString( "%1 -S" ).arg( ZULUCRYPTzuluCrypt ) ).splitOutput( '\n' ) ; } ) ; for( const auto& it : l ){ QFont nonSystem = this->font() ; QFont system = this->font() ; system.setItalic( !system.italic() ) ; system.setBold( !system.bold() ) ; std::reference_wrapper font = system ; auto z = utility::split( it,'\t' ) ; if( z.size() >= 4 ){ const auto& fs = z.at( 3 ) ; if( !fs.contains( "member" ) ){ if( r.contains( z.first() ) ){ font = system ; }else{ font = nonSystem ; } const QString& size = z.at( 1 ) ; if( size == "1.0 KB" || size == "1,0 KB" || size == "Nil" ){ continue ; } if( m_showLuksOnly ){ if( fs.startsWith( "crypto_LUKS" ) ){ tablewidget::addRow( m_ui->tableWidget,z,font ) ; } }else if( m_showEncryptedOnly ){ //if( fs.startsWith( "crypto" ) || fs.contains( "Nil" ) ){ tablewidget::addRow( m_ui->tableWidget,z,font ) ; //} }else{ tablewidget::addRow( m_ui->tableWidget,z,font ) ; } } } } m_ui->pbOpen->setEnabled( m_ui->tableWidget->rowCount() > 0 ) ; m_ui->tableWidget->setFocus() ; this->enableAll() ; } void openvolume::enableAll() { m_ui->tableWidget->setEnabled( true ) ; m_ui->pbCancel->setEnabled( true ) ; m_ui->pbOpen->setEnabled( true ) ; m_ui->pbUUID->setEnabled( m_enableUUID ) ; m_ui->pbHelp->setEnabled( true ) ; } void openvolume::disableAll() { m_ui->tableWidget->setEnabled( false ) ; m_ui->pbCancel->setEnabled( false ) ; m_ui->pbOpen->setEnabled( false ) ; m_ui->pbUUID->setEnabled( false ) ; m_ui->pbHelp->setEnabled( false ) ; } void openvolume::HideUI() { if( m_ui->pbCancel->isEnabled() ){ this->hide() ; m_onExit() ; this->deleteLater() ; } } void openvolume::pbOpen() { auto table = m_ui->tableWidget ; if( table->rowCount() > 0 ){ this->tableEntryDoubleClicked( table->currentItem() ) ; } } void openvolume::tableEntryDoubleClicked( QTableWidgetItem * item ) { auto tw = m_ui->tableWidget ; if( m_disableNonLUKS ){ if( !tw->item( item->row(),3 )->text().startsWith( "crypto_LUKS" ) ){ DialogMsg m( this ) ; return m.ShowUIOK( tr( "ERROR" ),tr( "Only crypto_LUKS volumes can be selected" ) ) ; }else{ m_ui->pbUUID->setFlat( true ) ; } } if( m_option == openvolume::nonSystemVolumes ) { if( !( utility::userIsRoot() || utility::userBelongsToGroup( "zulucrypt" ) ) ){ if( item->font().italic() != this->font().italic() ){ //auto e = tr( "Insufficient privileges to operate on a system volume.\nRestart zuluCrypt from root's account to proceed" ) ; //return DialogMsg( this ).ShowUIOK( tr( "ERROR" ),e ) ; } } } if( m_ui->pbUUID->isFlat() ){ m_function( "UUID=\"" + tw->item( item->row(),4 )->text() + "\"" ) ; }else{ m_function( tw->item( item->row(),0 )->text() ) ; } this->HideUI() ; } void openvolume::closeEvent( QCloseEvent * e ) { e->ignore() ; this->HideUI() ; } openvolume::~openvolume() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/openvolume.h000066400000000000000000000046531425361753700207320ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef OPEN_PARTITION_H #define OPEN_PARTITION_H #include #include #include #include "utility.h" class QWidget ; class QCloseEvent ; class QAction ; class QTableWidgetItem ; namespace Ui { class openvolume ; } class openvolume : public QDialog { Q_OBJECT public: static openvolume& instance( QWidget * parent,bool e ) { return *( new openvolume( parent,e ) ) ; } openvolume( QWidget * parent,bool ) ; virtual ~openvolume() ; openvolume& showEncryptedOnly( void ) ; openvolume& showLuksOnly( void ) ; openvolume& setOnExit( std::function< void() > ) ; void ShowAllPartitions( std::function< void( const QString& ) > ) ; void ShowNonSystemPartitions( std::function< void( const QString& ) > ) ; void partitionList( const QString&,const QString&,std::function< void( const QString& ) > ) ; public slots: void tableEntryDoubleClicked( QTableWidgetItem * ) ; void HideUI( void ) ; void allowLUKSOnly( void ) ; private slots: void pbOpen( void ) ; void pbHelp( void ) ; void pbUUID( void ) ; void pbCancel( void ) ; void EnterKeyPressed( void ) ; void currentItemChanged( QTableWidgetItem * current,QTableWidgetItem * previous ) ; private: void disableAll( void ) ; void enableAll( void ) ; void partitionList( const QString&,const QString& ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::openvolume * m_ui ; enum { nonSystemVolumes,systemVolumes,allVolumes } m_option ; bool m_disableNonLUKS = false ; bool m_showEncryptedOnly = false ; bool m_showLuksOnly = false ; bool m_enableUUID ; std::function< void( const QString& ) > m_function ; std::function< void() > m_onExit = [](){} ; }; #endif zuluCrypt-6.2.0/zuluCrypt-gui/openvolume.ui000066400000000000000000000111011425361753700211020ustar00rootroot00000000000000 openvolume Qt::ApplicationModal 0 0 751 383 Select A Partition To Open true true 650 350 71 31 Use UUID 10 350 121 31 &Help false 310 350 131 31 Use &UUID false 440 350 131 31 &Cancel false false 10 10 731 341 10 30 711 301 QAbstractItemView::NoEditTriggers false false false QAbstractItemView::NoSelection QAbstractItemView::SelectRows false 5 false false partition AlignCenter size AlignCenter label AlignCenter type AlignCenter uuid AlignCenter 180 350 131 31 &Open tableWidget checkBoxUUID zuluCrypt-6.2.0/zuluCrypt-gui/partition.png000066400000000000000000000026521425361753700211040ustar00rootroot00000000000000‰PNG  IHDR D¤ŠÆsBITÛáOà pHYsvv}Õ‚ÌtEXtSoftwarewww.inkscape.org›î<[PLTEÿÿÿ333MMM LLLKKKIIINNNhhhiiiTTTWWW|||PPPEEEHHHwwwyyy“““ 000EEE!!!!!!ŽŽŽ£££žžž   ­­­®®®žžžŸŸŸªªª¬¬¬­­­®®®¯¯¯±±±²²²µµµ¸¸¸´´´”””•••ÀÀÀÁÁÀÁÁÁÂÂÁ¸¸¸¹¹¹¼¼¼½½½ÁÁÁÃÃÃÁÁÁÂÂÂÊÊÊÆÆÆ»»»ÉÉÉÐÐÐ&&&---4_4999IIILLLRRR[[[]]]```ggghjhjjjkkkmmmpppssstttuuuu†uvvvwwwyyy~~~†††’’’˜˜˜™™™šššŸŸŸ¡¡¡¢¢¢£££¤¤¤¥¥¥¦¦¦§§§¨¨¨©©©ªªª«««¬¬¬®®®¯¯¯°°°±±±²²²³³³´´´µµµ¶¶¶···¸¸¸¹¹¹ººº»»»¼¼¼½½½¾¾¾¿¿¿ÀÀÀÁÁÁÂÂÂÃÃÃÄÄÄÅÅÅÆÆÆÇÇÇÈÈÈÉÉÉÊÊÊËËËÌÌÌÍÍÍÎÎÎÏÏÏÐÐÐÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝàààáááâââãããäääåååæææççåçççèèæèèèêêêëëëìììííëîîìïïîïïïððîðððñññóóóôôôõõõöööùùùúúúûûûüüû>Àç¨PtRNS  "$(,44EI[[cwzzƒƒˆŒŒŽ¡¢££¨¾¾ÁÁÄÄÓÓÓÓÓÓÓÖÙÛÜÜãããããääççððññùúþþþ¬n[eIDATxÚ…ÎÍnYÅñSuËÝí¯Ä JB€Ye1š'˜€-¼Ø<Éðh6,BH€€Lˆ¤ýQuÆ×F°Ä_-õâþîÑůåAç²™4”4pÁ`{ò¢ Þ÷öï\¹.0Õâͤ&Qwÿ>ajv{òòuRUQL7†{ ¿Û;aê+P4êѪˆ@àu·EËð(Ö@ªâ°[HåÞç§; ¤^ 2H©à¦‰ t»óñp§"ȆSJ+ ¥E ÛUýLvc“ F)kгÎdsPñüU£!-£÷ ˜œþV¿_”=¬¢ ¥Ú¨½ì_v+ÌÇùk…ÔŸ’šŽjN6„Œà²È¿vÍóÓõ‚J9ÙÁï nß¼ñÇc¡A,á3;³ø¡qäoßmþn!·_•|]êMÈÏù÷ßÔL<ìSÞ_´éî€ò§Eï+|YÛ0ÒM-ÇZ’ZñÃøaðñ’µ7Û2{ß÷ÙñÖQjQÊ„dH&6'ö îmŽjtk2#äÙ´6]ÑKýò~W@×b€ŽúöºöH¶™ “oÈ_ÀÏåwò;áã%f[ìáXÛ]Îy9·ïè>ßc н¢=éÙ*vÚï/º¹ÝÅ­k„nB.@ux-¯–Š*GUìejx¿ðxŽO³c³ÂÂ’ö6©2Y§ÆM·õ$÷‰ú–½Ô˜zéÖöëÇm¯ÛÒÚÌY’͹€¦¢æÒæRøøà/T ªÒk2Õ3Õ/ÜË8bb@ÈM‡°¿…™½U©‘~ðsõiBº¦vLïP>tð·ÖÞÞ—Ý–Iqìw¢ý­Ák€z×z—z iôr´Ú‚Eû¡ÿ÷wN7Œ tcqE¾JžBžÒ{û^H`ˆëP_ù­Ò)¥a„›OZ×Ç÷™wïåô\ÔŠ¼Yò;Úöxí™ú@ñG Ñ‘è  Ɔ:‚1þëÀÛœ5@ž]^N^^Éþ¿(‹(B2 “ù) C¤…Ûج=t¼ýˆhHteIèë]ýÉýª¢Ÿ„§„ú¬Æúuu‘u±ŒŠÿ›^*É*jYMÌË3j…8êIFÔRK½ÊRGÿØ™è“è,tzä™ðœxNÝ’À²çeÏÖ'-Hš¨öÖ — wB¢î„v„>y;³AP§_×EHÛÂTáãK;íÚÙíf‡²¬æZ­“Z‹7¡žîMýi"Σ‰ZõGjåjÅ©˜Ej¹èjj¥>¼ž ˆ£æ ­Ñ]è@fbFé opÿÉcÀc€5+À;$'$Àî¨C’CüÔ5…=¢‚ŽîÚÈMׯ]?CÈOCeûÊ*‡ðN$+:Ãï\ûùÚ 5=ópߟ=(i.¹Gr§Úl¬ä|êq®@¹âH¡™h3V@õÆ_©Ù•@Y„¶aîéh„ÃÄÚSOéÄùÝÁ¼RA>ÀÖ¡H–J~“ü6V=Õ/>(>€ßÇÛÅ;ö·Ô6U6ÿ@HÑ`a_‘¦±°êMåÊ0€ûGï±îmbŸ¬Õ{téQÕ‡æZ:üA™‘ˆ\´7N¤ Çsp\Hm@ýÙçú•Ì ñNÑ8€ÆŽ˜…ËÕaÁ0Ç·b)»Fv·ìîYá8JTÏÏl3Ýü%¹î¹^„ w§! ÔD?pªþšÊÆ»*ý{ róVJ¸§ºüìö†ý cw×Eq¬0P?cÂ<êÍí€*ãf" žú—Ö1ênXÙÔ’×ðú ƧŸQŸºAýePÖzB$B¢fˆÁ.Ë?ž¿9ßäáêh÷¡7ü†—¿Ô°Ô•á ~²pzÚwâÿ3°—ãx6°>k3Z ÄÐ0ÂÀ°a°ee]0ÐqXá[Ôò¡ŒÎa.ú4Ùˆç_p¢^¬âèý6²é¨º«^W½®T”û©~ióÓ>sý:S7õJj!IêQ­Q‰„<[&òox¾.ìËÃáÓ‘Kn,ŒžP2WRÊâ+Ãj1Æa€ëfRéc…l©Õnb¥—Ps¼@UF¡$õ–Úvõ±õØaŒÀY½#?¬ÃN­SôS¬V¬–½4RÉs†çƒÏiÄ,âÝàż²üÞ%H?Héýã»Gó½"ä©CCq£¯¿Û¬Sú9€è¸HËI lµáDÌøp ³±%DRoh¦þÄ+ëŸSq¦ Ñ;0pCCmµ‡4µ!úOáõ½€Aõ™ š4ÿ÷ŒŒs„¹z¹zéÑÙ§Òæ¦Í%¤2½Â»Â‹¶ßDmí:¾ŒÖöv»r<®Ñ²ØÔKúñ, laܦ¢‹Ñ³·1[càMxºã|- T£‘G›£æîÉÌd¿¹Û^¥^¥À“ÊŸ’?ÙÝë¸×KHyx‰w‰íÐ7­ü:Á9BZýùW„:ËVb%”9µœ*N£ëÇ`|Ó@œèp4Äa£fÅu©¿ÃßÌ8 PfŒ~]ÄBÊâ[‹oâ®ÆÅÇÅü`±'bðÎÆxGxGxôäzúË¿ºóîNô›BÃ’µë ´ yüªþJýmB„ñ­;D’~m¸y¥h:j~¡yrRïäàÉÂâ G*h8Ê ‡1ßé ÆšO¨¿Z†‰À¸ŒË(•q·ÆåŒËˆpEˆøòü¹ü¹µCujujìÁ§_5NlœP¼½¸«¸Ó¿§´£Ø»ø!w¯WL©`Ò6^ø‡h@øì¦mdÏÍ<ùÀÛìb«Ûý«ôlVÍ`¤` Ì@ F  “Em:‰‘ I´6~îÈH]Gù{£ù0J!J É&©!© =+Ã9Ùõ>­9ckÆV€d©”E) W8”Ÿ¼íw;ˆäÚgÍÉb ]|úyÃëÇñ„ü̽Ÿ_£¿³¹3ï™BW6_¢I…¿›Í(6íLØjcÒ³Õ˜H2÷1ªQ\q •á¯âœÏ¹Ès‘¾Ò¾;|wXÙ[Z‚nrihH\˜x4ѱ¼Škæ³Ëg !é“Z“§Rgú°³.;qãùàØÈøDSó‰üÑ*Âbtˆ:¶rˆƒ->ñ!µÆ6êy˜  PËÄ€8Ça¬$œOx‘ðàÒayy€À3W]=Ä¼Æ ‘ ‘¸`|±÷b¯íÙk½WW]]CH”Æu7–R{ñÑ–Z‡æù³²4žÿzIìâ/—xöN9³¢­/â[{1×&»Ęˆk[[ŠZ^ƒz½+õ®Ljãd\<üýNLØIæ“&¢c%8>x xÀLÛ|Ÿù>+›Õ6«ÁoŠÃLáL!À2 ½.½–ñ¼y©^©—ŸÚ†ÊÞ L$¤L¿˜Wâ@ÈÍú˜î؆­Õ™ 2ô³ÜòÂr%yò>°Ôà_–|“ƒ… >fMm²—zQ0õâ-ÔóÏ`âƒ8à¿E)O©I© à ß_Î_ Ï*ïDÞ €ìíÃ_¢Zræ•ê””mˆÚm}Ôë%Wӧݧ†Ôœÿ„nBÈTõ?¨ô1íÜÞ1¹Ë J+"4j‹D!P~°‡_ˆA6µßWÔÞï¨w˜c ¹ÔZ˜¯:jÅ0 82–Òvfb6zì]pôÝÑw.Z.e.ež gΰ”½+.{]öð¾ésØÇñs6§Ïœvo}73¢0â!í«…EísÂUÅ÷À‰OÖ¦¾¬C}¦‡úSƦ½ŠZj$>šÉ-táØvý±ÃAO{p>fãXúX¸½ª½*ûûcKíŒíÌÓ|säìæü@®¯Ìå÷„4èÔ&Öfï àùgûYÈÏ’û]îþ¬ü 0œZÿ £rÒŒ˜" +ÇåŒûüx´‡vEëíüÑBÛB`è$ê/×ÈÖÈ$ZG÷D?a×]×áÞãFœÝç¶ÜM=(«4¦°¿ÈôáœG˜¨Ÿ<ÉÚÃ:À²1¾>,aý“¿º‚ˆ z#Acè1L1¡Êøëg2±2ûevSÅëu¯¹¸JEÏiÒ†œWO2µŠ¦ýjÈ5RÞ€·ënÿÂ+r~,®i¹MØâCètôLœ.µä.¼¾35ç"Î#XƒVŠ3ZÆ†Ä jE#j‰ÔÚ˜©µ¾Ô_HRü œMqìÊù–óŽÓFLŒÞ§Û8[^›Ì¶éðW¬^áa~¿ƒÜÏncW³êâý{yõRuj­—Ôóñ}MGœÏtê™ذة*ýÔSݨ'ã˜x<‹Zú>&2ÃøúÕ‚KH/¤D­ú'H=ïsê…[©m€I  ‹ÿ†»õzÖO¬4VÚ’HÎJŽGé3'ü\#LeP^(±x‰zÎrjõG¨1K=½zÚ\j%C,˜=|ÆÄɰ°“œ0ðiÔ)Æ]bý?-´™­X#°"zTXtSoftwarexÚ+//×ËÌË.NN,HÕË/J6ØXSÊ\IEND®B`‚zuluCrypt-6.2.0/zuluCrypt-gui/password.ui000066400000000000000000000313611425361753700205650ustar00rootroot00000000000000 PasswordDialog Qt::ApplicationModal 0 0 581 279 50 false Qt::TabFocus true Open Encrypted Volume true 120 240 111 31 &Options true false 230 240 121 31 &Open true true 350 240 111 31 &Cancel true false 140 70 331 31 Mount In &Read Only Mode false 440 40 31 31 select mount point path true 440 10 31 31 open volume path true false 140 210 301 31 100 QLineEdit::Password 470 210 31 31 open key file true 140 10 301 31 140 40 301 31 0 210 131 31 Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 10 40 121 31 Mount Name Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 10 10 121 31 Volume Path Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 440 210 31 31 140 180 301 31 Password KeyFile Key+KeyFile Plugin 140 90 301 41 &Share Mount Point 140 120 301 31 LUKS/TrueCrypt/BitLocker VeraCrypt VeraCrypt System PLAIN dm-crypt 10 120 121 31 Volume Type Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 440 120 31 31 440 150 31 31 140 150 301 29 QLineEdit::Password 10 150 121 31 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 440 180 31 31 0 -10 581 281 true QFrame::Raised TextLabel false Qt::AlignCenter true 230 230 121 33 &OK 10 10 561 261 true QFrame::StyledPanel QFrame::Raised 60 129 441 41 Enter Comma Separated Volume's File System Options Below Qt::AlignCenter 60 170 441 31 170 200 111 33 Set 280 200 111 33 Cancel OpenVolumePath PushButtonVolumePath MountPointPath PushButtonMountPointPath checkBoxReadOnly cbShareMountPoint cbVolumeType pushButtonPlainDmCryptOptions lineEditVolumeProperty cbKeyType checkBoxVisibleKey PassPhraseField pbKeyOption pushButtonPassPhraseFromFile PushButtonOpen PushButtonCancel zuluCrypt-6.2.0/zuluCrypt-gui/password_dialog.cpp000066400000000000000000000674451425361753700222650ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "password_dialog.h" #include "zulucrypt.h" #include "lxqt_wallet.h" #include "../plugin_path.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_password.h" #include "openvolume.h" #include "tcrypt.h" #include "task.hpp" #include "utility.h" #include "dialogmsg.h" #include "plugin_path.h" #include "tablewidget.h" #include "../zuluCrypt-cli/constants.h" #include "favorites2.h" #include "utility.h" passwordDialog::passwordDialog( QTableWidget * table, QWidget * parent, secrets& s, std::function< void( const QString& ) > f ) : QDialog( parent ), m_ui( new Ui::PasswordDialog() ), m_secrets( s ), m_openFolder( std::move( f ) ) { m_ui->setupUi( this ) ; m_ui->frameOptions->setVisible( false ) ; m_label.setOptions( m_ui->veraCryptWarning,m_ui->pbOK ) ; m_ui->PassPhraseField->setMaxLength( 32767 ) ; m_parent = parent ; this->setFixedSize( this->size() ) ; this->setWindowFlags( Qt::Window | Qt::Dialog ) ; this->setFont( parent->font() ) ; this->setDefaultOpenMode() ; m_ui->cbShareMountPoint->setChecked( utility::mountWithSharedMountPoint() ) ; m_ui->PushButtonMountPointPath->setIcon( QIcon( ":/folder.png" ) ) ; m_ui->pushButtonLuksExternalHeaderPath->setIcon( QIcon( ":/file.png" ) ) ; m_open_with_path = false ; m_table = table ; m_pluginMenu = new QMenu( this ) ; m_pluginMenu->setFont( this->font() ) ; connect( m_ui->PushButtonCancel,SIGNAL( clicked() ),this,SLOT( HideUI() ) ) ; connect( m_ui->PushButtonOpen,SIGNAL( clicked() ),this,SLOT( openVolume() ) ) ; connect( m_ui->PushButtonMountPointPath,SIGNAL( clicked() ),this,SLOT( mount_point() ) ) ; connect( m_ui->PushButtonVolumePath,SIGNAL( clicked() ),this,SLOT( file_path() ) ) ; connect( m_ui->pushButtonPassPhraseFromFile,SIGNAL( clicked() ),this,SLOT( clickedPassPhraseFromFileButton() ) ) ; connect( m_ui->OpenVolumePath,SIGNAL( textChanged( QString ) ),this,SLOT( mountPointPath( QString ) ) ) ; connect( m_ui->checkBoxReadOnly,SIGNAL( stateChanged( int ) ),this,SLOT( cbStateChanged( int ) ) ) ; connect( m_ui->pbKeyOption,SIGNAL( clicked() ),this,SLOT( pbKeyOption() ) ) ; connect( m_ui->cbKeyType,SIGNAL( currentIndexChanged( int ) ),this,SLOT( cbActicated( int ) ) ) ; connect( m_ui->cbVolumeType,SIGNAL( currentIndexChanged( int ) ),this,SLOT( cbVolumeType( int ) ) ) ; connect( m_ui->checkBoxVisibleKey,SIGNAL( stateChanged( int ) ),this,SLOT( cbVisibleKeyStateChanged( int ) ) ) ; connect( m_ui->cbShareMountPoint,&QCheckBox::stateChanged,[]( int s ){ utility::mountWithSharedMountPoint( s == Qt::Checked ) ; } ) ; m_ui->cbVolumeType->setCurrentIndex( utility::defaultUnlockingVolumeType() ) ; this->cbVolumeType( utility::defaultUnlockingVolumeType() ) ; m_ui->PushButtonMountPointPath->setVisible( false ) ; m_ui->pushButtonPassPhraseFromFile->setVisible( false ) ; m_veraCryptWarning.setWarningLabel( m_ui->veraCryptWarning ) ; m_ui->cbShareMountPoint->setToolTip( utility::shareMountPointToolTip() ) ; m_ui->cbKeyType->addItem( tr( "TrueCrypt/VeraCrypt Keys" ) ) ; m_ui->cbKeyType->addItem( tr( "YubiKey Challenge/Response" ) ) ; connect( m_ui->PushButtonOptions,&QPushButton::clicked,[ this ](){ auto m = m_ui->OpenVolumePath->text() ; m_ui->lineEditFsOptions->setText( utility::fileSystemOptions( m ) ) ; m_ui->lineEditFsOptions->setText( m_fsOptions ) ; m_ui->frameOptions->setVisible( true ) ; } ) ; connect( m_ui->pbSet,&QPushButton::clicked,[ this ](){ m_fsOptions = m_ui->lineEditFsOptions->text() ; m_ui->frameOptions->setVisible( false ) ; } ) ; connect( m_ui->pbCancel,&QPushButton::clicked,[ this ](){ m_ui->frameOptions->setVisible( false ) ; } ) ; m_ui->pushButtonPlainDmCryptOptions->setMenu( [ this ](){ auto m = new QMenu( this ) ; connect( m,SIGNAL( triggered( QAction * ) ), this,SLOT( plainDmCryptOption( QAction * ) ) ) ; auto s = utility::plainDmCryptOptions() ; if( s.isEmpty() ){ m_plainDmCryptProperty = "aes.cbc-essiv:sha256.256.ripemd160" ; m->addAction( "aes.cbc-essiv:sha256.256.ripemd160" ) ; }else{ m_plainDmCryptProperty = s.first() ; for( const auto& it : s ){ m->addAction( it ) ; } } return m ; }() ) ; connect( m_ui->pushButtonLuksExternalHeaderPath,&QPushButton::clicked,[ this ](){ auto a = tr( "Select External LUKS Header File" ) ; auto Z = QFileDialog::getOpenFileName( this,a,utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->lineEditVolumeProperty->setText( Z ) ; } } ) ; m_ui->checkBoxVisibleKey->setToolTip( tr( "Check This Box To Make Password Visible" ) ) ; this->setWindowTitle( tr( "Unlock Encrypted Volume" ) ) ; this->installEventFilter( this ) ; } void passwordDialog::plainDmCryptOption( QAction * ac ) { m_plainDmCryptProperty = ac->text().remove( "&" ) ; } void passwordDialog::cbVolumeType( int e ) { m_ui->lineEditVolumeProperty->clear() ; m_ui->lineEditVolumeProperty->setToolTip( QString() ) ; if( e == 0 ){ /* * LUKS,TrueCrypt,BitLocker */ m_ui->labelVolumeProperty->setText( tr( "LUKS External Header Path" ) ) ; m_ui->lineEditVolumeProperty->setEnabled( true ) ; m_ui->pushButtonPlainDmCryptOptions->setEnabled( false ) ; m_veraCryptVolume = false ; m_ui->pushButtonLuksExternalHeaderPath->setEnabled( true ) ; m_ui->lineEditVolumeProperty->setEchoMode( QLineEdit::Normal ) ; }else if( e == 1 || e == 2 ){ /* * VeraCrypt volume */ m_ui->labelVolumeProperty->setText( tr( "PIM Value" ) ) ; m_ui->lineEditVolumeProperty->setEnabled( true ) ; m_ui->pushButtonPlainDmCryptOptions->setEnabled( false ) ; m_veraCryptVolume = true ; m_ui->pushButtonLuksExternalHeaderPath->setEnabled( false ) ; m_ui->lineEditVolumeProperty->setEchoMode( QLineEdit::Password ) ; }else if( e == 3 ){ /* * PLAIN dm-crypt */ m_ui->pushButtonPlainDmCryptOptions->setEnabled( true ) ; m_ui->labelVolumeProperty->setText( tr( "Offset" ) ) ; m_ui->lineEditVolumeProperty->setEnabled( true ) ; m_ui->lineEditVolumeProperty->setToolTip( tr( "Offset Will Be In Sectors If The Entry Is Made Up Of Only Digits\nAnd In Bytes If The Entry Ends With \"b\"\nAnd In Kilobytes If The Entry Ends With \"k\"\nAnd In Megabytes If The Entry Ends With \"m\"\nAnd In Terabytes If The Entry Ends With \"t\"" ) ) ; m_veraCryptVolume = false ; m_ui->pushButtonLuksExternalHeaderPath->setEnabled( false ) ; m_ui->lineEditVolumeProperty->setEchoMode( QLineEdit::Password ) ; } utility::defaultUnlockingVolumeType( e ) ; } bool passwordDialog::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void passwordDialog::pbPlugin() { m_pluginMenu->clear() ; m_pluginMenu->addSeparator() ; utility::addPluginsToMenu( *m_pluginMenu ) ; m_pluginMenu->addAction( tr( "Cancel" ) )->setObjectName( "Cancel" ) ; connect( m_pluginMenu,SIGNAL( triggered( QAction * ) ),this,SLOT( pbPluginEntryClicked( QAction * ) ) ) ; m_pluginMenu->exec( QCursor::pos() ) ; } void passwordDialog::pbPluginEntryClicked( QAction * e ) { auto m = e->objectName() ; utility::setDefaultPlugin( m ) ; auto text = e->text() ; text.remove( "&" ) ; if( m != "Cancel" ){ m_ui->PassPhraseField->setText( text ) ; } } void passwordDialog::tcryptGui() { this->disableAll() ; m_ui->PassPhraseField->setText( QString() ) ; tcrypt::instance( this,false,[ this ]( const QString& key,const QStringList& keyFiles ) { m_key = key.toLatin1() ; m_keyFiles = keyFiles ; this->openVolume() ; m_ui->cbKeyType->setCurrentIndex( passwordDialog::key ) ; m_ui->PassPhraseField->setText( QString() ) ; },[ this ](){ m_key.clear() ; m_keyFiles.clear() ; m_ui->cbKeyType->setCurrentIndex( passwordDialog::key ) ; m_ui->PassPhraseField->setText( QString() ) ; this->enableAll() ; } ) ; } void passwordDialog::cbStateChanged( int state ) { m_ui->checkBoxReadOnly->setEnabled( false ) ; m_ui->checkBoxReadOnly->setChecked( utility::setOpenVolumeReadOnly( this,state == Qt::Checked,"zuluCrypt-gui" ) ) ; m_ui->checkBoxReadOnly->setEnabled( true ) ; } void passwordDialog::autoSetPassword( const QString& keyID ) { auto m = favorites2::settings().autoMountBackEnd() ; if( m.isInvalid() ){ return ; } auto secret = m_secrets.walletBk( m.bk() ).getKey( keyID ) ; if( secret.notConfigured ){ DialogMsg msg( this ) ; msg.ShowUIOK( tr( "ERROR!" ),tr( "Internal wallet is not configured" ) ) ; }else{ if( secret.key.isEmpty() ){ secret = m_secrets.walletBk( m.bk() ).getKey( utility::pathToUUID( keyID ) ) ; } m_ui->PassPhraseField->setText( secret.key ) ; } } void passwordDialog::setDefaultOpenMode() { m_ui->checkBoxReadOnly->setChecked( utility::getOpenVolumeReadOnlyOption( "zuluCrypt-gui" ) ) ; } void passwordDialog::closeEvent( QCloseEvent * e ) { e->ignore() ; this->HideUI() ; } void passwordDialog::ShowUI( const QString& volumePath,const QString& mount_point ) { auto volume = volumePath.split( "/" ).last() ; this->setWindowTitle( tr( "Mount \"%1\"" ).arg( volume ) ) ; if( mount_point.isEmpty() ){ m_point = utility::mountPathPostFix( volume ) ; }else{ m_point = utility::mountPathPostFix( mount_point.split( "/" ).last() ) ; } m_open_with_path = true ; this->passphraseOption() ; m_ui->OpenVolumePath->setText( volumePath ) ; m_ui->OpenVolumePath->setEnabled( false ) ; m_ui->PushButtonVolumePath->setEnabled( false ) ; m_ui->MountPointPath->setText( m_point ) ; m_ui->PassPhraseField->setFocus() ; if( volumePath.startsWith( "/dev/" ) || volumePath.startsWith( "UUID=" ) ){ m_ui->PushButtonVolumePath->setIcon( QIcon( ":/partition.png" ) ) ; }else{ m_ui->PushButtonVolumePath->setIcon( QIcon( ":/file.png" ) ) ; } this->autoSetPassword( volumePath ) ; this->show() ; } void passwordDialog::ShowUI( QString dev ) { auto m_point = utility::homePath() + "/" + dev.split( "/" ).last() ; this->ShowUI( dev,m_point ) ; } void passwordDialog::cbVisibleKeyStateChanged( int s ) { if( m_ui->cbKeyType->currentIndex() == passwordDialog::key ){ if( s == Qt::Checked ){ m_ui->PassPhraseField->setEchoMode( QLineEdit::Normal ) ; }else{ m_ui->PassPhraseField->setEchoMode( QLineEdit::Password ) ; } m_ui->PassPhraseField->setFocus() ; } } void passwordDialog::ShowUI() { this->passphraseOption() ; m_ui->OpenVolumePath->setFocus() ; m_ui->PushButtonVolumePath->setIcon( QIcon( ":/file.png" ) ) ; this->show() ; } void passwordDialog::mountPointPath( QString path ) { m_ui->MountPointPath->setText( utility::mountPathPostFix( path.split( "/" ).last() ) ) ; } void passwordDialog::cbActicated( int e ) { if( e == passwordDialog::key || e == passwordDialog::yubikey ){ m_ui->checkBoxVisibleKey->setEnabled( true ) ; }else{ m_ui->checkBoxVisibleKey->setEnabled( false ) ; m_ui->checkBoxVisibleKey->setChecked( false ) ; } switch( e ){ case passwordDialog::key : return this->passphraseOption() ; case passwordDialog::yubikey : return this->passphraseOption() ; case passwordDialog::keyfile : return this->passphraseFromFileOption() ; case passwordDialog::keyKeyFile : return this->keyAndKeyFile() ; case passwordDialog::plugin : return this->pluginOption() ; case passwordDialog::tcryptKeys : return this->tcryptGui() ; } } void passwordDialog::keyAndKeyFile() { QByteArray key ; if( utility::pluginKey( this,&key,"hmac" ) ){ m_ui->cbKeyType->setCurrentIndex( 0 ) ; }else{ this->passphraseOption() ; m_ui->PassPhraseField->setEnabled( false ) ; m_ui->PassPhraseField->setText( key ) ; } } void passwordDialog::pbKeyOption() { if( m_ui->cbKeyType->currentIndex() == passwordDialog::plugin ){ this->pbPlugin() ; }else{ this->clickedPassPhraseFromFileButton() ; } } void passwordDialog::pluginOption() { m_ui->pushButtonPassPhraseFromFile->setToolTip( tr( "Choose A Module From The File System" ) ) ; m_ui->PassPhraseField->setToolTip( tr( "Enter A Module Name To Use To Get Passphrase" ) ) ; m_ui->PassPhraseField->setEchoMode( QLineEdit::Normal ) ; m_ui->pushButtonPassPhraseFromFile->setEnabled( false ) ; m_ui->labelPassphrase->setText( tr( "Plugin Name" ) ) ; m_ui->pushButtonPassPhraseFromFile->setIcon( QIcon( ":/keyfile.png" ) ) ; m_ui->pbKeyOption->setIcon( QIcon( ":/module.png" ) ) ; m_ui->pbKeyOption->setEnabled( true ) ; m_ui->PassPhraseField->setEnabled( false ) ; m_ui->PassPhraseField->setText( utility::defaultPlugin() ) ; } void passwordDialog::passphraseOption() { m_ui->PassPhraseField->setToolTip( tr( "Enter A Key" ) ) ; m_ui->PassPhraseField->setEchoMode( QLineEdit::Password ) ; m_ui->PassPhraseField->clear() ; m_ui->pushButtonPassPhraseFromFile->setEnabled( false ) ; m_ui->labelPassphrase->setText( tr( "Password" ) ) ; m_ui->pushButtonPassPhraseFromFile->setIcon( QIcon( ":/passphrase.png" ) ) ; m_ui->pbKeyOption->setIcon( QIcon() ) ; m_ui->pbKeyOption->setEnabled( false ) ; m_ui->PassPhraseField->setFocus() ; m_ui->PassPhraseField->setEnabled( true ) ; } void passwordDialog::passphraseFromFileOption() { m_ui->pushButtonPassPhraseFromFile->setToolTip( tr( "Choose A KeyFile From The File System" ) ) ; m_ui->PassPhraseField->setToolTip( tr( "Enter A Path To A Keyfile Location" ) ) ; m_ui->PassPhraseField->setEchoMode( QLineEdit::Normal ) ; m_ui->PassPhraseField->clear() ; m_ui->pushButtonPassPhraseFromFile->setEnabled( true ) ; m_ui->pushButtonPassPhraseFromFile->setFocus() ; m_ui->labelPassphrase->setText( tr( "KeyFile Path" ) ) ; m_ui->pushButtonPassPhraseFromFile->setIcon( QIcon( ":/keyfile.png" ) ) ; m_ui->pbKeyOption->setIcon( QIcon( ":/keyfile.png" ) ) ; m_ui->pbKeyOption->setEnabled( true ) ; m_ui->PassPhraseField->setEnabled( true ) ; } void passwordDialog::clickedPassPhraseFromFileButton() { QString msg ; if( m_ui->cbKeyType->currentIndex() == passwordDialog::keyfile ){ msg = tr( "Select A KeyFile" ) ; }else{ msg = tr( "Select A Key Module" ) ; } auto Z = QFileDialog::getOpenFileName( this,msg,utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->PassPhraseField->setText( Z ) ; } } void passwordDialog::mount_point( void ) { auto p = tr( "Select Path To Mount Point Folder" ) ; auto Z = QFileDialog::getExistingDirectory( this,p,utility::homePath(),QFileDialog::ShowDirsOnly ) ; while( true ){ if( Z.endsWith( '/' ) ){ Z.truncate( Z.length() - 1 ) ; }else{ break ; } } if( !Z.isEmpty() ){ Z = Z + "/" + m_ui->OpenVolumePath->text().split( "/" ).last() ; m_ui->MountPointPath->setText( Z ) ; } if( m_ui->MountPointPath->text().isEmpty() ){ m_ui->MountPointPath->setFocus() ; }else if( m_ui->PassPhraseField->text().isEmpty() ){ m_ui->PassPhraseField->setFocus() ; } } void passwordDialog::file_path( void ) { auto Z = QFileDialog::getOpenFileName( this,tr( "Select Encrypted volume" ),utility::homePath() ) ; m_ui->OpenVolumePath->setText( Z ) ; if( !Z.isEmpty() ){ this->autoSetPassword( Z ) ; m_ui->MountPointPath->setText( utility::mountPathPostFix( Z.split( "/" ).last() ) ) ; m_ui->PassPhraseField->setFocus() ; } } void passwordDialog::HideUI() { if( !m_working ){ this->hide() ; this->deleteLater() ; } } void passwordDialog::sendKey( const QString& sockpath ) { utility::keySend( sockpath,m_key ) ; } void passwordDialog::disableAll() { m_ui->PushButtonOptions->setEnabled( false ) ; m_ui->labelVolumeProperty->setEnabled( false ) ; m_ui->lineEditVolumeProperty->setEnabled( false ) ; m_ui->pushButtonPlainDmCryptOptions->setEnabled( false ) ; m_ui->cbVolumeType->setEnabled( false ) ; m_ui->labelVolumeType->setEnabled( false ) ; m_ui->cbShareMountPoint->setEnabled( false ) ; m_ui->checkBoxReadOnly->setEnabled( false ) ; m_ui->labelMoutPointPath->setEnabled( false ) ; m_ui->labelPassphrase->setEnabled( false ) ; m_ui->labelVolumePath->setEnabled( false ) ; m_ui->MountPointPath->setEnabled( false ) ; m_ui->OpenVolumePath->setEnabled( false ) ; m_ui->PassPhraseField->setEnabled( false ) ; m_ui->PushButtonCancel->setEnabled( false ) ; m_ui->PushButtonMountPointPath->setEnabled( false ) ; m_ui->PushButtonOpen->setEnabled( false ) ; m_ui->pushButtonPassPhraseFromFile->setEnabled( false ) ; m_ui->PushButtonVolumePath->setEnabled( false ) ; m_ui->pbKeyOption->setEnabled( false ) ; m_ui->cbKeyType->setEnabled( false ) ; m_ui->checkBoxVisibleKey->setEnabled( false ) ; m_ui->lineEditVolumeProperty->setEnabled( false ) ; m_ui->labelVolumeProperty->setEnabled( false ) ; m_ui->pushButtonLuksExternalHeaderPath->setEnabled( false ) ; } void passwordDialog::enableAll() { auto index = m_ui->cbVolumeType->currentIndex() ; if( index == 0 ){ m_ui->pushButtonLuksExternalHeaderPath->setEnabled( true ) ; } m_ui->PushButtonOptions->setEnabled( true ) ; m_ui->lineEditVolumeProperty->setEnabled( true ) ; m_ui->labelVolumeProperty->setEnabled( true ) ; m_ui->pushButtonPlainDmCryptOptions->setEnabled( index == 3 ) ; m_ui->cbVolumeType->setEnabled( true ) ; m_ui->labelVolumeType->setEnabled( true ) ; m_ui->cbShareMountPoint->setEnabled( true ) ; m_ui->checkBoxReadOnly->setEnabled( true ) ; m_ui->labelMoutPointPath->setEnabled( true ) ; m_ui->labelPassphrase->setEnabled( true ) ; m_ui->labelVolumePath->setEnabled( true ) ; m_ui->MountPointPath->setEnabled( true ) ; m_ui->OpenVolumePath->setEnabled( true ) ; m_ui->PassPhraseField->setEnabled( true ) ; m_ui->PushButtonCancel->setEnabled( true ) ; m_ui->PushButtonMountPointPath->setEnabled( true ) ; m_ui->PushButtonOpen->setEnabled( true ) ; m_ui->pushButtonPassPhraseFromFile->setEnabled( true ) ; m_ui->PushButtonVolumePath->setEnabled( true ) ; m_ui->cbKeyType->setEnabled( true ) ; auto m = m_ui->cbKeyType->currentIndex() ; if( m_open_with_path ){ m_ui->OpenVolumePath->setEnabled( false ) ; m_ui->PushButtonVolumePath->setEnabled( false ) ; } if( m == passwordDialog::key || m == passwordDialog::yubikey ){ m_ui->checkBoxVisibleKey->setEnabled( true ) ; m_ui->pushButtonPassPhraseFromFile->setEnabled( false ) ; m_ui->PassPhraseField->setEnabled( true ) ; }else{ m_ui->checkBoxVisibleKey->setEnabled( false ) ; m_ui->pbKeyOption->setEnabled( true ) ; m_ui->PassPhraseField->setEnabled( false ) ; } } void passwordDialog::openVolume() { this->disableAll() ; m_key = m_ui->PassPhraseField->text().toLatin1() ; m_device = utility::resolvePath( m_ui->OpenVolumePath->text() ) ; m_point = m_ui->MountPointPath->text() ; if( m_point.isEmpty() || m_device.isEmpty() ){ m_label.show( tr( "Atleast one required field is empty" ) ) ; return this->enableAll() ; } if( m_point.contains( "/" ) ){ m_label.show( tr( "\"/\" character is not allowed in mount name field" ) ) ; m_ui->OpenVolumePath->setFocus() ; return this->enableAll() ; } QString mode ; if( m_ui->checkBoxReadOnly->isChecked() ){ mode =" ro" ; }else{ mode = "rw" ; } QString passtype ; QString keyPath ; int keySource = m_ui->cbKeyType->currentIndex() ; if( keySource == passwordDialog::yubikey ){ auto m = utility::yubiKey( m_ui->PassPhraseField->text() ) ; if( m.has_value() ){ m_key = m.value() ; }else{ DialogMsg( this ).ShowUIOK( tr( "ERROR" ),tr( "Failed To Locate Or Run Yubikey's \"ykchalresp\" Program." ) ) ; return this->enableAll() ; } }else if( keySource == passwordDialog::keyfile ){ if( m_key.isEmpty() ){ m_label.show( tr( "Atleast one required field is empty" ) ) ; return this->enableAll() ; }else{ passtype = "-f" ; keyPath = utility::resolvePath( m_key ).replace( "\"","\"\"\"" ) ; } }else if( keySource == passwordDialog::key || keySource == passwordDialog::keyKeyFile ){ passtype = "-f" ; keyPath = utility::keyPath() ; this->sendKey( keyPath ) ; }else if( keySource == passwordDialog::plugin ){ if( m_key.isEmpty() ){ m_label.show( tr( "Atleast one required field is empty" ) ) ; return this->enableAll() ; }else{ auto r = m_ui->PassPhraseField->text() ; if( utility::equalsAtleastOne( r,"hmac","gpg","keykeyfile" ) ){ if( utility::pluginKey( m_secrets.parent(),&m_key,r ) ){ return this->enableAll() ; }else{ passtype = "-f" ; keyPath = utility::keyPath() ; this->sendKey( keyPath ) ; } }else if( r == "network" ){ auto e = utility::Task::makePath( m_device ) ; auto z = QString( "%1 -i -d %2" ).arg( ZULUCRYPTzuluCrypt,e ) ; auto& s = utility::Task::run( z ) ; auto q = utility::split( s.await().stdOut() ) ; if( q.size() < 2 ){ m_label.show( tr( "Volume is not a LUKS volume" ) ) ; m_ui->OpenVolumePath->setFocus() ; return this->enableAll() ; }else{ this->disableAll() ; auto s = utility::getKeyFromNetwork( q.at( 1 ) ) ; if( s.first ){ m_key = s.second ; passtype = "-f" ; keyPath = utility::keyPath() ; this->sendKey( keyPath ) ; }else{ m_label.show( tr( "Failed to get a key from the network" ) ) ; m_ui->OpenVolumePath->setFocus() ; return this->enableAll() ; } } }else{ auto env = QProcessEnvironment::systemEnvironment() ; env.insert( "zuluCryptPrintToStdOut","true" ) ; m_key = Task::process::run( ZULUCRYPTpluginPath + r,{},-1,"",env ).await().std_out() ; if( m_key.isEmpty() ){ m_label.show( tr( "Failed to get a key from a plugin" ) ) ; m_ui->OpenVolumePath->setFocus() ; return this->enableAll() ; }else{ passtype = "-f" ; keyPath = utility::keyPath() ; this->sendKey( keyPath ) ; } } } }else if( keySource == passwordDialog::tcryptKeys ){ passtype = "-f" ; keyPath = utility::keyPath() ; this->sendKey( keyPath ) ; }else{ utility::debug() << "Error: uncaught condition" ; } QString a = ZULUCRYPTzuluCrypt ; QString b = m_device ; b.replace( "\"","\"\"\"" ) ; QString c = m_point ; c.replace( "\"","\"\"\"" ) ; const QString& d = mode ; const QString& e = passtype ; const QString& f = keyPath ; if( !b.startsWith( "/dev/" ) ){ auto s = utility::loopDevicePath( b ) ; if( !s.isEmpty() ){ b = s ; } } auto exe = QString( "%1 -o -d \"%2\" -m \"%3\" -e %4 %5 \"%6\"" ).arg( a,b,c,d,e,f ) ; if( m_ui->cbVolumeType->currentIndex() == 0 ){ auto s = m_ui->lineEditVolumeProperty->text() ; if( !s.isEmpty() ){ exe += " -z " + utility::Task::makePath( s ) ; } } if( !m_keyFiles.isEmpty() ){ for( const auto& it : m_keyFiles ){ QString e = it ; e.replace( "\"","\"\"\"" ) ; exe += " -F \"" + e + "\"" ; } } if( m_ui->cbVolumeType->currentIndex() == 1 ){ auto e = m_ui->lineEditVolumeProperty->text() ; if( e.isEmpty() ){ exe += " -t vcrypt" ; }else { exe += " -t vcrypt." + e ; } }else if( m_ui->cbVolumeType->currentIndex() == 2 ){ auto e = m_ui->lineEditVolumeProperty->text() ; if( e.isEmpty() ){ exe += " -t vcrypt-sys" ; }else { exe += " -t vcrypt-sys." + e ; } }else if( m_ui->cbVolumeType->currentIndex() == 3 ){ auto e = m_ui->lineEditVolumeProperty->text() ; if( e.isEmpty() ){ exe += " -t " + m_plainDmCryptProperty + ".0" ; }else { exe += " -t " + m_plainDmCryptProperty + "." + e ; } } if( m_ui->cbShareMountPoint->isChecked() ){ exe += " -M" ; } utility::setFileSystemOptions( exe,m_device,m_point,m_fsOptions ) ; this->disableAll() ; m_veraCryptWarning.show( m_veraCryptVolume ) ; m_working = true ; auto r = utility::Task::run( utility::appendUserUID( exe ) ).await() ; m_working = false ; m_veraCryptWarning.stopTimer() ; if( r.success() ){ m_openFolder( utility::mountPath( m_point ) ) ; this->HideUI() ; }else{ this->failed( r ) ; m_veraCryptWarning.hide() ; } } void passwordDialog::failed( const utility::Task& e ) { int r = e.exitCode() ; if( r == 12 && m_ui->cbKeyType->currentIndex() == passwordDialog::plugin ){ /* * A user cancelled the plugin */ return this->enableAll() ; } switch ( r ){ case 0 : return ; case 1 : m_label.show( tr( "Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed?" ) ) ; break ; case 2 : m_label.show( tr( "There seem to be an open volume accociated with given address" ) ) ; break ; case 3 : m_label.show( tr( "No file or device exist on given path" ) ) ; break ; case 4 : m_label.show( tr( "Volume could not be opened with the presented key" ) ) ; break ; case 5 : m_label.show( tr( "Insufficient privilege to mount the device with given options" ) ) ; break ; case 6 : m_label.show( tr( "Insufficient privilege to open device in read write mode or device does not exist" ) ) ; break ; case 7 : m_label.show( tr( "Only root user can perform this operation" ) ) ; break ; case 8 : m_label.show( tr( "-O and -m options can not be used together" ) ) ; break ; case 9 : m_label.show( tr( "Could not create mount point, invalid path or path already taken" ) ) ; break ; case 10: m_label.show( tr( "Shared mount point path already taken" ) ) ; break ; case 11: m_label.show( tr( "There seem to be an opened mapper associated with the device" ) ) ; break ; case 12: m_label.show( tr( "Could not get a passphrase from the module" ) ) ; break ; case 13: m_label.show( tr( "Could not get passphrase in silent mode" ) ) ; break ; case 14: m_label.show( tr( "Insufficient memory to hold passphrase" ) ) ; break ; case 15: m_label.show( tr( "One or more required argument(s) for this operation is missing" ) ) ; break ; case 16: m_label.show( tr( "Invalid path to key file" ) ) ; break ; case 17: m_label.show( tr( "Could not get enought memory to hold the key file" ) ) ; break ; case 18: m_label.show( tr( "Insufficient privilege to open key file for reading" ) ) ; break ; case 19: m_label.show( tr( "Could not get a passphrase through a local socket" ) ) ; break ; case 20: m_label.show( tr( "Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered" ) ) ; break ; case 21: m_label.show( tr( "Could not create a lock on /etc/mtab" ) ) ; break ; case 22: m_label.show( tr( "Insufficient privilege to open a system volume.\n\nConsult menu->help->permission for more informaion\n" ) ) ; break ; case 113:m_label.show( tr( "A non supported device encountered,device is missing or permission denied\n\ Possible reasons for getting the error are:\n1.Device path is invalid.\n2.The device has LVM or MDRAID signature" ) ) ; break ; default: m_label.show( tr( "Error Code: %1\n--\nStdOut: %2\n--\nStdError: %3").arg( QString::number( e.exitCode() ),QString( e.stdError() ),QString( e.stdOut() ) ) ) ; } utility::debug() << e.stdOut() << "--" << e.stdError() ; this->enableAll() ; auto index = m_ui->cbKeyType->currentIndex() ; if( utility:: clearPassword() && ( index == passwordDialog::key || index == passwordDialog::yubikey ) ){ m_ui->PassPhraseField->clear() ; m_ui->PassPhraseField->setFocus() ; } if( r == 4 ){ if( index == passwordDialog::key || index == passwordDialog::yubikey ){ m_ui->PassPhraseField->setFocus() ; }else if( index == passwordDialog::keyKeyFile ){ m_ui->cbKeyType->setCurrentIndex( 0 ) ; this->passphraseOption() ; } } } passwordDialog::~passwordDialog() { m_pluginMenu->deleteLater() ; delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/password_dialog.h000066400000000000000000000063421425361753700217170ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef PASSWORD_DIALOG_H #define PASSWORD_DIALOG_H #include #include #include #include #include #include #include "utility.h" #include "secrets.h" namespace Ui { class PasswordDialog ; } class QWidget ; class QAction ; class QCloseEvent ; class QTableWidget ; class QMenu ; class passwordDialog : public QDialog { Q_OBJECT public: static passwordDialog& instance( QTableWidget * table,QWidget * parent,secrets& s,std::function< void( const QString& ) > f ) { return *( new passwordDialog( table,parent,s,std::move( f ) ) ) ; } passwordDialog( QTableWidget * table,QWidget * parent,secrets&,std::function< void( const QString& ) > ) ; virtual ~passwordDialog() ; signals : void addItemToTable( QString,QString,QString ) ; public slots: void HideUI( void ) ; void ShowUI( void ) ; void ShowUI( const QString& volumePath,const QString& mount_point ) ; void ShowUI( QString ) ; private slots : void openVolume( void ) ; void cbVisibleKeyStateChanged( int ) ; void cbVolumeType( int ) ; void cbActicated( int ) ; void pbKeyOption( void ) ; void pbPluginEntryClicked( QAction * ) ; void plainDmCryptOption( QAction * ) ; void pbPlugin( void ) ; void mount_point( void ) ; void clickedPassPhraseFromFileButton( void ) ; void passphraseFromFileOption( void ) ; void passphraseOption( void ) ; void pluginOption( void ) ; void file_path( void ) ; void mountPointPath( QString ) ; void cbStateChanged( int ) ; private : void autoSetPassword( const QString& ) ; void keyAndKeyFile( void ) ; void tcryptGui( void ) ; QString getUUIDFromPath( const QString& ) ; void sendKey( const QString& sockpath ) ; void setDefaultOpenMode( void ) ; void disableAll( void ) ; void enableAll( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; void failed( const utility::Task& ) ; void failed( void ) ; Ui::PasswordDialog * m_ui ; QTableWidget * m_table ; secrets& m_secrets ; bool m_open_with_path ; QMenu * m_pluginMenu ; QWidget * m_parent ; QByteArray m_key ; QStringList m_keyFiles ; QString m_fsOptions ; QString m_device ; QString m_point ; QString m_plainDmCryptProperty ; bool m_veraCryptVolume = false ; utility::veraCryptWarning m_veraCryptWarning ; bool m_working = false ; enum{ key = 0,keyfile = 1,keyKeyFile = 2,plugin = 3,tcryptKeys = 4,yubikey = 5 } ; std::function< void( const QString& ) > m_openFolder ; utility::label m_label ; }; #endif // PASSWORD_DIALOG_H zuluCrypt-6.2.0/zuluCrypt-gui/plugin.cpp000066400000000000000000000102611425361753700203620ustar00rootroot00000000000000/* * * Copyright ( c ) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "plugin.h" #include "../plugins/plugins.h" #include "ui_plugin.h" #include "utility.h" #include "dialogmsg.h" #include #include #include #include #include #include #include plugin::plugin( QWidget * parent,plugins::plugin t,std::function< void( const QByteArray& ) > function,const QString& e,const QVector& exe ) : QDialog( parent ),m_ui( new Ui::plugin ),m_function( std::move( function ) ),m_pluginType( t ),m_exe( exe ) { m_ui->setupUi( this ) ; if( !e.isEmpty() ){ m_ui->label->setText( e ) ; } this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; connect( m_ui->pbSetKey,SIGNAL( clicked() ),this,SLOT( pbSetKey() ) ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbClose() ) ) ; connect( m_ui->pbKeyFile,SIGNAL( clicked() ),this,SLOT( pbSelectKeyFile() ) ) ; m_ui->pbKeyFile->setIcon( QIcon( ":/file.png" ) ) ; m_ui->lineEdit->setFocus() ; this->ShowUI() ; } bool plugin::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void plugin::closeEvent( QCloseEvent * e ) { e->ignore() ; this->HideUI() ; } plugin::~plugin() { delete m_ui ; } void plugin::ShowUI() { this->show() ; } void plugin::HideUI() { m_function( m_key ) ; this->hide() ; this->deleteLater() ; } void plugin::pbSetKey() { auto passphrase = m_ui->lineEdit->text() ; auto keyFile = m_ui->lineEdit_2->text() ; DialogMsg msg( this ) ; if( keyFile.isEmpty() ){ return msg.ShowUIOK( tr( "ERROR" ),tr( "KeyFile Not Set" ) ) ; } this->disableAll() ; Task::run( [ this,passphrase,keyFile ](){ switch( m_pluginType ){ case plugins::plugin::gpg: return plugins::gpg( m_exe,keyFile,passphrase ) ; case plugins::plugin::hmac_key_1: return plugins::hmac_key_1( m_exe,keyFile,passphrase ) ; case plugins::plugin::hmac_key: return plugins::hmac_key( keyFile,passphrase ) ; case plugins::plugin::keyKeyFile: return plugins::keyKeyFile( m_exe,keyFile,passphrase ) ; case plugins::plugin::luks: return plugins::luks( m_exe,keyFile,passphrase ) ; case plugins::plugin::steghide: return plugins::steghide( m_exe,keyFile,passphrase ) ; default: return QByteArray() ; } } ).then( [ this ]( const QByteArray& e ){ m_key = e ; if( m_key.isEmpty() ){ DialogMsg msg( this ) ; msg.ShowUIOK( tr( "ERROR" ),tr( "Failed To Generate Key" ) ) ; this->enableAll() ; }else{ this->HideUI() ; } } ) ; } void plugin::pbSelectKeyFile() { m_ui->lineEdit_2->setText( QFileDialog::getOpenFileName( this,tr( "KeyFile" ),utility::homePath() ) ) ; } void plugin::pbClose() { this->HideUI() ; } void plugin::enableAll() { m_ui->pbCancel->setEnabled( true ) ; m_ui->pbKeyFile->setEnabled( true ) ; m_ui->pbSetKey->setEnabled( true ) ; m_ui->groupBox->setEnabled( true ) ; m_ui->label->setEnabled( true ) ; m_ui->label_2->setEnabled( true ) ; m_ui->label_3->setEnabled( true ) ; m_ui->lineEdit->setEnabled( true ) ; m_ui->lineEdit_2->setEnabled( true ) ; } void plugin::disableAll() { m_ui->pbCancel->setEnabled( false ) ; m_ui->pbKeyFile->setEnabled( false ) ; m_ui->pbSetKey->setEnabled( false ) ; m_ui->groupBox->setEnabled( false ) ; m_ui->label->setEnabled( false ) ; m_ui->label_2->setEnabled( false ) ; m_ui->label_3->setEnabled( false ) ; m_ui->lineEdit->setEnabled( false ) ; m_ui->lineEdit_2->setEnabled( false ) ; } zuluCrypt-6.2.0/zuluCrypt-gui/plugin.h000066400000000000000000000037031425361753700200320ustar00rootroot00000000000000/* * * Copyright ( c ) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef HMAC_H #define HMAC_H #include #include #include #include #include #include #include class QCloseEvent ; class QEvent ; #include "../plugins/plugins.h" namespace Ui { class plugin; } class plugin : public QDialog { Q_OBJECT public: static plugin& instance( QWidget * parent, plugins::plugin t, std::function< void( const QByteArray& ) > e, const QString& f = QString(), const QVector& g = QVector() ) { return *( new plugin( parent,t,e,f,g ) ) ; } plugin( QWidget * parent, plugins::plugin, std::function< void( const QByteArray& ) >, const QString& = QString(),const QVector& = QVector() ) ; ~plugin() ; private slots: void pbSetKey() ; void pbSelectKeyFile() ; void pbClose() ; private: void ShowUI() ; void HideUI() ; void enableAll() ; void disableAll() ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::plugin * m_ui ; QByteArray m_key = QByteArray() ; std::function< void( const QByteArray& ) > m_function ; plugins::plugin m_pluginType ; QVector m_exe ; }; #endif // HMAC_H zuluCrypt-6.2.0/zuluCrypt-gui/plugin.ui000066400000000000000000000067671425361753700202350ustar00rootroot00000000000000 plugin Qt::ApplicationModal 0 0 541 233 Key Generator Using A Passphrase And A KeyFile 140 200 131 31 &Set Key 270 200 131 31 &Cancel 110 140 321 31 QLineEdit::Password 430 170 31 31 10 0 521 141 10 20 501 101 Create an encryption key that is made up of a passphrase and a keyfile. A volume created with a key generated here should be opened with "hmac" plugin. Qt::AlignCenter true 11 140 91 31 Passphrase Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 110 170 321 31 11 170 91 31 KeyFile Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true zuluCrypt-6.2.0/zuluCrypt-gui/readonlywarning.cpp000066400000000000000000000046011425361753700222700ustar00rootroot00000000000000/* * * Copyright (c) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "readonlywarning.h" #include "ui_readonlywarning.h" #include "utility.h" #include #include #include bool readOnlyWarning::getOpenVolumeReadOnlyOption( const QString& app ) { Q_UNUSED( app ) return utility::readOnlyOption() ; } readOnlyWarning::readOnlyWarning( QWidget * parent,bool checked,const QString& app ) : QDialog( parent ),m_ui( new Ui::readOnlyWarning ),m_checked( checked ),m_app( app ) { m_ui->setupUi( this ) ; this->setFont( parent->font() ) ; this->setFixedSize( this->size() ) ; connect( m_ui->PbOK,SIGNAL( clicked() ),this,SLOT( pbOK() ) ) ; connect( m_ui->checkBox,SIGNAL( clicked( bool ) ),this,SLOT( checkBoxChecked( bool ) ) ) ; this->installEventFilter( this ) ; m_configPathReadOnly = utility::readOnlyOption() ; this->setReadOnlyOption( m_checked ) ; } void readOnlyWarning::pbOK() { this->HideUI() ; } void readOnlyWarning::checkBoxChecked( bool checked ) { utility::readOnlyWarning( !checked ) ; } void readOnlyWarning::setReadOnlyOption( bool readOnly ) { utility::readOnlyOption( readOnly ) ; } bool readOnlyWarning::showUIwarning() { return utility::readOnlyWarning() ; } bool readOnlyWarning::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void readOnlyWarning::closeEvent( QCloseEvent * e ) { e->ignore() ; this->HideUI() ; } void readOnlyWarning::ShowUI() { if( m_checked && this->showUIwarning() ){ this->show() ; }else{ this->deleteLater() ; } } void readOnlyWarning::HideUI() { this->hide() ; this->deleteLater() ; } readOnlyWarning::~readOnlyWarning() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/readonlywarning.h000066400000000000000000000034201425361753700217330ustar00rootroot00000000000000/* * * Copyright (c) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef READONLYWARNING_H #define READONLYWARNING_H #include #include class QWidget ; class QCloseEvent ; namespace Ui { class readOnlyWarning ; } class readOnlyWarning : public QDialog { Q_OBJECT public: static bool showWarning( QWidget * parent = 0,bool checked = false,const QString& app = QString() ) { auto w = new readOnlyWarning( parent,checked,app ) ; w->ShowUI() ; return checked ; } static bool getOpenVolumeReadOnlyOption( const QString& app ) ; explicit readOnlyWarning( QWidget * parent = 0,bool checked = false,const QString& app = QString() ) ; ~readOnlyWarning() ; void ShowUI( void ) ; void HideUI( void ) ; private slots: void pbOK( void ) ; void checkBoxChecked( bool ) ; private: void setReadOnlyOption( bool ) ; bool showUIwarning( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::readOnlyWarning * m_ui ; bool m_checked ; QString m_app ; QString m_configPathReadOnly ; QString m_configPathShowUI ; }; #endif // READONLYWARNING_H zuluCrypt-6.2.0/zuluCrypt-gui/readonlywarning.ui000066400000000000000000000026431425361753700221270ustar00rootroot00000000000000 readOnlyWarning 0 0 431 172 WARNING 80 80 341 51 Do Not Show This Message Again. 10 10 411 71 Setting this option will cause the volume to open in read only mode. Qt::AlignCenter true 150 140 131 31 &Ok zuluCrypt-6.2.0/zuluCrypt-gui/secrets.cpp000066400000000000000000000073451425361753700205450ustar00rootroot00000000000000/* * * Copyright ( c ) 2016 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "secrets.h" #include "utility.h" secrets::secrets( QWidget * parent ) : m_parent( parent ),m_backends( m_parent ) { } void secrets::changeInternalWalletPassword( const QString& walletName, const QString& appName, std::function< void( bool ) > ff ) { auto e = m_backends.get( LXQt::Wallet::BackEnd::internal ) ; e->changeWalletPassWord( walletName,appName,[ ff = std::move( ff ) ]( bool q ){ ff( q ) ; } ) ; } void secrets::changeWindowsDPAPIWalletPassword( const QString& walletName, const QString& appName, std::function< void( bool ) > f ) { auto s = m_backends.get( LXQt::Wallet::BackEnd::windows_dpapi ) ; s->changeWalletPassWord( walletName,appName,[ f = std::move( f ) ]( bool q ){ f( q ) ; } ) ; } secrets::~secrets() { this->close() ; } void secrets::close() { m_backends.close() ; } secrets::wallet secrets::walletBk( LXQt::Wallet::BackEnd e ) const { return m_backends.get( e ) ; } QWidget * secrets::parent() const { return m_parent ; } secrets::wallet::wallet() { } secrets::wallet::wallet( LXQt::Wallet::Wallet * w ) : m_wallet( w ) { } secrets::wallet::~wallet() { } secrets::wallet::wallet( secrets::wallet&& w ) { m_wallet = w.m_wallet ; } secrets::wallet::walletKey secrets::wallet::getKey( const QString& keyID,QWidget * widget ) { auto _getKey = []( LXQt::Wallet::Wallet * wallet,const QString& volumeID ){ return ::Task::await( [ & ](){ return wallet->readValue( volumeID ) ; } ) ; } ; walletKey w{ false,false,"" } ; auto s = m_wallet->backEnd() ; auto walletInfo = this->walletInfo() ; auto _open = [ & ]( bool s ){ if( s ){ auto m = this->openSync( [](){ return true ; }, [ & ](){ if( widget ){ widget->hide() ; } }, [ & ](){ if( widget ){ widget->show() ; } } ) ; w.opened = m ; if( w.opened ){ w.key = _getKey( m_wallet,keyID ) ; } }else{ w.notConfigured = true ; } } ; if( s == LXQt::Wallet::BackEnd::internal ){ _open( LXQt::Wallet::walletExists( s,walletInfo.appName,walletInfo.appName ) ) ; }else if( s == LXQt::Wallet::BackEnd::windows_dpapi ){ _open( true ) ; }else{ _open( true ) ; w.opened = m_wallet->open( walletInfo.appName,walletInfo.appName ) ; if( w.opened ){ w.key = _getKey( m_wallet,keyID ) ; } } return w ; } secrets::wallet::info secrets::wallet::walletInfo() { if( m_wallet->backEnd() == LXQt::Wallet::BackEnd::kwallet ){ return { utility::KWalletDefaultName(),utility::applicationName() } ; }else{ return { utility::walletName(),utility::applicationName() } ; } } secrets::backends::backends( QWidget * w ) : m_parent( w ) { } LXQt::Wallet::Wallet * secrets::backends::get( LXQt::Wallet::BackEnd e ) { for( const auto& it : m_backends ){ if( it.bk == e ){ return it.wallet ; } } auto a = LXQt::Wallet::getWalletBackend( e ).release() ; a->setParent( m_parent ) ; m_backends.emplace_back( e,a ) ; return a ; } void secrets::backends::close() { for( auto& it : m_backends ){ delete it.wallet ; } m_backends.clear() ; } zuluCrypt-6.2.0/zuluCrypt-gui/secrets.h000066400000000000000000000076511425361753700202120ustar00rootroot00000000000000/* * * Copyright ( c ) 2016 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef SECRETS_H #define SECRETS_H #include "lxqt_wallet.h" #include #include #include #include #include #include "utility2.h" void windowsDebugWindow( const QString& e,bool s ) ; class secrets { public: class wallet { public: wallet( LXQt::Wallet::Wallet * ) ; wallet() ; ~wallet() ; wallet( wallet&& ) ; LXQt::Wallet::Wallet& bk() const { return *m_wallet ; } LXQt::Wallet::Wallet * operator->() { return m_wallet ; } operator bool() const { return m_wallet ; } template< typename Function,typename Before,typename After > utility2::result< std::result_of_t< Function() > > openSync( Function&& function, Before&& b = [](){}, After&& a = [](){} ) { if( m_wallet->opened() ){ return function() ; }else{ m_wallet->setImage( QIcon( ":/zuluCrypt" ) ) ; m_wallet->log( []( QString e ){ Q_UNUSED( e ) } ); auto s = this->walletInfo() ; b() ; auto m = m_wallet->open( s.walletName,s.appName ) ; a() ; if( m ){ return function() ; }else{ return {} ; } } } template< typename Function > utility2::result< std::result_of_t< Function() > > open( Function&& function ) { return this->openSync( std::move( function ),[](){},[](){} ) ; } bool open() { return this->openSync( []{ return true ; },[](){},[](){} ).has_value() ; } template< typename Opened,typename Before,typename After > void open( Opened&& o,Before&& b,After&& a ) { if( m_wallet->opened() ){ o() ; }else{ b() ; auto s = this->walletInfo() ; m_wallet->setImage( QIcon( ":/zuluCrypt" ) ) ; m_wallet->log( []( QString e ){ Q_UNUSED( e ) } ); m_wallet->open( s.walletName,s.appName,std::move( a ) ) ; } } template< typename Opened,typename After > void open( Opened&& ofunction,After&& afunction ) { this->open( std::move( ofunction ),[](){},std::move( afunction ) ) ; } struct walletKey { bool opened ; bool notConfigured ; QString key ; } ; walletKey getKey( const QString& keyID,QWidget * widget = nullptr ) ; private: struct info{ QString walletName ; QString appName ; }; info walletInfo() ; LXQt::Wallet::Wallet * m_wallet = nullptr ; }; secrets::wallet walletBk( LXQt::Wallet::BackEnd ) const ; QWidget * parent() const ; void changeInternalWalletPassword( const QString&,const QString&,std::function< void( bool ) > ) ; void changeWindowsDPAPIWalletPassword( const QString&,const QString&,std::function< void( bool ) > ) ; void close() ; secrets( QWidget * parent = nullptr ) ; secrets( const secrets& ) = delete ; secrets& operator=( const secrets& ) = delete ; ~secrets() ; private: QWidget * m_parent = nullptr ; class backends{ public: backends( QWidget * ) ; LXQt::Wallet::Wallet * get( LXQt::Wallet::BackEnd ) ; void close() ; private: struct bks{ bks( LXQt::Wallet::BackEnd e,LXQt::Wallet::Wallet * s ) : bk( e ),wallet( s ) { } LXQt::Wallet::BackEnd bk ; LXQt::Wallet::Wallet * wallet ; } ; std::vector< bks > m_backends ; QWidget * m_parent ; } mutable m_backends ; } ; #endif zuluCrypt-6.2.0/zuluCrypt-gui/sharedObjects/000077500000000000000000000000001425361753700211405ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluCrypt-gui/sharedObjects/CMakeLists.txt000066400000000000000000000032741425361753700237060ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) set( SRC ../dialogok.cpp ../dialogmsg.cpp ../tablewidget.cpp ../utility.cpp ../readonlywarning.cpp ../plugin.cpp ../favorites.cpp ../executablesearchpaths.cpp ../systemsignalhandler.cpp ../debugwindow.cpp ../tcrypt.cpp ../favorites.cpp ../openvolume.cpp ../secrets.cpp ../favorites2.cpp ../../zuluMount-gui/oneinstance.cpp ../../zuluMount-gui/monitor_mountinfo.cpp ../../zuluMount-gui/zulumounttask.cpp ../../zuluMount-gui/volumeproperty.cpp ) set( MOC_FILES ../dialogok.h ../dialogmsg.h ../readonlywarning.h ../plugin.h ../utility.h ../debugwindow.h ../tcrypt.h ../utility.h ../openvolume.h ../favorites2.h ../../zuluMount-gui/oneinstance.h ../../zuluMount-gui/monitor_mountinfo.h ) set( UI_FILES ../dialogmsg.ui ../readonlywarning.ui ../plugin.ui ../dialogok.ui ../debugwindow.ui ../tcrypt.ui ../openvolume.ui ../favorites2.ui ../openvolume.ui ) add_definitions( -D_FILE_OFFSET_BITS=64 -Wextra -Wall -pedantic -I${PROJECT_BINARY_DIR}/zuluCrypt-gui/sharedObjects -I${PROJECT_BINARY_DIR}) Qt5_WRAP_UI( UI ${UI_FILES} ) Qt5_WRAP_CPP( MOC ${MOC_FILES} ) Qt5_ADD_RESOURCES( ICON icon.qrc ) add_library( sharedObject STATIC ${MOC} ${SRC} ${UI_FILES} ${ICON} ) if( BUILDKWALLET ) target_link_libraries( sharedObject -lgcrypt lxqt-wallet ${kwallet_library} -lblkid ${Qt5Network_LIBRARIES} mhogomchungu_task ) else() target_link_libraries( sharedObject -lgcrypt lxqt-wallet -lblkid ${Qt5Network_LIBRARIES} mhogomchungu_task ) endif() set_target_properties( sharedObject PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wall -s -fPIC -pthread -pedantic" ) set_target_properties( sharedObject PROPERTIES LINK_FLAGS "-pie" ) zuluCrypt-6.2.0/zuluCrypt-gui/sharedObjects/icon.qrc000066400000000000000000000001471425361753700226010ustar00rootroot00000000000000 ../file.png zuluCrypt-6.2.0/zuluCrypt-gui/showluksslots.cpp000066400000000000000000000170261425361753700220360ustar00rootroot00000000000000/* * * Copyright ( c ) 2020 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "showluksslots.h" #include "ui_showluksslots.h" #include "utility.h" #include "openvolume.h" #include "luksdeletekey.h" #include "luksaddkey.h" #include "bin_path.h" #include "tablewidget.h" #include showLUKSSlots::showLUKSSlots( QWidget * parent,const QString& p,std::function< void() > function ) : QDialog( parent ), m_ui( new Ui::showLUKSSlots ), m_function( std::move( function ) ), m_path( p ), m_parent( parent ) { m_ui->setupUi( this ) ; this->installEventFilter( this ) ; this->setFixedSize( this->size() ) ; this->setFont( parent->font() ) ; m_ui->labelError->setVisible( false ) ; m_ui->pbOK->setVisible( false ) ; m_ui->checkBox->setChecked( utility::showOnlyOccupiedSlots() ) ; m_ui->tableWidget->verticalHeader()->setSectionResizeMode( QHeaderView::ResizeToContents ) ; m_ui->tableWidget->verticalHeader()->setMinimumSectionSize( 30 ) ; m_ui->tableWidget->horizontalHeader()->setStretchLastSection( true ) ; m_ui->pbFile->setIcon( QIcon( ":/file.png" ) ) ; m_ui->pbDevice->setIcon( QIcon( ":/partition.png" ) ) ; m_ui->tableWidget->setContextMenuPolicy( Qt::CustomContextMenu ) ; connect( m_ui->checkBox,&QCheckBox::stateChanged,[ this ]( int s ){ utility::showOnlyOccupiedSlots( s != Qt::Unchecked ) ; this->showData() ; } ) ; connect( m_ui->tableWidget,&QTableWidget::customContextMenuRequested,[ this ]( QPoint s ){ Q_UNUSED( s ) auto item = m_ui->tableWidget->currentItem() ; if( item ){ this->showMenu( item ) ; } } ) ; connect( m_ui->pbOK,&QPushButton::clicked,[ this ](){ m_ui->labelError->setVisible( false ) ; m_ui->pbOK->setVisible( false ) ; this->enableAll() ; } ) ; connect( m_ui->tableWidget,&QTableWidget::itemClicked,[ this ]( QTableWidgetItem * item ){ this->showMenu( item ) ; } ) ; connect( m_ui->tableWidget,&QTableWidget::currentItemChanged, []( QTableWidgetItem * c,QTableWidgetItem * p ){ tablewidget::selectRow( c,p ) ; } ) ; connect( m_ui->pbFile,&QPushButton::clicked,[ this ](){ auto Z = QFileDialog::getOpenFileName( this,tr( "Encrypted LUkS Volume Path" ),utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->lineEdit->setText( Z ) ; m_ui->lineEdit->setFocus() ; this->showData() ; } } ) ; connect( m_ui->pbDevice,&QPushButton::clicked,[ this ](){ this->hide() ; auto& m = openvolume::instance( this,false ) ; m.setOnExit( [ this ](){ this->show() ; } ) ; m.showLuksOnly() ; m.ShowAllPartitions( [ this ]( const QString& e ){ m_ui->lineEdit->setText( e ) ; this->showData() ; } ) ; } ) ; connect( m_ui->pbClose,&QPushButton::clicked,[ this ](){ this->HideUI() ; } ) ; } showLUKSSlots::~showLUKSSlots() { delete m_ui ; } void showLUKSSlots::deleteSlot( QTableWidgetItem * item ) { auto m = utility::split( item->text(),'\n' ).first() ; if( !m.isEmpty() ){ auto mm = utility::split( m,' ' ) ; if( mm.size() > 1 ){ this->hide() ; auto s = m_ui->lineEdit->text() ; luksdeletekey::instance( m_parent ).ShowUI( s,mm.at( 2 ),[ this ](){ this->show() ; this->showData() ; } ) ; } } } void showLUKSSlots::addSlot( QTableWidgetItem * item ) { auto m = utility::split( item->text(),'\n' ).first() ; if( !m.isEmpty() ){ auto mm = utility::split( m,' ' ) ; if( mm.size() > 1 ){ this->hide() ; auto s = m_ui->lineEdit->text() ; luksaddkey::instance( m_parent ).ShowUI( s,mm.at( 2 ),[ this ](){ this->show() ; this->showData() ; } ) ; } } } void showLUKSSlots::showData() { this->disableAll() ; tablewidget::clearTable( m_ui->tableWidget ) ; auto m = m_ui->lineEdit->text() ; auto exe = utility::appendUserUID( "%1 -b -b -d \"%2\"" ) ; auto s = utility::Task::run( exe.arg( ZULUCRYPTzuluCrypt,m ) ).await() ; bool showOnlyOccupiedSlots = utility::showOnlyOccupiedSlots() ; QString tmp ; if( s.success() ){ auto a = utility::split( s.stdOut(),"\n\n" ) ; if( a.isEmpty() ){ m_ui->labelError->setVisible( true ) ; m_ui->pbOK->setVisible( true ) ; m_ui->labelError->setText( "Failed To Get Data From zuluCrypt-cli" ) ; return ; } m_ui->tableWidget->horizontalHeaderItem( 0 )->setText( a.takeAt( 0 ) ) ; for( const auto& it : a ){ auto b = utility::split( it,"\n" ) ; if( b.size() == 2 ){ if( !showOnlyOccupiedSlots ){ tmp = b.at( 0 ) + "\n" + b.at( 1 ) ; } }else if( b.size() > 2 ){ if( b.at( 1 ).contains( "Active" ) ){ tmp = b.at( 0 ) + "\n" + b.at( 1 ) + "\n" + b.at( 2 ) + "\n" + b.at( 3 ) ; for( int i = 4 ; i < b.size() ; i++ ){ if( i % 6 == 0 ){ tmp += "\n" + b.at( i ) ; }else{ tmp += ", " + b.at( i ) ; } } } } if( !tmp.isEmpty() ){ tablewidget::addRow( m_ui->tableWidget,{ tmp } ) ; } tmp.clear() ; } this->enableAll() ; }else{ m_ui->labelError->setVisible( true ) ; m_ui->pbOK->setVisible( true ) ; m_ui->labelError->setText( s.stdOut() ) ; } } void showLUKSSlots::HideUI() { utility::showOnlyOccupiedSlots( m_ui->checkBox->isChecked() ) ; this->hide() ; m_function() ; this->deleteLater() ; } void showLUKSSlots::ShowUI() { if( m_path.isEmpty() ){ this->show() ; }else{ this->show() ; m_ui->lineEdit->setText( m_path ) ; this->showData() ; } } void showLUKSSlots::enableAll() { m_ui->tableWidget->setEnabled( true ) ; m_ui->pbClose->setEnabled( true ) ; m_ui->pbFile->setEnabled( true ) ; m_ui->pbDevice->setEnabled( true ) ; m_ui->lineEdit->setEnabled( true ) ; m_ui->label->setEnabled( true ) ; m_ui->label_2->setEnabled( true ) ; m_ui->checkBox->setEnabled( true ) ; } void showLUKSSlots::disableAll() { m_ui->checkBox->setEnabled( false ) ; m_ui->label_2->setEnabled( false ) ; m_ui->label->setEnabled( false ) ; m_ui->tableWidget->setEnabled( false ) ; m_ui->pbClose->setEnabled( false ) ; m_ui->pbFile->setEnabled( false ) ; m_ui->pbDevice->setEnabled( false ) ; m_ui->lineEdit->setEnabled( false ) ; } void showLUKSSlots::showMenu( QTableWidgetItem * item ) { QMenu m ; auto text = item->text() ; if( text.contains( "Slot Status: Active" ) ){ m.addAction( tr( "Delete Key Slot" ) )->setObjectName( "Delete Key Slot" ) ; }else if( text.contains( "Slot Status: Inactive" ) ){ m.addAction( tr( "Add Key To This Slot" ) )->setObjectName( "Add Key To This Slot" ) ; } m.addAction( tr( "Cancel" ) )->setObjectName( "Cancel" ) ; connect( &m,&QMenu::triggered,[ this,item ]( QAction * ac ){ auto txt = ac->objectName() ; if( txt == "Delete Key Slot" ){ this->deleteSlot( item ) ; }else if( txt == "Add Key To This Slot" ){ this->addSlot( item ) ; } } ) ; m.exec( QCursor::pos() ) ; } void showLUKSSlots::closeEvent( QCloseEvent * e ) { e->ignore() ; this->HideUI() ; } bool showLUKSSlots::eventFilter(QObject * watched, QEvent * event) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } zuluCrypt-6.2.0/zuluCrypt-gui/showluksslots.h000066400000000000000000000033271425361753700215020ustar00rootroot00000000000000/* * * Copyright ( c ) 2020 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef SHOWLUKSSLOTS_H #define SHOWLUKSSLOTS_H #include #include #include #include class QTableWidgetItem ; namespace Ui { class showLUKSSlots; } class showLUKSSlots : public QDialog { Q_OBJECT public: static void Show( QWidget * parent,const QString& path,std::function< void() > function ) { auto m = new showLUKSSlots( parent,path,std::move( function ) ) ; m->ShowUI() ; } explicit showLUKSSlots( QWidget * parent,const QString& path,std::function< void() > ) ; ~showLUKSSlots() ; private: void deleteSlot( QTableWidgetItem * ) ; void addSlot( QTableWidgetItem * ) ; void showData() ; void HideUI() ; void ShowUI() ; void enableAll() ; void disableAll() ; void showMenu( QTableWidgetItem * ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::showLUKSSlots * m_ui ; std::function< void() > m_function ; QString m_path ; QWidget * m_parent ; }; #endif // SHOWLUKSSLOTS_H zuluCrypt-6.2.0/zuluCrypt-gui/showluksslots.ui000066400000000000000000000074571425361753700217000ustar00rootroot00000000000000 showLUKSSlots Qt::ApplicationModal 0 0 824 546 LUKS' Slot Properties 170 480 481 31 650 480 41 33 690 480 41 33 70 350 461 41 Enter Path To A LUKS Volume Below Qt::AlignCenter 70 20 681 401 QAbstractItemView::NoEditTriggers QAbstractItemView::NoSelection Key Slots Status AlignCenter 330 510 161 33 Close 170 450 481 31 Set Volume Path Below Qt::AlignCenter 100 120 621 271 true TextLabel Qt::AlignCenter true 360 340 101 33 OK 170 420 481 31 Show Only Occupied Slots zuluCrypt-6.2.0/zuluCrypt-gui/systemsignalhandler.cpp000066400000000000000000000053331425361753700231500ustar00rootroot00000000000000/* * * Copyright (c) 2018 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "systemsignalhandler.h" #include "utility.h" #include #include #include #include #include #include static int sighupFd[ 2 ] ; static int sigtermFd[ 2 ] ; static void setup_unix_signal_handlers() { struct sigaction hup ; struct sigaction term ; hup.sa_handler = []( int q ){ Q_UNUSED( q ) char a = 1 ; if( ::write( sighupFd[ 0 ],&a,sizeof( a ) ) ){} } ; sigemptyset( &hup.sa_mask ) ; hup.sa_flags = 0 ; hup.sa_flags |= SA_RESTART ; sigaction( SIGHUP,&hup,nullptr ) ; term.sa_handler = []( int q ){ Q_UNUSED( q ) char a = 1 ; if( ::write( sigtermFd[ 0 ],&a,sizeof( a ) ) ){} } ; sigemptyset( &term.sa_mask ) ; term.sa_flags |= SA_RESTART ; sigaction( SIGTERM,&term,nullptr ) ; } systemSignalHandler::systemSignalHandler( QObject * parent ) : m_parent( parent ) { if( !utility::unMountVolumesOnLogout() ){ return ; } setup_unix_signal_handlers() ; ::socketpair( AF_UNIX,SOCK_STREAM,0,sighupFd ) ; ::socketpair(AF_UNIX,SOCK_STREAM,0,sigtermFd ) ; auto snHup = new QSocketNotifier( sighupFd[ 1 ],QSocketNotifier::Read,m_parent ) ; QObject::connect( snHup,&QSocketNotifier::activated,[ snHup,this ]( int ){ #if 1 snHup->setEnabled( false ) ; m_function( signal::hup ) ; #else snHup->setEnabled( false ) ; char tmp ; ::read( sighupFd[ 1 ],&tmp,sizeof( tmp ) ) ; m_function( signal::hup ) ; snHup->setEnabled( true ) ; #endif } ) ; auto snTerm = new QSocketNotifier( sigtermFd[ 1 ],QSocketNotifier::Read,m_parent ) ; QObject::connect( snTerm,&QSocketNotifier::activated,[ snTerm,this ]( int ){ #if 1 snTerm->setEnabled( false ) ; m_function( signal::term ) ; #else snTerm->setEnabled( false ) ; char tmp ; ::read( sighupFd[ 1 ],&tmp,sizeof( tmp ) ) ; m_function( signal::term ) ; snTerm->setEnabled( true ) ; #endif } ) ; } void systemSignalHandler::setAction( std::function< void( signal ) > function ) { m_function = std::move( function ) ; } zuluCrypt-6.2.0/zuluCrypt-gui/systemsignalhandler.h000066400000000000000000000022161425361753700226120ustar00rootroot00000000000000/* * * Copyright (c) 2018 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef HANDLE_SYSTEM_SIGNAL_H #define HANDLE_SYSTEM_SIGNAL_H #include #include class systemSignalHandler { public: enum class signal{ hup,term }; systemSignalHandler( QObject * parent ) ; void setAction( std::function< void( systemSignalHandler::signal ) > ) ; private: QObject * m_parent ; std::function< void( systemSignalHandler::signal ) > m_function ; } ; #endif zuluCrypt-6.2.0/zuluCrypt-gui/tablewidget.cpp000066400000000000000000000127361425361753700213700ustar00rootroot00000000000000/* * * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "tablewidget.h" #include "utility.h" #include #include #include #include using count_t = decltype( QTableWidget().rowCount() ) ; using function_t = std::function< void( count_t,count_t ) > ; static void _for_each_column( QTableWidget * table,count_t row,function_t function ) { if( row >= 0 && row < table->rowCount() ){ count_t col = table->columnCount() ; for( count_t i = 0 ; i < col ; i++ ){ function( row,i ) ; } table->setCurrentCell( row,col - 1 ) ; } } static void _for_each_row( QTableWidget * table,count_t col,function_t function ) { if( col >= 0 && col < table->columnCount() ){ count_t row = table->rowCount() ; for( count_t i = 0 ; i < row ; i++ ){ function( i,col ) ; } } } static void _update_table_row( QTableWidgetItem * item,bool setSelected ) { if( item ){ auto table = item->tableWidget() ; count_t row = item->row() ; count_t col = table->columnCount() ; for( count_t i = 0 ; i < col ; i++ ){ table->item( row,i )->setSelected( setSelected ) ; } if( setSelected ){ table->setCurrentCell( row,col - 1 ) ; } table->setFocus() ; } } static QTableWidgetItem * _set_item( QTableWidgetItem * item, const QString& text = QString(), const QFont& font = QFont() ) { item->setText( text ) ; item->setTextAlignment( Qt::AlignCenter ) ; item->setFont( font ) ; return item ; } void tablewidget::selectRow( QTableWidgetItem * current,QTableWidgetItem * previous ) { if( current && previous && previous->row() == current->row() ){ auto table = current->tableWidget() ; table->setCurrentCell( current->row(),table->columnCount() - 1 ) ; table->setFocus() ; }else{ _update_table_row( current,true ) ; _update_table_row( previous,false ) ; } } int tablewidget::columnHasEntry( QTableWidget * table,const QString& entry,int column ) { if( column < 0 || column >= table->columnCount() ){ return -1 ; }else{ count_t rows = table->rowCount() ; for( count_t i = 0 ; i < rows ; i++ ){ if( table->item( i,column )->text() == entry ){ return i ; } } return -1 ; } } void tablewidget::addRow( QTableWidget * table,const QStringList& l,const QFont& font ) { count_t row = table->rowCount() ; table->insertRow( row ) ; _for_each_column( table,row,[ & ]( count_t row,count_t col ){ table->setItem( row,col,_set_item( new QTableWidgetItem,l.at( col ),font ) ) ; } ) ; } int tablewidget::addRow( QTableWidget * table ) { count_t row = table->rowCount() ; table->insertRow( row ) ; _for_each_column( table,row,[ table ]( count_t row,count_t col ){ table->setItem( row,col,_set_item( new QTableWidgetItem ) ) ; } ) ; return row ; } void tablewidget::updateRow( QTableWidget * table,const QStringList& list,int row,const QFont& font ) { _for_each_column( table,row,[ & ]( count_t row,count_t col ){ _set_item( table->item( row,col ),list.at( col ),font ) ; } ) ; } void tablewidget::setFont( QTableWidget * table ,int row,const QFont& font ) { _for_each_column( table,row,[ & ]( count_t row,count_t col ){ table->item( row,col )->setFont( font ) ; } ) ; } void tablewidget::deleteRow( QTableWidget * table,int row ) { if( row >= 0 && row < table->rowCount() ){ table->removeRow( row ) ; tablewidget::selectLastRow( table ) ; } } void tablewidget::deleteRow( QTableWidget * table,const QString& value,int column ) { tablewidget::deleteRow( table,tablewidget::columnHasEntry( table,value,column ) ) ; } void tablewidget::selectRow( QTableWidget * table,int row ) { if( row >= 0 && row < table->rowCount() ){ table->setCurrentCell( row,table->columnCount() - 1 ) ; } table->setFocus() ; } void tablewidget::selectRow( QTableWidget * table,const QString& e,int column ) { tablewidget::selectRow( table,tablewidget::columnHasEntry( table,e,column ) ) ; } void tablewidget::selectLastRow( QTableWidget * table ) { tablewidget::selectRow( table,table->rowCount() - 1 ) ; } QStringList tablewidget::columnEntries( QTableWidget * table,int col ) { QStringList l ; _for_each_row( table,col,[ & ]( count_t row,count_t col ){ l.append( table->item( row,col )->text() ) ; } ) ; return l ; } QStringList tablewidget::rowEntries( QTableWidget * table,int row ) { QStringList l ; _for_each_column( table,row,[ & ]( count_t row,count_t col ){ l.append( table->item( row,col )->text() ) ; } ) ; return l ; } void tablewidget::clearTable( QTableWidget * table ) { auto j = table->rowCount() ; for( decltype( j ) i = 0 ; i < j ; i++ ){ table->removeRow( 0 ) ; } } void tablewidget::setRowToolTip( QTableWidget * table,int row,const QString& tooltip ) { _for_each_column( table,row,[ & ]( count_t row,count_t col ){ table->item( row,col )->setToolTip( tooltip ) ; } ) ; } zuluCrypt-6.2.0/zuluCrypt-gui/tablewidget.h000066400000000000000000000034721425361753700210320ustar00rootroot00000000000000/* * * Copyright ( c ) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef TABLEWIDGET_H #define TABLEWIDGET_H #include #include #include #include class QTableWidget ; class QTableWidgetItem ; namespace tablewidget { void selectRow( QTableWidgetItem * current,QTableWidgetItem * previous ) ; void selectRow( QTableWidget *,int row ) ; void selectRow( QTableWidget *,const QString&,int column = 0 ) ; void selectLastRow( QTableWidget * ) ; void addRow( QTableWidget *,const QStringList&,const QFont& = QFont() ) ; int addRow( QTableWidget * ) ; void updateRow( QTableWidget *,const QStringList&,int row,const QFont& ) ; void setFont( QTableWidget *,int row,const QFont& ) ; void deleteRow( QTableWidget *,int row ) ; void deleteRow( QTableWidget *,const QString&,int = 0 ) ; int columnHasEntry( QTableWidget *,const QString&,int = 0 ) ; QStringList columnEntries( QTableWidget * table,int = 0 ) ; QStringList rowEntries( QTableWidget * table,int = 0 ) ; void clearTable( QTableWidget * ) ; void setRowToolTip( QTableWidget *,int row,const QString& ) ; } #endif // TABLEWIDGET_H zuluCrypt-6.2.0/zuluCrypt-gui/tcrypt.cpp000066400000000000000000000066601425361753700204210ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "dialogmsg.h" #include "tcrypt.h" #include "ui_tcrypt.h" #include "tablewidget.h" #include #include #include #include #include #include #include tcrypt::tcrypt( QWidget * parent,bool e, std::function< void( const QString&,const QStringList& ) > p, std::function< void() > q ) : QDialog( parent ),m_ui( new Ui::tcrypt ),m_success( std::move( p ) ),m_cancelled( std::move( q ) ) { m_ui->setupUi( this ) ; this->setFixedSize( this->size() ) ; connect( m_ui->pbSend,SIGNAL( clicked() ),this,SLOT( pbSend() ) ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->pbAddKeyFile,SIGNAL( clicked() ),this,SLOT( pbAddKeyFIle() ) ) ; connect( m_ui->tableWidget,SIGNAL( currentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ), this,SLOT(currentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ) ) ; connect( m_ui->tableWidget,SIGNAL( itemClicked( QTableWidgetItem * ) ), this,SLOT( itemClicked( QTableWidgetItem * ) ) ) ; this->installEventFilter( this ) ; m_ui->tableWidget->setColumnWidth( 0,426 ) ; if( e ){ m_ui->pbSend->setText( tr( "&Set" ) ) ; } this->setWindowTitle( tr( "TrueCrypt/VeraCrypt Keys" ) ) ; this->show() ; } void tcrypt::currentItemChanged( QTableWidgetItem * current,QTableWidgetItem * previous ) { tablewidget::selectRow( current,previous ) ; } void tcrypt::itemClicked( QTableWidgetItem * item ) { Q_UNUSED( item ) } bool tcrypt::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void tcrypt::HideUI() { this->hide() ; this->deleteLater() ; } void tcrypt::closeEvent( QCloseEvent * e ) { e->ignore() ; this->HideUI() ; } void tcrypt::dragEnterEvent( QDragEnterEvent * e ) { e->accept() ; } void tcrypt::dropEvent( QDropEvent * e ) { for( const auto& it : e->mimeData()->urls() ){ tablewidget::addRow( m_ui->tableWidget,{ it.path() } ) ; } } void tcrypt::pbSend() { auto l = tablewidget::columnEntries( m_ui->tableWidget ) ; if( l.isEmpty() ){ DialogMsg msg( this ) ; msg.ShowUIOK( tr( "ERROR" ),tr( "At least one keyfile is required" ) ) ; }else{ /* * we call hide() because the GUI doesnt seem to hide when called later on in HideUI() */ this->hide() ; m_success( m_ui->lineEdit->text(),l ) ; this->HideUI() ; } } void tcrypt::pbCancel() { m_cancelled() ; this->HideUI() ; } void tcrypt::pbAddKeyFIle() { auto e = QFileDialog::getOpenFileName( this,tr( "Select A KeyFile" ),utility::homePath() ) ; if( !e.isEmpty() ){ tablewidget::addRow( m_ui->tableWidget,{ e } ) ; } } tcrypt::~tcrypt() { delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/tcrypt.h000066400000000000000000000040051425361753700200550ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef TCRYPT_H #define TCRYPT_H #include #include "utility.h" class QCloseEvent ; class QTableWidgetItem ; #include #include #include #include #include #include namespace Ui { class tcrypt; } class tcrypt : public QDialog { Q_OBJECT public: static tcrypt& instance( QWidget * parent, bool b, std::function< void( const QString&,const QStringList& ) > e, std::function< void() > f ) { return *( new tcrypt( parent,b,std::move( e ),std::move( f ) ) ) ; } tcrypt( QWidget * parent, bool, std::function< void( const QString&,const QStringList& ) >, std::function< void() > ) ; ~tcrypt() ; private slots: void currentItemChanged( QTableWidgetItem * current,QTableWidgetItem * previous ) ; void itemClicked ( QTableWidgetItem * item ) ; void dragEnterEvent( QDragEnterEvent * e ) ; void dropEvent( QDropEvent * ) ; void pbSend( void ) ; void pbCancel( void ) ; void pbAddKeyFIle( void ) ; private: void HideUI( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::tcrypt * m_ui ; std::function< void( const QString&,const QStringList& ) > m_success ; std::function< void() > m_cancelled ; }; #endif // TCRYPT_H zuluCrypt-6.2.0/zuluCrypt-gui/tcrypt.ui000066400000000000000000000075121425361753700202510ustar00rootroot00000000000000 tcrypt 0 0 623 382 true TrueCrypt Keys 110 350 101 31 &Open 410 350 101 31 &Cancel 90 320 441 31 QLineEdit::Password 210 350 201 31 Add &Keyfile 90 50 441 231 true drag and drop key files to add them to the list QAbstractItemView::NoEditTriggers false false false QAbstractItemView::NoDragDrop QAbstractItemView::NoSelection QAbstractItemView::SelectRows Qt::NoPen Keyfile Paths drag and drop key files to add them to the list AlignCenter 10 5 601 41 Enter key files below to be used to open the volume Qt::AlignCenter true 10 280 601 41 Enter A Passphrase Below To Be Used To Open The Volume Qt::AlignCenter true zuluCrypt-6.2.0/zuluCrypt-gui/utility.cpp000066400000000000000000001764721425361753700206100ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../zuluCrypt-cli/constants.h" #include "../zuluCrypt-cli/bin/bash_special_chars.h" #include "version.h" #include "locale_path.h" #include "mount_prefix_path.h" #include "dialogmsg.h" #include "support_whirlpool.h" #include "readonlywarning.h" #include "../plugins/plugins.h" #include "plugin.h" #include "install_prefix.h" #include "utility.h" #include "executablesearchpaths.h" #include "zuluPolkit.h" #include "luks_slot_status.h" #include "cryptsetup_library_path.h" #include #include #include #include #include #include "../zuluCrypt-cli/pluginManager/libzuluCryptPluginManager.h" #include "../zuluCrypt-cli/utility/process/process.h" #include "plugin_path.h" #include "../zuluCrypt-cli/utility/process/process.h" #include "reuse_mount_point.h" #include "share_mount_prefix_path.h" #include "zuluPolkit.h" #include "favorites.h" struct jsonResult { bool finished ; int exitCode ; int exitStatus ; QByteArray stdError ; QByteArray stdOut ; }; static std::function< void() > _failed_to_connect_to_zulupolkit ; static QSettings * _settings ; static debugWindow * _debugWindow ; static QWidget * _mainWindow ; static void _post_backend_cmd( const QString& b ) { QString a = "***************************\n" ; QString c = "\n***************************" ; _debugWindow->UpdateOutPut( a + b + c,false ) ; } void utility::setDebugWindow( debugWindow * w ) { _debugWindow = w ; } void utility::mainWindowWidget( QWidget * e ) { _mainWindow = e ; } QWidget * utility::mainWindowWidget() { return _mainWindow ; } std::unique_ptr< utility::RandomDataSource > utility::RandomDataSource::get( utility::RandomDataSource::types type ) { if( type == utility::RandomDataSource::types::urandom ){ return std::make_unique< utility::UrandomDataSource >() ; }else{ return std::make_unique< utility::CRandDataSource >() ; } } utility::RandomDataSource::~RandomDataSource() { } static QByteArray _json_command( const QByteArray& cookie, const QByteArray& password, const QString& exe, const QString& path = QString(), const QByteArray& data = QByteArray() ) { QJsonObject obj ; obj.insert( "cookie",cookie.constData() ) ; obj.insert( "password",password.constData() ) ; obj.insert( "command",exe.toLatin1().constData() ) ; obj.insert( "path",path.toLatin1().constData() ) ; obj.insert( "data",data.constData() ) ; return QJsonDocument( obj ).toJson( QJsonDocument::JsonFormat::Indented ) ; } static jsonResult _json_result( const QByteArray& e ) { if( !e.isEmpty() ){ QJsonParseError error ; auto doc = QJsonDocument::fromJson( e,&error ) ; if( error.error == QJsonParseError::NoError ){ auto obj = doc.object() ; return { obj.value( "finished" ).toBool(), obj.value( "exitCode" ).toInt(), obj.value( "exitStatus" ).toInt(), obj.value( "stdError" ).toString().toUtf8(), obj.value( "stdOut" ).toString().toUtf8() } ; } } return { false,255,255,"","" } ; } static bool _connected( QLocalSocket& s ) { s.connectToServer( utility::helperSocketPath() ) ; for( int i = 0 ; ; i++ ){ if( s.waitForConnected() ){ return true ; }else if( i == 2 ){ utility::debug() << "ERROR: Failed To Connect To zuluPolkit" ; break ; }else{ utility::debug() << s.errorString() ; utility::Task::suspendForOneSecond() ; } } return false ; } static QByteArray _cookie ; static bool _run_through_polkit ; ::Task::future< utility::Task >& utility::Task::run( const QString& exe,USEPOLKIT e ) { return utility::Task::run( exe,-1,e ) ; } ::Task::future< utility::Task >& utility::Task::run( const QString& exe,int s,USEPOLKIT e ) { return ::Task::run( [ = ](){ auto env = QProcessEnvironment::systemEnvironment() ; return utility::Task( exe,s,env,_cookie,[](){ umask( 0 ) ; },e ) ; } ) ; } void utility::polkitFailedWarning( std::function< void() > e ) { _failed_to_connect_to_zulupolkit = std::move( e ) ; } void utility::Task::execute( const QString& exe, int waitTime, const QProcessEnvironment& env, const QByteArray& password, std::function< void() > f, USEPOLKIT polkit ) { if( polkit == USEPOLKIT::True && utility::useZuluPolkit() ){ QLocalSocket s ; if( _connected( s ) ){ _post_backend_cmd( exe ) ; s.write( _json_command( _cookie,password,exe ) ) ; s.waitForBytesWritten() ; s.waitForReadyRead( -1 ) ; auto e = _json_result( s.readAll() ) ; m_finished = e.finished ; m_exitCode = e.exitCode ; m_exitStatus = e.exitStatus ; m_stdError = e.stdError ; m_stdOut = e.stdOut ; }else{ _failed_to_connect_to_zulupolkit() ; m_finished = false ; m_exitCode = -1 ; m_exitStatus = -1 ; m_stdError = "" ; m_stdOut = QObject::tr( "zuluCrypt: Failed To Establish Connection With zuluPolkit" ).toLatin1() ; } }else{ _post_backend_cmd( exe ) ; #if QT_VERSION < QT_VERSION_CHECK( 5,15,0 ) auto p = ::Task::process::run( exe,{},waitTime,password,env,std::move( f ) ).get() ; #else auto s = QProcess::splitCommand( exe ) ; auto ee = s.first() ; s.removeFirst() ; auto p = ::Task::process::run( ee,s,waitTime,password,env,std::move( f ) ).get() ; #endif m_finished = p.finished() ; m_exitCode = p.exit_code() ; m_exitStatus = p.exit_status() ; m_stdOut = p.std_out() ; m_stdError = p.std_error() ; } } void utility::setDefaultEnvironment() { } QString utility::passwordSocketPath() { return "/tmp/zuluCrypt-" + QString::number( getuid() ) ; } #if QT_VERSION > QT_VERSION_CHECK( 5,0,0 ) #include QString utility::socketPath() { return QStandardPaths::writableLocation( QStandardPaths::RuntimeLocation ) ; } #else #include QString utility::socketPath() { return QDesktopServices::storageLocation( QDesktopServices::DataLocation ) ; } #endif void utility::setSettingsObject( QSettings * e ) { _settings = e ; } QSettings& utility::settingsObject() { return *_settings ; } static QString zuluPolkitExe() { auto exe = utility::executableFullPath( "pkexec" ) ; if( exe.isEmpty() ){ return QString() ; }else{ return QString( "%1 %2 %3 fork" ).arg( exe,zuluPolkitPath,utility::helperSocketPath() ) ; } } static ::Task::future< utility::Task >& _start_zulupolkit( const QString& e ) { utility::UrandomDataSource randSource ; if( randSource.open() ){ _cookie = randSource.getData( 16 ).toHex() ; }else{ _cookie = utility::CRandDataSource().getData( 16 ).toHex() ; } return ::Task::run( [ = ]{ return utility::Task( e, -1, utility::systemEnvironment(), _cookie, [](){}, utility::Task::USEPOLKIT::False ) ; } ) ; } static bool _enable_polkit_support( const QString& m ) { struct stat st ; if( m == "zuluCrypt" ){ stat( ZULUCRYPTzuluCrypt,&st ) ; }else{ stat( zuluMountPath,&st ) ; } bool s = st.st_mode & S_ISUID ; return !s ; } void utility::startHelperExecutable( QObject * obj,const QString& arg,const QString& exe, const char * slot,const char * slot1 ) { if( _enable_polkit_support( exe ) ){ auto exe = zuluPolkitExe() ; if( !exe.isEmpty() ){ _start_zulupolkit( exe ).then( [ = ]( const utility::Task& e ){ _run_through_polkit = e.success() ; QMetaObject::invokeMethod( obj, slot, Q_ARG( bool,e.success() ), Q_ARG( QString,arg ) ) ; } ) ; }else{ DialogMsg().ShowUIOK( QObject::tr( "ERROR" ), QObject::tr( "Failed to locate pkexec executable" ) ) ; QMetaObject::invokeMethod( obj,slot1 ) ; } }else{ QMetaObject::invokeMethod( obj,slot,Q_ARG( bool,true ),Q_ARG( QString,arg ) ) ; } } QString utility::helperSocketPath() { auto a = QString::number( getuid() ) ; auto b = QCoreApplication::applicationName() ; return QString( "/tmp/zuluCrypt-%1/%2.polkit.socket" ).arg( a,b ) ; } bool utility::useZuluPolkit() { return _run_through_polkit ; } bool utility::requireSystemPermissions( const QString& e,utility::background_thread thread ) { const char * exe ; const char * group ; if( QCoreApplication::applicationName() == "zuluCrypt" ){ exe = ZULUCRYPTzuluCrypt" -S" ; group = "zulucrypt" ; }else{ exe = zuluMountPath" -S" ; group = "zulumount" ; } auto s = [ & ](){ if( thread == utility::background_thread::True ){ return utility::Task::run( exe ).get().stdOut() ; }else{ return utility::Task::run( exe ).await().stdOut() ; } }() ; if( utility::split( s ).contains( e ) ){ if( utility::userBelongsToGroup( group ) ){ return false ; }else{ return true ; } }else{ return false ; } } bool utility::enablePolkit( utility::background_thread thread ) { if( _run_through_polkit ){ return true ; } auto exe = zuluPolkitExe() ; if( !exe.isEmpty() ){ auto socketPath = utility::helperSocketPath() ; if( thread == utility::background_thread::True ){ if( _start_zulupolkit( exe ).get().success() ){ _run_through_polkit = true ; while( !utility::pathExists( socketPath ) ){ utility::Task::waitForOneSecond() ; } } }else{ if( _start_zulupolkit( exe ).await().success() ){ _run_through_polkit = true ; while( !utility::pathExists( socketPath ) ){ utility::Task::suspendForOneSecond() ; } } } } return _run_through_polkit ; } void utility::quitHelper() { auto e = utility::helperSocketPath() ; if( utility::pathExists( e ) ){ QLocalSocket s ; s.connectToServer( e ) ; if( s.waitForConnected() ){ s.write( _json_command( _cookie,"","exit" ) ) ; s.waitForBytesWritten() ; } } } std::pair< bool,QByteArray > utility::privilegedReadConfigFile( const QString& path ) { if( utility::enablePolkit( utility::background_thread::False ) ){ QLocalSocket s ; if( _connected( s ) ){ s.write( _json_command( _cookie,QByteArray(),"Read",path ) ) ; s.waitForBytesWritten() ; s.waitForReadyRead() ; return { true,_json_result( s.readAll() ).stdOut } ; } } return { false,QByteArray() } ; } void utility::privilegedWriteConfigFile( const QByteArray& data,const QString& path ) { if( utility::enablePolkit( utility::background_thread::False ) ){ QLocalSocket s ; if( _connected( s ) ){ s.write( _json_command( _cookie,QByteArray(),"Write",path,data ) ) ; s.waitForBytesWritten() ; } } } bool utility::reUseMountPointPath() { return REUSE_MOUNT_POINT ; } bool utility::reUseMountPoint() { return utility::reUseMountPointPath() ; } int utility::getUID() { return static_cast< int >( getuid() ) ; } int utility::getUserID() { return utility::getUID() ; } int utility::getGUID( int uid ) { auto e = getpwuid( static_cast< uid_t >( uid ) ) ; if( e ){ return static_cast< int >( e->pw_gid ) ; }else{ return uid ; } } QString utility::getStringUserID() { return QString::number( utility::getUserID() ) ; } QString utility::appendUserUID( const QString& e ) { if( utility::useZuluPolkit() ){ return e + " -K " + utility::getStringUserID() ; }else{ return e ; } } static passwd * _getPassWd() { return getpwuid( static_cast< uid_t >( utility::getUserID() ) ) ; } QString utility::userName() { return _getPassWd()->pw_name ; } QString utility::homePath() { return getpwuid( static_cast< uid_t >( utility::getUserID() ) )->pw_dir ; } static int _help() { std::cout << "\n" << VERSION_STRING << std::endl ; QString helpMsg = QObject::tr( "\n\ options:\n\ -d path to where a volume to be auto unlocked/mounted is located\n\ -m tool to use to open a default file manager(default tool is xdg-open)\n\ -e start the application without showing the GUI\n" ) ; std::cout << helpMsg.toLatin1().constData() << std::endl ; return 0 ; } static bool _printHelpOrVersionInfo() { QStringList q = QCoreApplication::arguments() ; return q.contains( "-h" ) || q.contains( "-help" ) || q.contains( "--help" ) || q.contains( "-v" ) || q.contains( "-version" ) || q.contains( "--version" ) ; } int utility::startApplication( const char * appName,std::function start ) { QCoreApplication::setApplicationName( appName ) ; if( _printHelpOrVersionInfo() ){ return _help() ; }else{ return start() ; } } void utility::startApplication( QObject * s,const char * e ) { QMetaObject::invokeMethod( s,e,Qt::QueuedConnection ) ; } void utility::keySend( const QString& path,const QByteArray& key ) { ::Task::exec( [ path,key ](){ auto handle = ::zuluCryptPluginManagerOpenConnection( path.toLatin1().constData() ) ; if( handle ){ size_t size = static_cast< size_t >( key.size() ) ; /* * ZULUCRYPT_KEYFILE_MAX_SIZE is defined in ../zuluCrypt-cli/constants.h * The variable holds the maximum keyfile size */ if( size > ZULUCRYPT_KEYFILE_MAX_SIZE ){ size = ZULUCRYPT_KEYFILE_MAX_SIZE ; } ::zuluCryptPluginManagerSendKey( handle,key.constData(),size ) ; ::zuluCryptPluginManagerCloseConnection( handle ) ; } } ) ; } void utility::keySend( const QString& keyPath,const QString& key ) { utility::keySend( keyPath,key.toLatin1() ) ; } void utility::addPluginsToMenu( QMenu& menu ) { QStringList e ; QDir dir( ZULUCRYPTpluginPath ) ; if( dir.exists() ){ e = dir.entryList() ; e.removeOne( "zuluCrypt-testKey" ) ; e.removeOne( "." ) ; e.removeOne( ".." ) ; e.removeOne( "keyring" ) ; e.removeOne( "kwallet" ) ; } auto _add_actions = [ &menu ]( const QStringList& r ){ for( const auto& it : r ){ menu.addAction( it )->setObjectName( it ) ; } } ; _add_actions( e ) ; } ::Task::future& utility::exec( const QString& exe ) { return ::Task::run( [ exe ](){ return utility::Task( exe ).exitCode() ; } ) ; } ::Task::future& utility::luksEmptySlots( const QString& volumePath ) { return ::Task::run( [ volumePath ](){ auto e = utility::appendUserUID( "%1 -b -d \"%2\"" ) ; auto r = utility::Task( e.arg( ZULUCRYPTzuluCrypt,volumePath ) ) ; if( r.success() ){ const auto& s = r.stdOut() ; int i = 0 ; for( const auto& it : s ){ if( it == '1' || it == '3' ){ i++ ; } } return QStringList{ QString::number( i ),QString::number( s.size() - 1 ) } ; } return QStringList() ; } ) ; } ::Task::future& utility::getUUIDFromPath( const QString& dev ) { return ::Task::run( [ dev ](){ auto device = dev ; device = device.replace( "\"", "\"\"\"" ) ; auto exe = utility::appendUserUID( "%1 -U -d \"%2\"" ).arg( ZULUCRYPTzuluCrypt,device ) ; auto r = utility::Task( exe ) ; if( r.success() ){ QString uuid = r.stdOut() ; uuid.remove( "\n" ) ; if( uuid == "UUID=\"\"" ){ return QString() ; }else{ return uuid ; } }else{ return QString() ; } } ) ; } ::Task::future& utility::openPath( const QString& path,const QString& opener ) { return ::Task::run( [ = ](){ auto e = opener + " " + utility::Task::makePath( path ) ; return utility::Task::run( e,utility::Task::USEPOLKIT::False ).get().failed() ; } ) ; } void utility::openPath( const QString& path,const QString& opener, QWidget * obj,const QString& title,const QString& msg ) { openPath( path,opener ).then( [ title,msg,obj ]( bool failed ){ if( failed && obj ){ DialogMsg m( obj ) ; m.ShowUIOK( title,msg ) ; } } ) ; } static ::Task::future& _getKey( LXQt::Wallet::Wallet& wallet,const QString& volumeID ) { return ::Task::run( [ & ]()->QString{ decltype( wallet.readValue( volumeID ) ) key ; if( volumeID.startsWith( "UUID=" ) ){ key = wallet.readValue( volumeID ) ; }else{ auto uuid = utility::getUUIDFromPath( volumeID ).get() ; if( uuid.isEmpty() ){ key = wallet.readValue( utility::getVolumeID( volumeID ) ) ; }else{ key = wallet.readValue( uuid ) ; if( key.isEmpty() ){ key = wallet.readValue( volumeID ) ; } } } return key ; } ) ; } utility::wallet utility::getKey( LXQt::Wallet::Wallet& wallet,const QString& keyID,const QString& app ) { utility::wallet w{ false,false,"" } ; auto s = wallet.backEnd() ; if( s == LXQt::Wallet::BackEnd::kwallet || s == LXQt::Wallet::BackEnd::libsecret ){ if( s == LXQt::Wallet::BackEnd::kwallet ){ w.opened = wallet.open( "default",utility::applicationName() ) ; }else{ w.opened = wallet.open( utility::walletName(),utility::applicationName() ) ; } if( w.opened ){ w.key = _getKey( wallet,keyID ).await() ; } }else if( s == LXQt::Wallet::BackEnd::internal ){ auto walletName = utility::walletName() ; auto appName = utility::applicationName() ; if( LXQt::Wallet::walletExists( s,walletName,appName ) ){ wallet.setImage( utility::getIcon( app ) ) ; if( wallet.opened() ){ w.opened = true ; }else{ w.opened = wallet.open( walletName,appName ) ; } if( w.opened ){ w.key = _getKey( wallet,keyID ).await() ; w.notConfigured = false ; } }else{ w.notConfigured = true ; } } return w ; } static quint64 _volumeSize( const QString& e,size_t size ) { utility::fileHandle h ; if( size == 0 ){ if( h.open( e ) ){ return h.size() ; }else{ return 0 ; } }else{ return size ; } } static int _openVolume( const QString& e ) { return open( e.toLatin1().constData(),O_RDWR ) ; } static std::function< void( int ) > _closeFunction( const QString& e ) { return [ & ]( int fd ){ if( fd != -1 ){ for( int i = 0 ; i < 5 ; i++ ){ if( close( fd ) == 0 ){ utility::Task( utility::appendUserUID( "%1 -q -d \"%2\"" ).arg( ZULUCRYPTzuluCrypt,e ) ) ; break ; } } } } ; } static bool _writeToVolume( int fd,std::array< char,1024 >& buffer ) { return write( fd,buffer.data(),buffer.size() ) != -1 ; } ::Task::future< int >& utility::clearVolume( const QString& volume, std::atomic_bool * exit, size_t volumeSize, std::function< void( quint64 size,quint64 offset ) > function ) { return ::Task::run( [ volume,exit,volumeSize,function ](){ auto volumePath = volume ; volumePath.replace( "\"","\"\"\"" ) ; auto a = utility::appendUserUID( "%1 -k -J -d \"%2\"" ).arg( ZULUCRYPTzuluCrypt,volumePath ) ; int r = utility::Task( a ).exitCode() ; if( r != 0 ){ return r ; }else{ auto volumeMapperPath = utility::mapperPath( volume ) ; utility::fileHandle f( _openVolume( volumeMapperPath ),_closeFunction( volumePath ) ) ; int fd = f.handle() ; if( fd == -1 ){ return 1 ; }else{ std::array< char,1024 > buffer ; quint64 size = _volumeSize( volumeMapperPath,volumeSize ) ; quint64 size_written = 0 ; if( size == 0 ){ return 0 ; } while( _writeToVolume( fd,buffer ) ){ if( *exit ){ /* * erasedevice::taskResult() has info on why we return 5 here. */ return 5 ; }else{ size_written += buffer.size() ; function( size,size_written ) ; if( size_written >= size ){ break ; } } } } return 0 ; } } ) ; } QString utility::cryptMapperPath() { //return QString( crypt_get_dir() ) return "/dev/mapper/" ; } bool utility::userIsRoot() { return getuid() == 0 ; } QString utility::shareMountPointToolTip() { QString x ; #if USE_HOME_PATH_AS_MOUNT_PREFIX x = QDir::homePath() + "/" ; #else x = "/run/media/private/" ; #endif return QObject::tr( "\ If the option is checked,a primary private mount point will be created in \"%1\"\n\ and a secondary publicly accessible \"mirror\" mount point will be created in \"%2\"" ).arg( x,SHARE_MOUNT_PREFIX "/" ) ; } QString utility::shareMountPointToolTip( const QString& path ) { auto s = QString( SHARE_MOUNT_PREFIX "/" ) + path.split( "/" ).last() ; if( QFile::exists( s ) ){ return QObject::tr( "public mount point: " ) + s ; }else{ return QString() ; } } QString utility::sharedMountPointPath( const QString& path ) { if( path == "/" ){ return QString() ; }else{ auto s = SHARE_MOUNT_PREFIX "/" + path.split( "/" ).last() ; if( QFile::exists( s ) ){ return s ; }else{ return QString() ; } } } bool utility::pathPointsToAFile( const QString& path ) { utility::fileHandle h ; if( h.open( path ) ){ return h.isFile() ; }else{ return false ; } } bool utility::pathPointsToAFolder( const QString& path ) { utility::fileHandle h ; if( h.open( path ) ){ return h.isFolder() ; }else{ return false ; } } bool utility::useDmCryptForRandomData() { if( !_settings->contains( "UseDmCryptForRandomData" ) ){ _settings->setValue( "UseDmCryptForRandomData",false ) ; } return _settings->value( "UseDmCryptForRandomData" ).toBool() ; } QString utility::localizationLanguage( const QString& program ) { Q_UNUSED( program ) if( _settings->contains( "LocalizationLanguage" ) ){ return _settings->value( "LocalizationLanguage" ).toString() ; }else{ _settings->setValue( "LocalizationLanguage","en_US" ) ; return "en_US" ; } } void utility::setLocalizationLanguage( const QString& program,const QString& language ) { Q_UNUSED( program ) _settings->setValue( "LocalizationLanguage",language ) ; } QString utility::localizationLanguagePath( const QString& program ) { return QString( TRANSLATION_PATH ) + program ; } QString utility::walletName() { return "zuluCrypt" ; } QString utility::applicationName() { return "zuluCrypt" ; } bool utility::pathIsReadable( const QString& path,bool isFolder ) { QFileInfo s( path ) ; if( isFolder ){ return s.isReadable() && s.isDir() ; }else{ return s.isReadable() && s.isFile() ; } } bool utility::pathIsWritable( const QString& path,bool isFolder ) { QFileInfo s( path ) ; if( isFolder ){ return s.isWritable() && s.isDir() ; }else{ return s.isWritable() && s.isFile() ; } } bool utility::configDirectoriesAreNotWritable( QWidget * w ) { auto a = utility::socketPath() ; auto b = utility::passwordSocketPath() ; QDir().mkpath( b ) ; utility::changePathOwner( b ) ; utility::changePathPermissions( b,0700 ) ; if( utility::pathIsWritable( a ) && utility::pathIsWritable( b ) ){ return false ; }else{ auto e = QObject::tr( "\"%1\" and \"%2\" Folders Must Be Writable." ).arg( a,b ) ; DialogMsg( w ).ShowUIOK( QObject::tr( "ERROR" ),e ) ; return true ; } } bool utility::setOpenVolumeReadOnly( QWidget * parent,bool checked,const QString& app ) { return readOnlyWarning::showWarning( parent,checked,app ) ; } bool utility::getOpenVolumeReadOnlyOption( const QString& app ) { return readOnlyWarning::getOpenVolumeReadOnlyOption( app ) ; } QString utility::keyPath() { utility::UrandomDataSource randomSource ; QByteArray data ; if( randomSource.open() ){ data = randomSource.getData( 64 ) ; }else{ data = utility::CRandDataSource().getData( 64 ) ; } QString a = utility::passwordSocketPath() ; return QString( "%1/%2" ).arg( a,utility::hashPath( data ).mid( 1 ) ) ; } bool utility::eventFilter( QObject * gui,QObject * watched,QEvent * event,std::function< void() > function ) { if( watched == gui ){ if( event->type() == QEvent::KeyPress ){ auto keyEvent = static_cast< QKeyEvent* >( event ) ; if( keyEvent->key() == Qt::Key_Escape ){ function() ; return true ; } } } return false ; } QStringList utility::split( const QString& str,char token ) { if( str.isEmpty() ){ return {} ; } #if QT_VERSION < QT_VERSION_CHECK( 5,15,0 ) return str.split( token,QString::SkipEmptyParts ) ; #else return str.split( token,Qt::SkipEmptyParts ) ; #endif } QStringList utility::split( const QByteArray& str,char token ) { return utility::split( QString( str ),token ) ; } QStringList utility::split( const QByteArray& str,const char * token ) { return utility::split( QString( str ),token ) ; } QStringList utility::split( const QString& str,const char * token ) { if( str.isEmpty() ){ return {} ; } #if QT_VERSION < QT_VERSION_CHECK( 5,15,0 ) return str.split( token,QString::SkipEmptyParts ) ; #else return str.split( token,Qt::SkipEmptyParts ) ; #endif } bool utility::mapperPathExists( const QString& path ) { return utility::pathExists( utility::mapperPath( path ) ) ; } QString utility::mountPath( const QString& path ) { auto pass = _getPassWd() ; #if USE_HOME_PATH_AS_MOUNT_PREFIX return QString( "%1/%2" ).arg( QString( pass->pw_dir ) ).arg( path ) ; #else return QString( "/run/media/private/%1/%2" ).arg( QString( pass->pw_dir ).split( "/" ).last(),path ) ; #endif } QString utility::homeMountPath( const QString& path ) { return QString( "%1/%2" ).arg( _getPassWd()->pw_dir,path ) ; } QString utility::mountPathPostFix( const QString& path ) { if( path.isEmpty() ){ return path ; }else{ auto _usable_mount_point = []( const QString& e ){ if( utility::reUseMountPointPath() ){ if( utility::pathExists( e ) ){ return utility::pathPointsToAFolder( e ) ; }else{ return true ; } }else{ return !utility::pathExists( e ) ; } } ; auto e = utility::mountPath( path ) ; if( _usable_mount_point( e ) ){ return path ; }else{ QString z ; for( int i = 1 ; i < 1000 ; i++ ){ z = QString::number( i ) ; if( _usable_mount_point( QString( "%1_%2" ).arg( e,z ) ) ){ return QString( "%1_%2" ).arg( path,z ) ; } } return path ; } } } QString utility::mapperPath( const QString& r,const QString& component ) { auto rpath = r ; auto path = utility::cryptMapperPath() + "zuluCrypt-" + utility::getStringUserID() ; if( rpath.startsWith( "UUID=" ) ){ rpath.remove( '\"' ) ; rpath.replace( "UUID=","UUID-" ) ; path += "-" + rpath + utility::hashPath( rpath.toLatin1() ) ; }else{ if( component.isEmpty() ){ path += "-NAAN-" + rpath.split( "/" ).last() + utility::hashPath( rpath.toLatin1() ) ; }else{ path += component + rpath.split( "/" ).last() + utility::hashPath( rpath.toLatin1() ) ; } } for( const auto& it : BASH_SPECIAL_CHARS ){ path.replace( it,'_' ) ; } return path ; } QString utility::hashPath( const QByteArray& p ) { int l = p.size() ; uint32_t hash = 0 ; auto key = p.constData() ; for( int i = 0 ; i < l ; i++ ){ hash += static_cast< unsigned int >( *( key + i ) ) ; hash += ( hash << 10 ) ; hash ^= ( hash >> 6 ) ; } hash += ( hash << 3 ) ; hash ^= ( hash >> 11 ) ; hash += ( hash << 15 ) ; return "-" + QString::number( hash ) ; } bool utility::pathExists( const QString& path ) { return QFile::exists( path ) ; } bool utility::canCreateFile( const QString& path ) { auto s = path ; auto e = s.lastIndexOf( '/' ) ; if( e != -1 ){ s.truncate( e ) ; } return utility::pathIsWritable( s ) ; } QString utility::resolvePath( const QString& path ) { if( path.size() == 1 && path.at( 0 ) == QChar( '~' ) ){ return utility::homePath() + "/" ; }else if( path.startsWith( "~/" ) ){ return utility::homePath() + "/" + path.mid( 2 ) ; }else if( path.startsWith( "UUID= ") ){ return path ; }else if( path.startsWith( "/dev/" ) ){ return path ; }else if( path.startsWith( "file://" ) ){ return path.mid( 7 ) ; }else{ QDir r( path ) ; auto rp = r.canonicalPath() ; if( rp.isEmpty() ) { return path ; }else{ return rp ; } } } QString utility::executableFullPath( const QString& f ) { QString e = f ; if( e.startsWith( "/" ) ){ auto s = QDir( f ).canonicalPath() ; for( const auto& it : utility::executableSearchPaths() ){ if( s.startsWith( it ) ){ return s ; } } return QString() ; } if( e == "ecryptfs" ){ e = "ecryptfs-simple" ; } QString exe ; for( const auto& it : utility::executableSearchPaths() ){ exe = it + e ; if( utility::pathExists( exe ) ){ return exe ; } } return QString() ; } static QString _absolute_exe_path( const QString& exe ) { auto e = utility::executableFullPath( exe ) ; if( e.isEmpty() ){ return exe ; }else{ return e ; } } QString utility::cmdArgumentValue( const QStringList& l,const QString& arg,const QString& defaulT ) { int j = l.size() ; for( int i = 0 ; i < j ; i++ ){ if( l.at( i ) == arg ){ auto e = [ & ](){ if( i + 1 < j ){ return l.at( i + 1 ) ; }else{ return defaulT ; } } ; if( arg == "-m" ){ return _absolute_exe_path( e() ) ; }else{ return e() ; } } } return defaulT ; } QString utility::deviceIDToPartitionID( const QString& id ) { if( id.startsWith( "/dev/disk/by-id" ) ){ auto l = id.split( '\t' ) ; if( l.size() > 1 ){ QDir d( l.first() ) ; auto e = d.canonicalPath() ; if( e.isEmpty() ){ return l.first() + '\t' + l.at( 1 ) ; }else{ return e + '\t' + l.at( 1 ) ; } }else{ return id ; } }else{ return id ; } } static QString _partition_id_to_device_id( const QString& id,bool expand ) { if( id.startsWith( "/dev/" ) ){ auto l = utility::directoryList( "/dev/disk/by-id" ) ; QDir r ; for( const auto& it : l ){ const auto& e = it ; if( !e.startsWith( "dm" ) ){ auto q = QString( "/dev/disk/by-id/%1" ).arg( e ) ; r.setPath( q ) ; if( r.canonicalPath() == id ){ if( expand ){ return q ; }else{ return e ; } } } } return id ; }else{ return id ; } } QString utility::getVolumeID( const QString& id,bool expand ) { return _partition_id_to_device_id( id,expand ) ; } bool utility::showWarningOnExtendingCoverFile() { if( !_settings->contains( "ShowWarningOnExtendingCoverFile" ) ){ utility::showWarningOnExtendingCoverFile( true ) ; } return _settings->value( "ShowWarningOnExtendingCoverFile" ).toBool() ; } void utility::showWarningOnExtendingCoverFile( bool e ) { _settings->setValue( "ShowWarningOnExtendingCoverFile",e ) ; } void utility::addToFavorite( const QString& dev,const QString& m_point ) { if( !( dev.isEmpty() || m_point.isEmpty() ) ){ QStringList s ; if( _settings->contains( "Favotites" ) ){ s = _settings->value( "Favotites" ).toStringList() ; } auto e = QString( "%1\t%2" ).arg( _partition_id_to_device_id( dev,true ),m_point ) ; s.append( e ) ; _settings->setValue( "Favotites",s ) ; } } QStringList readFavorites() { if( _settings->contains( "Favotites" ) ){ QStringList l ; for( const auto& it : _settings->value( "Favotites" ).toStringList() ){ if( it.startsWith( "/dev/disk/by-id" ) ){ l.append( utility::deviceIDToPartitionID( it ) ) ; }else{ l.append( it ) ; } } return l ; }else{ return QStringList() ; } } bool utility::unMountVolumesOnLogout() { if( !_settings->contains( "unMountVolumesOnLogout" ) ){ _settings->setValue( "unMountVolumesOnLogout",false ) ; } return _settings->value( "unMountVolumesOnLogout" ).toBool() ; } void utility::readFavorites( QMenu * m,bool truncate,bool showFolders ) { m->clear() ; auto _add_action = [ m,truncate ]( const favorites::entry& e ){ auto ac = new QAction( m ) ; if( truncate ){ ac->setText( e.volumePath ) ; }else{ ac->setText( e.volumePath + "\t" + e.mountPointPath ) ; } ac->setEnabled( !e.volumePath.startsWith( "/dev/disk/by-id" ) ) ; return ac ; } ; m->addAction( new QAction( QObject::tr( "Manage Favorites" ),m ) ) ; m->addAction( new QAction( QObject::tr( "Mount All" ),m ) ) ; m->addSeparator() ; favorites::instance().entries( [ & ]( const favorites::entry& e ){ if( showFolders ){ m->addAction( _add_action( e ) ) ; }else{ const auto& s = e.volumePath ; if( utility::pathExists( s ) ){ if( !utility::pathPointsToAFolder( s ) ){ m->addAction( _add_action( e ) ) ; } } } } ) ; } int utility::favoriteClickedOption( const QString& opt ) { if( opt == QObject::tr( "Manage Favorites" ) ){ return 1 ; }else if( opt == QObject::tr( "Mount All" ) ){ return 2 ; }else{ return 3 ; } } bool utility::userHasGoodVersionOfWhirlpool() { #ifdef GCRYPT_VERSION_NUMBER return GCRYPT_VERSION_NUMBER >= 0x010601 && SUPPORT_WHIRLPOOL ; #else return SUPPORT_WHIRLPOOL ; #endif } void utility::licenseInfo( QWidget * parent ) { QString s = "\nGpg key fingerprint: E3AF84691424AD00E099003502FC64E8DEBF43A8" ; QString license = QString( "%1\n\n\ 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.\n\ \n\ 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." ).arg( VERSION_STRING + s ) ; DialogMsg m( parent ) ; m.ShowUIInfo( QObject::tr( "about zuluCrypt" ),false,license ) ; } static utility::array_t _default_dimensions( const char * defaults ) { auto l = QString( defaults ).split( ' ' ) ; utility::array_t e ; auto f = e.data() ; auto j = l.size() ; for( int i = 0 ; i < j ; i++ ){ *( f + i ) = l.at( i ).toInt() ; } return e ; } static utility::array_t _dimensions( const char * defaults,int size ) { if( _settings->contains( "Dimensions" ) ){ auto l = _settings->value( "Dimensions" ).toStringList() ; utility::array_t p ; if( l.size() != size || size > int( p.size() ) ){ utility::debug() << "Failed to parse config file" ; return _default_dimensions( defaults ) ; } auto f = p.data() ; auto j = l.size() ; for( int i = 0 ; i < j ; i++ ){ bool ok ; int e = l.at( i ).toInt( &ok ) ; if( ok ){ *( f + i ) = e ; }else{ qDebug() << "failed to parse config file option" ; return _default_dimensions( defaults ) ; } } return p ; }else{ return _default_dimensions( defaults ) ; } } utility::array_t utility::getWindowDimensions( const QString& application ) { if( application == "zuluCrypt" ){ return _dimensions( "297 189 782 419 298 336 100",7 ) ; }else{ return _dimensions( "205 149 910 477 220 320 145 87 87",9 ) ; } } void utility::setWindowDimensions( const QString& application,const std::initializer_list& e ) { Q_UNUSED( application ) QStringList s ; for( const auto& it : e ){ s.append( QString::number( it ) ) ; } _settings->setValue( "Dimensions",s ) ; } QFont utility::getFont( QWidget * widget ) { if( !_settings->contains( "Font") ){ return widget->font() ; }else{ auto l = _settings->value( "Font" ).toStringList() ; if( l.size() >= 4 ){ QFont F ; const QString& fontFamily = l.at( 0 ) ; const QString& fontSize = l.at( 1 ) ; const QString& fontStyle = l.at( 2 ) ; const QString& fontWeight = l.at( 3 ) ; F.setFamily( fontFamily ) ; F.setPointSize( fontSize.toInt() ) ; if( fontStyle == "normal" ){ F.setStyle( QFont::StyleNormal ) ; }else if( fontStyle == "italic" ){ F.setStyle( QFont::StyleItalic ) ; }else{ F.setStyle( QFont::StyleOblique ) ; } if( fontWeight == "normal" ){ F.setWeight( QFont::Normal ) ; }else{ F.setWeight( QFont::Bold ) ; } return F ; }else{ return widget->font() ; } } } void utility::saveFont( const QFont& Font ) { auto s = QString( "%1\n%2\n" ).arg( Font.family(),QString::number( Font.pointSize() ) ) ; if( Font.style() == QFont::StyleNormal ){ s = s + "normal\n" ; }else if( Font.style() == QFont::StyleItalic ){ s = s + "italic\n" ; }else{ s = s + "oblique\n" ; } if( Font.weight() == QFont::Normal ){ s = s + "normal\n" ; }else{ s = s + "bold" ; } _settings->setValue( "Font",utility::split( s,'\n' ) ) ; } bool utility::runningInMixedMode() { return utility::useZuluPolkit() ; } bool utility::notRunningInMixedMode() { return !utility::runningInMixedMode() ; } bool utility::userBelongsToGroup( const char * groupname ) { auto user = getpwuid( static_cast< gid_t >( utility::getUserID() ) ) ; if( user != nullptr ){ auto grp = getgrnam( groupname ) ; if( grp != nullptr ){ auto name = user->pw_name ; for( auto e = grp->gr_mem ; *e ; e++ ){ if( strcmp( *e,name ) == 0 ){ return true ; } } } } return false ; } int utility::pluginKey( QWidget * w,QByteArray * key,const QString& p ) { plugins::plugin pluginType ; QString pluginString ; QVector exe ; if( p == "hmac" ){ pluginType = plugins::plugin::hmac_key ; pluginString = QObject::tr( "hmac plugin.\n\nThis plugin generates a key using below formular:\n\nkey = hmac(sha256,passphrase,keyfile contents)" ) ; }else if( p == "keykeyfile" ){ pluginType = plugins::plugin::keyKeyFile ; pluginString = QObject::tr( "keykeyfile plugin.\n\nThis plugin generates a key using below formular:\n\nkey = passphrase + keyfile contents" ) ; }else if( p == "gpg" ){ pluginType = plugins::plugin::gpg ; pluginString = QObject::tr( "gpg plugin.\n\nThis plugin retrives a key locked in a gpg file with a symmetric key" ) ; if( utility::pathExists( "/usr/bin/gpg" ) ){ exe.append( "/usr/bin/gpg" ) ; }else if( utility::pathExists( "/usr/local/bin/gpg" ) ){ exe.append( "/usr/local/bin/gpg" ) ; }else if( utility::pathExists( "/usr/sbin/gpg" ) ){ exe.append( "/usr/sbin/gpg" ) ; }else{ DialogMsg msg( w ) ; msg.ShowUIOK( QObject::tr( "ERROR" ),QObject::tr( "Could not find \"gpg\" executable in \"/usr/local/bin\",\"/usr/bin\" and \"/usr/sbin\"" ) ) ; return 1 ; } }else{ return 1 ; } QEventLoop l ; plugin::instance( w,pluginType,[ & ]( const QByteArray& e ){ *key = e ; if( e.isEmpty() ){ l.exit( 1 ) ; }else{ l.exit( 0 ) ; } },pluginString,exe ) ; return l.exec() ; } void utility::showTrayIcon( QAction * ac,QSystemTrayIcon& trayIcon,bool show ) { bool opt_show = true ; if( ac ){ if( !_settings->contains( "ShowTrayIcon" ) ){ _settings->setValue( "ShowTrayIcon",true ) ; } ac->setCheckable( true ) ; if( _settings->value( "ShowTrayIcon" ).toBool() ){ ac->setChecked( true ) ; opt_show = true ; }else{ ac->setChecked( false ) ; opt_show = false ; } } if( show ? show : opt_show ){ trayIcon.show() ; utility::Timer( 2000,[ &trayIcon ]( int counter ){ if( counter < 6 ){ if( !trayIcon.isVisible() || !QSystemTrayIcon::isSystemTrayAvailable() ){ /* * Try again to show the icon */ trayIcon.show() ; return false ; }else{ /* * The icon is visible, exiting */ return true ; } }else{ /* * We waited long enough for the icon to show up, giving up. */ return true ; } } ) ; } } void utility::trayProperty( QSystemTrayIcon * trayIcon,bool zuluCrypt ) { Q_UNUSED( zuluCrypt ) if( _settings->contains( "ShowTrayIcon" ) ){ if( _settings->value( "ShowTrayIcon" ).toBool() ){ _settings->setValue( "ShowTrayIcon",false ) ; trayIcon->hide() ; }else{ _settings->setValue( "ShowTrayIcon",true ) ; trayIcon->show() ; } } } class translator { public: void set( const QString& app,const QByteArray& r,int s ) { QCoreApplication::installTranslator( [ & ](){ auto f = m_translator.data() ; auto e = *( f + s ) ; if( e ){ QCoreApplication::removeTranslator( e ) ; delete e ; } e = new QTranslator() ; e->load( r.constData(),utility::localizationLanguagePath( app ) ) ; *( f + s ) = e ; return e ; }() ) ; } ~translator() { for( auto e : m_translator ){ if( e ){ /* * QApplication appear to already be gone by the time we get here. */ //QCoreApplication::removeTranslator( e ) ; delete e ; } } } private: std::array< QTranslator *,2 > m_translator = { { nullptr,nullptr } } ; } static _translator ; static void _selectOption( QMenu * m,const QString& opt ) { utility::selectMenuOption s( m,false ) ; s.selectOption( opt ) ; } void utility::setLocalizationLanguage( bool translate,QMenu * m,const QString& app ) { auto r = utility::localizationLanguage( app ).toLatin1() ; if( translate ){ _translator.set( app,r,0 ) ; if( app == "zuluMount-gui" ){ /* * We are loading zuluCrypt-gui translation file to get translations for * lxqtwallet strings. */ _translator.set( "zuluCrypt-gui",r,1 ) ; } }else{ QDir d( utility::localizationLanguagePath( app ) ) ; auto t = d.entryList() ; if( !t.isEmpty() ){ t.removeOne( "." ) ; t.removeOne( ".." ) ; for( auto& it : t ){ m->addAction( it.remove( ".qm" ) )->setCheckable( true ) ; } } _selectOption( m,r ) ; } } void utility::languageMenu( QWidget * w,QMenu * m,QAction * ac,const char * app ) { Q_UNUSED( w ) auto e = ac->text() ; e.remove( "&" ) ; utility::setLocalizationLanguage( app,e ) ; utility::setLocalizationLanguage( true,m,app ) ; _selectOption( m,e ) ; return ; } QStringList utility::directoryList( const QString& e ) { QDir d( e ) ; auto l = d.entryList() ; l.removeOne( "." ) ; l.removeOne( ".." ) ; return l ; } void utility::setIconMenu( const QString& app,QAction * ac,QWidget * w, std::function< void( const QString& ) >&& function ) { ac->setMenu( [ & ](){ auto m = new QMenu( w ) ; auto n = new utility::selectMenuOption( m,true,std::move( function ) ) ; w->connect( m,SIGNAL( triggered( QAction * ) ),n,SLOT( selectOption( QAction * ) ) ) ; if( !_settings->contains( "IconName" ) ){ _settings->setValue( "IconName",app ) ; } QString s = _settings->value( "IconName" ).toString() ; QDir d( INSTALL_PREFIX "/share/icons/hicolor/48x48/apps/" ) ; d.setNameFilters( { "zuluCrypt.*","zuluMount.*" } ) ; for( auto& it : d.entryList() ){ if( it.startsWith( app ) ){ if( it != "zuluCrypt.png" && it != "zuluMount.png" ){ it.remove( app + "." ) ; } it.remove( ".png" ) ; auto ac = m->addAction( it ) ; ac->setCheckable( true ) ; ac->setChecked( it == s ) ; } } return m ; }() ) ; } void utility::setIcons( const QString& app,const QString& iconName ) { Q_UNUSED( app ) _settings->setValue( "IconName",iconName ) ; } QIcon utility::getIcon( const QString& app ) { if( !_settings->contains( "IconName" ) ){ _settings->setValue( "IconName",app ) ; } QString e = _settings->value( "IconName" ).toString() ; if( e == "zuluCrypt" || e == "zuluMount" ){ QIcon icon( INSTALL_PREFIX "/share/icons/hicolor/48x48/apps/" + e + ".png" ) ; return QIcon::fromTheme( app,icon ) ; }else{ return QIcon( INSTALL_PREFIX "/share/icons/hicolor/48x48/apps/" + app + "." + e + ".png" ) ; } } QString utility::autoSetVolumeAsVeraCrypt() { if( !_settings->contains( "AutoSetVolumeAsVeraCryptType" ) ){ _settings->setValue( "AutoSetVolumeAsVeraCryptType",QString() ) ; } return _settings->value( "AutoSetVolumeAsVeraCryptType" ).toString() ; } void utility::autoSetVolumeAsVeraCrypt( const QString& opt ) { _settings->setValue( "AutoSetVolumeAsVeraCryptType",opt ) ; } int utility::defaultUnlockingVolumeType() { if( !_settings->contains( "DefaultUnlockingVolumeType" ) ){ _settings->setValue( "DefaultUnlockingVolumeType",0 ) ; } return _settings->value( "DefaultUnlockingVolumeType" ).toInt() ; } void utility::defaultUnlockingVolumeType( int e ) { _settings->setValue( "DefaultUnlockingVolumeType",e ) ; } void utility::autoOpenFolderOnMount( const QString& app,bool e ) { Q_UNUSED( app ) _settings->setValue( "AutoOpenFolderOnMount",e ) ; } bool utility::autoOpenFolderOnMount( const QString& app ) { Q_UNUSED( app ) if( _settings->contains( "AutoOpenFolderOnMount" ) ){ return _settings->value( "AutoOpenFolderOnMount" ).toBool() ; }else{ _settings->setValue( "AutoOpenFolderOnMount",true ) ; return true ; } } QString utility::defaultPlugin() { if( !_settings->contains( "DefaultPlugin" ) ){ QMenu m ; utility::addPluginsToMenu( m ) ; auto s = m.actions() ; if( s.size() ){ _settings->setValue( "DefaultPlugin",s.at( 0 )->text() ) ; } } return _settings->value( "DefaultPlugin" ).toString() ; } void utility::setDefaultPlugin( const QString& e ) { if( !e.isEmpty() ){ _settings->setValue( "DefaultPlugin",e ) ; } } QString utility::powerOffCommand() { if( _settings->contains( "PowerOffCommand" ) ){ return _settings->value( "PowerOffCommand" ).toString() ; }else{ _settings->setValue( "PowerOffCommand","" ) ; return QString() ; } } void utility::setDoNotMinimizeToTray( bool e ) { _settings->setValue( "doNotMinimizeToTray",e ) ; } bool utility::doNotMinimizeToTray() { if( !_settings->contains( "doNotMinimizeToTray" ) ){ _settings->setValue( "doNotMinimizeToTray",false ) ; } return _settings->value( "doNotMinimizeToTray" ).toBool() ; } void utility::mountWithSharedMountPoint( bool e ) { _settings->setValue( "mountWithSharedMountPoint",e ) ; } bool utility::mountWithSharedMountPoint() { if( !_settings->contains( "mountWithSharedMountPoint" ) ){ _settings->setValue( "mountWithSharedMountPoint",false ) ; } return _settings->value( "mountWithSharedMountPoint" ).toBool() ; } QString utility::prettyfySpaceUsage( quint64 s ) { auto _convert = [ & ]( const char * p,double q ){ auto e = QString::number( double( s ) / q,'f',2 ) ; e.remove( ".00" ) ; return QString( "%1 %2" ).arg( e,p ) ; } ; switch( QString::number( s ).size() ){ case 0 : case 1 : case 2 : case 3 : return QString( "%1 B" ).arg( QString::number( s ) ) ; case 4 : case 5 : case 6 : return _convert( "KB",1024 ) ; case 7 : case 8 : case 9 : return _convert( "MB",1048576 ) ; case 10: case 11 : case 12 : return _convert( "GB",1073741824 ) ; default: return _convert( "TB",1024.0 * 1073741824 ) ; } } QStringList utility::plainDmCryptOptions() { if( _settings->contains( "PlainDmCryptOptions" ) ){ return _settings->value( "PlainDmCryptOptions" ).toStringList() ; }else{ QStringList s = { { "aes.cbc-essiv:sha256.256.sha256" }, { "aes.cbc-essiv:sha256.256.sha512" }, { "aes.cbc-essiv:sha256.256.sha1" }, { "aes.cbc-essiv:sha256.256.ripemd160" }, { "aes.cbc-essiv:sha256.512.sha256" }, { "aes.cbc-essiv:sha256.512.sha512" }, { "aes.cbc-essiv:sha256.512.sha1" }, { "aes.cbc-essiv:sha256.512.ripemd160" }, { "aes.xts-plain64.256.sha256" }, { "aes.xts-plain64.256.sha512" }, { "aes.xts-plain64.256.sha1" }, { "aes.xts-plain64.256.ripemd160" }, { "aes.xts-plain64.512.sha256" }, { "aes.xts-plain64.512.sha512" }, { "aes.xts-plain64.512.sha1" }, { "aes.xts-plain64.512.ripemd160" }, }; _settings->setValue( "PlainDmCryptOptions",s ) ; return s ; } } QString utility::KWalletDefaultName() { if( !_settings->contains( "KWalletDefaultName" ) ){ _settings->setValue( "KWalletDefaultName","default" ) ; } return _settings->value( "KWalletDefaultName" ).toString() ; } QStringList utility::supportedFileSystems() { if( _settings->contains( "SupportedFileSystems" ) ){ return _settings->value( "SupportedFileSystems" ).toStringList() ; }else{ QStringList s{ "ext4","vfat","ntfs","ext2","ext3","exfat","ntfs","btrfs" } ; _settings->setValue( "SupportedFileSystems",s ) ; return s ; } } std::pair< bool,QByteArray > utility::getKeyFromNetwork( const QString& e ) { Q_UNUSED( e ) return { false,QByteArray() } ; #if 0 if( !_settings->contains( "NetworkAddress" ) ){ return _settings->setValue( "NetworkAddress","127.0.0.1" ) ; } QFile f( utility::homePath() + "/.zuluCrypt/network" ) ; if( !f.open( QIODevice::ReadOnly ) ){ return { false,"" } ; } QUrl url ; QByteArray data = "device=" + utility::split( e,' ' ).last().toLatin1() ; QByteArray host ; for( const auto& it : utility::split( f.readAll() ) ){ if( it.startsWith( "url=" ) ){ url.setUrl( it.toLatin1().constData() + 4 ) ; }else if( it.startsWith( "host=" ) ){ host = it.toLatin1().constData() + 5 ; }else{ data += "&" + it ; } } QNetworkRequest n( url ) ; n.setRawHeader( "Host",host ) ; n.setRawHeader( "Content-Type","application/x-www-form-urlencoded" ) ; NetworkAccessManager m ; auto s = m.post( n,data ) ; if( s->error() == QNetworkReply::NoError ){ return { true,s->readAll() } ; }else{ return { false,"" } ; } #endif } void utility::setHDPI( const QString& e ) { Q_UNUSED( e ) #if QT_VERSION >= 0x050600 QApplication::setAttribute( Qt::AA_EnableHighDpiScaling ) ; if( !_settings->contains( "ScaleFactor" ) ){ _settings->setValue( "ScaleFactor","1" ) ; } qputenv( "QT_SCALE_FACTOR",_settings->value( "ScaleFactor" ).toString().toLatin1() ) ; #endif } bool utility::platformIsLinux() { return true ; } bool utility::platformIsOSX() { return false ; } QStringList utility::executableSearchPaths() { return ::executableSearchPaths::values() ; } QString utility::executableSearchPaths( const QString& e ) { if( e.isEmpty() ){ return utility::executableSearchPaths().join( ":" ) ; }else{ return e + ":" + utility::executableSearchPaths().join( ":" ) ; } } static inline bool _terminalEchoOff( struct termios * old,struct termios * current ) { if( tcgetattr( 1,old ) != 0 ){ return false ; } *current = *old; current->c_lflag &= static_cast< unsigned int >( ~ECHO ) ; if( tcsetattr( 1,TCSAFLUSH,current ) != 0 ){ return false ; }else{ return true ; } } QString utility::readPassword( bool addNewLine ) { std::cout << "Password: " << std::flush ; struct termios old ; struct termios current ; _terminalEchoOff( &old,¤t ) ; QString s ; int e ; int m = 1024 ; for( int i = 0 ; i < m ; i++ ){ e = std::getchar() ; if( e == '\n' || e == -1 ){ break ; }else{ s += static_cast< char >( e ) ; } } tcsetattr( 1,TCSAFLUSH,&old ) ; if( addNewLine ){ std::cout << std::endl ; } return s ; } QString utility::fileManager() { if( _settings->contains( "FileManager" ) ){ return _settings->value( "FileManager" ).toString() ; }else{ _settings->setValue( "FileManager","xdg-open" ) ; return "xdg-open" ; } } void utility::setFileManager( const QString& e ) { if( e.isEmpty() ){ _settings->setValue( "FileManager","xdg-open" ) ; }else{ _settings->setValue( "FileManager",e ) ; } } QProcessEnvironment utility::systemEnvironment() { auto e = QProcessEnvironment::systemEnvironment() ; e.insert( "zuluCryptRuntimePath",utility::passwordSocketPath() + "/" ) ; e.insert( "CRYFS_NO_UPDATE_CHECK","TRUE" ) ; e.insert( "CRYFS_FRONTEND","noninteractive" ) ; e.insert( "LANG","C" ) ; e.insert( "PATH",utility::executableSearchPaths( e.value( "PATH" ) ) ) ; return e ; } bool utility::clearPassword() { if( _settings->contains( "ClearPassword" ) ){ return _settings->value( "ClearPassword" ).toBool() ; }else{ _settings->setValue( "ClearPassword",true ) ; return true ; } } bool utility::readOnlyOption() { if( _settings->contains( "ReadOnly" ) ){ return _settings->value( "ReadOnly" ).toBool() ; }else{ _settings->setValue( "ReadOnly",false ) ; return false ; } } void utility::readOnlyOption( bool e ) { _settings->setValue( "ReadOnly",e ) ; } bool utility::readOnlyWarning() { if( _settings->contains( "ReadOnlyWarning" ) ){ return _settings->value( "ReadOnlyWarning" ).toBool() ; }else{ _settings->setValue( "ReadOnlyWarning",true ) ; return true ; } } void utility::readOnlyWarning( bool e ) { _settings->setValue( "ReadOnlyWarning",e ) ; } QString utility::failedToStartzuluPolkit() { return QObject::tr( "Failed To Start Helper Application.\n\n\"org.zulucrypt.zulupolkit.policy\" polkit file is misconfigured,\nzuluPolkit executable could not be found\n or pkexec failed to start zuluPolkit." ) ; } static utility2::result< int > _convert_string_to_version( const QString& e ) { auto _convert = []( const QString& e )->utility2::result< int >{ bool ok ; auto s = e.toInt( &ok ) ; if( ok ){ return s ; }else{ return {} ; } } ; auto s = utility::split( e,'.' ) ; auto components = s.size() ; int major = 1000000 ; int minor = 1000 ; int patch = 1 ; if( components == 1 ){ auto a = _convert( s.first() ) ; if( a ){ return major * a.value() ; } }else if( components == 2 ){ auto a = _convert( s.at( 0 ) ) ; auto b = _convert( s.at( 1 ) ) ; if( a && b ){ return major * a.value() + minor * b.value() ; } }else if( components == 3 ){ auto a = _convert( s.at( 0 ) ) ; auto b = _convert( s.at( 1 ) ) ; auto c = _convert( s.at( 2 ) ) ; if( a && b && c ){ return major * a.value() + minor * b.value() + patch * c.value() ; } } return {} ; } static utility2::result< QString > _installed_version( const QString& backend ) { auto _remove_junk = []( QString e ){ e.replace( "v","" ).replace( ";","" ) ; QString m ; for( int s = 0 ; s < e.size() ; s++ ){ auto n = e.at( s ) ; if( n == '.' || ( n >= '0' && n <= '9' ) ){ m += n ; }else{ break ; } } return m ; } ; auto exe = utility::executableFullPath( backend ) ; if( exe.isEmpty() ){ return {} ; } auto cmd = [ & ](){ if( backend == "securefs" ){ return backend + " version" ; }else{ return backend + " --version" ; } }() ; auto s = utility::systemEnvironment() ; auto r = [ & ](){ if( backend == "encfs" ){ return QString( ::Task::process::run( cmd,{},-1,{},s ).get().std_error() ) ; }else{ return QString( ::Task::process::run( cmd,{},-1,{},s ).get().std_out() ) ; } }() ; if( r.isEmpty() ){ return {} ; } auto m = utility::split( utility::split( r,'\n' ).first(),' ' ) ; if( utility::equalsAtleastOne( backend,"cryfs","encfs","sshfs" ) ){ if( m.size() >= 3 ){ return _remove_junk( m.at( 2 ) ) ; } }else if( utility::equalsAtleastOne( backend,"gocryptfs","securefs","ecryptfs-simple" ) ){ if( m.size() >= 2 ){ return _remove_junk( m.at( 1 ) ) ; } } return {} ; } ::Task::future< utility2::result< QString > >& utility::backEndInstalledVersion( const QString& backend ) { return ::Task::run( _installed_version,backend ) ; } static utility2::result< int > _installedVersion( const QString& backend ) { auto s = utility::backEndInstalledVersion( backend ).get() ; if( s && !s.value().isEmpty() ){ return _convert_string_to_version( s.value() ) ; }else{ return {} ; } } template< typename Function > ::Task::future< utility2::result< bool > >& _compare_versions( const QString& backend, const QString& version, Function compare ) { return ::Task::run( [ = ]()->utility2::result< bool >{ auto installed = _installedVersion( backend ) ; auto guard_version = _convert_string_to_version( version ) ; if( installed && guard_version ){ return compare( installed.value(),guard_version.value() ) ; }else{ return {} ; } } ) ; } ::Task::future< utility2::result< bool > >& utility::backendIsGreaterOrEqualTo( const QString& backend, const QString& version ) { return _compare_versions( backend,version,std::greater_equal() ) ; } ::Task::future< utility2::result< bool > >& utility::backendIsLessThan( const QString& backend, const QString& version ) { return _compare_versions( backend,version,std::less() ) ; } utility::UrandomDataSource::UrandomDataSource() : m_file( "/dev/urandom" ) { } bool utility::UrandomDataSource::open() { m_file.open( QIODevice::ReadOnly ) ; return m_file.isOpen() ; } qint64 utility::UrandomDataSource::getData( char * data,qint64 size ) { return m_file.read( data,size ) ; } QByteArray utility::UrandomDataSource::getData( qint64 size ) { return m_file.read( size ) ; } utility::CRandDataSource::CRandDataSource() { } bool utility::CRandDataSource::open() { return true ; } qint64 utility::CRandDataSource::getData( char * data,qint64 size ) { time_t t ; srand( static_cast< unsigned int >( time( &t ) ) ) ; for( int i = 0 ; i < size ; i++ ){ *( data + i ) = static_cast< char >( rand() ) ; } return size ; } QByteArray utility::CRandDataSource::getData( qint64 size ) { QByteArray data ; data.resize( static_cast< int >( size ) ) ; utility::CRandDataSource().getData( data.data(),size ) ; return data ; } QString utility::loopDevicePath( const QString& e ) { const auto s = QDir( "/sys/block" ).entryList() ; QFile file ; for( const auto& it : s ){ if( it.startsWith( "loop" ) ){ QString m = "/sys/block/" + it + "/loop/backing_file" ; if( utility::pathExists( m ) ){ file.setFileName( m ) ; file.open( QIODevice::ReadOnly ) ; QString s = file.readAll() ; file.close() ; if( s.startsWith( e ) ){ return "/dev/" + it ; } } } } return QString() ; } static bool _removeYkchalrespNewLineCharacter() { if( !_settings->contains( "RemoveYkchalrespNewLineCharacter" ) ){ _settings->setValue( "RemoveYkchalrespNewLineCharacter",true ) ; } return _settings->value( "RemoveYkchalrespNewLineCharacter" ).toBool() ; } static QString _ykchalrespArguments() { if( !_settings->contains( "YkchalrespArguments" ) ){ _settings->setValue( "YkchalrespArguments","-2 -i -" ) ; } return _settings->value( "YkchalrespArguments" ).toString() ; } static QString _ykchalresp_path() { static QString m = utility::executableFullPath( "ykchalresp" ) ; return m ; } utility2::result utility::yubiKey( const QString& challenge ) { QString exe = _ykchalresp_path() ; if( !exe.isEmpty() ){ auto args = utility::split( _ykchalrespArguments(),' ' ) ; auto s = [ & ](){ if( challenge.isEmpty() ){ return ::Task::process::run( exe,"\n" ).await() ; }else{ return ::Task::process::run( exe,args,challenge.toUtf8() ).await() ; } }() ; _post_backend_cmd( exe + " " + args.join( " " ) ) ; if( s.success() ){ auto m = s.std_out() ; if( _removeYkchalrespNewLineCharacter() ){ m.replace( "\n","" ) ; } return m ; }else{ std::cout << "Failed to get a responce from ykchalresp" << std::endl ; std::cout << "StdOUt:" << s.std_out().constData() << std::endl ; std::cout << "StdError:" << s.std_error().constData() << std::endl ; } } return {} ; } utility::progress::progress( int s,std::function< void( const utility::progress::result& )> function ) : m_offset_last( 0 ), m_total_time( 0 ), m_function( std::move( function ) ), m_duration( s ), m_time( m_duration.timer() ), m_previousTime( static_cast< double >( m_time.currentMSecsSinceEpoch() ) ) { } void utility::progress::update_progress( quint64 size,quint64 offset ) { int i = int( ( offset * 100 / size ) ) ; auto time_expired = m_duration.passed() ; if( !time_expired ){ m_duration.reset() ; } if( i > m_progress || time_expired ){ m_progress = i ; double currentTime = static_cast< double >( m_time.currentMSecsSinceEpoch() ) ; double time_diff = ( currentTime - m_previousTime ) / 1000 ; double offset_diff = static_cast< double >( offset - m_offset_last ) ; m_total_time = m_total_time + time_diff ; QString current_speed = this->speed( offset_diff,time_diff ) ; QString average_speed = this->speed( static_cast< double >( offset ),m_total_time ) ; double avg_speed = static_cast< double >( offset ) / m_total_time ; double remaining_data = static_cast< double >( size - offset ) ; QString eta = this->time( remaining_data / avg_speed ) ; m_function( { current_speed, average_speed, eta, this->time( m_total_time ), i } ) ; m_offset_last = offset ; m_previousTime = currentTime ; } } std::function< void( quint64 size,quint64 offset ) > utility::progress::updater_quint() { return [ this ]( quint64 size,quint64 offset ){ this->update_progress( size,offset ) ; } ; } std::function< void( qint64 size,qint64 offset ) > utility::progress::updater_qint() { return [ this ]( qint64 size,qint64 offset ){ this->update_progress( quint64( size ),quint64( offset ) ) ; } ; } QString utility::progress::time( double s ) { int milliseconds = int( s ) * 1000 ; int seconds = milliseconds / 1000; milliseconds = milliseconds % 1000; int minutes = seconds / 60 ; seconds = seconds % 60 ; int hours = minutes / 60 ; minutes = minutes % 60 ; QTime time ; time.setHMS( hours,minutes,seconds,milliseconds ) ; return time.toString( "hh:mm:ss" ) ; } QString utility::progress::speed( double size,double time ) { QString s ; if( size < 1024 ){ s = "B" ; }else if( size <= 1024 * 1024 ){ s = "KB" ; size = size / 1024 ; }else if( size <= 1024 * 1024 * 1024 ){ s = "MB" ; size = size / ( 1024 * 1024 ) ; }else if( size <= 1024 * 1024 * 1024 * 1024ll ){ s = "GB" ; size = size / ( 1024 * 1024 * 1024 ) ; }else{ s = "B" ; } size = size / time ; return QString::number( size,'f',2 ) + " " + s + "/s" ; } utility::duration::duration( long miliseconds ) : m_milliseconds( miliseconds ) { this->reset() ; } bool utility::duration::passed() { auto now = m_time.currentMSecsSinceEpoch() ; if( now - m_start_time >= m_milliseconds ){ this->reset() ; return true ; }else{ return false ; } } void utility::duration::reset() { m_start_time = m_time.currentMSecsSinceEpoch() ; } QDateTime& utility::duration::timer() { return m_time ; } bool utility::showOnlyOccupiedSlots() { if( !_settings->contains( "ShowOnlyOccupiedSlots" ) ){ _settings->setValue( "ShowOnlyOccupiedSlots",true ) ; } return _settings->value( "ShowOnlyOccupiedSlots" ).toBool() ; } void utility::showOnlyOccupiedSlots( bool e ) { _settings->setValue( "ShowOnlyOccupiedSlots",e ) ; } bool utility::canShowKeySlotProperties() { return SUPPORT_crypt_keyslot_get_pbkdf ; } bool utility::libCryptSetupLibraryNotFound() { return false ; //return !utility::pathExists( CRYPTSETUP_LIBRARY_PATH ) ; } void utility::setFileSystemOptions( QString& exe, const QString& device, const QString& mountpoint, const QString& mountOptions ) { QString mOpts ; favorites::instance().entries( [ & ]( const favorites::entry& e ){ if( e.volumePath == device && e.mountPointPath == mountpoint ){ mOpts = e.mountOptions ; return true ; } return false ; } ) ; if( mOpts.isEmpty() ){ if( mountOptions.isEmpty() ){ /* * Both are empty, do nothing. */ }else{ exe += " -Y " + mountOptions ; } }else{ if( mountOptions.isEmpty() ){ exe += " -Y " + mOpts ; }else{ /* * remove duplicate entries */ auto m = utility::split( mountOptions,',' ) ; for( const auto& it : utility::split( mOpts,',' ) ){ m.removeAll( it ) ; } if( m.isEmpty() ){ exe += " -Y " + mOpts ; }else{ exe += " -Y " + mOpts + "," + m.join( ',' ) ; } } } } QString utility::fileSystemOptions( const QString& path ) { QString m ; if( !path.isEmpty() ){ favorites::instance().entries( [ & ]( const favorites::entry& e ){ if( e.volumePath == path ){ m = e.mountOptions ; return true ; } return false ; } ) ; } return m ; } QString utility::pathToUUID( const QString& path ) { if( path.startsWith( "UUID=" ) ){ return path ; }else{ auto z = utility::getUUIDFromPath( path ).await() ; if( z.isEmpty() ){ return utility::getVolumeID( path ) ; }else{ return z ; } } } zuluCrypt-6.2.0/zuluCrypt-gui/utility.h000066400000000000000000000550251425361753700202430ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef MISCFUNCTIONS_H #define MISCFUNCTIONS_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "utility2.h" #include "task.hpp" #include "lxqt_wallet.h" #include "debugwindow.h" #include #include #include #include #include #include #include #include #include #include namespace utility { class label { public: void setOptions( QLabel * l,QPushButton * b ) { m_label = l ; m_pushButton = b ; m_label->setVisible( false ) ; m_pushButton->setVisible( false ) ; QObject::connect( m_pushButton,&QPushButton::clicked,[ this ](){ this->hide() ; if( m_runEventLoop ){ m_eventLoop.exit() ; } } ) ; } void show( const QString& e,bool runEventLopp = true ) { m_runEventLoop = runEventLopp ; m_label->setText( e ) ; m_label->setVisible( true ) ; m_pushButton->setVisible( true ) ; m_pushButton->setFocus() ; if( runEventLopp ){ m_eventLoop.exec() ; } } void hide() { m_label->clear() ; m_label->setVisible( false ) ; m_pushButton->setVisible( false ) ; } private: bool m_runEventLoop ; QLabel * m_label ; QPushButton * m_pushButton ; QEventLoop m_eventLoop ; }; } namespace utility { struct RandomDataSource { enum class types{ urandom,crand }; static std::unique_ptr< RandomDataSource > get( types = types::urandom ) ; virtual ~RandomDataSource() ; virtual bool open() = 0 ; virtual qint64 getData( char * data,qint64 size ) = 0 ; virtual QByteArray getData( qint64 size ) = 0 ; } ; class UrandomDataSource : public RandomDataSource { public: UrandomDataSource() ; bool open() override ; qint64 getData( char * data,qint64 size ) override ; QByteArray getData( qint64 size ) override ; private: QFile m_file; } ; class CRandDataSource : public RandomDataSource { public: CRandDataSource() ; bool open() override ; qint64 getData( char * data,qint64 size ) override ; QByteArray getData( qint64 size ) override ; } ; class debug { public: debug( bool s = true ) : m_stdout( s ) { } template< typename T > utility::debug operator<<( const T& e ) { if( m_stdout ){ std::cout << e << std::endl ; }else{ std::cerr << e << std::endl ; } return utility::debug( m_stdout ) ; } utility::debug operator<<( const QByteArray& e ) { if( m_stdout ){ std::cout << e.constData() << std::endl ; }else{ std::cerr << e.constData() << std::endl ; } return utility::debug( m_stdout ) ; } utility::debug operator<<( const QString& e ) { if( m_stdout ){ std::cout << e.toLatin1().constData() << std::endl ; }else{ std::cerr << e.toLatin1().constData() << std::endl ; } return utility::debug( m_stdout ) ; } utility::debug operator<<( const QStringList& e ) { if( m_stdout ){ for( const auto& it : e ){ std::cout << it.toLatin1().constData() << std::endl ; } }else{ for( const auto& it : e ){ std::cerr << it.toLatin1().constData() << std::endl ; } } return utility::debug( m_stdout ) ; } private: bool m_stdout ; }; } namespace utility { class selectMenuOption : public QObject { Q_OBJECT public: using function_t = std::function< void( const QString& e ) > ; selectMenuOption( QMenu * m,bool e, function_t && f = []( const QString& e ){ Q_UNUSED( e ) } ) : m_menu( m ),m_function( f ) { if( e ){ this->setParent( m ) ; } } public slots : void selectOption( const QString& f ) { for( const auto& it : m_menu->actions() ){ QString e = it->text() ; e.remove( "&" ) ; it->setChecked( f == e ) ; } m_function( f ) ; } void selectOption( QAction * ac ) { auto e = ac->text() ; e.remove( "&" ) ; this->selectOption( e ) ; } private: QMenu * m_menu ; std::function< void( const QString& ) > m_function ; }; } namespace utility { int getUID() ; int getUserID() ; int getGUID( int uid ) ; QString getStringUserID() ; QString appendUserUID( const QString& ) ; QString homePath() ; template< typename T > void changePathOwner( const T& f ) { int uid = utility::getUID() ; int gid = utility::getGUID( uid ) ; int fd = f.handle() ; if( uid != -1 && fd != -1 ){ if( fchown( fd,uid,gid ) ){;} } } static inline void changePathOwner( const char * path ) { int uid = utility::getUID() ; int gid = utility::getGUID( uid ) ; if( uid != -1 ){ if( chown( path,uid,gid ) ){;} } } static inline void changePathOwner( const QString& path ) { utility::changePathOwner( path.toLatin1().constData() ) ; } template< typename T > void changePathPermissions( const T& f,int mode = 0666 ) { if( fchmod( f.handle(),mode ) ){;} } static inline void changePathPermissions( const QString& f,int mode = 0666 ) { if( chmod( f.toLatin1().constData(),mode ) ){;} } } namespace utility { struct wallet { bool opened ; bool notConfigured ; QString key ; }; bool libCryptSetupLibraryNotFound() ; int startApplication( const char * appName,std::function ) ; void startApplication( QObject *,const char * ) ; wallet getKey( LXQt::Wallet::Wallet&,const QString& keyID, const QString& app = QString() ) ; QString cmdArgumentValue( const QStringList&,const QString& arg, const QString& defaulT = QString() ) ; QIcon getIcon( const QString& ) ; void setIcons( const QString&,const QString& ) ; void setIconMenu( const QString& app,QAction * ac,QWidget *, std::function< void( const QString& ) >&& ) ; QString fileSystemOptions( const QString& path ) ; QString autoSetVolumeAsVeraCrypt() ; void autoSetVolumeAsVeraCrypt( const QString& ) ; int defaultUnlockingVolumeType() ; void defaultUnlockingVolumeType( int ) ; bool showOnlyOccupiedSlots() ; void showOnlyOccupiedSlots( bool ) ; void autoOpenFolderOnMount( const QString&,bool ) ; bool autoOpenFolderOnMount( const QString& ) ; QProcessEnvironment systemEnvironment() ; enum class background_thread{ True,False } ; bool requireSystemPermissions( const QString&,utility::background_thread = utility::background_thread::False ) ; bool enablePolkit( utility::background_thread ) ; void setSettingsObject( QSettings * ) ; QSettings& settingsObject() ; ::Task::future< utility2::result< QString > >& backEndInstalledVersion( const QString& backend ) ; ::Task::future< utility2::result< bool > >& backendIsLessThan( const QString& backend, const QString& version ) ; ::Task::future< utility2::result< bool > >& backendIsGreaterOrEqualTo( const QString& backend, const QString& version ) ; utility2::result< QByteArray > yubiKey( const QString& ) ; bool useDmCryptForRandomData() ; void setDefaultEnvironment() ; QString passwordSocketPath() ; QString socketPath() ; bool clearPassword() ; bool userBelongsToGroup( const char * groupname ) ; bool runningInMixedMode( void ) ; bool notRunningInMixedMode( void ) ; void addToFavorite( const QString& dev,const QString& m_point ) ; void readFavorites( QMenu *,bool = false,bool = true ) ; void setHDPI( const QString& ) ; bool pathExists( const QString& ) ; bool canCreateFile( const QString& ) ; bool useZuluPolkit( void ) ; void startHelperExecutable( QObject *,const QString&,const QString&,const char *,const char * ) ; void setDebugWindow( debugWindow * w ) ; QString deviceIDToPartitionID( const QString& ) ; QString fileManager( void ) ; QString loopDevicePath( const QString& ) ; void setFileManager( const QString& ) ; QString failedToStartzuluPolkit() ; QString prettyfySpaceUsage( quint64 ) ; QString resolvePath( const QString& ) ; QString hashPath( const QByteArray& ) ; QWidget * mainWindowWidget() ; void mainWindowWidget( QWidget * ) ; QString cryptMapperPath( void ) ; QString mapperPath( const QString&,const QString& component = QString() ) ; QString getVolumeID( const QString&,bool = false ) ; bool userIsRoot( void ) ; bool mapperPathExists( const QString& path ) ; QString mountPath( const QString& ) ; QString homeMountPath( const QString& ) ; QString mountPathPostFix( const QString& ) ; QString userName( void ) ; QString shareMountPointToolTip( void ) ; QString shareMountPointToolTip( const QString& ) ; QString sharedMountPointPath( const QString& ) ; QString defaultPlugin( void ) ; void setDefaultPlugin( const QString& ) ; bool pathPointsToAFile( const QString& ) ; bool pathPointsToAFolder( const QString& ) ; bool configDirectoriesAreNotWritable( QWidget * ) ; QString localizationLanguage( const QString& ) ; QString localizationLanguagePath( const QString& ) ; void setLocalizationLanguage( const QString&,const QString& ) ; QString walletName( void ) ; QString applicationName( void ) ; QString readPassword( bool = true ) ; bool pathIsReadable( const QString&,bool isFolder = true ) ; bool pathIsWritable( const QString&,bool isFolder = true ) ; bool setOpenVolumeReadOnly( QWidget * parent,bool check,const QString& app ) ; bool getOpenVolumeReadOnlyOption( const QString& app ) ; QString keyPath( void ) ; void keySend( const QString& keyPath,const QByteArray& key ) ; void keySend( const QString& keyPath,const QString& key ) ; bool eventFilter( QObject * gui,QObject * watched,QEvent * event,std::function< void() > ) ; QStringList split( const QString&,char token = '\n' ) ; QStringList split( const QByteArray&,char token = '\n' ) ; QStringList split( const QByteArray&,const char * token ) ; QStringList split( const QString&,const char * token ) ; QStringList directoryList( const QString& ) ; QStringList plainDmCryptOptions( void ) ; QStringList supportedFileSystems( void ) ; QString KWalletDefaultName( void ) ; bool userHasGoodVersionOfWhirlpool( void ) ; void licenseInfo( QWidget * ) ; void showTrayIcon( QAction *,QSystemTrayIcon&,bool = true ) ; void trayProperty( QSystemTrayIcon *,bool = true ) ; void setDoNotMinimizeToTray( bool ) ; bool doNotMinimizeToTray() ; bool mountWithSharedMountPoint() ; void mountWithSharedMountPoint( bool ) ; bool platformIsLinux( void ) ; bool platformIsOSX( void ) ; QString pathToUUID( const QString& path ) ; QStringList executableSearchPaths( void ) ; QString executableSearchPaths( const QString& ) ; QString helperSocketPath( void ) ; void quitHelper( void ) ; std::pair< bool,QByteArray > getKeyFromNetwork( const QString& ) ; QString powerOffCommand( void ) ; void setFileSystemOptions( QString& exe, const QString& device, const QString& mountpoint, const QString& mountOptions = QString() ) ; int favoriteClickedOption( const QString& ) ; QString executableFullPath( const QString& ) ; bool showWarningOnExtendingCoverFile() ; void showWarningOnExtendingCoverFile( bool ) ; bool reUseMountPointPath( void ) ; bool reUseMountPoint( void ) ; bool readOnlyOption( void ) ; void readOnlyOption( bool ) ; bool canShowKeySlotProperties() ; bool readOnlyWarning( void ) ; void readOnlyWarning( bool ) ; void polkitFailedWarning( std::function< void() > ) ; void setLocalizationLanguage( bool translate,QMenu * ac,const QString& ) ; void languageMenu( QWidget *,QMenu *,QAction *,const char * ) ; bool unMountVolumesOnLogout( void ) ; using array_t = std::array< int,10 > ; utility::array_t getWindowDimensions( const QString& application ) ; void setWindowDimensions( const QString& application,const std::initializer_list& ) ; void addPluginsToMenu( QMenu& ) ; int pluginKey( QWidget *,QByteArray *,const QString& ) ; std::pair< bool,QByteArray > privilegedReadConfigFile( const QString& ) ; void privilegedWriteConfigFile( const QByteArray&,const QString& ) ; QFont getFont( QWidget * ) ; void saveFont( const QFont& ) ; ::Task::future< int >& clearVolume( const QString& volumePath, std::atomic_bool * exit, size_t size, std::function< void( quint64 size,quint64 offset ) > ) ; ::Task::future< int >& exec( const QString& ) ; ::Task::future< QStringList >& luksEmptySlots( const QString& volumePath ) ; ::Task::future< QString >& getUUIDFromPath( const QString& ) ; ::Task::future< bool >& openPath( const QString& path,const QString& opener ) ; void openPath( const QString& path,const QString& opener,QWidget *,const QString&,const QString& ) ; } namespace utility { template< typename ... F > bool atLeastOnePathExists( const F& ... f ){ for( const auto& it : { f ... } ){ if( utility::pathExists( it ) ){ return true ; } } return false ; } template< typename E,typename ... F > bool containsAtleastOne( const E& e,const F& ... f ) { for( const auto& it : { f ... } ){ if( e.contains( it ) ){ return true ; } } return false ; } template< typename E,typename ... F > bool startsWithAtLeastOne( const E& e,const F& ... f ) { for( const auto& it : { f ... } ){ if( e.startsWith( it ) ){ return true ; } } return false ; } template< typename E,typename ... F > bool endsWithAtLeastOne( const E& e,const F& ... f ) { for( const auto& it : { f ... } ){ if( e.endsWith( it ) ){ return true ; } } return false ; } template< typename E,typename ... F > bool equalsAtleastOne( const E& e,const F& ... f ) { for( const auto& it : { f ... } ){ if( e == it ){ return true ; } } return false ; } } namespace utility { class fileHandle { public: fileHandle() { } fileHandle( int r ) : m_fd( r ) { } fileHandle( int r,std::function< void( int ) > cmd ) : m_fd( r ),m_releaseResource( std::move( cmd ) ) { } bool open( const char * filePath,bool ro = true ) { if( ro ){ m_fd = ::open( filePath,O_RDONLY ) ; }else{ m_fd = ::open( filePath,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH ) ; } m_path = filePath ; return m_fd != -1 ; } bool open( const QString& filePath,bool ro = true ) { return this->open( filePath.toLatin1().constData(),ro ) ; } bool isFile() { struct stat st ; fstat( m_fd,&st ) ; return S_ISREG( st.st_mode ) != 0 ; } bool isFolder() { struct stat st ; fstat( m_fd,&st ) ; return S_ISDIR( st.st_mode ) != 0 ; } quint64 size() { return static_cast< quint64 >( blkid_get_dev_size( m_fd ) ) ; } void unlink() { m_unlink = true ; } int handle() const { return m_fd ; } const char * path() { return m_path.constData() ; } bool opened() const { return m_fd != -1 ; } char getChar() const { char z ; while( true ){ while( ::read( m_fd,&z,1 ) != 1 ){;} if( z > ' ' && z < '~' ){ /* * we are creating a keyfile that is made up * of only printable characters */ break ; } } return z ; } void writeChar( char r ) const { if( ::write( m_fd,&r,1 ) ){;} } ~fileHandle() { m_releaseResource( m_fd ) ; if( m_unlink ){ ::unlink( m_path.constData() ) ; } } private: bool m_unlink = false ; int m_fd = -1 ; QByteArray m_path ; std::function< void( int ) > m_releaseResource = []( int fd ){ if( fd != -1 ){ ::close( fd ) ; } } ; } ; } namespace utility { class monitor_mountinfo { public: monitor_mountinfo() { m_handle.open( "/proc/self/mountinfo" ) ; m_monitor.fd = m_handle.handle() ; m_monitor.events = POLLPRI ; } operator bool() { return m_handle.opened() ; } bool gotEvent() const { poll( &m_monitor,1,-1 ) ; return true ; } private: utility::fileHandle m_handle ; mutable struct pollfd m_monitor ; }; } namespace utility { class Task { public : enum class USEPOLKIT{ True,False } ; static ::Task::future< utility::Task >& run( const QString& exe,USEPOLKIT e ) ; static ::Task::future< utility::Task >& run( const QString& exe,int,USEPOLKIT e ) ; static ::Task::future< utility::Task >& run( const QString& exe ) { return ::Task::run( [ exe ](){ return utility::Task( exe ) ; } ) ; } static void wait( int s ) { sleep( s ) ; } static void waitForOneSecond( void ) { sleep( 1 ) ; } static void waitForTwoSeconds( void ) { sleep( 2 ) ; } static void suspendForOneSecond( void ) { utility::Task::suspend( 1 ) ; } static void suspend( int s ) { QTimer t ; QEventLoop l ; QObject::connect( &t,SIGNAL( timeout() ),&l,SLOT( quit() ) ) ; t.start( 1000 * s ) ; l.exec() ; } static QString makePath( QString e ) { e.replace( "\"","\"\"\"" ) ; return "\"" + e + "\"" ; } Task() { } Task( const QString& exe,int waitTime = -1,const QProcessEnvironment& env = utility::systemEnvironment(), const QByteArray& password = QByteArray(),const std::function< void() >& f = [](){},USEPOLKIT e = USEPOLKIT::True ) { this->execute( exe,waitTime,env,password,f,e ) ; } Task( const QString& exe,const QProcessEnvironment& env,const std::function< void() >& f,USEPOLKIT e = USEPOLKIT::True ) { this->execute( exe,-1,env,QByteArray(),f,e ) ; } QStringList splitOutput( char token ) const { return utility::split( m_stdOut,token ) ; } void stdOut( const QByteArray& r ) { m_stdOut = r ; } const QByteArray& stdOut() const { return m_stdOut ; } const QByteArray& stdError() const { return m_stdError ; } int exitCode() const { return m_exitCode ; } int exitStatus() const { return m_exitStatus ; } bool success() const { return m_exitCode == 0 && m_exitStatus == QProcess::NormalExit && m_finished == true ; } bool failed() const { return !this->success() ; } bool finished() const { return m_finished ; } bool ok() const { return this->splitOutput( '\n' ).size() > 12 ; } private: void execute( const QString& exe,int waitTime,const QProcessEnvironment& env, const QByteArray& password,std::function< void() > f,USEPOLKIT ) ; QByteArray m_stdOut ; QByteArray m_stdError ; int m_exitCode ; int m_exitStatus ; bool m_finished ; }; } namespace utility { class veraCryptWarning : public QObject { Q_OBJECT public: veraCryptWarning() { connect( &m_timer,SIGNAL( timeout() ),this,SLOT( update() ) ) ; } void setWarningLabel( QLabel * l ) { m_label = l ; m_label->setVisible( false ) ; } void show( QString w ) { m_warning = std::move( w ) ; this->show( true ) ; } void stopTimer() { m_timer.stop() ; } void show( bool show ) { if( show ){ m_label->setVisible( true ) ; m_timer.start( 1000 * 1 ) ; this->update() ; } } void hide() { m_timer.stop() ; m_time = 0 ; m_label->setVisible( false ) ; m_label->setText( m_warning + tr( "Elapsed time: 0 seconds" ) ) ; } private slots: void update() { QString e ; if( m_time >= 60 ){ e = tr( "Elapsed time: %0 minutes" ).arg( QString::number( m_time / 60,'f',2 ) ) ; }else{ e = tr( "Elapsed time: %0 seconds" ).arg( QString::number( m_time ) ) ; } m_time++ ; m_label->setText( m_warning + e ) ; } private: QLabel * m_label ; QTimer m_timer ; float m_time = 0 ; QString m_warning = tr( "Please be patient as unlocking a VeraCrypt volume may take a very long time.\n\n" ) ; }; } namespace utility { static inline ::Task::future< void > * startTask( std::function< void() > task, std::function< void() > continuation ) { auto& e = ::Task::run( std::move( task ) ) ; e.then( std::move( continuation ) ) ; return std::addressof( e ) ; } static inline void stopTask( ::Task::future< void > * task, std::function< void() >& function ) { if( task ){ auto e = task->first_thread() ; if( e->isRunning() ){ e->terminate() ; }else{ function() ; } }else{ function() ; } } } namespace utility { class duration{ public: duration( long miliseconds ) ; bool passed() ; void reset() ; template< typename Function > void passed( Function&& function ) { if( this->passed() ){ function() ; } } QDateTime& timer() ; private: long m_milliseconds ; qint64 m_start_time ; QDateTime m_time ; }; } namespace utility{ static inline void Timer( int interval,std::function< bool( int ) > function ) { class Timer{ public: Timer( int interval,std::function< bool( int ) > function ) : m_function( std::move( function ) ) { auto timer = new QTimer() ; QObject::connect( timer,&QTimer::timeout,[ timer,this ](){ m_counter++ ; if( m_function( m_counter ) ){ timer->stop() ; timer->deleteLater() ; delete this ; } } ) ; timer->start( interval ) ; } private: int m_counter = 0 ; std::function< bool( int ) > m_function ; } ; new Timer( interval,std::move( function ) ) ; } class progress{ public: struct result { const QString& current_speed ; const QString& average_speed ; const QString& eta ; const QString& total_time ; int percentage_done ; } ; progress( int s,std::function< void( const result& ) > function ) ; std::function< void( quint64 size,quint64 offset ) > updater_quint() ; std::function< void( qint64 size,qint64 offset ) > updater_qint() ; private: void update_progress( quint64 size,quint64 offset ) ; QString time( double s ) ; QString speed( double size,double time ) ; int m_progress = 0 ; quint64 m_offset_last ; double m_total_time ; std::function< void( const result& ) > m_function ; utility::duration m_duration ; QDateTime& m_time ; double m_previousTime ; }; } #endif // MISCFUNCTIONS_H zuluCrypt-6.2.0/zuluCrypt-gui/utility2.h000066400000000000000000000131671425361753700203260ustar00rootroot00000000000000/* * * Copyright (c) 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef UTILITY_TWO_H #define UTILITY_TWO_H #include #include #include namespace utility2 { /* * This method takes a function that returns a resource,a function that deletes * the resource and arguments that are to be passed to the function that returns a * resource. * * example usecase of a function: * * auto woof = utility2::unique_rsc( ::fopen,::fclose,"/woof/foo/bar","r" ) ; */ template< typename Function,typename Deleter,typename ... Arguments > auto unique_rsc( Function&& function,Deleter&& deleter,Arguments&& ... args ) { using A = std::remove_pointer_t< std::result_of_t< Function( Arguments&& ... ) > > ; using B = std::decay_t< Deleter > ; return std::unique_ptr< A,B >( function( std::forward< Arguments >( args ) ... ), std::forward< Deleter >( deleter ) ) ; } /* * This function takes a type,a deleter for the type and optional arguments the * construction of the object of the given type need. * * example: * auto woof = unique_ptr(foo_deleter, arg1, arg2, argN); * auto woof = unique_ptr(foo_deleter); * * The deleter must be a function that takes a single argument of type "Foo *". */ template< typename Type,typename Deleter,typename ... Arguments > auto unique_ptr( Deleter&& deleter,Arguments&& ... args ) { auto create_object = []( Arguments&& ... args ){ if( sizeof ... ( args ) == 0 ){ return new Type() ; }else{ return new Type( std::forward< Arguments >( args ) ... ) ; } } ; return unique_rsc( std::move( create_object ), std::forward< Deleter >( deleter ), std::forward< Arguments >( args ) ... ) ; } /* * This function takes a type,a deleter for the type and optional arguments the * construction of the object of the given type need. * * example: * Foo *xxx = new Foo(12,"bar"); * auto woof = unique_ptr(xxx, foo_deleter); * * The deleter must be a function that takes a single argument of type "Foo*". * */ template< typename Type,typename Deleter > auto unique_ptr( Type type,Deleter&& deleter ) { return unique_rsc( []( auto arg ){ return arg ; }, std::forward< Deleter >( deleter ),type ) ; } /* * Example use cases of this method * * auto exe = utility2::unique_qptr< QProcess >() ; * auto exe1 = utility2::unique_qptr< QProcess >( "ls" ) ; */ template< typename Type,typename ... Arguments > auto unique_qptr( Arguments&& ... args ) { return utility2::unique_ptr< Type >( []( Type * e ){ e->deleteLater() ; }, std::forward< Arguments >( args ) ... ) ; } template< typename Type > auto unique_qptr( Type e ) { return unique_rsc( []( auto arg ){ return arg ; }, []( Type e ){ e->deleteLater() ; },e ) ; } namespace detail { template< typename E,typename F,typename G > void stringListToStrings( const F& s,G n,G k,E& e ) { if( n < k ){ e = s.at( n ) ; } } template< typename E,typename F,typename G,typename ... T > void stringListToStrings( const E& s,G n,G k,F& e,T& ... t ) { if( n < k ){ e = s.at( n ) ; utility2::detail::stringListToStrings( s,n + 1,k,t ... ) ; } } } template< typename E,typename ... F > void stringListToStrings( const E& s,F& ... t ) { using type_t = decltype( s.size() ) ; utility2::detail::stringListToStrings( s,type_t( 0 ),s.size(),t ... ) ; } } namespace utility2 { class raii { public: raii( std::function< void() > s ) : m_function( std::move( s ) ) { } ~raii() { if( m_run ){ m_function() ; } } void cancel() { m_run = false ; } private: bool m_run = true ; std::function< void() > m_function ; }; template< typename T > class result_ref { public: result_ref() : m_value( nullptr ) { } result_ref( T e ) : m_value( std::addressof( e ) ) { } typename std::remove_reference< T >::type * operator->() const { return m_value ; } T& value() const { return *m_value ; } T& operator*() const { return this->value() ; } bool has_value() const { return m_value != nullptr ; } operator bool() const { return this->has_value() ; } private: typename std::remove_reference< T >::type * m_value ; } ; template< typename T > class result { public: result() { } result( T e ) : m_valid( true ),m_value( std::move( e ) ) { } T * operator->() { return &m_value ; } const T * operator->() const { return &m_value ; } T& operator*() { return m_value ; } const T& operator*() const { return m_value ; } operator bool() { return m_valid ; } bool has_value() const { return m_valid ; } T& value() { return m_value ; } const T& value() const { return m_value ; } T&& RValue() { return std::move( m_value ) ; } void set( T value ) { m_value = std::move( value ) ; m_valid = true ; } private: bool m_valid = false ; T m_value ; } ; } #endif zuluCrypt-6.2.0/zuluCrypt-gui/warnwhenextendingcontainerfile.cpp000066400000000000000000000035361425361753700253750ustar00rootroot00000000000000/* * Copyright ( c ) 2019 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "warnwhenextendingcontainerfile.h" #include "ui_warnwhenextendingcontainerfile.h" #include "utility.h" void warnWhenExtendingContainerFile::Show( QWidget * parent,std::function< void() > function ) { if( utility::showWarningOnExtendingCoverFile() ){ new warnWhenExtendingContainerFile( parent,function ) ; }else{ function() ; } } warnWhenExtendingContainerFile::warnWhenExtendingContainerFile( QWidget * parent,std::function< void() > function ) : QDialog( parent ), m_ui( new Ui::warnWhenExtendingContainerFile ), m_function( std::move( function ) ) { m_ui->setupUi( this ) ; connect( m_ui->pbOk,&QPushButton::pressed,[ this ](){ this->Hide() ; } ) ; connect( m_ui->checkBox,&QCheckBox::stateChanged,[]( int s ){ utility::showWarningOnExtendingCoverFile( s == Qt::Unchecked ) ; } ) ; this->show() ; } warnWhenExtendingContainerFile::~warnWhenExtendingContainerFile() { delete m_ui ; } void warnWhenExtendingContainerFile::Hide() { this->hide() ; m_function() ; this->deleteLater() ; } void warnWhenExtendingContainerFile::closeEvent( QCloseEvent * e ) { e->ignore() ; this->Hide() ; } zuluCrypt-6.2.0/zuluCrypt-gui/warnwhenextendingcontainerfile.h000066400000000000000000000026031425361753700250340ustar00rootroot00000000000000/* * Copyright ( c ) 2019 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef WARNWHENEXTENDINGCONTAINERFILE_H #define WARNWHENEXTENDINGCONTAINERFILE_H #include #include #include namespace Ui { class warnWhenExtendingContainerFile ; } class warnWhenExtendingContainerFile : public QDialog { Q_OBJECT public: static void Show( QWidget * parent,std::function< void() > ) ; explicit warnWhenExtendingContainerFile( QWidget * parent,std::function< void() > ) ; ~warnWhenExtendingContainerFile() ; private: void Hide() ; void closeEvent( QCloseEvent * ) ; Ui::warnWhenExtendingContainerFile * m_ui ; std::function< void() > m_function ; }; #endif // WARNWHENEXTENDINGCONTAINERFILE_H zuluCrypt-6.2.0/zuluCrypt-gui/warnwhenextendingcontainerfile.ui000066400000000000000000000046521425361753700252300ustar00rootroot00000000000000 warnWhenExtendingContainerFile 0 0 651 337 WARNING!! 269 300 111 33 OK 200 270 321 31 Dont Show This Warning Again. 10 40 631 231 Your cover file will be irreversibly changed and we suggest continuing with a backup file and not the original. To unlock the volume about to be created, you will need to enter the password you will choose and the volume offset automatically generated by zuluCrypt. Instructions to unlock the volume are as follows: 1. From the menu, choose Open -> Volume Hosted In A File. 2. Select file, then choose "Volume Type" = PLAIN dm-crypt. 3. Enter the generated offset value along with your password. Qt::AlignCenter true 0 0 651 41 12 75 true IMPORTANT!!! Qt::AlignCenter true zuluCrypt-6.2.0/zuluCrypt-gui/zuluCrypt-0.png000066400000000000000000000476671425361753700212700ustar00rootroot00000000000000‰PNG  IHDRj…ê¢sRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ 28#Ä0æ IDATxÚì½Ùdùuç÷ùÝýÆ‘ûR{u-ÝÍ^¸¨©&9#R¤K‹ã±¤/# ¯øeŒñ<ðƒç°ãmA´5¢¤!9ÜšÕ]ÕµdUefå{ÄÝ‹²²˜•Y•Õݤhª¸ˆ¨Ì¨ˆq?yÎùó=ç'Œ1|rûÉÞ„âÇùúæ'tQÅ'ðüÿ’¿i >çg˜7LŸÀó7Í0ó“€èx~2ЈSüL|L ˜Ó‡èx~|МÇóîO’9åýiáúP}ÏšÃ`>Žû™xHÇ`Ž<>zp¿?6ˆ>çãG<ë9÷‡?ËúŠ~νù0 = Oàùx¡9˜£‡}äþ¸CœÏIÀh@=çñ‹Àt*€>çÃó, sç˜ûƒÇö‘çŠ:¸P‡AP‡î O¸WGž«Oé… r>ÁãCƒsð»ÃîççÈáw8àÚàÚ6NÉǵ$66V)ÀUãì¸@¶²1ŒVh­Ð¹BkÌ…™Jr x Lqè‡îå @¶Jâ´KýOày1pŽZ›Ã®æ(,Þ¡Ã<‚’OP³¸¾¡\)a—\üz?)Ê!^àâú)NÙÁˆ¦ãS q\P8)þX¢•@2ÎÉ2I–ÈD“¤štœ‘HÈ€ü˜£8$q X !„8j}>q[/ÎQ÷drCî!PŽÀq=›pªLÅø8K†ú¥ÌÅ™H²NÂh#ÇÑŽd8̈º1Qœ“ÄŠDB¤ìupa’G,‘>âÊŽu_ŸÀóâàXGb™ÃÖ%BÇ¡äû”¯E°`S»l1cÏ‘ŸŸ¦~å!KÓ5¼…áÒ§± ÎðEîòW4ÛcòÙ7 Xc–1»›¨…ª¨ e…Å”ë?ìR«è³gÙÜòèo·a°A}sLo½ èIâÝ”¼/iï%ŒzŠá aœ ¢T=)áiët`Nè0<Ÿ¸­ç8KaàPõl*Õ€ÊÜ4õ¹Zxum™òW{üÜB…G{|fþ2Îr—inGëü}V»ò©‚Úv™"á}ª pVŽq: ijn–î0$Möô?0ôí^ÓbFä,]ó0#ÁÅÄc÷¦"5¶W=«Cò­„Þ†ËÞVB¿oä‚q*™ñcˆ¬Çñ ƒàü)vØ}}byNÎaksð@Sr Rò©O;4f—i,Ö©¾Yãü²Á|všùWµÕoòéóËÜA3×YaéшȞ°wþ"%B¼Þ€(˜fY®ÑÞiõvž_ Ü|@­×À¦>æAPÏ,5ÊdKu&FãVa”DÔû9 bH/ P/_b %Öæˆù=Íî†fk-f¸³³±·1¦³Ð™(‰dDG,Ñ+;º{b}>±<§ç°µ €Pê5CsÞgîJ™ú•—h^ŸÅþr‹«K;œåsüÅy‹áÝ?åï/,òh£J“›´Á7Vé´3Ò!ÌÚÔ«jg‡t¤Y¾±*AwìªMŸ”«NÊð+9L$=#p´d¶V'H:ìŸf¸ZðúÞ:cA Ýð)ÿzðßtxcÆãþ5›­÷mVï jë)í´ OÇå“>Éóœžã‚âÃ.ª:Ô]¨5§hÍXøÔ Ë_hRýòW¸x.AP¡ÌmÎð9¾ñÞ7yMLþr‡ek‚wÄ”IØBCEBQiRÛZg¯Ô¤ hØ6rbÈ-…Ý´T[„m,|e¨{6EÉf„$l4)§œ³+¯\dXR´\˜±èî¦Ì5]ÒaFCÜý³-Ì1÷î'Ü{ð¨³9Pt¢‚ácW–>¶@ê¸øÇcœOÀy.8'x N%p¨OW˜Z ™½ržùù‡,|ý2SÓ/Ÿûß*þ€/Œ=¡§X¿Ã™›LÙ.㮡³×árd˜hEÉʰ•¦–Ž“Y3øî€8OQ…Æ1}4á EùàJå ìŠCÏr ² …Á™ì2òÌûfïß aY„éû˜´ j+òªÇTÃ!›©òfÝ"þ9M^ä¸c‰«=L#£§çpŽÍý8Ÿ€sªçÀMU‡FÃev~–æÛpíõ³4¬Þ¸îuöp)»Wøæ»?ä‹í6­ñûÁéÁ9ÇAãB/%’IF0˜E0êæˆÔ &yÙEø`{…VH@§9vÚc¬ ¢,ujºîRž ¨„àϸ8–œd”Ê.ÖÒ4i¬Å\ ÎÖžÃZ q£Œë?ŸpyܦæBÄCA\Oå‚ÔInËùˆqÁÏKGàq¹ªpšó.sW\8¿ˆÿK3\þ•Sƒ‹¬'³¼ºp–?/zøô-^÷>ΦCYg¸eŸ&ÑÊÁP2ꤘí­ ñÕ&ÎËㆇýÚ"Ù’ÓZ"k¸n™Íâ•ÒH¿ø.,O† [ó,<a6Ò Þʀ袲‹uœ¥{¦L£\‚ç¶8Oƒ0÷Z‰³—-®~9¦ñ• Ö@ÌàÎÏ3ùËU>Ãî­=fW‡”FSLT Ýz½Oï^´A|z‰ñWæq¾Ü¢ý<—_YdóæMæ_ù;ü€˜KØ”ö is —ñ§®°²öˆZ¯ÏDt˜Y¶ñ­Åè߯,EÓô:>ñ­÷Û¤Z³³ì¶ á´ 4_¡–Î’lçØQ’÷ æl‡qâаs–‡ÕÐ¢æº ‹‚˜§‹·ú…-ÏO™¼òÃÞÌ XÃÉ¿àñŠª±ä2÷©ç^õøÔ§¦}žõQÊË‹³´ßPߨcv³Ç½{—z9ñHSo'$»C’6z¹†ü­KÈ//á~ùŸò—37éóC¾°Õ%¢ÁònÌì+«Ì’–’â2ʺ0ÎÉ›„ßXeêåyÚ¹&÷áRÈV_Ñüâ÷-IQŸ¥êøÔö:Øÿn ñNŠx¿@ýÕˆÞ•ƒÔ¢dØM…ÑU%˜(›l¬©äŠø3,ÎSà„õ—™‹æ—m^Ýcþ|%fɼGp¿Mù¯6h„6£<䜽ÀînŸÒ·×†d%…û»¯Púk_½ÂlZL¾ñ þƒ—C²µ]¬E‹UËA½³Ë´p(ä»±<¢ÛêÚ]Šït(=(pòÿ¥ ÔSG¥”ÿÏ»üêÓ¬ßßdÚ*PMCç7ÏàýNÿn‚óÜA}wLúÇ{D›¥/U™|æ ‰#`œa'ŠñvNÙ+¨ ƒ¯ ½ÿù[qê˜ç”Ð|åOÚÚW-6'¬®ž$C‡ZÓcêBÈÂgê\y»Âòóø i³ÐŽPïô ÖRo„ÛK©ŒÛl®ö?Ho_eôhü󯣨ñ ý&ƒËÜøÃÁ/¾µÈÚ.ÝÌ™}ôoè­vñ&® ›a¬pdŸ¥qŽyo…`{ˆñ#š¶ÂúvŸoÞgt®Jÿ+ÔtÆ êc‡.­Ë.ÖKkù:SoŽ)½î‘¼7ƒøVNz_RnXx±"t ŒkHm)lXø‡ÒÇ©?ÔjëyòÉgÁô7γ¤š‡Ïïx«õ3%æ^aé+gxékSLé îdÿÏî³(C:wG¸;šR5!ߌXßQÈó[SøÿíqÞÚã.5*ä”í*÷ÿÕ·ø…•!ݱ…so—`gŒÜës=Vø‰ÆÕa®TÔ•&÷ t’a‰7p±óœZIïdTîLW:ðh¸sp¹ÌÖC‹Ù‡}^­W¿þiB§ÀþÇ-6þõÖÿõ“¸Z§½mQÝÊðí¤CͶ±,æi™É‰ÜùåÃ&í蛉ŸxŽO™#E¿ƒ›}4Hj3Ós’…ň—¯öh½³¥Œ¯ÿ6´ß£û ÀD ÓË‘[»ìÝ“Ì5ÉßjRùÇ—i½µÄ;ìâí®Ð˜»Âø}—ñª$~§ËÕwýÁ»?ÄK*‘b˜kzJ3ІÜ@&J*”ˆ¶ÀÑ @hrÊ%r?§äkG@Ã#Ÿ ÉogÌê¥E—]£63f/Ïi¶%漡õïO>Ü#õ ¦7×Ä»µ^B1cKžòú9§´8Çå?+ãŽSÁýMYŸÃÖæ’£Š»ÃYÓƒs~â®¨Ö S-›å U®~q‘™qH}OÐZÄöë7z\6p’½6d³«ˆf}ìÿèõßmÑmÔÉx…9õ{«Ôßý.âû&/§fÏf¸±F8NPlKIW zÒ0Æ0¶,r¹†Bk€eac°ŠœÀ(Â4§ìXT,Cô&†éL3W7º¤ŽG©ÒÙ‘8¡!zoÌ™s;×CX—Ìe9E*У‘JŠÝ5PÈLc„ü`=ë¹ðœ2ivœ:îàg§Ñáþ¤¬Ž>tdL+ëÔ¡åçS凚Cí\ÀÜg›,}q3×g˜ ]âTàE6ê¯Rß“XR#·övR¢3MøúãßnR3 IÎ0\gñî¾»I­íbßê³LÀd;¢3ŠYÕ†]{ÒÐ3Š‘†HÒ4'¤mc”zrްmƒk®4øÂ¦d*™¦Q¦³„ÙAÁl]0—Y”ˆñ|ÃÔ‚E§dЉ¤.,Jd"à *í9–ØOV'ŽƒB+É8õjKœL<üHÏr‘í;8c#Rb޾“cƒ@‚ó2É¡çɧNòÉïpœ§ŸÃþ¿”@gò)ïè)çi!ÔAöÔ>luÊ͇™i͹Å×V „å’îåä·G46B„ ñ·ÇllOæ×—ðsšêEÃ­É o>¸Ïdk‹ÉŸ®p½ãl:Lw%»“©d½0ljMÇú…Ú—F¨ýzÒ“ÒÀ!pžÄfJí'0 ck˦œÔRI3’Ì `©›±<”œŸ˜¡Eµb!Z^+ Î2ÊÆ ¥&Ú*h$ $ý4'É%¹TO•&N´BÎ)b¬B*å²Mͱ)Õ5UåP­øØH¢@8Óh«‡;˜"id…Ò Œ¿…ci„ ÑÃYUâ…cÜÜE9Nn£”‹–Ú78CîGØvVq“˜ÂRˆ¬Ð¡°”FX °Al#Pi‚ÒÆ@&±´ˆ'š‰Lú “|¿øW‚'J%›ê”ËlËæÜ\™«2 «×lHjk9Þ–Á¤”zša'¡·‘}~Š©ß9G<²ü§ܯ}žõ¿ø·,™ÞO(G)ÞjÎ^gª„uFÐ. C¥ó#…_q¤¦dž±*´¸ <¾­(åPö]vÃf"ØL »CÁÅY‡¥ªC11´)É  ™ÄîiŠ‘A$ý\1¶l¥N.ˆžÆòœ”ª=¨V,¦l¦/VX8We¶,hVlœ\Ñ´-¤cHúUjH¨U)0h»ÀŒ§¨X.¹ãbû.yæ2rbÜ|ˆ[ºJ Õ™ç8•G8X“–-вNßj`‹ÂÞÁÎ÷°Ã"n+EáŸÇË;„¾"õKÔ·Ú­ Ì“÷7±·{ ×Ç ºŠéÐIúž~E=¾aàP™öi,ט{kÒùk<øãÿ‹I}o—àNw#Am 쑦»•‘ºIùëóÔ½U•Ѱl¬ùã­tY|°ÍK{ ³•po¢¹­àA¡Y—š=ƒCB¬£à§£9IëžÚ?BmZ†žô¤dW…lÆp¹ZpÙ˜ñzäÂ×*ènBØO™HØÅ¡£ä˜‹çô<·u8Îñ=(O9´^*1ÿj•Ëç-®\󘑚±FVª`Ë2­BãΗéøe$6eJ<¢ &f—سtÿ.×G’øÊ4QPfž¤C‘b —‚*í¸Çâ@Q Zd­3ì0Æ'úöwøÅ·>ß–8Cµ·ÊÙVÈ}*Ôn¼Ã§ÎÏðþ¦‹?ÎÙûVŒ_-Ø^/Xq k$=.Z@ØTçK´.•h~z‘Y ~£o yy5à N-„±Ù&Œö›>ÁùŒé•-¤ëÓëÚ¸+’3w¢‘œû‰à¦Ü)4¤¦ýœ“ÄWÏÒ?KCí±Ü—˜ŽµbœÛôdL¯lÓÍ =^òË–Bƒe'”E/6¬Ú÷ ìÁøñÕQx>”åyⲪ.Õy‡™+W^5¼þ+Mæ.4°wl¼²KR­âbi“à#tÒFxgð‚*µ ‡ÅXp&¼CG"©ÜÞ¥5ë²9|ªæÑO&¨{h]l³f—>C¶œpãû#¾ööuþÕc.pq|XÒü3íºKi£OXNpÏX,O7¨Û1Í<ÁŽt*Åþ_¿å;”k>õÅ eêsUæh²’ލ¥‘ÑŒ"ÉÜXÑD{ñ×T~©…\n1rl²H ¶côhL·_PÙŽØåÜÊ5w”`M*vôá‰üóYàp<YÕ”=¾NJHQDJ1A3”‚¡o³hÎZš#LJ¢=kîk‹Ý"g|LLhNÔó‰wÄIñN`¨,»Ì}ée.}¡Â«b€ûƒþb•­`' lC<ŽðÞßd~Ô¡(z ë)¼!Í5鈊Q—¬Ô"ÁÇAÂΈæŸïðf«Ê¨¦1­‹WØÉSò>x eÖCìÍœ 7#ㄹ…ïÑÌ5CS0¹·ÇtÔÇ÷,’Gš`1c=ʨvbÎo Ꚏç’g†Åsej{»]›I· ;¸–¡Rw©/Th¼½„g#¬½Œé8GD’’c‘džþFWj¯Ö¨V AÎvi¯WP꧈ o'&æÜÏ$÷rÁº„] ]`|Dl%¬ ÍsêqG“µêÐ ÷èâ UÄŠÈØŒÐ´m‹u5lJF“[Ùm¥ÙÊ2ÚIÁè·õ–ç‰Ûr]‚¦O}¦ÂìrˆWhÊ}®½ÊNe–ðý-Âшl¤h8qZ¡?¶( +,ífäï3Ô婈Ü>–Ì)1Ö¤ƒ³cU Î`Fma…ä¥ ;z@û:\È~b[>ñ£»7nÓZ^¢Uì¢s wúÌx6ã*Ù/ɜٯ4Ùž©±»½AÍóˆµÄ³,h®¸6C×b`ƒP ã@µéиPgñÍ«w·°˜î9¸C3q°’8Lú)ég›´®µ¨¾ù2ÛS x?\§´=Fo&”#ƒn›iØ( Ú-Îø±»J±8§Ê­‰8$Ö²­.C”IHSETúžbË2”\‰÷83—’a"È‚I¶vþŒÀýÔIÂ'³ž–ƒ‚ºÊY¨.O;˜<§øá Á_­2×èé€ÌmÐô\rNêc6“,ÃË8Œð Ä%i¹HËÆwkda@6Šð¿»GKvðƒ€´RÆAbdëXĹ!Dà%ãQ…Òƒ-¤e#Þ-xy³M­VA¨ «U¥\õ±6À³3Âê ÉÖ&•¶¤5‘D¾`Ž‚ªe¨ZÿòËåÙ*SB*ÎKÈûH¿÷PQ_öoæÔ÷:=I´b¿¹€ýõ×Q-‹dwû;w™¹=`üP¢7 :‰f½€ÍÇÁñð«:XYuU'YsBÍð8ˆ,>Ø~œyI!kð7Ú·+ÆóPR’f?:?Õ9mžÇ,Çì+ê,»µÅôR ..Ð4¦Kò™ivc½Rì²ER'¤+–4XÊÅ)UÛe.*ðtŽpmÆ¶ÂÆŠr‰ž±Ú¢¤ "“èILKÊŽ…öFÒfNG´­¯3¦!JdÜráM /)b_À¹Ê^;*àªî°A€EKjBËbAÙ¦>ïS¾b“Ñ¥§x*Á‰ FX0(Çq¿ =ïQ¾âµtÓ>A®ÉšÓ´u ¨3ÞË[YΞçhÔqÕæ”Vçès~p`…ÀÎÁ΋'ñ’)ò§’¨G»HŸÙ»uË#x\,s,DÙÇÞ3³ÚAÖB*'“Pv=œ¿h“ß2TûC*–²,„m1y}E,4 £ÁÒ#Êv(,2˜Á ”bÏ„ÖØÆ =‹ !Àh†–Í@*²Lc‘cdŠ3TØŽÄéKJ3!á#Íg£[¹Œ³[„„–Eˆ&ñ,슠Ú(¶ú|ªºÎúC²Õeѱɤ&ÈÝ\0 lh ÊÓÐ`´—m§Ôº’ Ö8‘d3“lŠN¡È}W•§x8§íF8Î.ø ž†`?~Ï£ÙÃñCô —'žU`tÀ<^º¶ N ì;mævG´ªìª1Þ9M1]A!ŽÑ¸“ ®ÈZ™<,A¢(CÖÝÅ}bßÇ.…dÆ#0šÔ€k‚8¥œ§hÏ%.5±ŒBÌ2D¡@‚µ= ÏË›#¢aÎH ¤½ÿ±­\₲±™òÄr…n;Æ[5,ÇSxx–Àà)ç‚S²©Ä}Φ Jµ›®Mkm—Fª¨D9~.Y‹ ù\ˆ»ìcÍ;ˆ÷·™¿ÛcV:tV¶)í 0ƒŒ½\²WhúúGàd'@óB“)NHäšcªÞÇAd ¯8iÆÏ±çö¢£Ð ´ÒÈ’‰ èIjrD'`ùDM›ìíg^m°uažÉÃ>s»ÛdFà|õ úgÆ>)ù;Cœ™2îÌ,,ÌcDÒœŠ1ì÷‘{ÂrÐå*,Î3i–˜l™"¬P1^žæá8û¯¾…w;ÄÜáw2Ò"Ï JÂ’5ç38[¡Ò0—ÚT´$V¡A) ŒÁÁ צYwiÙOiÅÀõTc 2±"›(Š«!áÙ`b(« Ñ$Âä6y¬HFŠR¦é†nV0”O/Ç ^°üY¿{HÇA¤yþÜN ÎóàyªñKJŠÂ%ígD—‘±[Ⱥaý{¸tù"Ñb‹xP°xwB¤z™ dÕiÜÌxÉ˵œÍÝ•©EŠLP÷}v6a¨ o ¸l)&&ÃÜgÊAFLÚ95ÀT-&iA°qmV0üGŸƒo¯aL›ÚjÎ`k‚Ø"Ⱥƒ,êY„33E1î!íòœJb PØÐË”|¯ìQÒîH2ŸˆØI wMr¤Ö蚃½Tŧ” C^1¬þõ.—Ó2JlÊ‚4ŒôÓ1ÎsÁyÑ’Ïé¸J<ÃݤƒúP’Œ£¾PJÈAº7bÜlÑ+ìE†ò®bz¦JïáÕÙ‰$ý6~žqæÂ,ÛA…q?aÐ;#Τ9âÚm“Ý’Leì!:({%’¥»GLÛØçKÜíz43EÉÑÈqÎtÉ&ÞíÐ\Pt§¯¢[³Ôç"ìÄ¢Ö3p,¬™ öù÷|€×˜BŰYbò(aÎr‰BfŠ43ûæ¼äb/V±g|Âv—þËIWWiÍÌR”Ú˜Á„a¢ˆ+.Ž[PžmМÓÜo'´v3Zå*½Íˆf"éš~¦?žJ‘Ÿ&Íÿ‘eƘg¨?Í üüTVﴖ瞢€tœ3¨‡ìl¥<Yœ-–My½GV±)î§„¾MV$¤‰¢¾Õ§a÷q£‚Y!È´a¤mXksÖq(l‡B€”ž1V=Ϧç4}Íø‡]^¯—°}6Kf>àï §”V2ÔV'ŒÔ_ØxFa pKxŸiÿv“(QTú’r”㎠¼T£cÉP bÆQ²q§-ðgK¬µSZ™@YRHd¢qr¬»ˆ…IhßK¸¬ ›j'BŠ<ÍIÅH|Ðâ¨g%?ŽÚO†¼8D/då>Ïrú>õøKÈ"Éh¤h«„ÕØãÛžæ%ÇæRZPq ð3&ZSV ãX$ŽÆ1¡ 7` ô€Ü•ŒµEÅHV®¨»®6ŽEhܲMPq( ÈMA¹¢´E3˨¼±À£5›òÓiDÑ/ÐEA>–8 òZșϕ(U¬t‚Jô^F5ÒÈAAe\p?UÄòÀBÔ\˜¯¢­°‘Ý”p¬Ê&CÓ‘©]¶qZîúˆ©³5Ö•Í ŸÐŠ%³c‰,4=)ˆõÓ²|Vðãëÿ+ô±ó"–GY“ING»¬¤e ¯ 3ÆPÒxh ËÆ6 ¶ÖcPæñ2Ü ,‹.b_@f º„¹e%‡¸â ªÝO)îÙ83!ùÏÍÓÀ½»ESÕð—jf±±5ÂKŠ¿w©_­0^–X”v8wcª{9º§¨L4Y¤éä†q¡IËAÕŽ0Ed€ë3Ü-¸`BÖŒ ®`KŠšG¥éâV-Æ«]–28»=AH]6¥&S)úCg?Ö þQ!zØÏŠyÄ¡¯8ÈL$ýD +‰-èZ†û…b ›’.p4¸Z#„²llmö]ƒaôã×¶°Ð` „Kì¿—+ÀrÀË%ÞÄàïd8دThþ¸‰q®ïÑb¹µ]»„éF8wG¤Ÿ9óõëT¿qÿÆÎÍ!—ÖS’Ý‚h#§6XCÃJ¤ØN ýT7-ÜÀÂ*4³Ë¶Æ’°âÒ \‰…²,’L! ˜ŠGá JyŽ}¦Ä£]I«î‘¬NXÒ† ‹DØdJ@—s¬ËúqïNóã~}çæÎüHô‡x ÈŠýÚqYì×JŒÄ36ξ, Û€ƒ|zYhÙûKE µÿXil,<mQ¶åIA%ÔÏT>Û ÇŒpS IDATú_]e;±¨nFxkCU§û`ƒÙ¥ ˜ù~D>âýb•G¯Î&mrè õž…‚Ó׬% ÁV¦º`ÂU€SÑŽK¼¹IóósˆF…ÊÎ6uEåÙ‘c§ž Ñ# 5Ð8©ƒ. F“ëŒBîWÏš8ú3q{žÛâPÜóTT@QHâ§$¨ê)óÛqô ²VM”ÑÔJf:$|¥ù ö—àÉ‚Š2¤+#¼»cöþ×È~ï ¦ií®1—–ÉMv'ô×ÇÌíÆô†ïgš‡‰¦­mÇàƒ´4VK3\ÝåŠÌ±7ú 3rÛ+Af@;µp-M)aΖ¸×ƒÚÈAn:"N%Y¡Ÿ ’æ€yÑî ÃÓ}ʇƒèœÎ>©ç$=tøø5×BM9ð’ƒûŠËüÿp–{7º¼4=Ëú÷vhíöi¡Ì° ›ö½ÁÃ1úW>Ï£þ; *X¤ÂÞÊ…w4pV3¼Ý”|Pp+U¬dš #è+…tmJF¢tF¾»Ã¢¶¨´âP°ÕyÕHeHH pV= Š…¸EäÛ1u•‘(EaØ_=þ¬[œcáy†ë:Ú΢Üìº&Ä3ôAÎc=´>л`-…¯OSû|•àµ{÷ÆLã¶còaF÷AÌüHX<Ìßèbþáuÿýÿȃ긄Al? õÃ6îÊku„Õ6؃‚wcÅû¹æA¾_åNK«ý€ÞµÑ–‹ @X¡öÈJ›™"P)¹6` ð,¤gcÅle´ X¨—]¡(È)Ô)²È?³–瀧·§½œX~Ò ‡Á9À m¼YŸÒEŸÖuCíKM–Þ¸B:¼>¢ÿ'™])¨Ö8Æšx¶–à PtX"Ÿ­3š ˆb‹ la96R%¸:ÇÆ SÊ$ŒÆ–ÆÍKX}A}œ¡â!CÂq°žjDü¿Y!Éô¬ÍÁ8&H~2Û/p¨W-¦Îûœy­ÆK·ÅâÏŸcnzûì<›£‚t­M|s`so£Oü`Äù•2òw/2ùÃïò.2\›Pþó¿àÒƒùª"è$l %7 ÉܰV(Úòƒ­.P¶ÆÆ(˜cß|Àœ˜Ðëu(|ÉN–c+M J Lá€Ò+°P¥3_fÇwICÉõƱíŒ&ŸþùE?ž˜çCÔJŽ›_|xvq%0´–mÞšañ—.2ÿkW© î±òí–ßï3µ™£WcüD`3MÞÝeœAúŸ_`ð?Žao›Æ•:ßùÓïòs+1­w:4QIK{J°V(vsÐÊ{³R ­5:dŸÛ˜í„rOÒôJ$X”BDZ0|’j Ë-˜l$Ì$9‰§ØgU‚ÛVOÁsÔ›¿UðœB;ò,xŽ‚S­ÚL]ª±ðÙi.ýܦ^óyeå}ÒÛ›LזּGyè qÄèÖz3¥ø•áÛ5LØØêRšŸgëæ}üG½–ÑèfŒbÅ\²’+JÅÎcpôÃù¡Už”ã sŽ b»ÆðìE¶·6h–ë¤õE&œ¨lc»û5¸Ä8›|£Ç\ššœbà03Û Ówñâ {a“ÿ{ø©Zm¶èvt®ßá¡Õ²CóBùëgXøÜ2_{ƒ¬1毋66SÊ|e±9ÈY䘇1£•˜ü·Î þÅÔæ3¿¸ìÐZr˜»¨Yx£àâµ×zNü(C Ùû6M—b,1ŽÏ£Íò‡}ì¯NÓûoæÍ9 oÇÔvnrn#¦t?eéAÓ)°vbn¦ð^Vð0l+E§›ë žîoÒì«#•pÐEJ³VCw°gBJÓŰÏ›+%—˜LaÆ9²7&]ªÒèÅÔÜ”õÞÁ¦¢V€%cøà<¿Ã‡ù[ Ï3À9ÎULLo,T™¹>ÇÒçΰøëŸ§rµÁ£øgL(ɰؤØm³è voÈÞé¢ñ,Ñý¼÷ÅW1(J—÷˜ü Kø÷8¿3a24v#ng†;©æ^&Ø| Îä8òPŽéIw¦„Bjr¥ÚB¥*A ËБ KyÕÇñ<4QRÀ¸ kÔÈçklµf–²dˆ“B/%pl\ÇàIù Á »·ÚÇ}û°²ŒÓœ—ó1‚st4[T¨×¦—*̾^bñï6q®Î0¢›™iiÖþz—+»©›Ó¿Õ'»Q¼\ÁùÝ%²O?äâ7ïráÍ%¾ÿ˜Y0XéãleTÛ)÷2¸iîæš-¥ž´óîÊ,ŽÔæ÷4) RÁp8 šY¢9ã«‚Zs™±Ü$™ tq<°rÊ\ÌdˆImÂsÓì¤6Óó5Üf I0)ðäÓ5¿Ÿ¸ëú¨ZžƒÿÿaÅ`§=™ãŠOæOÌ\®³øÅ:—~yŠsoû8|ìÞ&×nth¬Ìoi¼TQº7&¹¡›~cšñ!úÞ&Ì"þ_wyýûfD,w4á^Îfª¹• ->Îá®Ì£y¨'IÈ'šl½‡ºx†™dˆªT‰LƒÙü>&pK.Wà$[èRíÙ䣌æXbtLQrÉ¢êØ„öÓîŽë•ú©çèk=S†ú!Oæ¤]ïB ì@½æ2µ8ËÌ˘ûR™+oâï­*‹é-ñíž]'ïIò[md;gRòÉÿÉyöþÙ¯±QX¼±ôÎ]êý¥M<´iucº‰æ½LrO Öµ¢sdI~ŽÞ˜çÓQ?Pk”hÍU˜~³ÂùÏ¿Bù—§©d‹.Å2ª7û4zýr€iØMIƒþ/®RýgŸáÝÍ[|ª9MçÛ«4¿ß§õ^B±“íæ 2Á- ·‹ý±%Ç%Oêµ>:¯PæŠ<ÊIû#¢G u€S‚|\@'cÎXÈТV 7 Fyo»ÜÄšhŒ5ÄÛ@©A\ñ}×2øC˜J¼#ðk}>*@§Ü÷ýYŽoÅy¦ ³>̹ròÄôPõmšçë,\ŸbðŸþk\ã½õ‚f[ÑüÞœò€j$VzLº’ü.aþ§ÿ„˜˜¥|HQôèn+)îZJ³+qÃíIÂí4gõ9à¨gdÀŸh³äZ+˜hÍÈ·ðŸòbl©Æä\ƒÎ…j*@d3Ö#EœyÔ|—$ŠQÊ%ä,.—(ê>¥Ð¢îÚ”Ç~'$>ª«oϹNÇ?>é/Ÿ½èöÏÚ‹ª TË>Íe›…×9wm÷koÓc›fþ}.í8[Š`àô2ÜÁˆt˜Ó¿9Füj ÷Ÿ¾DÌ6 &„–EûC–ÞM˜ZË©v$ÝH±ª +ÚeUìÈJz^øqýhyªIC–:Œý%ßGf!@¦ûœMy%'h$¸½‚|+E¤³™¢X´‘Ÿ=Ãýû}>U\](Ñ]±Ù+•qödà§ËñÃ’ž²B§ R_ÐÒÁê-;<NÕbú¥¥/–¸ö¥«ÈÏZô³-rþ_.ï8Œ¥lßïàŒ förîߣgBìF_›&Eø‡ùÝ]²›=ØjQÚHñw"ÖRÁí\ñ°0liñÄU Ž“‚À³çØ<ÑaKH&š¨/lç´›óØ@GX-Ÿ´2±˜qñç=üÕ˜Éj‡ÁÚ2 ó>q®p ÿƒ¼úÒï~y±[0?RLåšdœ‘Kù”K=|N'|Nà*žN·÷»WÚ×QùÕ¿f°•@Ûªõ ÆGÊY'¤6>û8/讞J:P <3†…ëU–¿àÐøåŸçAþ/ù;¾â½á»œû†aò½{¼ž*ú*çþÊéøq¯m⻂¸á?Œ™ë†Ûej«J;)[¹àýBóP[lkMOîïÿ}X“søƒYœ~XÒÑVê\ &qAw(ØK&ó.2lQd¦§Xp]ÌÙ*ÅZ÷ ÆÞIP:lÌÎÓë xõ\€¬ì±;{‘ÁªÅÛo•ùAb1C¬;ÈáÓç{ð<Ý\ùÜ™=Ï€Æ:š+å%ú¹)M:xÃkR0ªúŒ>{&t'ûVý¤‚^xûë˜ÒC¨VK4Ï•˜;o1ýùeÂÍ[ÜÆ~˜RZ»ÃÕh}£D_ ’~‚º5"%ö?9Ëà—Ï2·µÎ¨QQ¯öß8³-÷ÒaÁÝ\s?SlÐSû#ö³#‰?q(ý8']ŒÃݰYñXÑKàÑÐæìK /×éÕª‰B[P_yT7bÒµ˜h-B- Y.ô=ŸèaŸW^Ži g^qé¦çɃLò'âðøÛâ˜@ßœëˆnê mò$u8T*6µE™×ê´®ÎÐ\QjTñþõ ~dmTËz«æb=ÅäOÏ5´ø-Çì¹YvhL7™¾Veñ­€…¯Ïqm· ÆÂµ-vîgx½õ±E7±èÞíPº?ÆüöÙÿ¯½3ûÑóºïûçœg}÷}Î É!EQ"¥H޼DŽ•ˆã$H“Ö‰‘A‹íE (zÑ˽iïŠÞÈÐh$M]ÄvÇK$Å–¬…;g_Þ}{öçœÓ‹¡¨ápHŽvŠðbæ%ß!øüžïó;Ûw¯\b¡jsx¬ƒu{JûVHíî o7#™f܈s6rÃA¬v›ãgTÇSvž¶zyÚ2”ã“æ<'Œ,fÍè0£{ X÷r ’I»Äý$ÇM2Ä U¼WW‡›È›ºá’®(줜+ú$¹¼Pcg·Oþ…ó¬÷mh±ûcD¤Vl·šÓOØÜOa0œì6 èAeÕ£¹X¡þ‹UÖ¯ž§üÊyš—K\òŠÈó«˜wïéÊÝŒó[1ÅÂŒñ‹á“žBm+<){â©™›%›Úr™ÎµU–^/ÒùýÅh‡ìʯR¡¿Ùe)[&¹³KɫἳCúƒ]Äï?‡øO/±];Gºµ?whlNXèfè Ly›þHr/×ìåš~bÖõ±ÿ‹ËǶ±gÎiËГçŒ#ÿ¡é0¤k¥l«ƒër‰âj™î,§í ‚ª"}¹Ez³ï °–±_AZs «?Oš7è•¶Xþü/±ÿõ[\ÿg_¥ B2?À'Ãé8¡Â}àUèrœò$s„ãB‚Ó€óQ˜LÁ³¨øÕEAçå×j¬ýÂeÖ^ÿEjþ9B>`t“ë—‹l˜%:³.íI¡'éY†îƒyerlX=• yÖø€‡]§ìS;_fñrƒÅ_~‘ ¿çñJg‚¾_¢6¼Åp#¡óÞ˜ö‡!‡‡Ù»wÈÞ¾Cñ^bþï¿Ä fa¿ûW¢ˆ½MÃjf‘ôª3M9lgû‰fçDÙÇfŒ. ³gÌN†´©KÑã7è£Ïç@’ç±ËP–Øv«Üh/"KMÊ•qY0o9L“+žpáÓ‹ìÄâÆª6r±HyvÀxoŠÑHºÜûô‡+¢?üüÉŒ%ÇÁ¾7À=˜Rîg RuªÙ哜HO£÷ï8¾gQ*Y”J4 Ô®Xùì*?sçÚ ö 1¬ÒZ_äÆV‰¿pì°¶¿Çþ!Tæ~øhºñ©Ç*ö»Žø›Êr•æå"ÏtXþ͹º4¡Î„Ù8cðÀË÷o±¿˜Þ;ôÿvˆõë/“ü›_£ré7øÆýÿÂçò ÑÌÔÁ³$‰¶°'!Û †™!ŠrTöqÍGã®wàœÖq>ê,ÇÑ/ï9ö™8ÓÌ& Ã~@÷ö˜õv•Ú~ŠWóHµ¬ú„Í)Ù/­`ÛU ÿõ]ÂÛsb©Ù+µ¸x{ù¢¢W¨Qò÷±Ë¼ªyù_¾Áª³Á7¿ýW\ÜUÔ·3ŠóT0Ò‡qIO² ãê‹ 8žïJ ‡bæºV¦¹Ð¢x¥Cù•EøJœ>šŒœ‹C2t“lr11 ½œE)(ƒw #àÌÇ'~•dQ;}^¯pýùer4·îïrñÛ(ÀܵiÍ4ó­Óê…eÂßY'yq ‹¯³¼¾FòÁÊ÷ժώíãݰÓL3R4¢êP²´mð”¦$4™k©ä „8îic¡Qà‚•g¨´--°)š4Ò„±& r‚àÑÐùnP$qÎ|,zs¶‹U+eñzgÑ%½°þb››¶ ¬ –¾z•ñvó§÷È48ƒKUjJ°ÍP/”YÀbaïCÒÂ鿸Bõ³¿DõÏþŠÅb÷\˜b‚ 'Nqš’ ÈmûÝFüêyüqŸü›c¢†Çþó Óe?%S?Ä9×b>ÑïÑÜáêW/2˜zŒÿ÷F!×÷Æt'z\b’SF¹ R¹(•”í€Èz¿’QnX8í Å…þÕ"+× µç3NDwëåõ:ïͧ¨»*‡1 3M6QJ ÛÁŸæ¸âIFmª(¥a$Žy2öQð<%´ä‘ÉrÅ¢Üqh_ôYû‡€ß.³Í‡¬×^¥¸ñ“AúnDz ÷c&Ý9Á›8o<÷áÛlÜÙ'ú•*âÅ«t?Ücáfçƒ>Í—Û„¿÷fÑfZ»D3Þc¯PcMvzŸÁwÞg-ëà N¦Ü±êó>k¥UR§F(r\•3gN­ÓѦ¶‹ê\dn2LoB%³™Ž¡·1ü`Êæûcö¢‡tÙ±ïqž3‹l£”]Ûpÿ¦ v±È IH¹iÃúLÖúû,ÿáïcgCöÕ.ï ˜šr±Öaíö˜Á°Ççß\f3Ÿ’þî"ÖÏ]ãp¿G; ¸ò»‚ò¹ŸÇ½¡©Þ=`<.³¾sŸ^baOG„¦‚t8”°ÅLk>¥ZÊÂj»Ù†5‡êz‰¬6¥s?`m{Ê0wYmžgþNHùæ‹¡m‘aSé¸d#MiÙCä)¦`HmHÚu„›PÉ©º3Î:a>•rQ–T–ŠÔW|Úõ=JÝŒfvˆ =øÖë‚ ¡;Ïè †m¹TÄ)ú4¯,ðÝ%Áäë·øÒR›½N™þï.ðÎ…Û|î·ÖÙÔEÚeb4ŸGÑeø\ C›äÐÆ[,³EF-i³: ©6‹„V‡}"šÌX¦Måà&ó¥ßšóº˜pit£%›zÓCþ÷®-¸Tã{"H{I–=6™N;É™NVw}‡ŠѺR¡2ÓÈûF.«Ë‰9Îù×ë¸6ÄßÝGÏ#T¾Ääy 16Ô,CT+qëO÷ùÔËØlù ¯¯ñÝ¿üo\ÎÙø”ÍÒ§^#&æ<Ÿ!m2ކ\‰ &i“Ååb‘]Âjm™5w‹F±@Ä ·‰)1¢•Ô)ûì;„oÏymrŸÉ^Œ$V¦É 6a¬©mF$¿Ö@wªŒ†åý€vA"q@?\’œáœÍzÂiì#¯‚Mm¥DçÅ ç^?Ç•ËUæÛ+³ ùD}í=ŠS‰è&ìÎ5ýyÊl¡€u®„¥F½_!¸¹ÏµV‰½÷Ç´¬ ïÝ!ŸZp؉B*B‘êgÂ>5Îñ=ÑÁ{ïCÎ{7"Ü?¤±âзWÐ[w1÷澿Í+[êÓ”èæÅy‹ÕïlpaIóîµ+ìŸK,—ét$ó½WÎÛ¢˜æX1šä¤ó„Y¨ŠYi0¹8rbP\ã[JJŒ›v)'Y[¢÷íï"Ö—ŠÄþ÷¡‘G9z¹ˆ•ˆúS.\z·§4Ә·öù\Óf7S³r²BÍœ]Ú,n°W¹„£î³zÎÅ’ЛP[k°ï?‡šÝDoÍ(þ`›OÝ;¤q¿µEe¿ÌÊ×·XGlÅe $õ*EH{å›S¦QŠü­sÌÇ k‰Â‹ ÑfLu”“†Üž$lG†~¦ËÝ:y´r¶¥º¶NðÓ€úx—åûm¬Ö:³Ã bNݲ‰¦kfñ¡J9:ÌI6¦¤ÑŒ’©±Sk±±w‡rÁp'§Úb©€‹¥„q+g\³8êcu „¨Á˜Z§Åþ\Ñîï±8Ÿsi ð“ ¿ Ù‚|ÓÐ’×Ü¥oÛð koþqjQŒ1£„j”“ãÐP’J_òJž1t {L$Û‰cC€•çL'9ŽvpÉñ³Â|Êb$h\ª“Ž$ÎÝ>m·€^©0.ÅœûÊùáÒŸqùψ¿q@f Ö-äªÌ\f¶ËüÆ6ë–Ãä]C«³(#Ú˜Sº~Û»‹ã.Í­€«›P+JR0L@Ï í™Á›n2 Ö4§ÍPJPè÷2Ôf.ò³öím.—$QÙ°¿QÝM‰æ.Y`rMþ!óI&̇/ l×Ã.U¨]ýõÛ\ù'×ùæ·ºü‚*31ec3Ђ0ÎÉlÈRE:˰nW{Ø*¤=H‰°ab²Èb ©í@EÏŒIDATÇ”F 2W8X¤Ä76åPƒã¢ÊéA@:ÒÌváÁ|®Žýå6îo¯`‡°&ø[3–µƒMpbɶL±ˆD|¶È¤Ó†­“ó‚-©¶lZ’‹‹‚ËV ï|͉¢u8Ä61£ƒg RÈ…Á(…Q@}¤•#‡ªyˆN-“¡ÓÇoPNƉFS@¦àÚ²ÌÁÖ‚Ùh†l,Ã`„?Ó4ãÚ‹Ô­j kÔ e¢pNVk¢J5´g“úUŠ­*S·Œ]+·*䶃5‹°Bg'fo¢Ù‹4ÓT?tk?m¥‚¹&OJ[`|aSíN°}C¿tŽ…Ï\äû•Ÿc>z›Ë!Î_àpÍSC½¿‡øþ>voˆÎ ¾§Ñ>Ø~ƒr3™kLâb~o¢î qMçæ>Õ혥ÃÇkÑJ],SAè õb•8 Éd…`n1½0úA@8VÄŸ_ÂúW—‘ÿñUò/.bY dEì˜Ú\mg¸¡„‘bc®¸ål…ŠæávÆ“˜ g7w`|‹™£˜MºX_û.—Šuì,@^\Ät3Â~FÁvH 1nÃAL>‰É÷4YÅf c4§Te7šSp#'G ™˜š`"ÁÑ!>“'È`Nz¸‡‰¥ä K±ïÞ£—fxŒí0RŠ®ETÈ´ ‡¤R5=J¯j,Ë`ª”›’Ý9²!£+‰q³G÷2Ì)(ˆÄ\#DŠŽsˆsž[-S­š Eäz‘äÍ׿ò~Ñš)^ü4ïÿƒçŸ~þ×÷ü6¿’ýÅ!AÍF®xŒ3tÛƒTá4 ýbâ<¥¦,ÜnH6OP³„òl޶FyŠ·µG< ñ"ÊeرCÃt¨IƒxÞ_µÐ×ËÔ¯N±äñ1Îóë„wØ»!ñ½éˆÎ@“5ÑD³+sÁ<ã±yàt0ú8Z`fòΔ)ÃN•­TÓzeþ\áG‚jÁçÐ^¡’õIœ-‡çÙ0÷±Ó6^?$#&‘Â?HTL, %¯€côAŠ-R!1y†Ét¿‡ Bl[kCnÙ}äRjÉœ8×$¶Ä$H­‰uŽÄ*û¨‹k¸ÍœÝœ•ƒÕˈ§†b¢‘ÆB<ô ;}wú‘¡­â¿ã¯Íq5ÍÈMoû?³¾ö‹,f’IœqϲhÎ^âo~øßøÒË‚ƒ-¬õßánÿ›¬.4ê216Ú XP²ƒ}Ôò—IÞý••³ÑˆâÅK´‡¼y@¥;¢òR“­»´U†®†ŽWÃÑ6îÛ8÷3^˜ôPà„†> 9™‰È±ÑäMõ“ê’ƒŽÚ‚ÔÊÉ•b2Œ‰­2«]ÖÖ Ü¯÷ifc6d/°RÞ¥±6¤n»Ü~å2Ñ+_àÞ_ôø—^!þëxé«ì}ø&‹sAÜO0ã 9K(ÌrdlpÒe¨²Dw,X_€†ÄéX¼„Ê——ÙŽXÔ)y3§ßXĵëØƒxsƒÂ(áçÇ=–8½ˆÞÌBõ4ÎØ §†7sÁ;¹â^fè&ù©«¬OÜyò|dÆ"·,&‘$•†xoF»-IãáYôpQ÷‡,v‹*jwÇèË-Â^ ]¯Pb3ü._äÿó5^ûêë¼—ßâRV¥v~Hp®Æd`sa±Æ H,²s¹]¢¹iƒŒ)yŠÂÆû¸ƒ åõ½—Zloî±Ð˜ÑÛéá&µr{9góo6èìÌÂaÌŽSÆIã˜ÃL‘ ÈDþ˜ÚâY¤,ähu¤sOb‹™'™ÞÓµ"^ˆwh'TÔ„4Üe@Ž»2'«Jzworù³ÏóîŸüoüöunÎïsñRƒÚ«~¨^º¬vØ,BLD#”ÿ*õ·þœ´ê‘sü$¥4S¾R¦qý{{,ê9‡]ÜÛÍ%S°ûö.í[sÜÄfšVqç ga!§‡‘ↆ”æv&ÙŠ†ÙÇsœ1Ýøaœ$‰&0.“Ôe¼1 1›ÑYoqXÈÔ6»„©bÊMVûSÔ–MGÿ1Ÿ×Šn1÷bêIo}—_ž$ì¦W©öS2áÒÿÞ‡\³ ¹Æ_”â’’ÑÞìsѵè.ÇŒœ"~’RÅ}g‹åŠÍtKàÝê³"4&ªÓ ŠÈµ2Û°úƒ>/ëAë9J½9^,˜F& r®ä0Òš ?½PÇ™†§R<òØä™"ò%sæŒLN/ë³ZH¸à–¢{¼X ™Ê=Âm/£ÿÖÛ¼‘kv·/SË2²¢Gï½›\õ<|¥p:M¶ðI™Ð‘—ë-¨°¾¯²Ò"âwXª˜ö$Î+¹q•ÖÐêú¼•³Ü›pmn‘ªóøýÒ\‘Îæ8ã”a¢¹ŸÁ]c¸¯ Û™a?Mèg<ÂÊ”¥úcß0#š&‡‘ͽâ íI1˜`– ˆý˜¢sƒü°‡ ? ô·¹Pq(½v“îáæ_þ€úµç˜Œs’CÍüÞ€kú6÷jI‘¤œó|FB†T¤Xvq‚ÕíQÎvé$Ššê³³ö"¥© 1EÜqLµ;ÂJVÙ%®–É߉Xî(ÙÐSj¢OЋ¨Ì4ù(§(f³Œ­z¡fú”ÉáqjÇ©§õy~£*"2•†¾ ØÏRze‹ >U/§ÙÛÆ¹°ÄLdXEE\õïãœ/X#âA̹V~’µïâA­^ÄJæÛ;X³.kSCSŒ¹ñ2Uk›È°·çT6ȩƶ\RåanÎY:˜R 5óØ¢˜ Ƀ 9Wìg†Û¹a[ö´¦› *gò8gR£<ôh:åüâ8Ñè# q¹êЩ۬Õ-®­¯ðbpÀgÝ57GöC¢ç×°ÇC,¯áœÀu°–˜„!v¦ðKE&[û”ÚU·ˆQyÈJÉÅÍÚ²f’ªkÓ•’Šï5žcßñ0ù„n¡Ng2¦^ôQR¡’ ;i ð<: Q¹A[i˜ãÎ2ì0ÇI4½Lðnžófï%†­iFÿ©þ´¢=É ä¸ `ÛT¬œŠçÒ´ MÛb±\`Á‚eG²\/Q‰çÔ;‚Z…$ IœŒå¶‡- ª^d?“Ô—*lHI£]$Pç`€Î •B­{lÒæâÆ6K…*ËÑÃg¦±sƒL%N¨`A¤Ñ‰á0Rô3Í1þ†®ôµ`¬r&ùǦè„þí‰éËÁcŒ9ÏsRbSt¡ZõéTa¥Xb= xÁ)sQf,NªË-Ü(D)ƒÿ€3™û%TËò¦3 Ó\ ³˜‚-ž…B¤DZ8B R ÁMRraH,‡B–¢-KçÇFH696ž8Š^B€ÉrP‰$K2SŒ2EÏà–Òl‡9½ôÑ'î´}ñc‡Çˆæ6”,(;Uߣ) i :¶C-OY«•(:.URÚ¯â`¢Ò‘¶‹WðYÆ“He(!‰ð¨Ï§hlÜ$FÚ.¶2˜$#O ˜jìX1M5ã$c˜kFÐS†¡ÖôŒ•`¤S•3Ë?–hÇ<ž¼üÌXì§ç¸Q“s @•ªMËqh[pÎX,’Ó Õ¢ƒçH¥1¶ƒ­ZØh¥°,0ÒÁ¨ , ¥QÂÝ –Ñ` ¹Ýö;¾Z#ŒËBjƒ~»$…DKq«-‚£xmDh$F‚6†ÄÀÃÀhö¥Í~ªé¦9ƒôc÷°ÓZµy ÛàI—¨º>àÛ6Ei(ûPµ<*hjŽEÍ’Ô”-C]ª6Ô‚cÛ`Y„Ä@#•BØnš0™ÆHI¨4Y®™iA  3`®ÓÊlW–DkA* ÁL f*cš>nŽp©²x†Nê1­àÙ6 | E!)Ú’‚%¨˜œ’”øRP#°Å‘¦£ FçX„í ´:ÚçÒš I" 5†H@  0šP ­„¢üc°$'˜”Ù)æ‰Ù`§ièÅGïŸAEµNå£6íò¨‘‘eƒmŽ‘ˆlëã4Wpüýë+Wûlä -Ž,ãòãªÐcE;Y̧¹jœE7u!ý8œÉ< éë™ÎgÎ'¢dðxPÛ“Àò³âv~VÝú'ªž‘ÅqZúÏiö)â)??«ŽÏRÈžE§ožug³Ÿô¹gxÝñ3–O¦¹U‚.t–zý]:ó ®ÏœåÁøD¾§}þØ›‰¿G ù±ïÇ\'ñ¸>ó½îgýÞÓúgº-ý¼ÿ¾ÕêïzÍâ,¿ÿÿ:€~ù?«5ûq^«ø çfüÿ¯Ÿ"˜~Ò¡(ÿ^GÍ~¸'»LIEND®B`‚zuluCrypt-6.2.0/zuluCrypt-gui/zuluCrypt.desktop.README000066400000000000000000000003231425361753700227260ustar00rootroot00000000000000 zuluCrypt.desktop file will be edited during the configuration stage. If you want your changes to not get overwritten, add them to the desktop file section in the "CMakeLists.txt" file located in this folder. zuluCrypt-6.2.0/zuluCrypt-gui/zuluCrypt.nicolas.png000066400000000000000000000053041425361753700225400ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs  šœtIMEà;Šuà QIDAThÞÍšYP[×€¿#‰UÆ€16l@Fb±ƒ—ØØ`³¸­Ý,vêÄÅK’6I'/M:“éC—§¼ô¡ÓN¦íLÛ—fZ'Ó6ìÔi:q=qZ›UÇ;›$À€ÙwB åž>dƒ»“þ/÷êêœsÿïœÿ?ÿιBJÉJeº Å寭HÐhp»P ШB­FÁj‰X Àt]évãt)¸p«4þ £VܨA F¨TV³l)%HɤÃͤKâBeD¨ü•<Š ÅÝ â{AÔ¬bÉÓåv‡Â„KHE­^ü §®*Å-ƒ5R¢h‚@€@<9€érn§ ›l)BýXïÊÇÔ“‹TF Ýh…ЩPiÔxC¬.€”©H¬vcŠ´K5¬®#ªVX(„6Tã5©Å˜Ö¼ÓÿÙÆŒL"G …˜Õã®Âû{¶ÁÈY÷s÷²JºYáÁB„„,ÀóH21ábp\‘#v‰S¥æIÉl5¥›ÈPAdˆAóƒÌ˜¾w9Ý Œ¹åÀ¸d\Q-Q£¹@å™#¦v³N«_§UkUjÕœ 3·›«ËÖg“¡Ã“bÊ\|_'YUð‹$•”¬ –DkÅÏ"ÖüZ*•Ê``ÐfìŸPïï—¸PÍߺ\L¯Ë©;áÇîåÆ#ýÎ@¸‰Ö 6†)"Lê ð·Kwäý.Ù;“ Y£·W„?(¿€+ó €ñ>*{*8ÏÑm¼E¼q¿µßÆÙ+µÜiê&{ÇVv§% 4Ä“ôVïù›¥$ç7ú®SÞ[AƒÕÂî˜×fÔöI\n7wÓÐÖKmcû2¶¢KŒ[š> µOE9ë:ýS¡vðU½Üº÷œï›3ór*’k÷[¨yÐ;í:öoK"2zÝ´•>~1#ÀJÂüé´¶P5PIU¿«{lÞ·ù¤ÄGò,_ÜjãVSŸk15w°û©dv§ë ^`$üôè >9çðÙ&‡¹5PAu펮Eu—€ðúátŽíÓQXb¢ðš™ÆÞšþsÓƒNö¤%¡OND¨U«æŠâ fè_Ub²Ö{áv¬×Ñ<Ú…Õa_<€¢HÆìN6®¼ó|*Ùi±–˜¹t£…»Í]4¶õ°³µ›i:b6ŬØ?Z¬µÜªàÞÈ—8p}Ä&Nês9’°›—ü‰[}‹0w óË¢œÊ3°;!Œ½ºpöêö’¾‰¿_m ¦e€Ššf,­]ìHM"#U‡6<|>1S†ìíÜ1rw¸’ae€µ¡œH>ÈIC[£—gB+›(¯íätžÓy¢µ‚ûâØkØHQ‰™¢R3½V;WªkizØÃö”$R’QÍã™tY©5R3RI‡ã!j¡â™„=è’ið–-l ×>¼t€¾;¿ÿô.U ݼ|(…çvŰ%RÃOާs`Û&ŠJL\¾ÙJs÷{hní"ÝÄæ„ÍsæRºi»Iݨ‘ÆñûÈ©"OoÐsRŸÃ‹q™Þ²“½[ÊøØRŽÕi_À´T›{¸ÓÜGEÖVNçx*^K¶>‚lCçÒb9wÕDCû5-´vö–ÜMJr"Ѽ#Ñc7Q?f¤a¬Ϋ©ßà¤>—(BS»(¶”Rl)¥y¤{ù&4[.…óe*ë:9“ŸÂéüÖ¸9s` Y©±–˜8_fÁjwR]×HK{)ÉIÄë"yàü“­’!eÈÛÞ¶¨ÞÙyœü¨4ï³KÝ·)²”bìª_Ò ¦YJáŽï}| c}?<šA¦.œÄ¨~þÒv²ÒbùÅGÕ´õYéµÑ{«íd¶µ3ÚÔò£Œc^åoY[)6—ò¯U8×’§`Íræí@š€Y ù¼´(þ¥¥­Ïú(09F|êèòÍèíœk+çýšË´õ/;†, @¬áµo¥óÆátƒæŠ!óIX@Gž Ÿñ+¿$€m[Öñæ³Ûy~W 0Sù¡ ÁÙ+uÜlì· ¡¤Fƃ†&Æž[q_@9zÞ8’ÎÖè Ÿÿ–a>¸RÇÕ{í ¾L-Th¼[1«#óį_Ãޤójn¢ï¼.Ô|ðßFÎ~^K÷Ð8_—ø8´#ž7¿½½:ß4¡¶cœ³Wêøôz3_·Ì™¾õ|¯I'<Ð×Q/\oçÃ/ê1µñÿ s®Þ>–F:f<ï¶*|øE=ù¼)¿åBÔØÝŽ¥›Ðìý›Û­V~{ñ6׺¿ÅŸÁ³ {øÈt»ýþMÕgUÒ5hã¢ñÁÌžÒ°!"µJ»Ó‰Ë-ù§±c}§óR8“ŸBTˆäľ8²Ò<É[Q‰™¡±É•;¡JÍѤL ô9ì]«ó>¿:PG¡©„úAÏš!Dh8žÉþ ©so-*(ØFí\¬h”çKÍT5zq3 9gàèӱފׇ9wͳ&ðëÔz3l~à q|rô]4IŸ´ñ~íev®×ñ\Ì.o™z{ÅæR>i2bsM ’phc:' 9KÎAÁ oî>lï—ÅeŠÊiœ @­â…ý:Nåعe7˜–? °ÄL}Ûà’f˰j’"s Åæ2ŽõyÒ—5±œÒçpÂ;¾~m”v®3?ÛëžgÕ5å…R3Wµ0æðÄ„Më´œ9”©\S ]ۋ¾\;sþZ$À'7¸`)§ºÇäÉ™4Z¾»õ†Òc’Å|‡ p¸Nþ]Õ,‹K-\¹ßåMãö§Æp:ÏÀs»íL¼ò›n˜{üDiùcþÛì ÷ØzÕHEæR.µT£HI *ŽmÙC>‡ü¤ÝBˆ…O2¹\ü)¥ôÀ4¶ôÊâ2 çËéõDÉ„ a¼°_GÉýŽ™Sì>nM>‡}›"c¦ÎøVùo¶YI)1Þi‘çË,\¬nÅî^Ü,ô¸D¨ƒ9¡Ëâ¤>—q©b!SY5€ÇAœ“>­ôL»×z‘³÷ãæÐ x&n'§ô¹ÖíbjiºÜÃn±Òo%¤”ô÷(ÊÌ¢¸ÌBm·Í/@fdú^ÒkBÃVå› !W)µ”RRgéòøGEýã./@Bp$É9©Ï%a}¼XI?1¯( Wo¶È ¥&®XË9žG>—ÌÍÛB¬ê—*«ð8ÈÄø=25v“ÐhV]ñiùƒ2©½íJûVIEND®B`‚zuluCrypt-6.2.0/zuluCrypt-gui/zuluCrypt.papirus.dark.png000066400000000000000000000017171425361753700235170ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYs)†)†"ìߌtEXtSoftwarewww.inkscape.org›î<LIDAThí™ÉkA‡¿§IÔh nADqù ‚K4—ˆ‚èE^U“L·]®nÓ3‘ù``¦ëUÕï7ÝUýª *TÈ„D]TÕ`Ð ,fæ)ªˆÀKàÐ'"¿ÂPÕ…Àq`ù$‹óeè‘Åì?†ò_`8R|'¦…vR¾âVbí1ÂZóÓ’š€Æ°¥9 I˲âa³r’–€Æ°)Ç”7PUjÀ0<^oo"òMUç€ý@MTåR®Ed4*@D>½ª:8S ïÓ"òÄ£Î]ÊÄÀSà”ˆ|õ¬™³A¾ž]"ò3EÝÍ®‚¼ |º}Å«ê ØçЉ30ôì`òé¸óÊ?TçEäKL|-Ð ¬Æäb 9Ä<:â ôˆÈµä²Ç‘aÌì°¸§ªÓ€½À.Œ`oâ ÜKÓ`ˆÀ|ù.PÕ*  X“¥ƒÉ~+fðF±‡Œâ!ÞÀƬÛ€7޲-ÿ ýXTu§ªÎKÓ°ª®ÚÏe,NÓn˜¸10 è:ì`,0 œ‘‡®ŠV|fr1á “ß10 œH(¾#².#" ¼óì;ñ\!ñ–8Âo{ôí$©´âU.c2ÒL$1E<ÀF;hØ´âp øžHmåBYŃÙ(h„ ì:ࢪ^ÖcîÖ  ¨M ï¯­ë>â]¨j=°8ÌÆ¬û¦ÑE+²v`Ƙh‘í…ïqÐÅ4âmŸE¤8k/5GmúàÓÎ'é.¸bâ ôûtæà>PȃÖ6óô%2„üw%š€svÜøà|éÅØêÙI-},N©j·ª6'|¬6¹ â*·©É!úã#QØÁׄc!ni´ŸªúxÎø¶Ê0fAUoÅ·¹‰›…Ê–¤³Ð”à¿30R~ÒŽ°×9 IK@cØÀÍ…¤% 1l sV® b4Ž0`Oÿ:)Oƒ˜cÖÀN¶ë »šàAw©ŽžFtGnÃW¨?ÕIüÞ}*^ÿIEND®B`‚zuluCrypt-6.2.0/zuluCrypt-gui/zuluCrypt.papirus.png000066400000000000000000000016031425361753700225710ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYs)†)†"ìߌtEXtSoftwarewww.inkscape.org›î<IDAThíÙÍEÆñÏ ë*˜hÔeÕĈ‰‚'‚ñ%ÆMŒ&âËAƒÀÝßą à8jLDANdCŒ JDã è¢"A‚쎇ê!3mWõÛ:³$óM:éîªúÕóÔtWýº† ZÑÉ]Ïa*(7=,â~îßìæ*½Y«O?ÁÞwòå—{¦q¦Fêl•ÔRHÇ„±$–Ƙ [-ÌŠAú`•Òæò¾ £õâ¿#j݈öx«´¢) tÃÞÏïæþwMRyê Ñ×R>Û¡×ôidŠÖ[éìFF:gÎ1zx‰ÊSMj'5Ì]) ›„Laï­pçÓON·™Kæÿ9b}%‡Z·úC“«>=É{n)±åé…ÇW‘/,ã~ò&VÿðÝœ_ýÛ×zdª5¢óulSúiî,‘Yö‘ÿVgí™z~cµÇ°c‰Y^6òÓÚ@°y³ÂÇ(”œàæ·³ïDç;ó˜¯4™ÿëÛid7áü€kN®P:ÓÆèD¨n!R›@ŸÔÑ®ÍýIÿLŠÞØö\ˆ@ ~ÆÀËû‚§w—zN¬>ºIàq¦,¦î¶¹s¹ƒóE´Ã5ª~ ñýSÈ=Aá‘S”_o±Ðêq*†ª’„–Aþ¬`͎ۘ¥Ñ»†P;u„çaι(·w©¶u+ŸBPÞì°%§S"LÃ@ ¡4¤ "¥…hÒ!Ò#ŒØCb!â˜ÀiÔºÌGЊû‹¼cGž«Ž´p^XŽ« ï%ýå—È}yýt“ï¹=ó@A€Ù|+f‡+¹«sËn›¼#ˆ_ïÉ -ÞˆJh@öž {?>Áû'²Œ[Âq® ¨†nû!x:ZƦ­BTÖÁq›ˆ—q¿=Ïy± Ê·meÇJŒöÌ©ŽÏÂ= ª˜ßšFœmñu7àq`6‰¶a_v7báŒË¬²°Ôå–ÎØjÌ)_1Ÿhú¢ú×(¥(>´{ïáŽB½ÞÅpÛSÛX5Rø§^cdS™¶m³¶¸J®Õá<¾®pr&väšÉ1ôr@½lQºu‚±WNcÍù4wgwŒ"¿¹„s®ÃA7ä)`h&4aÐt€ŽTt{´z:5Kg§¼âIfÖ¸è5Ei´ÄÖt…øÑ92MqŒÓ N/@Ó–p Ñí’ZYÃjÌ1âèûJô*ŠXI®1$[®Ê3<9Œóè1ÄbHã×y:úË ü•ÅŠsQ5°k‘ÜG@)ü¦¤aH†„ Õ•Ôì¥&Ù¹ ö±ÔóuBC'B'V!½P¢£¡…½N@»Þà r- xoŽb'Æ‚‘qÅd³J¾#ƒ˜µ Âé&ù¹6¯x'“hÚ^­ófýáq ñ‚ &Z§­Kã@,æºàÌ’¹¯Œú`•N¡YŠ8Ž ‡G‰k«cü0ÆêD¸ÿx‚à ̧S)¨x ”`(§ØìF¤g]Âá¡çR:Ñ$ÝèñªTT× ¯6ðnjàÿh€jËÁçDí˜æq—ùFÀžM%b¬¢CÜr‘Ù4*>G`êâh ×°È_3J8Ù¢vsRŠÀ•+ÄöyOÃóñh=+=z]ÅÌÀ¦UoSú.Zn ¡KšþQ7fåh›ïOkŒ«¦„@H…ý¸ †£¡OÙDwN`9ñZx*Mææ<Å'æÉÍ÷˜µ5ÂɦB  ]Ñ1}‰Þ i+‰Ä«úFQ]\èÏí8V´çº£³õ†S[ò‡š¯{¿¿ oÍG?ÒA,D¼`jx#9¼Z€- ‚´ÂCÌPQ.púð2¦sE ýz ð"EÕq"q?Éi‚íïŸ`ô§Ðži ­£&¯bñcïDÿ«oQx­ÍKÃe“¢¿FAj˜RŽòQQ@7t70‹_Š1®ç2ÝĽՀ% šÜïp¨|x˜É¥ã`tOÑþâïQ{ò,›R£½Øãq gLŸr¹a\¥ˆÒ6 Í0‰”"|³ùPp?ÉECÀÈÁÄC%n«¤)X&²…ÿ;;©Æ äÿó•9Ÿçü˜€•Lš`(G7mÄšÍI]|Ë[šDì|5p­¶€±Ï\Ëí÷±ý„‡ù| yu–î{ÊÈ‚=‡«Ìµzü0†ó€”½Ð$ CDJ!} ‰¡ ôP½u ´7Ø0"áÝ÷—¸îƒã\ZÄG{ŸŸ!ÐçGz2oØüÑíÜøÙûØ_Ø6d2{ê,³n›Õ~^0¨> ¨||?·ÿåî~µFñÑe¢z—µ¿» ÷Ðy†ŸnXå¥H±ÔÏ¡"Pòɪ©„êŽFy2ÏžmY‚vLoº…5Y¡wÓ.V÷æ)Ÿ[dh¶{±ü˜IæÆJ;?µ›Ûÿì:nÝ1A% °j¥k¯úÌ$ûî’„ÆK1ö± ö¥S¤¿yŽáC«œû½´¢6›–"‰<Þ”)Œ*nÕu\ ô”@‹š¤D ¯*©?Qçù ¦öŒÇώ̱œòÙüáí¸S§ó£ Ó¤²Ë@üíµT^ì1òl•óMšB"lëö £÷gÙ±SQ Ö(<ùŽ&U!c Õ…4ÀzGŽMWÁäO^'xO)»†æV·• þtn¾@ª>Ë&G²Ú‰ØXn†\ÖÆ †#™Y㫘ڒϹ£ Ž¥yhgHú¡1Â>CV / wa¢Âöϼ‹RmT§N\¢à6)vÊW±Ï®a.öP÷Q®‹)×y¡Á=`¤åNáÙ&NÕg.“¢ýÔ,[¤FÊ[#7û å‚CØ èÊgÍc³.@ɤ%ù®Ù•¼»¨óƒNÌ’T,Ÿìðt¡ÎžbžS‚ö¿<Èò羋îU ç…®ÞUÇ7èD’Öá9ÆÏ®2\p–|ôŸ¶p÷åæÙ²\šG_’ÔK…µÔ" Q•<Á\›ð»gY+ilA¢kl!Êõ±´4ÝoÂD¿¾LPw)jM Éœkk¯mñ-k–OÞ7Iáîq´º÷‹ÇÉ^A»®€^Óp†Rd\‚Û!× H-G´>݇ËXoÃz¼Žµ¨Ñè^ȧà Ùh;"\í¢våé}é¬VˆåUÉÎÛÌ¶ê ™)Ë¢«bÄjŒf§‘‘GÊЇӨZDæL—n /z¥X©>Ú dÛü¶u„ʶ˜ð‘³ú\“îÿdüD ‚Ýë¡tEsÄÀoëÎͤC_Y@<]ǘö9Ô8Ÿƒ›X¡'XYŒ‰D›ô~InXflj}S/¬µ)lÝDCëÈËè&C¦ŽÑÐ0£6â´ªIºÑ…þV”¨º,Ìûüð™Eä’ϦFªfɦóÙ=¨á2kY‡°qãøYƽö|û»óXÇ:ˆÓ‚ÞBÇ;!_ë]Ð@зc zöf<^ªÆ+†âŽï·Ö¡¨¾nÊé(ÀLF=ì(ÄÔNÇÅ´RÐ `9$Z 8؉YàFhIÅLÕãûˆ¥y›{Nùl·Ùdb §Iç «u2¾"W÷±ç|Ä|¿rf-äG<JÎp¡îz±k9È;,]P.ZìS’w:£±ÀP „†B!%R¢„@C¦%¥4EEœ?ö"ŽË /ôr‰¯64ÆS:»³6»mÅ”©‘1 ì0BïEDR£íEÔº!'#É ©˜•RܵÄÿ÷©‹ä}THF°4 T’£‰äÉJ^´?\uAðµ‚ǺN¥ð™,ס(4rJ‘B¡¡(…«Mu!Aj'fè ôŒY€þ€9Ѐ¾’G¿žlÐÏ|G?Y2îe®ktÇëæ öÓú®ý% HÙ•¤}rà,/S Zd#ž¯Ö•å}j ~Á÷ Wz¨_Pz3ïSW2ç•~=òKó4/9þÍ"P@“Ì xIEND®B`‚zuluCrypt-6.2.0/zuluCrypt-gui/zuluCrypt.pro000066400000000000000000000112051425361753700211220ustar00rootroot00000000000000#------------------------------------------------- # # Project created by QtCreator 2011-09-09T10:15:19 # #------------------------------------------------- QT += core gui TARGET = zuluCrypt TEMPLATE = app SOURCES += main.cpp\ zulucrypt.cpp\ password_dialog.cpp \ dialogok.cpp \ openvolume.cpp \ luksaddkey.cpp \ luksdeletekey.cpp \ createvolume.cpp \ createfile.cpp \ warnwhenextendingcontainerfile.cpp \ createkeyfile.cpp \ utility.cpp \ partitionproperties.cpp \ cryptoinfo.cpp \ erasedevice.cpp \ cryptfiles.cpp \ dialogmsg.cpp \ managesystemvolumes.cpp \ filemanager.cpp \ keystrength.cpp \ userfont.cpp \ tablewidget.cpp \ socketsendkey.cpp \ openvolumereadonly.cpp \ ../zuluMount-gui/oneinstance.cpp \ openmountpointinfilemanager.cpp \ savemountpointpath.cpp \ md5/md5.c \ lxqt_wallet/backend/lxqtwallet.c \ lxqt_wallet/frontend/secret_service.c \ lxqt_wallet/frontend/password_dialog.cpp \ lxqt_wallet/frontend/task.cpp \ lxqt_wallet/frontend/lxqt_wallet.cpp \ lxqt_wallet/frontend/lxqt_secret_service.cpp \ lxqt_wallet/frontend/lxqt_kwallet.cpp \ lxqt_wallet/frontend/lxqt_internal_wallet.cpp \ lxqt_wallet/frontend/changepassworddialog.cpp \ task.cpp \ keyfiletask.cpp \ filetask.cpp \ erasetask.cpp \ crypttask.cpp \ createvolumeinexistingfile.cpp \ walletconfig.cpp \ walletconfiginput.cpp \ createvolumedialog.cpp \ favorites.cpp \ managevolumeheader.cpp \ tcrypt.cpp \ readonlywarning.cpp \ checkforupdates.cpp \ plugin.cpp \ help.cpp \ debugwindow.cpp HEADERS += zulucrypt.h \ password_dialog.h \ dialogok.h \ filemanager.h \ openvolume.h \ luksaddkey.h \ luksdeletekey.h \ createvolumeinexistingfile.h \ createvolume.h \ createfile.h \ createkeyfile.h \ utility.h \ partitionproperties.h \ cryptoinfo.h \ erasedevice.h \ cryptfiles.h \ createvolumedialog.h \ dialogmsg.h \ managesystemvolumes.h \ keystrength.h \ warnwhenextendingcontainerfile.h \ userfont.h \ tablewidget.h \ socketsendkey.h \ openvolumereadonly.h \ ../zuluMount-gui/oneinstance.h \ openmountpointinfilemanager.h \ savemountpointpath.h \ lxqt_wallet/backend/lxqtwallet.h \ lxqt_wallet/frontend/password_dialog.h \ lxqt_wallet/frontend/task.h \ lxqt_wallet/frontend/lxqt_wallet.h \ lxqt_wallet/frontend/lxqt_secret_service.h \ lxqt_wallet/frontend/lxqt_kwallet.h \ lxqt_wallet/frontend/lxqt_internal_wallet.h \ lxqt_wallet/frontend/changepassworddialog.h \ task.h \ filetask.h \ keyfiletask.h \ erasetask.h \ crypttask.h \ walletconfig.h \ walletconfiginput.h \ favorites2.h \ managevolumeheader.h \ tcrypt.h \ readonlywarning.h \ checkforupdates.h \ plugin.h \ help.h \ debugwindow.h FORMS += zulucrypt.ui password.ui \ openvolume.ui \ luksaddkey.ui \ dialogok.ui \ filemanager.ui \ luksdeletekey.ui \ createvolume.ui \ createfile.ui \ createkeyfile.ui \ cryptoinfo.ui \ erasedevice.ui \ cryptfiles.ui \ createvolumeinexistingfile.ui \ createvolumedialog.ui \ warnwhenextendingcontainerfile.ui \ dialogmsg.ui \ managesystemvolumes.ui \ lxqt_wallet/frontend/password_dialog.ui \ lxqt_wallet/frontend/changepassworddialog.ui \ walletconfig.ui \ walletconfiginput.ui \ favorites2.ui \ managevolumeheader.ui \ tcrypt.ui \ readonlywarning.ui \ plugin.ui \ help.ui \ debugwindow.ui TRANSLATIONS = ../translations/zuluCrypt/en_US.ts \ ../translations/zuluCrypt/de_DE.ts \ ../translations/zuluCrypt/fr_FR.ts \ ../translations/zuluCrypt/ar_SA.ts RESOURCES = icon.qrc LIBS += -lblkid -lpwquality -L/home/local/KDE4/lib/ -lkwalletbackend -lgcrypt -lzuluCryptPluginManager QMAKE_CXXFLAGS += -D_FILE_OFFSET_BITS=64 -Wall OTHER_FILES += \ backupluksheaderui \ lxqt_wallet/SOURCE \ lxqt_wallet/README.md \ lxqt_wallet/lxqt_wallet.pro.user \ # lxqt_wallet/lxqt_wallet.pro \ lxqt_wallet/LICENSE \ lxqt_wallet/CMakeLists.txt \ lxqt_wallet/changelog \ lxqt_wallet/BUILD_INSTRUCTIONS \ lxqt_wallet/backend/README \ lxqt_wallet/backend/CMakeLists.txt \ lxqt_wallet/frontend/README \ lxqt_wallet/frontend/CMakeLists.txt \ lxqt_wallet/frontend/secret_service/CMakeLists.txt INCLUDEPATH +=/home/ink/projects/build/zuluCrypt /usr/include /usr/include/glib-2.0/ /usr/lib/glib-2.0/include/ /usr/include/libsecret-1 /usr/include/libsecret-1/libsecret zuluCrypt-6.2.0/zuluCrypt-gui/zulucrypt.cpp000066400000000000000000001036321425361753700211520ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "zulucrypt.h" #include "ui_zulucrypt.h" #include "utility.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../zuluCrypt-cli/constants.h" #include "../zuluMount-gui/oneinstance.h" #include "password_dialog.h" #include "openvolume.h" #include "luksaddkey.h" #include "luksdeletekey.h" #include "createvolume.h" #include "createfile.h" #include "filemanager.h" #include "createkeyfile.h" #include "favorites2.h" #include "cryptoinfo.h" #include "erasedevice.h" #include "managevolumeheader.h" #include "cryptfiles.h" #include "dialogmsg.h" #include "managesystemvolumes.h" #include "tablewidget.h" #include "utility.h" #include "task.hpp" #include "about.h" #include "help.h" #include "createvolumeinexistingfile.h" #include "pdf_path.h" #include "warnwhenextendingcontainerfile.h" #include "showluksslots.h" #include zuluCrypt::zuluCrypt( QWidget * parent ) : QMainWindow( parent ), m_secrets( this ), m_mountInfo( this,false,[ this ](){ this->quitApplication() ; } ), m_signalHandler( this ) { utility::mainWindowWidget( this ) ; m_signalHandler.setAction( [ this ]( systemSignalHandler::signal s ){ Q_UNUSED( s ) this->emergencyQuitApplication() ; } ) ; } void zuluCrypt::setLocalizationLanguage( bool translate ) { if( translate ){ utility::setLocalizationLanguage( translate,nullptr,"zuluCrypt-gui" ) ; }else{ utility::setLocalizationLanguage( translate,m_language_menu,"zuluCrypt-gui" ) ; } } void zuluCrypt::languageMenu( QAction * ac ) { utility::languageMenu( this,m_language_menu,ac,"zuluCrypt-gui" ) ; m_ui->retranslateUi( this ) ; } void zuluCrypt::helperStarted( bool e,const QString& volume ) { if( e ){ this->setLocalizationLanguage( true ) ; m_ui = new Ui::zuluCrypt ; this->setupUIElements() ; this->setupConnections() ; this->initFont() ; this->initKeyCombo() ; this->initTray( m_startHidden ) ; this->info() ; this->setLocalizationLanguage( false ) ; this->updateVolumeList( volume ) ; m_mountInfo.start() ; if( !m_startHidden ){ this->setVisible( true ) ; this->show() ; this->raise() ; this->setWindowState( Qt::WindowActive ) ; } }else{ DialogMsg( this ).ShowUIOK( tr( "ERROR" ),utility::failedToStartzuluPolkit() ) ; this->closeApplication() ; } } void zuluCrypt::updateVolumeList( const QString& volume ) { m_ui->tableWidget->setEnabled( false ) ; emit updateVolumeListSignal( volume,Task::await( [](){ utility::Task::waitForOneSecond() ; auto r = utility::Task( QString( "%1 -L" ).arg( ZULUCRYPTzuluCrypt ) ) ; if( r.success() ){ return r.stdOut() ; }else{ return QByteArray() ; } } ) ) ; } void zuluCrypt::updateVolumeList( QString volume,QString r ) { tablewidget::clearTable( m_ui->tableWidget ) ; if( !r.isEmpty() ){ for( const auto& it : utility::split( r,'\n' ) ){ auto z = utility::split( it,'\t' ) ; if( z.size() >= 3 ){ const auto& q = z.at( 2 ) ; if( q.startsWith( "crypto_LUKS" ) ){ auto s = q ; z.replace( 2,s.replace( "crypto_","" ).toLower() ) ; }else{ auto e = q ; e.remove( "crypto_" ) ; z.replace( 2,e.toLower() ) ; } tablewidget::addRow( m_ui->tableWidget,z ) ; } } } m_ui->tableWidget->setEnabled( true ) ; m_ui->tableWidget->setFocus() ; if( !volume.isEmpty() ){ this->ShowPasswordDialog( volume,volume.split( "/" ).last() ) ; } } void zuluCrypt::initKeyCombo() { } void zuluCrypt::initFont() { this->setUserFont( utility::getFont( this ) ) ; } void zuluCrypt::raiseWindow( const QString& device ) { this->setVisible( true ) ; this->show() ; this->raise() ; this->setWindowState( Qt::WindowActive ) ; if( !device.isEmpty() ){ this->ShowPasswordDialog( device,device.split( "/" ).last() ) ; } } void zuluCrypt::polkitFailedWarning() { DialogMsg( this ).ShowUIOK( tr( "ERROR" ),tr( "zuluCrypt Failed To Connect To zuluPolkit.\nPlease Report This Serious Bug." ) ) ; } void zuluCrypt::start() { /* * Entry point is here, the "instance" class checks if there is already a running zuluCrypt-gui process. * If yes,this instance tells the existing instance to get focus and then it exits. * * If no,then it knowns it is the only running instance and it calls "setUpApp() to set up the GUI and * runs. */ const auto l = QCoreApplication::arguments() ; m_openPath = utility::cmdArgumentValue( l,"-m",utility::fileManager() ) ; m_startHidden = l.contains( "-e" ) ; auto s = utility::socketPath() ; if( utility::configDirectoriesAreNotWritable( this ) ){ return this->closeApplication() ; } utility::polkitFailedWarning( [ this ](){ QMetaObject::invokeMethod( this,"polkitFailedWarning",Qt::QueuedConnection ) ; } ) ; if( utility::libCryptSetupLibraryNotFound() ){ auto a = tr( "Cryptsetup library could not be found and zuluCrypt will most likely not work as expected." ) ; auto b = tr( "\n\nPlease recompile zuluCrypt to force it to re-discover the new library" ) ; DialogMsg( this ).ShowUIOK( tr( "ERROR" ),a + b ) ; } oneinstance::instance( this, s + "/zuluCrypt-gui.socket", utility::cmdArgumentValue( l,"-d" ), [ this ]( const QString& e ){ utility::startHelperExecutable( this, e, "zuluCrypt", "helperStarted", "closeApplication" ) ; }, [ this ]( int s ){ this->closeApplication( s ) ; }, [ this ]( const QString& e ){ this->raiseWindow( e ) ; } ) ; } void zuluCrypt::initTray( bool e ) { utility::setIconMenu( "zuluCrypt",m_ui->actionSelect_Icons,this,[ this ]( const QString& e ){ utility::setIcons( "zuluCrypt",e ) ; this->setIcons() ; } ) ; this->setIcons() ; utility::showTrayIcon( m_ui->actionTray_icon,m_trayIcon,e ) ; } void zuluCrypt::showTrayIcon( bool e ) { if( e ){ m_trayIcon.show() ; }else{ m_trayIcon.hide() ; } } void zuluCrypt::trayProperty() { m_ui->actionTray_icon->setEnabled( false ) ; utility::trayProperty( &m_trayIcon ) ; m_ui->actionTray_icon->setEnabled( true ) ; } void zuluCrypt::setupUIElements() { m_ui->setupUi( this ) ; //m_secrets.setParent( this ) ; m_trayIcon.setParent( this ) ; const auto f = utility::getWindowDimensions( "zuluCrypt" ) ; const auto e = f.data() ; this->window()->setGeometry( *( e + 0 ),*( e + 1 ),*( e + 2 ),*( e + 3 ) ) ; const auto table = m_ui->tableWidget ; table->setColumnWidth( 0,*( e + 4 ) ) ; table->setColumnWidth( 1,*( e + 5 ) ) ; table->setColumnWidth( 2,*( e + 6 ) ) ; } void zuluCrypt::setIcons() { const auto& icon = utility::getIcon( "zuluCrypt" ) ; m_trayIcon.setIcon( icon ) ; this->setWindowIcon( icon ) ; } void zuluCrypt::itemEntered( QTableWidgetItem * item ) { auto m_point = item->tableWidget()->item( item->row(),1 )->text() ; if( !m_point.isEmpty() ){ item->setToolTip( utility::shareMountPointToolTip( m_point ) ) ; } } void zuluCrypt::createVolumeInFile() { auto e = QFileDialog::getOpenFileName( this,tr( "Path To A File" ),QDir::homePath() ) ; if( !e.isEmpty() ){ createvolume::instance( this ).ShowFile( e ) ; } } void zuluCrypt::setupConnections() { m_ui->tableWidget->setMouseTracking( true ) ; m_ui->tableWidget->setContextMenuPolicy( Qt::CustomContextMenu ) ; connect( m_ui->tableWidget,&QTableWidget::customContextMenuRequested,[ this ]( QPoint s ){ Q_UNUSED( s ) auto item = m_ui->tableWidget->currentItem() ; if( item ){ this->itemClicked( item,QCursor::pos() ) ; } } ) ; connect( m_ui->actionClear_Dead_Mount_Points,&QAction::triggered,[](){ utility::Task::run( ZULUCRYPTzuluCrypt" --clear-dead-mount-points" ).await() ; } ) ; connect( this,SIGNAL( updateVolumeListSignal( QString,QString ) ),this,SLOT( updateVolumeList( QString,QString ) ),Qt::QueuedConnection ) ; connect( m_ui->actionEncrypted_Container_In_A_File,SIGNAL( triggered() ),this,SLOT( createVolumeInFile() ) ) ; connect( m_ui->tableWidget,SIGNAL( itemEntered( QTableWidgetItem * ) ),this,SLOT( itemEntered( QTableWidgetItem * ) ) ) ; connect( m_ui->actionErase_data_on_device,SIGNAL( triggered() ),this,SLOT( ShowEraseDataDialog() ) ) ; connect( m_ui->actionPartitionOpen,SIGNAL( triggered() ),this,SLOT( ShowOpenPartition() ) ) ; connect( m_ui->actionFileOpen,SIGNAL( triggered() ),this,SLOT( ShowPasswordDialog() ) ) ; connect( m_ui->actionFileCreate,SIGNAL( triggered() ),this,SLOT( ShowCreateFile() ) ) ; connect( m_ui->actionEncrypted_Container_In_An_Existing_FIle,SIGNAL( triggered() ),this,SLOT( createVolumeInExistingFile() ) ) ; connect( m_ui->actionManage_names,SIGNAL( triggered() ),this,SLOT( ShowFavoritesEntries() ) ) ; connect( m_ui->tableWidget,SIGNAL( currentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ), this,SLOT( currentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ) ) ; connect( m_ui->actionCreatekeyFile,SIGNAL( triggered() ),this,SLOT( ShowCreateKeyFile() ) ) ; connect( m_ui->tableWidget,SIGNAL( itemClicked( QTableWidgetItem * ) ),this,SLOT( itemClicked( QTableWidgetItem * ) ) ) ; connect( m_ui->actionAbout,SIGNAL( triggered() ),this,SLOT( aboutMenuOption() ) ) ; connect( m_ui->actionAddKey,SIGNAL( triggered() ),this,SLOT( ShowAddKey() ) ) ; connect( m_ui->actionDeleteKey,SIGNAL( triggered() ),this,SLOT( ShowDeleteKey() ) ) ; connect( m_ui->actionPartitionCreate,SIGNAL( triggered() ),this,SLOT( ShowNonSystemPartitions() ) ) ; connect( m_ui->actionFonts,SIGNAL( triggered() ),this,SLOT( fonts() ) ) ; connect( m_ui->menuFavorites,SIGNAL( aboutToShow() ),this,SLOT( readFavorites() ) ) ; connect( m_ui->menuFavorites,SIGNAL( aboutToHide() ),this,SLOT( favAboutToHide() ) ) ; connect( m_ui->actionTray_icon,SIGNAL( triggered() ),this,SLOT( trayProperty() ) ) ; connect( &m_trayIcon,SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ),this,SLOT( trayClicked( QSystemTrayIcon::ActivationReason ) ) ) ; connect( m_ui->menuFavorites,SIGNAL( triggered( QAction * ) ),this,SLOT( favClicked( QAction * ) ) ) ; connect( m_ui->action_close,SIGNAL( triggered() ),this,SLOT( closeApplication() ) ) ; connect( m_ui->action_update_volume_list,SIGNAL( triggered() ),this,SLOT( updateVolumeList() ) ) ; connect( m_ui->actionMinimize_to_tray,SIGNAL( triggered() ),this,SLOT( minimizeToTray() ) ) ; connect( m_ui->actionClose_all_opened_volumes,SIGNAL( triggered() ),this,SLOT( closeAllVolumes() ) ) ; connect( m_ui->actionEncrypt_file,SIGNAL( triggered() ),this,SLOT( encryptFile() ) ) ; connect( m_ui->actionDecrypt_file,SIGNAL( triggered() ),this,SLOT( decryptFile() ) ) ; connect( m_ui->actionManage_system_partitions,SIGNAL( triggered() ),this,SLOT( ShowManageSystemPartitions() ) ) ; connect( m_ui->actionManage_non_system_partitions,SIGNAL( triggered() ),this,SLOT( ShowManageNonSystemPartitions() ) ) ; connect( m_ui->actionOpen_zuluCrypt_pdf,SIGNAL( triggered() ),this,SLOT( openpdf() ) ) ; connect( m_ui->actionSet_File_Manager,SIGNAL( triggered() ),this,SLOT( setFileManager() ) ) ; connect( this,SIGNAL( closeVolume( QTableWidgetItem *,int ) ),this,SLOT( closeAll( QTableWidgetItem *,int ) ) ) ; m_ui->actionDo_not_minimize_to_tray->setChecked( utility::doNotMinimizeToTray() ) ; connect( m_ui->actionDo_not_minimize_to_tray,&QAction::triggered,[ this ](){ auto s = !utility::doNotMinimizeToTray() ; m_ui->actionDo_not_minimize_to_tray->setChecked( s ) ; utility::setDoNotMinimizeToTray( s ) ; } ) ; m_autoOpenMountPoint = utility::autoOpenFolderOnMount( "zuluCrypt-gui" ) ; m_ui->actionAuto_Open_Mount_Point->setCheckable( true ) ; m_ui->actionAuto_Open_Mount_Point->setChecked( m_autoOpenMountPoint ) ; connect( m_ui->actionAuto_Open_Mount_Point,SIGNAL( toggled( bool ) ),this,SLOT( autoOpenMountPoint( bool ) ) ) ; m_ui->actionRestore_header->setText( tr( "Restore Volume Header" ) ) ; m_ui->actionBackup_header->setText( tr( "Backup Volume Header" ) ) ; connect( m_ui->actionBackup_header,SIGNAL( triggered() ),this,SLOT( volumeHeaderBackUp() ) ) ; connect( m_ui->actionRestore_header,SIGNAL( triggered() ),this,SLOT( volumeRestoreHeader() ) ) ; connect( m_ui->actionView_LUKS_Key_Slots,SIGNAL( triggered() ),this,SLOT( showLUKSSlotsData() ) ) ; m_ui->actionView_LUKS_Key_Slots->setEnabled( utility::canShowKeySlotProperties() ) ; using wbe = LXQt::Wallet::BackEnd ; auto a = LXQt::Wallet::backEndIsSupported( wbe::libsecret ) ; auto b = LXQt::Wallet::backEndIsSupported( wbe::kwallet ) ; m_ui->actionManage_volumes_in_gnome_wallet->setEnabled( a ) ; m_ui->actionManage_volumes_in_kde_wallet->setEnabled( b ) ; connect( m_ui->menuOptions,SIGNAL( aboutToShow() ),this,SLOT( optionMenuAboutToShow() ) ) ; connect( &m_mountInfo,SIGNAL( gotEvent() ),this,SLOT( updateVolumeList() ) ) ; m_language_menu = [ this ](){ auto m = new QMenu( tr( "Select Language" ),this ) ; connect( m,SIGNAL( triggered( QAction * ) ), this,SLOT( languageMenu( QAction * ) ) ) ; m_ui->actionSelect_Language->setMenu( m ) ; return m ; }() ; m_ui->actionVeracrypt_container_in_a_file->setEnabled( true ) ; m_ui->actionVeracrypt_container_in_a_partition->setEnabled( true ) ; connect( m_ui->actionShow_Debug_Window,&QAction::triggered,[ this ](){ m_debugWindow.Show() ; } ) ; this->setAcceptDrops( true ) ; this->updateTrayContextMenu() ; } void zuluCrypt::showLUKSSlotsData() { showLUKSSlots::Show( this,{},[](){} ) ; } void zuluCrypt::showLUKSSlotsInfo() { auto item = m_ui->tableWidget->currentItem() ; if( item ){ auto path = m_ui->tableWidget->item( item->row(),0 )->text() ; showLUKSSlots::Show( this,path,[](){} ) ; } } void zuluCrypt::updateTrayContextMenu() { m_trayIconMenu.clear() ; m_trayIconMenu.addMenu( m_ui->menu_zc ) ; m_trayIconMenu.addMenu( m_ui->menuOpen ) ; m_trayIconMenu.addMenu( m_ui->menuCreate ) ; //m_trayIconMenu.addMenu( m_ui->menuFavorites ) ; m_trayIconMenu.setFont( this->font() ) ; m_trayIconMenu.addAction( tr( "Show/Hide" ),this,SLOT( showTrayGUI() ) ) ; m_trayIconMenu.addAction( tr( "Quit" ),this,SLOT( closeApplication() ) ) ; m_trayIcon.setContextMenu( &m_trayIconMenu ) ; } void zuluCrypt::showTrayGUI() { this->trayClicked( QSystemTrayIcon::Trigger ) ; } void zuluCrypt::autoOpenMountPoint( bool e ) { m_autoOpenMountPoint = e ; utility::autoOpenFolderOnMount( "zuluCrypt-gui",e ) ; } void zuluCrypt::optionMenuAboutToShow() { auto a = utility::walletName() ; auto b = utility::applicationName() ; auto c = LXQt::Wallet::walletExists( LXQt::Wallet::BackEnd::internal,a,b ) ; m_ui->actionChange_internal_wallet_password->setEnabled( c ) ; } void zuluCrypt::cinfo() { } void zuluCrypt::info() { //cryptoinfo::instance( this,utility::homePath() + "/.zuluCrypt/doNotshowWarning.option",QString() ) ; } void zuluCrypt::createVolumeInExistingFile() { warnWhenExtendingContainerFile::Show( this,[ this ](){ createVolumeInExistingFIle::instance( this ) ; } ) ; } void zuluCrypt::failedToOpenWallet() { //DialogMsg msg( this ) ; //msg.ShowUIOK( tr( "ERROR" ),tr( "could not open selected wallet" ) ) ; } void zuluCrypt::permissionExplanation() { DialogMsg m( this ) ; m.ShowPermissionProblem( QString() ) ; } void zuluCrypt::ShowManageSystemPartitions() { manageSystemVolumes::instance( this,"/etc/zuluCrypt/system_volumes.list" ) ; } void zuluCrypt::ShowManageNonSystemPartitions() { manageSystemVolumes::instance( this,"/etc/zuluCrypt/nonsystem_volumes.list" ) ; } void zuluCrypt::currentItemChanged( QTableWidgetItem * current,QTableWidgetItem * previous ) { tablewidget::selectRow( current,previous ) ; if( m_ui->tableWidget->rowCount() > 12 ){ m_ui->tableWidget->setColumnWidth( 2,70 ) ; }else{ m_ui->tableWidget->setColumnWidth( 2,95 ) ; } } void zuluCrypt::emergencyQuitApplication() { this->hide() ; m_mountInfo.announceEvents( false ) ; Task::await( [ this ](){ auto table = m_ui->tableWidget ; auto volumeCount = table->rowCount() ; if( volumeCount > 0 ){ QVector< QTableWidgetItem * > tableItems( volumeCount ) ; auto it = tableItems.data() ; for( int i = 0 ; i < volumeCount ; i++ ){ *( it + i ) = table->item( i,0 ) ; } auto exe = utility::appendUserUID( "%1 -q -d \"%2\"" ) ; for( int i = tableItems.count() - 1 ; i >= 0 ; i-- ){ auto e = *( it + i ) ; auto device = e->text().replace( "\"","\"\"\"" ) ; utility::Task( exe.arg( ZULUCRYPTzuluCrypt,device ) ) ; } } } ) ; this->quitApplication() ; } void zuluCrypt::closeAllVolumes() { m_ui->tableWidget->setEnabled( false ) ; m_mountInfo.announceEvents( false ) ; Task::await( [ this ](){ utility::Task::waitForOneSecond() ; // for ui effect auto table = m_ui->tableWidget ; auto volumeCount = table->rowCount() ; if( volumeCount > 0 ){ QVector< QTableWidgetItem * > tableItems( volumeCount ) ; auto it = tableItems.data() ; for( int i = 0 ; i < volumeCount ; i++ ){ *( it + i ) = table->item( i,0 ) ; } auto exe = utility::appendUserUID( "%1 -q -d \"%2\"" ) ; for( int i = tableItems.count() - 1 ; i >= 0 ; i-- ){ auto e = *( it + i ) ; auto device = e->text().replace( "\"","\"\"\"" ) ; auto r = utility::Task( exe.arg( ZULUCRYPTzuluCrypt,device ) ) ; emit closeVolume( e,r.exitCode() ) ; utility::Task::waitForOneSecond() ; // for ui effect } } } ) ; m_mountInfo.announceEvents( true ) ; m_ui->tableWidget->setEnabled( true ) ; } void zuluCrypt::closeAll( QTableWidgetItem * item,int st ) { if( st ){ this->closeStatusErrorMessage( st ) ; }else{ this->removeRowFromTable( item->row() ) ; } } void zuluCrypt::removeRowFromTable( int x ) { tablewidget::deleteRow( m_ui->tableWidget,x ) ; } void zuluCrypt::minimizeToTray() { if( m_ui->actionTray_icon->isChecked() ){ this->hide() ; }else{ m_ui->actionTray_icon->setChecked( true ) ; this->trayProperty() ; this->hide() ; } } void zuluCrypt::closeEvent( QCloseEvent * e ) { e->ignore() ; if( utility::doNotMinimizeToTray() ){ this->hide() ; this->closeApplication() ; }else if( m_trayIcon.isVisible() ){ this->hide() ; }else{ this->hide() ; this->closeApplication() ; } } void zuluCrypt::dragEnterEvent( QDragEnterEvent * e ) { e->accept() ; } void zuluCrypt::dropEvent( QDropEvent * e ) { for( const auto& it : e->mimeData()->urls() ){ const auto& e = it.path() ; if( utility::pathPointsToAFile( e ) ){ this->ShowPasswordDialog( e,e.split( "/" ).last() ) ; } } } void zuluCrypt::quitApplication() { m_trayIcon.hide() ; this->hide() ; QCoreApplication::quit() ; } void zuluCrypt::closeApplication() { m_secrets.close() ; utility::quitHelper() ; m_mountInfo.stop()() ; } void zuluCrypt::closeApplication( int s ) { m_secrets.close() ; Q_UNUSED( s ) m_mountInfo.stop()() ; } void zuluCrypt::trayClicked( QSystemTrayIcon::ActivationReason e ) { if( e == QSystemTrayIcon::Trigger ){ if( this->isVisible() ){ this->hide() ; }else{ this->show() ; } } } void zuluCrypt::fonts() { int size = 11 ; bool ok ; QFont Font = QFontDialog::getFont( &ok,this->font(),this ) ; if( ok ){ int k = Font.pointSize() ; if( k > size ){ k = size ; Font.setPointSize( k ) ; UIMessage( tr( "INFO" ),tr( "Resetting font size to %1 because larger font sizes do not fit" ).arg( QString::number( size ) ) ) ; } this->setUserFont( Font ) ; utility::saveFont( Font ) ; } } void zuluCrypt::setUserFont( QFont Font ) { this->setFont( Font ) ; m_ui->tableWidget->horizontalHeaderItem( 0 )->setFont( Font ) ; m_ui->tableWidget->horizontalHeaderItem( 1 )->setFont( Font ) ; m_ui->tableWidget->horizontalHeaderItem( 2 )->setFont( Font ) ; m_ui->actionEncrypted_Container_In_An_Existing_FIle->setFont( Font ) ; m_ui->actionAbout->setFont( Font ) ; m_ui->actionAddKey->setFont( Font ) ; m_ui->actionCreatekeyFile->setFont( Font ) ; m_ui->actionDeleteKey->setFont( Font ) ; m_ui->actionFavorite_volumes->setFont( Font ) ; m_ui->actionFileCreate->setFont( Font ) ; m_ui->actionFileOpen->setFont( Font ) ; m_ui->actionFonts->setFont( Font ) ; m_ui->actionInfo->setFont( Font ) ; m_ui->actionManage_favorites->setFont( Font ) ; m_ui->actionPartitionCreate->setFont( Font ) ; m_ui->actionPartitionOpen->setFont( Font ) ; m_ui->actionEncrypted_Container_In_A_File->setFont( Font ) ; m_ui->actionSelect_random_number_generator->setFont( Font ) ; m_ui->actionTray_icon->setFont( Font ) ; m_ui->menuFavorites->setFont( Font ) ; m_ui->actionManage_names->setFont( Font ) ; m_ui->actionBackup_header->setFont( Font ) ; m_ui->actionRestore_header->setFont( Font ) ; m_ui->actionEncrypt_file->setFont( Font ) ; m_ui->actionDecrypt_file->setFont( Font ) ; m_ui->menu_zc->setFont( Font ) ; m_ui->actionPermission_problems->setFont( Font ) ; m_ui->actionLuks_header_backup->setFont( Font ) ; m_ui->actionManage_system_partitions->setFont( Font ) ; m_ui->actionManage_non_system_partitions->setFont( Font ) ; m_ui->actionManage_volumes_in_gnome_wallet->setFont( Font ) ; m_ui->actionManage_volumes_in_internal_wallet->setFont( Font ) ; m_ui->actionManage_volumes_in_kde_wallet->setFont( Font ) ; m_ui->actionUse_kde_default_wallet->setFont( Font ) ; m_ui->actionChange_internal_wallet_password->setFont( Font ) ; m_ui->actionVeracrypt_container_in_a_file->setFont( Font ) ; m_ui->actionVeracrypt_container_in_a_partition->setFont( Font ) ; m_ui->actionOpen_zuluCrypt_pdf->setFont( Font ) ; m_ui->actionSelect_Language->setFont( Font ) ; m_ui->actionAuto_Open_Mount_Point->setFont( Font ) ; m_ui->actionSelect_Icons->setFont( Font ) ; } void zuluCrypt::aboutMenuOption( void ) { about::instance( this ) ; } void zuluCrypt::HelpLuksHeaderBackUp() { QString msg = tr( "\nLUKS,TrueCrypt and VeraCrypt based encrypted volumes have what is called a \"volume header\".\n\n\ A volume header is responsible for storing information necessary to open a header using encrypted volume and any damage \ to it will makes it impossible to open the volume causing permanent loss of encrypted data.\n\n\ The damage to the header is usually caused by accidental formatting of the device or use of \ some buggy partitioning tools or wrongly reassembled logical volumes.\n\n\ Having a backup of the volume header is strongly advised because it is the only way the encrypted data will be accessible \ again after the header is restored if the header on the volume get corrupted.\n\n" ) ; DialogMsg m( this ) ; m.ShowUIInfo( tr( "Important Information On Volume Header Backup" ),false,msg ) ; } void zuluCrypt::volume_property() { m_ui->tableWidget->setEnabled( false ) ; auto item = m_ui->tableWidget->currentItem() ; if( item == nullptr ){ return ; } auto x = m_ui->tableWidget->item( item->row(),0 )->text() ; x.replace( "\"","\"\"\"" ) ; Task::run( [ x ](){ auto e = utility::appendUserUID( "%1 -s -d \"%2\"" ) ; auto r = utility::Task( e.arg( ZULUCRYPTzuluCrypt,x ) ) ; if( r.success() ){ auto data = r.stdOut() ; return QString( " %1" ).arg( QString( data.mid( data.indexOf( '\n' ) + 2 ) ) ) ; }else{ return QString() ; } } ).then( [ this ]( const QString& r ){ DialogMsg msg( this ) ; if( r.isEmpty() ){ msg.ShowUIOK( tr( "ERROR!" ),tr( "Volume is not open or was opened by a different user" ) ) ; }else{ msg.ShowUIVolumeProperties( tr( "Volume Properties" ),r ) ; } m_ui->tableWidget->setEnabled( true ) ; } ) ; } void zuluCrypt::favAboutToHide() { } void zuluCrypt::favClicked( QAction * ac ) { auto r = ac->text() ; r.remove( "&" ) ; auto _show_dialog = [ this ]( const QString& v,const QString& m ){ if( !utility::pathPointsToAFolder( v ) ){ this->ShowPasswordDialog( v,m ) ; } } ; auto e = utility::favoriteClickedOption( r ) ; if( e == 1 ){ this->ShowFavoritesEntries() ; }else if( e == 2 ){ favorites::instance().entries( [ & ]( const favorites::entry& e ){ _show_dialog( e.volumePath,e.mountPointPath ) ; } ) ; }else{ auto m = utility::split( r,'\t' ) ; _show_dialog( m.at( 0 ),m.at( 1 ) ) ; } } void zuluCrypt::readFavorites() { utility::readFavorites( m_ui->menuFavorites,false,false ) ; this->updateTrayContextMenu() ; } void zuluCrypt::addToFavorite() { auto item = m_ui->tableWidget->currentItem() ; auto x = m_ui->tableWidget->item( item->row(),0 )->text() ; auto y = x.split( "/" ).last() ; utility::addToFavorite( x,y ) ; } void zuluCrypt::menuKeyPressed() { auto table = m_ui->tableWidget ; if( table->rowCount() > 0 ){ this->itemClicked( m_ui->tableWidget->currentItem(),false ) ; } } void zuluCrypt::openFolder() { auto table = m_ui->tableWidget ; if( table->rowCount() > 0 ){ auto item = table->currentItem() ; this->openFolder( table->item( item->row(),1 )->text() ) ; } } void zuluCrypt::openSharedFolder() { this->openFolder( m_sharedMountPoint ) ; } void zuluCrypt::openFolder( const QString& path ) { auto x = tr( "WARNING!" ) ; auto y = tr( "Could not open mount point because \"%1\" tool does not appear to be working correctly").arg( m_openPath ) ; utility::openPath( path,m_openPath,this,x,y ) ; } void zuluCrypt::openpdf() { help::instance( this,m_openPath ) ; } void zuluCrypt::itemClicked( QTableWidgetItem * it ) { this->itemClicked( it,true ) ; } void zuluCrypt::itemClicked( QTableWidgetItem * item,QPoint point ) { QMenu m ; m.setFont( this->font() ) ; auto m_point = item->tableWidget()->item( item->row(),1 )->text() ; m_sharedMountPoint = utility::sharedMountPointPath( m_point ) ; if( m_sharedMountPoint.isEmpty() ){ connect( m.addAction( tr( "Open Folder" ) ) ,SIGNAL( triggered() ),this,SLOT( openFolder() ) ) ; }else{ connect( m.addAction( tr( "Open Private Folder" ) ),SIGNAL( triggered() ), this,SLOT( openFolder() ) ) ; connect( m.addAction( tr( "Open Shared Folder" ) ),SIGNAL( triggered() ), this,SLOT( openSharedFolder() ) ) ; } m.addSeparator() ; auto ac = m.addAction( tr( "Properties" ) ) ; //ac->setEnabled( !m_ui->tableWidget->item( item->row(),2 )->text().startsWith( "bitlocker" ) ) ; connect( ac,SIGNAL( triggered() ),this,SLOT( volume_property() ) ) ; m.addSeparator() ; if( m_ui->tableWidget->item( item->row(),2 )->text().startsWith( "luks" ) ){ m.addSeparator() ; connect( m.addAction( tr( "Add Key" ) ),SIGNAL( triggered() ),this,SLOT( luksAddKeyContextMenu() ) ) ; connect( m.addAction( tr( "Remove Key" ) ),SIGNAL( triggered() ),this,SLOT( luksDeleteKeyContextMenu() ) ) ; auto ac = m.addAction( tr( "Show Key Slots Information" ) ) ; ac->setEnabled( utility::canShowKeySlotProperties() ) ; connect( ac,SIGNAL( triggered() ),this,SLOT( showLUKSSlotsInfo() ) ) ; m.addSeparator() ; connect( m.addAction( tr( "Backup LUKS Header" ) ),SIGNAL( triggered() ),this,SLOT( luksHeaderBackUpContextMenu() ) ) ; } m.addSeparator() ; auto volume_id = m_ui->tableWidget->item( item->row(),0 )->text() + "\t" ; bool has_favorite = false ; favorites::instance().entries( [ & ]( const favorites::entry& e ){ if( e.volumePath.startsWith( volume_id ) ){ has_favorite = true ; return true ; } return false ; } ) ; ac = m.addAction( tr( "Add To Favorite" ) ) ; if( has_favorite ){ ac->setEnabled( false ) ; }else{ ac->setEnabled( true ) ; ac->connect( ac,SIGNAL( triggered() ),this,SLOT( addToFavorite() ) ) ; } m.addSeparator() ; connect( m.addAction( tr( "Unmount" ) ),SIGNAL( triggered() ),this,SLOT( close() ) ) ; m.addSeparator() ; m.addAction( tr( "Cancel" ) ) ; m.exec( point ) ; } void zuluCrypt::itemClicked( QTableWidgetItem * item,bool clicked ) { if( clicked ){ this->itemClicked( item,QCursor::pos() ) ; }else{ int x = m_ui->tableWidget->columnWidth( 0 ) ; int y = m_ui->tableWidget->rowHeight( item->row() ) * item->row() + 20 ; this->itemClicked( item,m_ui->tableWidget->mapToGlobal( QPoint( x,y ) ) ) ; } } void zuluCrypt::setDefaultWallet() { m_ui->actionUse_kde_default_wallet->setEnabled( false ) ; m_ui->actionUse_kde_default_wallet->setEnabled( true ) ; } void zuluCrypt::luksAddKeyContextMenu( void ) { auto item = m_ui->tableWidget->currentItem() ; this->ShowAddKeyContextMenu( m_ui->tableWidget->item( item->row(),0 )->text() ) ; } void zuluCrypt::luksDeleteKeyContextMenu( void ) { auto item = m_ui->tableWidget->currentItem() ; this->ShowDeleteKeyContextMenu( m_ui->tableWidget->item( item->row(),0 )->text() ) ; } void zuluCrypt::UIMessage( QString title,QString message ) { DialogMsg msg( this ) ; msg.ShowUIOK( title,message ) ; } void zuluCrypt::closeStatusErrorMessage( int st ) { switch ( st ) { case 0 :break ; case 1 :UIMessage( tr( "ERROR!" ),tr( "Close failed, volume is not open or was opened by a different user" ) ) ; break ; case 2 :UIMessage( tr( "ERROR!" ),tr( "Close failed, one or more files in the volume are in use." ) ) ; break ; case 3 :UIMessage( tr( "ERROR!" ),tr( "Close failed, volume does not have an entry in /etc/mtab" ) ) ; break ; case 4 :UIMessage( tr( "ERROR!" ),tr( "Close failed, could not get a lock on /etc/mtab~" ) ) ; break ; case 5 :UIMessage( tr( "ERROR!" ),tr( "Close failed, volume is unmounted but could not close mapper,advice to close it manually" ) ) ; break ; case 6 :UIMessage( tr( "ERROR!" ),tr( "Close failed, could not resolve full path of device\n" ) ) ; break ; case 7 :UIMessage( tr( "ERROR!" ),tr( "Close failed, shared mount point appear to be busy\n" ) ) ; break ; case 8 :UIMessage( tr( "ERROR!" ),tr( "Close failed, shared mount point appear to belong to a different user or multiple mount points detected\n" ) ) ; break ; case 9 :UIMessage( tr( "ERROR!" ),tr( "Close failed, shared mount point appear to be in an ambiguous state,advice to unmount manually" ) ) ;break ; case 10:UIMessage( tr( "ERROR!" ),tr( "Close failed, multiple mount points for the volume detected" ) ) ; break ; case 110:UIMessage( tr( "ERROR!" ),tr( "Close failed, could not find any partition with the presented UUID" ) ) ; break ; default:UIMessage( tr( "ERROR!" ),tr( "Unrecognized error with status number %1 encountered" ).arg( st ) ) ; } } void zuluCrypt::close() { m_ui->tableWidget->setEnabled( false ) ; auto item = m_ui->tableWidget->currentItem() ; auto path = m_ui->tableWidget->item( item->row(),0 )->text().replace( "\"","\"\"\"" ) ; auto r = Task::await( [ path ](){ auto exe = utility::appendUserUID( "%1 -q -d \"%2\"" ).arg( ZULUCRYPTzuluCrypt,path ) ; return utility::Task( exe ).exitCode() ; } ) ; m_ui->tableWidget->setEnabled( true ) ; this->closeStatusErrorMessage( r ) ; } void zuluCrypt::setFileManager() { fileManager::instance( this,[ this ]( const QString& e ){ m_openPath = e ; } ) ; } void zuluCrypt::volumeRestoreHeader() { managevolumeheader::instance( this ).restoreHeader() ; } void zuluCrypt::volumeHeaderBackUp() { managevolumeheader::instance( this ).backUpHeader() ; } void zuluCrypt::luksHeaderBackUpContextMenu() { auto item = m_ui->tableWidget->currentItem() ; auto device = m_ui->tableWidget->item( item->row(),0 )->text() ; managevolumeheader::instance( this ).backUpHeader( device ) ; } void zuluCrypt::ShowAddKeyContextMenu( QString key ) { luksaddkey::instance( this ).ShowUI( key ) ; } void zuluCrypt::ShowAddKey() { luksaddkey::instance( this ).ShowUI() ; } void zuluCrypt::ShowDeleteKeyContextMenu( QString key ) { luksdeletekey::instance( this ).ShowUI( key ) ; } void zuluCrypt::ShowDeleteKey() { luksdeletekey::instance( this ).ShowUI() ; } void zuluCrypt::ShowCreateKeyFile() { createkeyfile::instance( this ) ; } void zuluCrypt::ShowFavoritesEntries() { favorites2::instance( this,m_secrets,[](){ } ) ; } void zuluCrypt::ShowCreateFile() { createfile::instance( this,[ this ]( const QString& file ){ if( utility::pathExists( file ) ){ createvolume::instance( this ).ShowFile( file ) ; } } ) ; } void zuluCrypt::ShowNonSystemPartitions() { openvolume::instance( this,false ).ShowNonSystemPartitions( [ this ]( const QString& e ){ createvolume::instance( this ).ShowPartition( e ) ; } ) ; } void zuluCrypt::ShowOpenPartition() { openvolume::instance( this,true ).showEncryptedOnly().ShowAllPartitions( [ this ]( const QString& e ){ this->setUpPasswordDialog().ShowUI( e ) ; } ) ; } passwordDialog& zuluCrypt::setUpPasswordDialog() { return passwordDialog::instance( m_ui->tableWidget,this,m_secrets,[ this ]( const QString& path ){ if( m_autoOpenMountPoint ){ this->openFolder( path ) ; } } ) ; } void zuluCrypt::ShowPasswordDialog() { this->setUpPasswordDialog().ShowUI() ; } void zuluCrypt::ShowPasswordDialog( QString x,QString y ) { if( x.endsWith( ".zc" ) || x.endsWith( ".zC" ) ){ this->decryptFile( x ) ; }else{ this->setUpPasswordDialog().ShowUI( x,y ) ; } } void zuluCrypt::ShowEraseDataDialog() { erasedevice::instance( this ).ShowUI() ; } void zuluCrypt::encryptFile() { cryptfiles::instance( this ).encrypt() ; } void zuluCrypt::decryptFile( void ) { cryptfiles::instance( this ).decrypt() ; } void zuluCrypt::decryptFile( const QString& e ) { cryptfiles::instance( this ).decrypt( e ) ; } zuluCrypt::~zuluCrypt() { if( !m_ui ){ return ; } auto q = m_ui->tableWidget ; const auto& r = this->window()->geometry() ; utility::setWindowDimensions( "zuluCrypt",{ r.x(), r.y(), r.width(), r.height(), q->columnWidth( 0 ), q->columnWidth( 1 ), q->columnWidth( 2 ) } ) ; delete m_ui ; } zuluCrypt-6.2.0/zuluCrypt-gui/zulucrypt.h000066400000000000000000000123471425361753700206210ustar00rootroot00000000000000/* * * Copyright ( c ) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ZULUCRYPT_H #define ZULUCRYPT_H #include #include #include #include #include #include "../zuluMount-gui/monitor_mountinfo.h" #include "lxqt_wallet.h" #include "utility.h" #include "secrets.h" #include "systemsignalhandler.h" #include "debugwindow.h" class QWidget ; class QTableWidgetItem ; class QDragEnterEvent ; class QDropEvent ; class QSystemTrayIcon ; class QCloseEvent ; class passwordDialog ; class openvolume ; class createvolume ; class luksdeletekey ; class luksaddkey ; class managevolumeheader ; class cryptfiles ; class walletconfig ; class QNetworkReply ; /* * below header is created at build time,it is set by CMakeLists.txt located in the root folder */ #include "version.h" namespace Ui { class zuluCrypt ; } class zuluCrypt : public QMainWindow { Q_OBJECT public: zuluCrypt( QWidget * parent = 0 ) ; ~zuluCrypt() ; signals: void closeVolume( QTableWidgetItem *,int ) ; void updateVolumeListSignal( QString,QString ) ; private slots : void showLUKSSlotsData( void ) ; void showLUKSSlotsInfo( void ) ; void createVolumeInFile() ; void showTrayIcon( bool ) ; void polkitFailedWarning( void ) ; void setFileManager( void ) ; void helperStarted( bool,const QString& ) ; void start( void ) ; void showTrayGUI( void ) ; void autoOpenMountPoint( bool ) ; void languageMenu( QAction * ) ; void currentItemChanged( QTableWidgetItem * current,QTableWidgetItem * previous ) ; void info( void ) ; void luksAddKeyContextMenu( void ) ; void luksDeleteKeyContextMenu( void ) ; void aboutMenuOption( void ) ; void close( void ) ; void closeAll( QTableWidgetItem *,int ) ; void itemClicked( QTableWidgetItem * item ) ; void itemClicked( QTableWidgetItem * item,bool ) ; void itemClicked( QTableWidgetItem * item,QPoint point ) ; void volume_property( void ) ; void UIMessage( QString title,QString message ) ; void fonts( void ) ; void addToFavorite( void ) ; void readFavorites( void ) ; void favClicked( QAction * ) ; void favAboutToHide( void ) ; void trayClicked( QSystemTrayIcon::ActivationReason ) ; void trayProperty( void ) ; void closeApplication( void ) ; void closeApplication( int ) ; void minimizeToTray( void ) ; void closeAllVolumes( void ) ; void emergencyQuitApplication( void ) ; void menuKeyPressed( void ) ; void ShowCreateFile( void ) ; void ShowFavoritesEntries( void ) ; void ShowCreateKeyFile( void ) ; void ShowDeleteKeyContextMenu( QString ) ; void ShowDeleteKey( void ) ; void ShowAddKeyContextMenu( QString ) ; void ShowAddKey( void ) ; void ShowNonSystemPartitions( void ) ; void ShowPasswordDialog( void ) ; void ShowOpenPartition( void ) ; void ShowManageSystemPartitions( void ) ; void ShowManageNonSystemPartitions( void ) ; void ShowPasswordDialog( QString,QString ) ; void ShowEraseDataDialog( void ) ; void luksHeaderBackUpContextMenu( void ) ; void volumeHeaderBackUp( void ) ; void volumeRestoreHeader( void ) ; void permissionExplanation( void ) ; void encryptFile( void ) ; void decryptFile( void ) ; void HelpLuksHeaderBackUp( void ) ; void setDefaultWallet( void ) ; void failedToOpenWallet( void ) ; void openFolder( void ) ; void openSharedFolder( void ) ; void itemEntered( QTableWidgetItem * ) ; void optionMenuAboutToShow( void ) ; void openpdf( void ) ; void cinfo( void ) ; void updateVolumeList( const QString& = QString() ) ; void updateVolumeList( QString,QString ) ; void createVolumeInExistingFile( void ) ; private: void raiseWindow( const QString& ) ; void setIcons( void ) ; void quitApplication( void ) ; void removeRowFromTable( int ) ; void openFolder( const QString& ) ; void dragEnterEvent( QDragEnterEvent * ) ; void dropEvent( QDropEvent * ) ; passwordDialog& setUpPasswordDialog( void ) ; void setLocalizationLanguage( bool ) ; void setupConnections( void ) ; void setupUIElements( void ) ; void closeEvent( QCloseEvent * ) ; void setUserFont( QFont ) ; void initTray( bool ) ; void initFont( void ) ; void initKeyCombo( void ) ; void closeStatusErrorMessage( int ) ; void decryptFile( const QString& ) ; void updateTrayContextMenu( void ) ; QMenu m_trayIconMenu ; secrets m_secrets ; Ui::zuluCrypt * m_ui = nullptr ; QMenu * m_language_menu = nullptr ; QSystemTrayIcon m_trayIcon ; QString m_sharedMountPoint ; QString m_openPath ; bool m_startHidden ; int m_userID ; bool m_autoOpenMountPoint ; monitor_mountinfo m_mountInfo ; systemSignalHandler m_signalHandler ; debugWindow m_debugWindow ; }; #endif // ZULUCRYPT_H zuluCrypt-6.2.0/zuluCrypt-gui/zulucrypt.ui000066400000000000000000000377271425361753700210200ustar00rootroot00000000000000 zuluCrypt Qt::NonModal true 0 0 782 419 zuluCrypt zuluCrypt.pngzuluCrypt.png Qt::ActionsContextMenu Qt::ActionsContextMenu QFrame::Raised 1 QAbstractItemView::NoEditTriggers false false false QAbstractItemView::NoSelection QAbstractItemView::SelectRows QAbstractItemView::ScrollPerItem Qt::NoPen 0 3 Encrypted Volume Path Encrypted Volume Mount Point Path Type 0 0 782 29 &Open &Create &Help &Volumes Optio&ns &Favorites &zC &Volume Hosted In A File Ctrl+Z Volume &Hosted In A Hard Drive Ctrl+X true &Encrypted Container In A New File Ctrl+A true true Encrypted &Container In A Hard Drive Ctrl+S true &About Ctrl+R &Add A Key To A Volume Ctrl+U &Delete A Key From A Volume Ctrl+W crypto info Ctrl+E &KeyFile Ctrl+D &Tray Icon Ctrl+K Select &Font Ctrl+L favorite volumes manage favorites select random number generator Ctrl+P close application Ctrl+C &Update Volume List Ctrl+T &Minimize To Tray Ctrl+Y &Quit Ctrl+Q &Close All Opened Volumes Ctrl+G &Manage Favorites Ctrl+F &Erase Data In A Device Ctrl+N &Backup Header Ctrl+B &Restore Header Ctrl+P permissions Ctrl+I Encrypt A &File Ctrl+R &Decrypt A File Ctrl+H &Header Backup Ctrl+J Manag&e System Volumes Ctrl+C Manage &Volumes In Internal Wallet Ctrl+V configure wallets Ctrl+V Manage &Non System Volumes Ctrl+M Manage Volumes In &KDE Wallet Shift+V Manage Volumes In &GNOME keyring Alt+V &Change Internal Wallet Password Ctrl+O tcrypt backup header tcrypt restore header VeraCrypt Container In A File Ctrl+E VeraCrypt Container In A Hard Drive Ctrl+I H&elp F1 Contact &Info Shift+I &Select Language &Auto Open Mount Point Ctrl+E Select &Icons Set Fi&le Manager true Do Not Minimize To Tray This Option Will Close The App Instead Of Minimizing It To Tray Encrypted Container Hidden In Video/Cover File (Steganography) Ctrl+I Show Debug Window Ctrl+Shift+D Encrypted Container In An Existing File Ctrl+J Clear Dead Mount Points Show LUKS Key Slots zuluCrypt-6.2.0/zuluCrypt.xml000066400000000000000000000005331425361753700163210ustar00rootroot00000000000000 Raw disk image zuluCrypt-6.2.0/zuluMount-cli.1000066400000000000000000000055071425361753700164350ustar00rootroot00000000000000 .TH zuluMount-cli 1 .br .SH NAME zuluMount-cli - command line tool that manages encrypted and unencrypted volumes .SH DESCRIPTION zuluMount-cli is a tool that has a primary mission of opening and closing encrypted volumes as well as mounting and unmounting unecrypted volumes and opened encrypted ones.Its primary purpose is to do what tools like udisks does. .br .SH USAGE usage: see examples below .br options: .br -m -- mount a volume : arguments: -d volume_path -z mount_point -e mode(rw/ro) -- additional arguments for crypto_LUKS,crypto_PLAIN,crypto_TCRYPT volumes, -p passphrase/-f keyfile .br -z -- mount point component to append to "/run/media/private/$USER/" .br -u -- unmount a volume: arguments: -d volume_path .br -s -- print properties of an encrypted volume: arguments: -d volume_path .br -o -- offset in sectors on where the volume starts in the volume.The volume is assumed to be plain type with this option and the option must be given when -u or -s arguments are used with a volume opened with this option .br -M -- this option will create a mount point in "/run/media/private/$USER/" and a publicly accessible "mirror" in "/run/media/public/' .br -l -- print expanded list of all volumes .br -Y -- file system options .br -e -- mount options .br -t -- volume type to assume when unlocking a volume.Use "vera" when unlocking a VeraCrypt volume. .br -L -- must be used with -d,print properties of a volume specified by d option .br -P -- print a list of all volumes .br -A -- print a list of all volumes .br -S -- print a list of system volumes .br -N -- print a list of non system volumes .br -E -- print a list of mounted volumes .br -D -- get a device node address from its mapper path( mapper paths are usually located in /dev/mapper ). Required argument: -d .br -F -- path to truecrypt multiple keyfiles.Keyfiles are separated by "\\011" character sequence .br examples: .br mount a volume : zuluMount-cli -m -d /dev/sdc1 .br unmount a volume: zuluMount-cli -u -d /dev/sdc1 .br mount an encrypted volume with a key "xyz" : zuluMount-cli -m -d /dev/sdc2 -p xyz .br .SH COPYRIGHT Copyright (c) 2011-2015 .br name : Francis Banyikwa .br email: mhogomchungu@gmail.com .br .br 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, see . .br .SH LAST EDIT Last change: Fri Mar 13 01:12:21 EAT 2015 zuluCrypt-6.2.0/zuluMount-cli/000077500000000000000000000000001425361753700163445ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluMount-cli/README000066400000000000000000000001071425361753700172220ustar00rootroot00000000000000 These source files are controlled by ../zuluCrypt-cli/CMakeLists.txt zuluCrypt-6.2.0/zuluMount-cli/crypto_mount.c000066400000000000000000000060731425361753700212600ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" int zuluMountCryptoMount( ARGS * args ) { const char * type = args->type ; const char * offset = args->offset ; const char * device = args->device ; const char * UUID = args->uuid ; const char * mode = args->m_opts ; uid_t uid = args->uid ; const char * key = args->key ; const char * key_source = args->key_source ; const char * m_point = args->m_point ; const char * fs_opts = args->fs_opts ; int mount_point_option = args->mpo ; int share = args->share ; int st ; /* * the struct is declared in ../zuluCrypt-cli/bin/libzuluCrypt-exe.h */ struct_opts opts ; const char * mapping_name ; char * path = NULL ; string_t str = StringVoid ; if( UUID == NULL ){ if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../zuluCrypt-cli/create_loop_device.c */ path = zuluCryptLoopDeviceAddress_1( device ) ; if( path == NULL ){ return 20 ; }else{ mapping_name = path + StringLastIndexOfChar_1( path,'/' ) + 1 ; } }else{ mapping_name = device + StringLastIndexOfChar_1( device,'/' ) + 1 ; } }else{ str = String( UUID ) ; StringRemoveString( str,"\"" ) ; mapping_name = StringReplaceString( str,"UUID=","UUID-" ) ; } /* * zuluCryptEXEGetOptsSetDefault() is defined in ../zuluCrypt-cli/bin/get_opts.c */ zuluCryptEXEGetOptsSetDefault( &opts ) ; if( StringPrefixEqual( key_source,"-G" ) ){ opts.plugin_path = key ; } opts.mount_point = m_point ; opts.device = device ; opts.m_opts = mode ; opts.key = key ; opts.key_source = key_source ; opts.mount_point_option = mount_point_option ; opts.share = share ; opts.fs_opts = fs_opts ; opts.env = StringListStringArray( args->env ) ; opts.offset = offset ; opts.type = type ; memcpy( opts.tcrypt_multiple_keyfiles,args->tcrypt_multiple_keyfiles, sizeof( args->tcrypt_multiple_keyfiles ) ) ; /* * zuluCryptEXEOpenVolume() is defined in ../zuluCrypt-cli/bin/open_volume.c */ st = zuluCryptEXEOpenVolume( &opts,mapping_name,uid ) ; StringDelete( &str ) ; StringFree( opts.env ) ; StringFree( path ) ; return st ; } zuluCrypt-6.2.0/zuluMount-cli/crypto_umount.c000066400000000000000000000033351425361753700214430ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" int zuluMountCryptoUMount( ARGS * args ) { const char * device = args->device ; const char * UUID = args->uuid ; uid_t uid = args->uid ; const char * mapping_name ; char * path = NULL ; int st ; string_t str = StringVoid ; if( UUID == NULL ){ if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../zuluCrypt-cli/create_loop_device.c */ path = zuluCryptLoopDeviceAddress_1( device ) ; if( path == NULL ){ return 20 ; } }else{ path = StringCopy_2( device ) ; } mapping_name = path + StringLastIndexOfChar_1( path,'/' ) + 1 ; }else{ str = String( UUID ) ; StringRemoveString( str,"\"" ) ; mapping_name = StringSubChar( str,4,'-' ) ; } /* * zuluCryptEXECloseVolume() is defined in ../zuluCrypt-cli/bin/close_volume.c */ st = zuluCryptEXECloseVolume( device,mapping_name,uid ) ; StringDelete( &str ) ; StringFree( path ) ; return st ; } zuluCrypt-6.2.0/zuluMount-cli/includes.h000066400000000000000000000045221425361753700203260ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "../zuluCrypt-cli/constants.h" #include "../zuluCrypt-cli/bin/libzuluCrypt-exe.h" #include "../zuluCrypt-cli/bin/includes.h" #include "../zuluCrypt-cli/lib/libzuluCrypt.h" #include "../zuluCrypt-cli/lib/includes.h" #include "../zuluCrypt-cli/bin/includes.h" typedef struct{ const char * device ; const char * action ; const char * m_point ; const char * m_opts ; const char * key ; const char * key_source ; const char * fs_opts ; const char * uuid ; const char * type ; const char * offset ; const char * u_id ; const char * tcrypt_multiple_keyfiles[ TRUECRYPT_MAX_KEYFILES + 1 ] ; stringList_t env ; int mpo ; uid_t uid ; int share ; }ARGS; int zuluMountVolumeStatus( const char * device,const char * UUID,uid_t uid ) ; int zuluMountUnEncryptedVolumeStatus( const char * device,const char * fs,const char * device1 ) ; int zuluMountPrintVolumesProperties( uid_t uid ) ; int zuluMountprintAListOfMountedVolumes( uid_t ) ; int zuluMountPrintDeviceProperties( const char * device,const char * UUID,uid_t uid ) ; int zuluMountUMount( ARGS * args ) ; int zuluMountPrintBitLockerProperties( const char * device,uid_t uid ) ; int zuluMountMount( ARGS * args ) ; int zuluMountCryptoMount( ARGS * args ) ; int zuluMountCryptoUMount( ARGS * args ) ; int _zuluExit( int st,string_t z,char * q,const char * msg ) ; int _zuluExit_1( int st,stringList_t z,char * q,const char * msg ) ; void zuluMountPartitionProperties( const char * mapper,const char * UUID,const char * device,const char * m_point ) ; zuluCrypt-6.2.0/zuluMount-cli/main.c000066400000000000000000000512221425361753700174360ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include "../zuluCrypt-cli/lib/includes.h" #include "../zuluCrypt-cli/bin/includes.h" #include #include #include #include #include #include #include #include #include #include static void _seteuid( uid_t uid ) { if( seteuid( uid ) ){} } static void _setuid( uid_t uid ) { if( setuid( uid ) ){} } /* * All functions with "EXE" in their names are defined somewhere in ../zuluCrypt-cli/bin */ static int _mount_get_opts( int argc,char * argv[],ARGS * args ) { int c ; int k = 0 ; while( ( c = getopt( argc,argv,"cEMLnASNshlPmuDd:z:e:Y:p:f:G:o:F:t:B:b:K:" ) ) != -1 ){ switch( c ){ case 'M' : args->share = 1 ; break ; case 'n' : args->mpo = 1 ; break ; case 'E' : args->action = "-E" ; break ; case 'D' : args->action = "-D" ; break ; case 's' : args->action = "-s" ; break ; case 'l' : args->action = "-l" ; break ; case 'L' : args->action = "-L" ; break ; case 'P' : args->action = "-P" ; break ; case 'A' : args->action = "-A" ; break ; case 'S' : args->action = "-S" ; break ; case 'N' : args->action = "-N" ; break ; case 'm' : args->action = "-m" ; break ; case 'u' : args->action = "-u" ; break ; case 'c' : args->action = "-c" ; break ; case 'B' : args->action = "-B" ; args->m_point = optarg ; break ; case 'b' : args->action = "-b" ; args->m_point = optarg ; break ; case 't' : args->type = optarg ; break ; case 'o' : args->offset = optarg ; break ; case 'd' : args->device = optarg ; break ; case 'z' : args->m_point = optarg ; break ; case 'e' : args->m_opts = optarg ; break ; case 'K' : args->u_id = optarg ; break ; case 'Y' : args->fs_opts = optarg ; break ; case 'p' : args->key = optarg ; args->key_source = "-p"; break ; case 'f' : args->key = optarg ; args->key_source = "-f"; break ; case 'G' : args->key = optarg ; args->key_source = "-G"; break ; case 'F' : if( k < TRUECRYPT_MAX_KEYFILES ){ /* * TRUECRYPT_MAX_KEYFILES is set at ../zuluCrypt-cli/bin/libzuluCrypt-exe.h */ args->tcrypt_multiple_keyfiles[ k ] = optarg ; k++ ; } break ; default : return -1 ; } } return 0 ; } int _zuluExit( int st,string_t z,char * q,const char * msg ) { StringFree( q ) ; StringDelete( &z ) ; if( msg != NULL ){ printf( "%s\n",msg ) ; } return st ; } static int _zuluExit_2( int st,stringList_t z,stringList_t q,const char * msg ) { zuluCryptSecurityUnlockMemory( z ) ; StringListMultipleDelete( &q,&z,NULL ) ; if( msg != NULL ){ printf( "%s\n",msg ) ; } return st ; } int _zuluExit_1( int st,stringList_t z,char * q,const char * msg ) { StringFree( q ) ; zuluCryptSecurityUnlockMemory( z ) ; StringListDelete( &z ) ; if( msg != NULL ){ printf( "%s\n",msg ) ; } return st ; } static int _zuluMountDeviceList( uid_t uid ) { /* * zuluCryptPrintPartitions() is defined in ../zuluCrypt-cli/partitions.c * ZULUCRYPTallPartitions is set in ../zuluCrypt-cli/constants.h */ return zuluCryptPrintPartitions( ZULUCRYPTallPartitions,0,uid ) ; } static int _zuluMountNonSystemDeviceList( uid_t uid ) { /* * zuluCryptPrintPartitions() is defined in ../zuluCrypt-cli/partitions.c * ZULUCRYPTallPartitions is set in ../zuluCrypt-cli/constants.h */ return zuluCryptPrintPartitions( ZULUCRYPTnonSystemPartitions,0,uid ) ; } static int _zuluMountSystemDeviceList( uid_t uid ) { /* * zuluCryptPrintPartitions() is defined in ../zuluCrypt-cli/partitions.c * ZULUCRYPTallPartitions is set in ../zuluCrypt-cli/constants.h */ return zuluCryptPrintPartitions( ZULUCRYPTsystemPartitions,0,uid ) ; } static int _zuluMountMountedList( uid_t uid ) { /* * zuluMountPrintVolumesProperties() is defined in volume_status.c */ return zuluMountPrintVolumesProperties( uid ) ; } static string_t _zuluCryptGetFileSystemFromDevice( const char * device ) { string_t st ; zuluCryptSecurityGainElevatedPrivileges() ; st = zuluCryptGetFileSystemFromDevice( device ) ; zuluCryptSecurityDropElevatedPrivileges() ; return st ; } static int _zuluPartitionHasCryptoFs( const char * device ) { int r ; /* * zuluCryptSecurityGainElevatedPrivileges() is defined in ../zuluCrypt-cli/bin/security.c */ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptDeviceHasEncryptedFileSystem() is defined in ../zuluCrypt-cli/lib/blkid_evaluate_tag.c */ r = zuluCryptDeviceHasEncryptedFileSystem( device ) ; /* * zuluCryptSecurityDropElevatedPrivileges() is defined in ../zuluCrypt-cli/bin/security.c */ zuluCryptSecurityDropElevatedPrivileges() ; return r ; } static int _zuluMountPrintVolumeDeviceName( const char * device ) { char * c ; /* * zuluCryptSecurityGainElevatedPrivileges() is defined in ../zuluCrypt-cli/bin/security.c */ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptVolumeDeviceName() is defined in ../lib/status.c */ c = zuluCryptVolumeDeviceName( device ) ; /* * zuluCryptSecurityDropElevatedPrivileges() is defined in ../zuluCrypt-cli/bin/security.c */ zuluCryptSecurityDropElevatedPrivileges() ; if( c == NULL ){ return 1 ; }else{ printf( "%s\n",c ) ; StringFree( c ) ; return 0 ; } } /* * This is an emergency function,to be used when a device was unplugged uncleanly causing the device * old path to be "locked" as pluggin in the device again will give it a different path */ static int _checkUnmount( const char * device,uid_t uid ) { stringList_t stx ; stringList_t stl ; ssize_t index ; int r ; char * m_point = NULL ; string_t st ; const char * g ; if( StringPrefixEqual( device,"/dev/mapper/zuluCrypt-" ) ){ /* * encrypted volumes are handled someplace else */ return 0 ; } /* * zuluCryptGetMoutedList() is defined in ../lib/process_mountinfo.c */ stx = zuluCryptGetMoutedList() ; st = String( device ) ; index = StringListHasStartSequence( stx,StringAppend( st," " ) ) ; StringDelete( &st ) ; if( index != -1 ){ st = StringListStringAt( stx,(size_t)index ) ; stl = StringListStringSplit( st,' ' ) ; device = StringListContentAtFirstPlace( stl ) ; /* * zuluCryptBindUnmountVolume() is defined in ../zuluCrypt-cli/bin/bind.c */ r = zuluCryptBindUnmountVolume( stx,device,uid ) ; if( r != 3 || r != 4 ){ st = StringListStringAtSecondPlace( stl ) ; /* * zuluCryptDecodeMountEntry() is defined in ../zuluCrypt-cli/lib/mount_volume.c */ g = zuluCryptDecodeMountEntry( st ) ; /* * zuluCryptMountPointPrefixMatch() is defined in ../zuluCrypt-cli/lib/create_mount_point.c */ r = zuluCryptMountPointPrefixMatch( g,uid,NULL ) ; if( r == 1 ){ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptUnmountVolume() is defined in ../zuluCrypt-cli/lib/unmount_volume.c */ if( zuluCryptUnmountVolume( device,&m_point ) == 0 ){ if( m_point != NULL ){ rmdir( m_point ) ; StringFree( m_point ) ; } } zuluCryptSecurityDropElevatedPrivileges() ; } } StringListDelete( &stl ) ; }else{ /* * Either the volume is not mounted or is encrypted. * If it is encrypted,then it is handled someplace else */ ; } StringListDelete( &stx ) ; return 0 ; } static int _zuluMountExe( ARGS * args ) { const char * device = args->device ; const char * action = args->action ; const char * uuid = args->uuid ; const char * offset = args->offset ; uid_t uid = args->uid ; string_t st ; int r ; if( StringsAreEqual( action,"-L" ) ){ return zuluMountPrintDeviceProperties( device,uuid,uid ) ; } if( StringsAreEqual( action,"-s" ) ){ st = _zuluCryptGetFileSystemFromDevice( device ) ; zuluCryptSecurityGainElevatedPrivileges() ; r = zuluCryptDeviceManagedByDislocker( device,uid ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( StringContains( st,zuluCryptBitLockerType() ) && r ){ r = zuluMountPrintBitLockerProperties( device,uid ) ; }else if( offset != NULL || st == StringVoid || StringsAreEqual_2( st,"Nil" ) || StringStartsWith( st,"crypto_" ) ){ r = zuluMountVolumeStatus( device,uuid,uid ) ; }else{ r = zuluMountUnEncryptedVolumeStatus( device,NULL,NULL ) ; } StringDelete( &st ) ; return r ; } if( StringsAreEqual( action,"-m" ) ){ if( offset != NULL || _zuluPartitionHasCryptoFs( device ) ){ /* * zuluMountMount() is defined in crypto_mount.c */ return zuluMountCryptoMount( args ) ; }else{ /* * zuluMountMount() is defined in mount.c */ return zuluMountMount( args ) ; } } if( StringsAreEqual( action,"-u" ) ){ if( offset != NULL || _zuluPartitionHasCryptoFs( device ) ){ /* * zuluMountMount() is defined in crypto_umount.c */ return zuluMountCryptoUMount( args ) ; }else{ /* * zuluMountMount() is defined in umount.c */ return zuluMountUMount( args ) ; } } return _zuluExit_1( 200,StringListVoid,NULL,gettext( "ERROR: unrecognized argument encountered" ) ) ; } static int _mount_help() { const char * doc6 ; const char * doc5 ; const char * doc4 ; const char * doc3 ; const char * doc2 ; const char * doc1 = gettext( "\ options:\n\ -m -- mount a volume : arguments: -d volume_path -z mount_point -e mode(rw/ro)\n\ -- additional arguments for crypto_LUKS,crypto_PLAIN,crypto_TCRYPT volumes, -p passphrase/-f keyfile\n\ -z -- mount point component to append to \"/run/media/private/$USER/\"\n\ -Y -- file system options\n\ -e -- mount options\n" ) ; doc2 = gettext( "\ -u -- unmount a volume: arguments: -d volume_path\n\ -s -- print properties of a volume: arguments: -d partition_path\n\ -M -- this option will create a mount point in \"/run/media/private/$USER\" and a publicly accessible \"mirror\" in \"/run/media/public/\'\n" ) ; doc3 = gettext( "\ -l -- print expanded list of all volumes\n\ -L -- must be used with -d,print properties of a volume specified by d option\n\ -P -- print a list of all volumes\n\ -D -- get a device node address from its mapper path( mapper paths are usually located in /dev/mapper ). Required argument: -d\n" ) ; doc4 = gettext( "\ -A -- print a list of all volumes\n\ -S -- print a list of system volumes\n\ -N -- print a list of non system volumes\n\ -E -- print a list of mounted volumes\n\ -t -- to unlock a volume as VeraCrypt volume,use \"-t vera\"\n" ) ; doc5= gettext( "\ -o -- offset in sectors on where the volume starts in the volume.The volume is assumed to be plain type with this option \ and the option must be given when -u or -s arguments are used with a volume opened with this option\n\ -F -- path to truecrypt multiple keyfiles.Keyfiles are separated by \":\" character\n\n" ) ; doc6= gettext( "\ examples:\n\ mount a volume : zuluMount-cli -m -d /dev/sdc1\n\ unmount a volume: zuluMount-cli -u -d /dev/sdc1\n\ mount and encrypted volume with a key \"xyz\" : zuluMount-cli -m -d /dev/sdc2 -p xyz\n" ) ; printf( "%s%s%s%s%s%s",doc1,doc2,doc3,doc4,doc5,doc6 ) ; return 201 ; } static void ExitOnMemoryExaustion( void ) { printf( gettext( "Unexpected exiting because you have run out of memory\n" ) ) ; exit( 1 ) ; } static int _zuluMountDoAction( ARGS * args ) { int fd = -1 ; int fd1 = -1 ; int status ; char * dev = NULL ; const char * msg = gettext( "ERROR: A non supported device encountered,device is missing or permission denied\n\ Possible reasons for getting the error are:\n1.Device path is invalid.\n2.The device has LVM or MDRAID signature\n" ) ; /* * zuluCryptGetDeviceFileProperties is defined in ../zuluCrypt-lib/file_path_security.c */ switch( zuluCryptGetDeviceFileProperties( args->device,&fd,&fd1,&dev,args->uid ) ){ case 0 : args->device = dev ; /* * zuluCryptDeviceIsSupported() is defined in ../zuluCrypt-cli/bin/volumes.c */ if( zuluCryptDeviceIsSupported( dev,args->uid ) ){ status = _zuluMountExe( args ) ; }else{ printf( "%s",msg ) ; status = 224 ; } if( dev != NULL ){ StringFree( dev ) ; } if( fd1 != -1 ){ close( fd ) ; } if( fd != -1 ){ close( fd ) ; } return status ; case 1 : printf( gettext( "ERROR: Devices in /dev/shm path is not suppored\n" ) ) ; return 220 ; case 2 : printf( gettext( "ERROR: Given path is a directory\n" ) ) ; return 221 ; case 3 : printf( gettext( "ERROR: A file can have only one hard link\n" ) ) ; return 222 ; case 4 : printf( gettext( "ERROR: Insufficient privilges to access the device\n" ) ) ; return 223 ; default: printf( "%s",msg ) ; return 224 ; } } static void _privilegeEvelationError( const char * msg ) { puts( msg ) ; exit( 255 ) ; } static void _forceTerminateOnSeriousError( int sig ) { if( sig ){;} puts( "SIGSEGV caught,exiting" ) ; exit( 255 ) ; } static int _create_mount_point( const char * label,const char * m_opts,uid_t uid ) { /* * zuluCryptCreateMountPoint() is defined in ../zuluCrypt-cli/bin/create_mount_point.c */ string_t st = zuluCryptCreateMountPoint( NULL,label,m_opts,uid ) ; int r ; if( st != StringVoid ){ r = 0 ; StringDelete( &st ) ; }else{ r = 1 ; } return r ; } static int _delete_mount_point( const char * m_path,uid_t uid ) { string_t st ; int r = 0 ; /* * zuluCryptReuseMountPoint() is defined in ../zuluCrypt-cli/bin/create_mount_point.c */ if( !zuluCryptReuseMountPoint() ){ /* * zuluCryptGetUserName() is defined in ../zuluCrypt-cli/lib/user_home_path.c */ st = zuluCryptGetUserName( uid ) ; if( StringPrefixEqual( m_path,StringPrepend( st,"/run/media/private/" ) ) ){ zuluCryptSecurityGainElevatedPrivileges() ; r = rmdir( m_path ) ; zuluCryptSecurityDropElevatedPrivileges() ; }else{ zuluCryptSecurityDropElevatedPrivileges() ; r = rmdir( m_path ) ; } StringDelete( &st ) ; } return r ; } int main( int argc,char * argv[] ) { char * action ; char * device ; string_t * k ; stringList_t stl ; stringList_t stx ; int status ; int i ; uid_t uid = getuid() ; gid_t gid = getgid() ; /* * ARGS structure is declared in ./includes.h */ ARGS args ; struct sigaction sa ; memset( &sa,'\0',sizeof( struct sigaction ) ) ; sa.sa_handler = _forceTerminateOnSeriousError ; sigaction( SIGSEGV,&sa,NULL ) ; setlocale( LC_ALL,"" ) ; bindtextdomain( "zuluMount-cli",TRANSLATION_PATH ) ; textdomain( "zuluMount-cli" ); zuluCryptExeSetOriginalUID( uid ) ; if( argc < 2 ){ return _mount_help() ; } if( argc == 2 ){ action = argv[ 1 ] ; if( StringAtLeastOneMatch_1( action,"-h","--help","-help",NULL ) ){ return _mount_help() ; } if( StringAtLeastOneMatch_1( action,"-v","-version","--version",NULL ) ){ printf( "%s\n",zuluCryptVersion() ); return 0 ; } if( StringsAreEqual( action,"--clear-dead-mount-points" ) ){ zuluCryptClearDeadMappers( uid,1 ) ; return 0 ; } } memset( &args,'\0',sizeof( args ) ) ; /* * setgroups() requires seteuid(0) ; */ _seteuid( 0 ) ; if( setgroups( 1,&gid ) != 0 ){ _privilegeEvelationError( gettext( "ERROR: setgroups() failed" ) ) ; } if( setegid( uid ) != 0 ){ _privilegeEvelationError( gettext( "ERROR: setegid() failed" ) ) ; } if( _mount_get_opts( argc,argv,&args ) != 0 ){ return _mount_help() ; } i = zuluCryptSecurityConvertUID( uid,args.u_id ) ; if( i == -1 ){ puts( gettext( "ERROR: user is not root privileged" ) ) ; return 255 ; }else{ args.uid = uid = (uid_t)i ; } /* * Run with higher priority to speed things up */ setpriority( PRIO_PROCESS,0,-15 ) ; _setuid( 0 ) ; _seteuid( uid ) ; /* * zuluCryptDisableMetadataLocking() is defined in ..zuluCrypt-cli/lib/create_luks.c */ zuluCryptDisableMetadataLocking() ; /* * zuluCryptClearDeadMappers() is defined in ../zuluCrypt-cli/bin/clear_dead_mapper.c */ zuluCryptClearDeadMappers( uid,0 ) ; /* * zuluCryptSecuritySetPrivilegeElevationErrorFunction() is defined in ../zuluCrypt-cli/bin/security.c * _privilegeEvelationError() function will be called when functions that elevate or drop privileges fail */ zuluCryptSecuritySetPrivilegeElevationErrorFunction( _privilegeEvelationError ) ; /* * zuluCryptSetUserUIDForPrivilegeManagement() is defined in ../zuluCrypt-bin/security.c */ zuluCryptSetUserUIDForPrivilegeManagement( uid ) ; /* * zuluCryptSecurityDropElevatedPrivileges() is defined in ../zuluCrypt-cli/bin/security.c */ zuluCryptSecurityDropElevatedPrivileges() ; StringExitOnMemoryExaustion( ExitOnMemoryExaustion ) ; StringListExitOnMemoryExaustion( ExitOnMemoryExaustion ) ; SocketExitOnMemoryExaustion( ExitOnMemoryExaustion ) ; ProcessExitOnMemoryExaustion( ExitOnMemoryExaustion ) ; stl = StringListInit() ; /* * zuluCryptSecuritySanitizeTheEnvironment() is defined in ../zuluCrypt-cli/bin/security.c */ zuluCryptSecuritySanitizeTheEnvironment( global_variable_user_uid,&stx ) ; #define _hide( z ) strncpy( ( char * )z,"x",StringLength( *k ) ) if( args.device != NULL ){ k = StringListAssign( stl ) ; *k = String( args.device ) ; _hide( args.device ) ; args.device = StringContent( *k ) ; } if( args.key != NULL ){ k = StringListAssign( stl ) ; *k = String( args.key ) ; _hide( args.key ) ; args.key = StringContent( *k ) ; } if( args.type != NULL ){ k = StringListAssign( stl ) ; *k = String( args.type ) ; _hide( args.type ) ; args.type = StringContent( *k ) ; } for( i = 0 ; args.tcrypt_multiple_keyfiles[ i ] != NULL ; i++ ){ k = StringListAssign( stl ) ; *k = String( args.tcrypt_multiple_keyfiles[ i ] ) ; _hide( args.tcrypt_multiple_keyfiles[ i ] ) ; args.tcrypt_multiple_keyfiles[ i ] = StringContent( *k ) ; } zuluCryptSecurityLockMemory( stl ) ; if( args.action == NULL ){ return _zuluExit_2( 212,stl,stx,gettext( "ERROR: Action not specified" ) ) ; } if( StringsAreEqual( args.action,"-E" ) ){ return _zuluExit_2( zuluMountprintAListOfMountedVolumes( uid ),stl,stx,NULL ) ; } if( StringsAreEqual( args.action,"-c" ) ){ return _zuluExit_2( _checkUnmount( args.device,uid ),stl,stx,NULL ) ; } if( StringsAreEqual( args.action,"-l" ) ){ return _zuluExit_2( _zuluMountMountedList( uid ),stl,stx,NULL ) ; } if( StringsAreEqual( args.action,"-P" ) || StringsAreEqual( args.action,"-A" ) ){ return _zuluExit_2( _zuluMountDeviceList( uid ),stl,stx,NULL ) ; } if( StringsAreEqual( args.action,"-S" ) ){ return _zuluExit_2( _zuluMountSystemDeviceList( uid ),stl,stx,NULL ) ; } if( StringsAreEqual( args.action,"-N" ) ){ return _zuluExit_2( _zuluMountNonSystemDeviceList( uid ),stl,stx,NULL ) ; } if( StringsAreEqual( args.action,"-B" ) ){ return _zuluExit_2( _create_mount_point( args.m_point,args.m_opts,args.uid ),stl,stx,NULL ) ; } if( StringsAreEqual( args.action,"-b" ) ){ return _zuluExit_2( _delete_mount_point( args.m_point,args.uid ),stl,stx,NULL ) ; } if( StringsAreEqual( args.action,"-h" ) ){ return _zuluExit_2( _mount_help(),stl,stx,NULL ) ; } if( args.device == NULL ){ return _zuluExit_2( 213,stl,stx,gettext( "ERROR: device argument missing" ) ) ; } if( StringsAreEqual( args.action,"-D" ) ){ return _zuluMountPrintVolumeDeviceName( args.device ) ; } if( args.m_opts == NULL ){ args.m_opts = "rw" ; } args.env = stx ; /* * zuluCryptEvaluateDeviceTags() is defined in ../zuluCrypt-cli/bin/path_access.c */ if( StringPrefixEqual( args.device,"UUID=" ) ){ device = zuluCryptEvaluateDeviceTags( "UUID",args.device + 5 ) ; if( device != NULL ){ args.uuid = args.device ; args.device = device ; status = _zuluMountDoAction( &args ) ; StringFree( device ) ; }else{ printf( gettext( "Could not resolve UUID\n" ) ) ; status = 214 ; } }else if( StringPrefixEqual( args.device,"LABEL=" ) ){ device = zuluCryptEvaluateDeviceTags( "LABEL",args.device + 6 ) ; if( device != NULL ){ args.device = device ; status = _zuluMountDoAction( &args ) ; StringFree( device ) ; }else{ printf( gettext( "Could not resolve LABEL\n" ) ) ; status = 215 ; } }else{ status = _zuluMountDoAction( &args ) ; } return _zuluExit_2( status,stl,stx,NULL ) ; } zuluCrypt-6.2.0/zuluMount-cli/mount.c000066400000000000000000000214361425361753700176600ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include "../zuluCrypt-cli/bin/includes.h" #include #include #include static int _zuluMountPartitionAccess( const char * device,const char * m_opts,uid_t uid ) { /* * this function is defined in ../zuluCrypt-cli/lib/mount_volume.c */ /* * MOUNTOPTIONS constant is defined in ../zuluCrypt-cli/lib/includes.h */ int ro ; int nouser ; int defaulT ; int user ; int users ; int system_partition ; int st = 1 ; string_t p ; stringList_t stl ; zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptGetFstabEntryList() is defined in ../zuluCrypt-cli/lib/mount_volume.c */ stl = zuluCryptGetFstabEntryList( device,uid ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( stl != StringListVoid ){ if( StringListSize( stl ) != 6 ){ StringListDelete( &stl ) ; return 3 ; } } p = StringListStringAt( stl,MOUNTOPTIONS ) ; /* * zuluCryptPartitionIsSystemPartition() is defined in ../zuluCrypt-cli/bin/partition.c */ system_partition = zuluCryptPartitionIsSystemPartition( device,uid ) ; if( system_partition ){ /* * zuluCryptExeOriginalUserIsNotRoot() is defined in ../zuluCrypt/bin/security.c */ if( zuluCryptExeOriginalUserIsNotRoot() ){ /* * zuluCryptUserIsAMemberOfAGroup() is defined in ../zuluCrypt/bin/security.c */ if( zuluCryptUserIsAMemberOfAGroup( uid,"zulumount" ) ){ system_partition = 0 ; } }else{ system_partition = 0 ; } } if( p == StringVoid ){ /* * partition does not have an entry in fstab */ if( system_partition ){ /* * partition is system partition */ if( uid == 0 ){ /* * cant say no to root */ st = 0 ; }else{ /* * system partition with no entry in fstab,refuse to mount this one */ st = 1 ; } }else{ /* * no entry in fstab,not a system partition,mount this one */ st = 0 ; } }else{ /* * has an entry in fstab */ ro = StringContains( p,"ro" ) ; nouser = StringContains( p,"nouser" ) ; defaulT = StringContains( p,"defaults" ) ; users = StringContains( p,"users" ); user = StringContains( p,"user" ) ; if( ro && StringHasComponent( m_opts,"rw" ) ){ /* * respect the option for the partition to be mounted read only */ st = 2 ; }else if( uid == 0 ){ /* * user is root,mount it */ st = 0 ; }else{ if( nouser ){ /* * normal user is not allowed to mount it */ st = 1 ; }else if( user || users ){ /* * the partition has option to allow normal user to mount it,mount it */ st = 0 ; }else if( defaulT ){ /* * zuluCryptUserIsAMemberOfAGroup() is defined in ../zuluCrypt/bin/security.c */ if( zuluCryptUserIsAMemberOfAGroup( uid,"zulumount" ) ){ /* * user is a member is zulumount group,mount it */ st = 0 ; }else{ st = 1 ; } }else{ /* * remaining options go there */ /* * zuluCryptUserIsAMemberOfAGroup() is defined in ../zuluCrypt/bin/security.c */ if( zuluCryptUserIsAMemberOfAGroup( uid,"zulumount" ) ){ /* * user is a member is zulumount group,mount it */ st = 0 ; }else{ st = 1 ; } } } } StringListDelete( &stl ) ; return st ; } int zuluMountMount( ARGS * args ) { const char * device = args->device ; const char * m_point = args->m_point ; const char * m_opts = args->m_opts ; const char * fs_opts = args->fs_opts ; uid_t uid = args->uid ; int share = args->share ; int status ; string_t z = StringVoid ; char * path = NULL ; const char * rm_point ; unsigned long m_flags ; const char * dev = device ; const char * msg = gettext( "\ ERROR: Insuffienct privilege to manage a system volume.\nnecessary privileges can be acquired by:\n\ 1. Adding an entry for the volume in fstab with \"user\" mount option\n\ 2. Add yourself to \"zulumount\" group" ) ; if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../zuluCrypt-cli/lib/create_loop_devices.c */ path = zuluCryptLoopDeviceAddress_1( device ) ; if( path == NULL ){ return _zuluExit( 112,z,path,gettext( "ERROR: Could not resolve path to device or device could not be opened in read write mode" ) ) ; }else{ dev = path ; } } if( m_opts == NULL ){ m_opts = "rw" ; } if( StringHasComponent( m_opts,"rw" ) ){ /* * zuluCryptCanOpenPathForWriting() is defined in ../zuluCrypt-cli/bin/path_access.c */ status = zuluCryptCanOpenPathForWriting( device,uid ) ; }else{ /* * zuluCryptCanOpenPathForReading() is defined in ../zuluCrypt-cli/bin/path_access.c */ status = zuluCryptCanOpenPathForReading( device,uid ) ; } if( status != 0 ){ return _zuluExit( 112,z,path,gettext( "ERROR: Could not resolve path to device or device could not be opened in read write mode" ) ) ; } /* * zuluCryptMountFlagsAreNotCorrect() is defined in ../zuluCrypt-cli/bin/mount_flags.c */ if( zuluCryptMountFlagsAreNotCorrect( m_opts,uid,&m_flags ) ){ return _zuluExit( 100,z,path,gettext( "ERROR: Insuffienct privileges to mount the volume with given mount options" ) ) ; } /* * zuluCryptPartitionIsMounted is defined in ../zuluCrypt-cli/lib/process_mountinfo.c */ if( zuluCryptPartitionIsMounted( dev ) ){ return _zuluExit( 102,z,path,gettext( "ERROR: Device already mounted" ) ) ; } status = _zuluMountPartitionAccess( dev,m_opts,uid ) ; switch( status ){ case 0 : break ; case 1 : return _zuluExit( 103,z,path,msg ) ; case 2 : return _zuluExit( 104,z,path,gettext( "ERROR: \"/etc/fstab\" entry for this volume requires it to be mounted read only" ) ) ; case 3 : return _zuluExit( 113,z,path,gettext( "ERROR: \"/etc/fstab\" entry for this volume is malformed" ) ) ; default: return _zuluExit( 105,z,path,gettext( "ERROR: \"/etc/fstab\" entry for this volume does not allow you to mount it" ) ) ; } /* * zuluCryptSecurityCreateMountPoint() is defined in ../zuluCrypt-cli/bin/create_mount_point.c */ z = zuluCryptCreateMountPoint( device,m_point,m_opts,uid ) ; if( z == StringVoid ){ return _zuluExit( 106,z,path,gettext( "ERROR: Could not create mount point path,path already taken" ) ) ; } rm_point = StringContent( z ) ; if( share ){ /* * zuluCryptBindSharedMountPointPathTaken() is defined in ../zuluCrypt-cli/bin/bind.c */ if( zuluCryptBindSharedMountPointPathTaken( z ) ){ zuluCryptSecurityGainElevatedPrivileges() ; rmdir( rm_point ) ; zuluCryptSecurityDropElevatedPrivileges() ; return _zuluExit( 114,z,path,gettext( "ERROR: Shared mount point path aleady taken" ) ) ; } } zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptMountVolume() defined in ../zuluCrypt-cli/lib/mount_volume.c */ status = zuluCryptMountVolume( device,rm_point,m_flags,fs_opts,uid ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( status == 0 ){ if( share ){ /* * user wish to share the mount point publicly, bind the mount point to a publicly accessed path of /run/share */ /* * zuluCryptBindMountVolume() is defined in ../zuluCrypt-cli/bin/bind.c */ zuluCryptBindMountVolume( device,z,m_flags ) ; } printf( gettext( "SUCCESS: Mount complete successfully\nvolume mounted at: %s\n" ),rm_point ) ; return _zuluExit( 0,z,path,NULL ) ; }else{ zuluCryptSecurityGainElevatedPrivileges() ; rmdir( rm_point ) ; zuluCryptSecurityDropElevatedPrivileges() ; switch( status ){ case -1: return _zuluExit( 108,z,path,gettext( "ERROR: Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered" ) ) ; case 1 : return _zuluExit( 109,z,path,gettext( "ERROR: Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed?" ) ) ; case 4 : return _zuluExit( 110,z,path,gettext( "ERROR: Mount failed,no or unrecognized file system" ) ) ; case 12: return _zuluExit( 111,z,path,gettext( "ERROR: Mount failed,could not get a lock on /etc/mtab~" ) ) ; default: return _zuluExit( 115,z,path,gettext( "ERROR: Failed to mount the partition" ) ) ; } } } zuluCrypt-6.2.0/zuluMount-cli/umount.c000066400000000000000000000116151425361753700200430ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "includes.h" #include #include #include int zuluMountUMount( ARGS * args ) { const char * device = args->device ; uid_t uid = args->uid ; char * loop_device ; char * m_point = NULL ; int status ; string_t st = StringVoid ; const char * dev = NULL ; const char * errorMsg = gettext( "\ ERROR: You can not umount volumes out of \"%s\" since you are not root and do not belong to group \"zulumount\"\n" ) ; string_t xt ; if( zuluCryptNoPartitionLoopDevice( device ) ){ /* * zuluCryptLoopDeviceAddress() is defined in ../zuluCrypt-cli/lib/create_loop_devices.c */ loop_device = zuluCryptLoopDeviceAddress( device ) ; if( loop_device == NULL ){ /* * the error msg is a lie,but its harmless since the user will most likely never see it as * this code path will not be passed. */ return _zuluExit( 100,StringVoid,m_point,gettext( "ERROR: Device does not appear to be mounted" ) ) ; }else{ st = StringInherit( &loop_device ) ; dev = StringContent( st ) ; /* * zuluCryptGetMountPointFromPath() is defined in defined in ../zuluCrypt-cli/lib/process_mountinfo.c */ m_point = zuluCryptGetMountPointFromPath( dev ) ; if( m_point == NULL ){ return _zuluExit( 100,st,m_point,gettext( "ERROR: Device does not appear to be mounted" ) ) ; } } }else{ /* * zuluCryptGetMountPointFromPath() is defined in defined in ../zuluCrypt-cli/lib/process_mountinfo.c */ m_point = zuluCryptGetMountPointFromPath( device ) ; if( m_point == NULL ){ return _zuluExit( 100,st,m_point,gettext( "ERROR: Device does not appear to be mounted" ) ) ; } } /* * zuluCryptMountPointPrefixMatch() is defined in ../zuluCrypt-cli/bin/create_mount_point.c */ if( zuluCryptMountPointPrefixMatch( m_point,uid,&xt ) ){ StringDelete( &xt ) ; }else{ /* * zuluCryptUserIsAMemberOfAGroup() is defined in ../zuluCrypt-cli/bin/security.c */ if( zuluCryptUserIsAMemberOfAGroup( uid,"zulumount" ) ){ StringDelete( &xt ) ; }else{ printf( errorMsg,StringContent( xt ) ) ; StringDelete( &xt ) ; return _zuluExit( 101,st,m_point,NULL ) ; } } StringFree( m_point ) ; m_point = NULL ; /* * zuluCryptBindUnmountVolume() is defined in ../zuluCrypt-cli/bin/bind.c */ switch( zuluCryptBindUnmountVolume( StringListVoid,device,uid ) ){ case 3 : return _zuluExit( 107,st,m_point,gettext( "ERROR: Shared mount point appear to be busy" ) ) ; case 4 : return _zuluExit( 108,st,m_point,gettext( "ERROR: Shared mount point appear to belong to a different user" ) ) ; case 5 : return _zuluExit( 109,st,m_point,gettext( "ERROR: Shared mount point appear to be in an ambiguous state,advice to unmount manually" ) ) ; default: ; } /* * zuluCryptSecurityGainElevatedPrivileges() is defined in ../zuluCrypt-cli/bin/security.c */ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptUnmountVolume() is defined in ../zuluCrypt-cli/lib/unmount_volume.c */ status = zuluCryptUnmountVolume( device,&m_point ) ; /* * zuluCryptSecurityDropElevatedPrivileges() is defined in ../zuluCrypt-cli/bin/security.c */ zuluCryptSecurityDropElevatedPrivileges() ; if( status == 0 ){ if( m_point != NULL ){ /* * zuluCryptReuseMountPoint() is defined in ../zuluCrypt-cli/bin/create_mount_point.c */ if( !zuluCryptReuseMountPoint() ){ zuluCryptSecurityGainElevatedPrivileges() ; rmdir( m_point ) ; zuluCryptSecurityDropElevatedPrivileges() ; } } return _zuluExit( 0,st,m_point,gettext( "SUCCESS: umount complete successfully" ) ) ; }else{ switch( status ) { case 1 : return _zuluExit( 103,st,m_point,gettext( "ERROR: Device does not exist" ) ) ; case 2 : return _zuluExit( 104,st,m_point,gettext( "ERROR: Failed to unmount,the mount point and/or one or more files are in use" ) ) ; case 4 : return _zuluExit( 105,st,m_point,gettext( "ERROR: Failed to unmount,could not get a lock on /etc/mtab~" ) ) ; case 10: return _zuluExit( 111,st,m_point,gettext( "ERROR: Failed to unmount,multiple mount points for the volume detected" ) ) ; break ; default: return _zuluExit( 106,st,m_point,gettext( "ERROR: Failed to unmount the partition" ) ) ; } } } zuluCrypt-6.2.0/zuluMount-cli/volume_status.c000066400000000000000000000532351425361753700214320ustar00rootroot00000000000000/* * * Copyright (c) 2011-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include #include #include #include #include "../zuluCrypt-cli/lib/includes.h" #include "../zuluCrypt-cli/bin/includes.h" stringList_t zuluCryptPartitionList( void ) ; static const char * _fs( const char * e ) { if( StringPrefixEqual( e,"fuse" ) ){ return e + 5 ; }else{ return e ; } } void zuluMountPartitionProperties( const char * dev,const char * UUID, const char * mapper,const char * m_point,const char * fs ) { #define SIZE 64 const char * g ; const char * e ; char * m ; blkid_probe blkid ; struct statvfs vfs ; u_int64_t total ; u_int64_t used ; u_int64_t free_space ; u_int32_t block_size ; u_int64_t volume_size = 0 ; char buff[ SIZE ] ; char * buffer = buff ; const char * device = NULL ; char * device_1 = NULL ; if( zuluCryptFUSEVolumeIsSupported( fs ) ){ if( m_point != NULL ){ printf( "%s\t%s\t%s\tNil\tNil\tNil\n",dev,m_point,_fs( fs ) ) ; }else{ printf( "%s\tNil\t%s\tNil\tNil\tNil\n",dev,_fs( fs ) ) ; } return ; } zuluCryptSecurityGainElevatedPrivileges() ; if( StringPrefixEqual( dev,"/dev/" ) ){ device = dev ; }else{ /* * got a path to an image file,convert it to its associated loop device first * because we dont want to pass image files paths to blkid. */ /* * zuluCryptGetALoopDeviceAssociatedWithAnImageFile() * is defined in ../zuluCrypt-cli/lib/create_loop_device.c */ device = device_1 = zuluCryptGetALoopDeviceAssociatedWithAnImageFile( dev ) ; } if( device == NULL ){ zuluCryptSecurityDropElevatedPrivileges() ; return ; } blkid = blkid_new_probe_from_filename( device ) ; if( blkid == NULL ){ zuluCryptSecurityDropElevatedPrivileges() ; printf( "%s\tNil\tNil\tNil\tNil\tNil\n",device ) ; StringFree( device_1 ) ; return ; } if( UUID != NULL ){ printf( "%s\t",UUID ) ; }else{ if( zuluCryptNoPartitionLoopDevice( dev ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../zuluCrypt-cli/lib/create_loop_device.c */ g = zuluCryptLoopDeviceAddress_1( dev ) ; if( g != NULL ){ printf( "%s\t",g ) ; StringFree( g ) ; }else{ printf( "%s\t",dev ) ; } }else{ printf( "%s\t",dev ) ; } } if( m_point == NULL ){ printf( "Nil\t" ) ; }else{ printf( "%s\t",m_point ) ; } if( StringsAreEqual( dev,mapper ) ){ blkid_do_probe( blkid ) ; if( StringPrefixEqual( fs,zuluCryptBitLockerType() ) ){ printf( "%s\t",fs ) ; }else{ e = zuluCryptVolumeType( blkid,device ) ; if( StringPrefixEqual( e,"crypto_LUKS" ) ){ m = zuluCryptGetVolumeType_1( device ) ; if( m ){ printf( "%s\t",m ) ; StringFree( m ) ; }else{ printf( "%s\t",e ) ; } }else{ printf( "%s\t",e ) ; } } if( blkid_probe_lookup_value( blkid,"LABEL",&g,NULL ) == 0 ){ printf( "%s",g ) ; }else{ printf( "Nil" ) ; } blkid_free_probe( blkid ) ; /* * zuluCryptGetVolumeSize() is defined in ../zuluCrypt-cli/lib/blkid_evaluate_tag.c */ if( m_point == NULL ){ volume_size = zuluCryptGetVolumeSize( device ) ; } }else{ blkid_free_probe( blkid ) ; blkid = blkid_new_probe_from_filename( mapper ) ; if( blkid == NULL ){ printf( "Nil\tNil" ) ; }else{ blkid_do_probe( blkid ) ; /* * zuluCryptGetVolumeTypeFromMapperPath() is defined in ../zuluCrypt-cli/lib/status.c */ e = zuluCryptGetVolumeTypeFromMapperPath( mapper ) ; if( blkid_probe_lookup_value( blkid,"TYPE",&g,NULL ) == 0 ){ printf( "%s/%s\t",e,g ) ; }else{ printf( "%s/Nil\t",e ) ; } if( blkid_probe_lookup_value( blkid,"LABEL",&g,NULL ) == 0 ){ printf( "%s",g ) ; }else{ printf( "Nil" ) ; } blkid_free_probe( blkid ) ; StringFree( e ) ; if( m_point == NULL ){ volume_size = zuluCryptGetVolumeSize( mapper ) ; } } } if( m_point == NULL ){ zuluCryptFormatSize( volume_size,buffer,SIZE ) ; printf( "\t%s\tNil\n",buffer ) ; }else{ if( statvfs( m_point,&vfs ) != 0 ){ printf( "\tNil\tNil\n" ) ; }else{ block_size = (unsigned int)vfs.f_frsize ; total = block_size * vfs.f_blocks ; zuluCryptFormatSize( total,buffer,SIZE ) ; printf( "\t%s",buffer ) ; free_space = block_size * vfs.f_bavail ; used = total - free_space ; if( used == total ){ puts( "\t100%" ) ; }else{ snprintf( buff,SIZE,"%.2f%%",100 * (double)( ( float ) used / ( float ) total ) ) ; printf( "\t%s\n",buff ) ; } } } StringFree( device_1 ) ; zuluCryptSecurityDropElevatedPrivileges() ; } static void _print_device_properties( string_t entry,const char * mapper_path,size_t mapper_length,uid_t uid ) { char * x ; const char * q ; const char * e ; const char * f ; const char * fs ; ssize_t index ; string_t st = StringVoid ; string_t xt ; stringList_t stx = StringListStringSplit( entry,' ' ) ; if( stx == StringListVoid ){ return ; } fs = StringListContentAtThirdPlace( stx ) ; q = StringListContentAtFirstPlace( stx ) ; if( StringPrefixMatch( q,mapper_path,mapper_length ) ){ /* * zuluCryptSecurityGainElevatedPrivileges() and zuluCryptSecurityDropElevatedPrivileges() * are defined in ../zuluCrypt-cli/bin/security.c */ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptVolumeDeviceName() is defined in ../zuluCrypt-cli/lib/status.c */ x = zuluCryptVolumeDeviceName( q ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( x != NULL ){ index = StringHasComponent_1( q,"-UUID-" ) ; if( index != -1 ){ st = String( q ) ; StringRemoveLeft( st,(size_t)index + 6 ) ; e = StringPrepend( st,"UUID=\"" ) ; index = StringLastIndexOfChar( st,'-' ) ; if( index >= 0 ){ StringSubChar( st,(size_t)index,'\"' ) ; e = StringSubChar( st,(size_t)index+1,'\0' ) ; } }else{ e = x ; } StringReplace( entry,e ) ; /* * zuluCryptDecodeMountEntry() is defined in ../zuluCrypt-cli/lib/mount_volume.c * it decodes space,tab,new line and backslash characters since they are written differently in "/etc/mtab" */ f = zuluCryptDecodeMountEntry( StringListStringAtSecondPlace( stx ) ) ; zuluMountPartitionProperties( x,e,q,f,fs ) ; StringFree( x ) ; StringDelete( &st ) ; }else{ StringReplaceChar_1( entry,0,' ','\0' ) ; } }else if( zuluCryptBitLockerVolume( q ) ){ st = zuluCryptBitLockerResolveMapperPath( q,uid ) ; e = zuluCryptDecodeMountEntry( st ) ; f = zuluCryptDecodeMountEntry( StringListStringAtSecondPlace( stx ) ) ; StringReplace( entry,e ) ; zuluCryptSecurityGainElevatedPrivileges() ; xt = zuluCryptGetFileSystemFromDevice( q ) ; if( xt != StringVoid ){ StringMultiplePrepend( xt,"/",zuluCryptBitLockerType(),NULL ) ; zuluMountPartitionProperties( e,NULL,e,f,StringContent( xt ) ) ; }else{ zuluMountPartitionProperties( e,NULL,e,f,zuluCryptBitLockerType() ) ; } zuluCryptSecurityDropElevatedPrivileges() ; StringMultipleDelete( &st,&xt,NULL ) ; }else{ StringReplaceChar_1( entry,0,' ','\0' ) ; e = zuluCryptDecodeMountEntry( StringListStringAtFirstPlace( stx ) ) ; f = zuluCryptDecodeMountEntry( StringListStringAtSecondPlace( stx ) ) ; zuluMountPartitionProperties( e,NULL,e,f,fs ) ; } zuluCryptSecurityDropElevatedPrivileges() ; StringListDelete( &stx ) ; } static int _starts_with_digits_only( string_t st ) { StringIterator it ; StringIterator end ; char e ; StringGetIterators( st,&it,&end ) ; while( it != end ){ e = *it ; it++ ; if( e == ' ' ){ return 1 ; } if( !( e >= '0' && e <= '9' ) ){ return 0 ; } } return 1 ; } static int _normal_mounted_volume( string_t st ) { if( StringStartsWithAtLeastOne( st,"/proc","/sys","/dev ",NULL ) ){ return 0 ; } if( StringsAreEqual_2( st,"/dev" ) ){ return 0 ; } if( StringStartsWith( st,"/" ) ){ return 1 ; } if( _starts_with_digits_only( st ) ) { return 1 ; } return 0 ; } int zuluMountPrintVolumesProperties( uid_t uid ) { stringList_t stl ; stringList_t stz ; StringListIterator it ; StringListIterator end ; string_t st ; const char * e ; const char * z ; size_t l ; /* * zuluCryptGetMoutedList() is defined in ../zuluCrypt-cli/lib/process_mountinfo.c * run StringListPrintList( stl ) to get a list of entries being worked on */ stl = zuluCryptGetMoutedList() ; /* * zuluCryptGetAListOfAllPartitions() is defined in ../zuluCrypt-cli/bin/volumes.c */ stz = zuluCryptGetAListOfAllVolumes() ; if( uid ){} /* * zuluCryptMapperPrefix() is defined in ../zuluCrypt-cli/lib/create_mapper_name.c * it should return something like "/dev/mapper" */ z = zuluCryptMapperPrefix() ; l = StringSize( z ) ; StringListGetIterators( stl,&it,&end ) ; /* * print a list of mounted volumes */ while( it != end ){ st = *it ; it++ ; if( _normal_mounted_volume( st ) ){ _print_device_properties( st,z,l,uid ) ; if( StringStartsWith( st,"UUID=" ) ){ e = StringRemoveString( st,"\"" ) ; /* * zuluCryptEvaluateDeviceTags() ../zuluCrypt-cli/bin/path_access.c */ e = zuluCryptEvaluateDeviceTags( "UUID",e + 5 ) ; StringListRemoveIfPresent( stz,e ) ; StringFree( e ) ; }else{ zuluCryptDecodeMountEntry( st ) ; StringListRemoveIfPresent_1( stz,st ) ; } }else{ zuluCryptDecodeMountEntry( st ) ; StringReplaceChar_1( st,0,' ','\0' ) ; StringListRemoveIfPresent_1( stz,st ) ; } } StringListGetIterators( stz,&it,&end ) ; /* * print a list of not mounted volumes */ while( it != end ){ e = StringContent( *it ) ; it++ ; zuluMountPartitionProperties( e,NULL,e,NULL,NULL ) ; } StringListMultipleDelete( &stl,&stz,NULL ) ; return 0 ; } static void _zuluMountprintAListOfMountedVolumes( string_t st,uid_t uid ) { const char * e ; const char * f ; /* * zuluCryptMapperPrefix() is defined in ../zuluCrypt-cli/lib/create_mapper_name.c * mapper_prefix will probably contain "/dev/mapper/" */ const char * mapper_prefix = zuluCryptMapperPrefix() ; string_t q ; if( StringStartsWith( st,mapper_prefix ) ){ /* * we will get here is the path starts with "/dev/mapper/". * This path could be an LVM path or an encrypted mapper path */ /* * zuluCryptConvertIfPathIsLVM() is defined in ../zuluCrypt-cli/lib/status.c */ q = zuluCryptConvertIfPathIsLVM( StringContent( st ) ) ; if( StringStartsWith( q,mapper_prefix ) ){ /* * volume is probably an encrypted one */ if( StringContains( q,"-NAAN-" ) ){ zuluCryptSecurityGainElevatedPrivileges() ; /* * zuluCryptVolumeDeviceName() is defined in ../zuluCrypt-cli/lib/status.c */ f = zuluCryptVolumeDeviceName( StringContent( q ) ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( f != NULL ){ puts( f ) ; StringFree( f ) ; } }else if( StringContains( q,"-UUID-" ) ){ StringReplaceString( q,"-UUID-","-UUID=\"" ) ; e = StringAppend( q,"\"" ) ; e = e + StringHasComponent_1( e,"UUID=" ) ; puts( e ) ; }else{ /* * Still assuming its an encrypted volume opened and outside of zuluCrypt/zuluMount */ zuluCryptSecurityGainElevatedPrivileges() ; f = zuluCryptVolumeDeviceName( StringContent( q ) ) ; zuluCryptSecurityDropElevatedPrivileges() ; if( f != NULL ){ puts( f ) ; StringFree( f ) ; }else{ /* * not exactly sure what this is,just print it and let the user sort it out */ zuluCryptDecodeMountEntry( q ) ; StringPrintLine( q ) ; } } }else{ /* * the volume is probably an LVM volume */ zuluCryptDecodeMountEntry( q ) ; StringPrintLine( q ) ; } StringDelete( &q ) ; }else if( zuluCryptBitLockerVolume( StringContent( st ) ) ){ q = zuluCryptBitLockerResolveMapperPath( StringContent( st ),uid ) ; StringPrintLine( q ) ; StringDelete( &q ) ; }else{ zuluCryptDecodeMountEntry( st ) ; StringPrintLine( st ) ; } } int zuluMountprintAListOfMountedVolumes( uid_t uid ) { /* * zuluCryptGetAListOfMountedVolumes() is defined in ../zuluCrypt-cli/lib/process_mountinfo.c */ stringList_t stz = zuluCryptGetAListOfMountedVolumes() ; stringList_t stx = StringListVoid ; string_t st ; StringListIterator it ; StringListIterator end ; const char * f ; /* * remove duplicates caused by bind mounts and other entries we dont care about */ StringListGetIterators( stz,&it,&end ) ; while( it != end ){ st = *it ; it++ ; if( _normal_mounted_volume( st ) ){ f = StringContent( st ) ; if( StringListHasNoEntry( stx,f ) ){ /* * Only print one entry if there are more due to bind mounts */ _zuluMountprintAListOfMountedVolumes( st,uid ) ; stx = StringListAppend( stx,f ) ; } } } StringListMultipleDelete( &stz,&stx,NULL ) ; return 0 ; } int zuluMountPrintDeviceProperties( const char * device,const char * UUID,uid_t uid ) { string_t p ; string_t q ; string_t z = StringVoid ; string_t f = StringVoid ; char * dev = NULL ; const char * device_1 ; const char * e ; /* * zuluCryptMapperPrefix() is defined in ../zuluCrypt-cli/lib/create_mapper_name.c * mapper_prefix will probably contain "/dev/mapper/" */ const char * mapper_prefix = zuluCryptMapperPrefix() ; size_t mapper_length = StringSize( mapper_prefix ) ; StringListIterator it ; StringListIterator end ; /* * zuluCryptGetMoutedList() is defined in ../zuluCrypt-cli/lib/process_mountinfo.c */ stringList_t stl = zuluCryptGetMoutedList() ; device_1 = device ; if( UUID == NULL ){ if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress() is defined in ../zuluCrypt-cli/lib/create_loop_device.c */ if( zuluCryptMultiPartitionLoopDevice( device ) ){ dev = StringCopy_2( device ) ; }else{ dev = zuluCryptLoopDeviceAddress( device ) ; } device_1 = dev ; z = String( dev ) ; e = zuluCryptDecodeMountEntry( z ) ; /* * ZULUCRYPTlongMapperPath is set in ../zuluCrypt-cli/constants.h * zuluCryptCreateMapperName() is defined at ../zuluCrypt-cli/lib/create_mapper_name.c */ e = e + StringLastIndexOfChar_1( e,'/' ) + 1 ; q = zuluCryptCreateMapperName( StringContent( z ),e,uid,ZULUCRYPTlongMapperPath ) ; }else{ /* * ZULUCRYPTlongMapperPath is set in ../zuluCrypt-cli/constants.h * zuluCryptCreateMapperName() is defined at ../zuluCrypt-cli/lib/create_mapper_name.c */ e = device + StringLastIndexOfChar_1( device,'/' ) + 1 ; q = zuluCryptCreateMapperName( device,e,uid,ZULUCRYPTlongMapperPath ) ; } }else{ p = String( UUID ) ; StringRemoveString( p,"\"" ) ; e = StringReplaceString( p,"UUID=","UUID-" ) ; q = zuluCryptCreateMapperName( device,e,uid,ZULUCRYPTlongMapperPath ) ; StringDelete( &p ) ; } e = StringContent( q ) ; p = StringListHasStartSequence_1( stl,e ) ; if( p != StringVoid ){ /* * mounted and encrypted volume opened by this user */ _print_device_properties( p,mapper_prefix,mapper_length,uid ) ; }else{ /* * We will get if: * 1. The volume is not mounted. * 2. The volume is mounted,encrypted and opened by a different user * 3. The volume is mouted and unencrypted */ f = String( device_1 ) ; p = StringListHasStartSequence_1( stl,StringAppend( f," " ) ) ; StringDelete( &f ) ; if( p != StringVoid ){ /* * volume is unencrypted and mounted by any user */ _print_device_properties( p,mapper_prefix,mapper_length,uid ) ; }else{ /* * We will get here is: * 1. The volume is not mounted * 2. The volume is encrypted and mounted by a different user */ StringListGetIterators( stl,&it,&end ) ; zuluCryptSecurityGainElevatedPrivileges() ; while( it != end ){ p = *it ; it++ ; if( StringStartsWith( p,mapper_prefix ) ){ e = StringReplaceChar_1( p,0,' ','\0' ) ; /* * zuluCryptVolumeDeviceName() is defined in ../zuluCrypt-cli/lib/status.c */ e = zuluCryptVolumeDeviceName( e ) ; if( StringsAreEqual( e,device ) ){ f = p ; StringReplaceChar_1( p,0,'\0',' ' ) ; StringFree( e ) ; break ; }else{ StringFree( e ) ; } } } zuluCryptSecurityDropElevatedPrivileges() ; if( f != StringVoid ){ /* * The volume is encrypted and mounted by any user,probably a different user * since volumes mounted by this user are already checked. */ _print_device_properties( f,mapper_prefix,mapper_length,uid ) ; }else{ /* * volume is not mounted */ zuluMountPartitionProperties( device,NULL,device,NULL,NULL ) ; } } } StringListDelete( &stl ) ; StringFree( dev ) ; StringDelete( &z ) ; StringDelete( &q ) ; return 0 ; } int zuluMountUnEncryptedVolumeStatus( const char * device,const char * fs,const char * device1 ) { char * e ; char * z ; stringList_t stl ; string_t p ; string_t q ; /* * zuluCryptGetMountEntry() is defined in ../zuluCrypt/cli/lib/process_mountinfo.c */ if( device1 != NULL ){ p = zuluCryptGetMountEntry( device1 ) ; }else{ p = zuluCryptGetMountEntry( device ) ; } stl = StringListStringSplit( p,' ' ) ; StringDelete( &p ) ; if( fs != NULL ){ p = String_1( "\n type: \t",fs,"\n cipher: \tNil\n keysize: \tNil\n offset: \tNil\n",NULL ) ; }else{ p = String( "\n type: \tNil\n cipher: \tNil\n keysize: \tNil\n offset: \tNil\n" ) ; } if( zuluCryptNoPartitionLoopDevice( device ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../zuluCrypt-cli/lib/create_loop_device.c */ e = zuluCryptLoopDeviceAddress_1( device ) ; /* * zuluCryptGetLoopDeviceAddress() is defined in ../zuluCrypt-cli/lib/create_loop_device.c */ z = zuluCryptGetLoopDeviceAddress( device ) ; if( e != NULL && z != NULL ){ StringMultipleAppend( p," device: \t",z,"\n loop: \t",e,NULL ) ; }else{ StringMultipleAppend( p," device: \t","Nil","\n loop: \tNil",NULL ) ; } StringFree( e ) ; StringFree( z ) ; }else{ StringMultipleAppend( p," device: \t",device," \n loop: \tNil",NULL ) ; } if( StringHasAtLeastOneComponent( StringListStringAt( stl,3 ),"ro,",",ro,",",ro",NULL ) ){ StringAppend( p," \n mode: \tread only\n active slots:\tNil" ) ; }else{ StringAppend( p," \n mode: \tread and write\n active slots:\tNil" ) ; } zuluCryptSecurityGainElevatedPrivileges() ; q = StringListStringAtSecondPlace( stl ) ; /* * zuluCryptFileSystemProperties() is defined in ../zuluCrypt-cli/lib/status.c * zuluCryptDecodeMountEntry() is defined in ../zuluCrypt-cli/lib/mount_volume.c */ if( device1 != NULL ){ zuluCryptFileSystemProperties( p,device1,zuluCryptDecodeMountEntry( q ) ) ; }else{ zuluCryptFileSystemProperties( p,device,zuluCryptDecodeMountEntry( q ) ) ; } zuluCryptSecurityDropElevatedPrivileges() ; /* * zuluCryptSecurityUUIDFromPath() is defined in ../zuluCrypt/cli/bin/path_access.c */ e = zuluCryptUUIDFromPath( device ) ; if( e != NULL ){ q = String( "" ) ; StringReplaceString( p,"\"Nil\"",StringMultipleAppend( q,"\"",e,"\"",NULL ) ) ; StringFree( e ) ; StringDelete( &q ) ; } StringPrintLine( p ) ; StringDelete( &p ) ; StringListDelete( &stl ) ; return 0 ; } int zuluMountVolumeStatus( const char * device,const char * UUID,uid_t uid ) { char * dev = NULL ; int st ; string_t p ; const char * e ; if( UUID == NULL ){ if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../zuluCrypt-cli/lib/create_loop_device.c */ dev = zuluCryptLoopDeviceAddress_1( device ) ; if( dev != NULL ){ e = dev + StringLastIndexOfChar_1( dev,'/' ) + 1 ; st = zuluCryptEXEVolumeInfo( e,dev,uid ) ; free( dev ) ; }else{ printf( gettext( "ERROR: Could not get volume properties,volume is not open or was opened by a different user\n" ) ) ; st = 1 ; } }else{ e = device + StringLastIndexOfChar_1( device,'/' ) + 1 ; st = zuluCryptEXEVolumeInfo( e,device,uid ) ; } }else{ p = String( UUID ) ; StringRemoveString( p,"\"" ) ; e = StringSubChar( p,4,'-' ) ; if( StringPrefixEqual( device,"/dev/loop" ) ){ /* * zuluCryptLoopDeviceAddress_1() is defined in ../zuluCrypt-cli/lib/create_loop_device.c */ dev = zuluCryptLoopDeviceAddress_1( device ) ; if( dev != NULL ){ st = zuluCryptEXEVolumeInfo( e,dev,uid ) ; StringFree( dev ) ; }else{ printf( gettext( "ERROR: Could not get volume properties,volume is not open or was opened by a different user" ) ) ; st = 1 ; } }else{ st = zuluCryptEXEVolumeInfo( e,device,uid ) ; } StringDelete( &p ) ; } return st ; } int zuluMountPrintBitLockerProperties( const char * device,uid_t uid ) { string_t xt ; string_t mt ; int r ; const char * e ; if( zuluCryptNoPartitionLoopDevice( device ) ){ xt = zuluCryptLoopDeviceAddress_2( device ) ; mt = StringCopy( xt ) ; e = zuluCryptBitLockerCreateMapperPath( xt,uid ) ; r = zuluMountUnEncryptedVolumeStatus( StringContent( mt ),"bitlocker",e ) ; StringDelete( &mt ) ; }else{ xt = String( device ) ; e = zuluCryptBitLockerCreateMapperPath( xt,uid ) ; r = zuluMountUnEncryptedVolumeStatus( device,"bitlocker",e ) ; } StringDelete( &xt ) ; return r ; } zuluCrypt-6.2.0/zuluMount-gui.1000066400000000000000000000010111425361753700164340ustar00rootroot00000000000000 .TH zuluMount-gui 1 .br .SH NAME zuluMount-gui - Graphical front end for zuluCrypt-cli .br .SH SUMMARY zuluMount-gui is a GUI front end to zuluCrypt-cli .br copyright: 2011-2013 Ink Francis,mhogomchungu@gmail.com .br license : GPLv2+ .br options: .br -d path to where a volume to be auto unlocked/mounted is located .br -m tool to use to open a default file manager(default tool is xdg-open) .br -e start the application without showing the GUI .br .br .SH LAST EDIT Last change: Mon Apr 8 20:03:01 EDT 2013 zuluCrypt-6.2.0/zuluMount-gui/000077500000000000000000000000001425361753700163615ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluMount-gui/CMakeLists.txt000066400000000000000000000066151425361753700211310ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) add_definitions( -D_FILE_OFFSET_BITS=64 -Wextra -Wall -pedantic -I${PROJECT_BINARY_DIR}/zuluMount-gui/ -I${PROJECT_BINARY_DIR}) include_directories( ${PROJECT_BINARY_DIR}/zuluMount-gui/ ) set (UI_FILES zulumount.ui keydialog.ui mountpartition.ui veracryptpimdialog.ui ../zuluCrypt-gui/tcrypt.ui ../zuluCrypt-gui/favorites2.ui ../zuluCrypt-gui/openvolume.ui ) set(MOC_FILES zulumount.h keydialog.h mountpartition.h oneinstance.h events.h monitor_mountinfo.h veracryptpimdialog.h ../zuluCrypt-gui/tcrypt.h ../zuluCrypt-gui/utility.h ../zuluCrypt-gui/favorites2.h ../zuluCrypt-gui/openvolume.h ) set(SRC main.cpp events.cpp zulumount.cpp keydialog.cpp zulumounttask.cpp mountpartition.cpp oneinstance.cpp monitor_mountinfo.cpp siritask.cpp volumeproperty.cpp ../zuluCrypt-gui/tcrypt.cpp veracryptpimdialog.cpp ../zuluCrypt-gui/favorites2.cpp ../zuluCrypt-gui/openvolume.cpp ../zuluCrypt-gui/secrets.cpp ) find_package( Qt5Widgets REQUIRED ) find_package( Qt5Core REQUIRED ) set( CMAKE_INCLUDE_CURRENT_DIR ON ) include_directories( ${Qt5Widgets_INCLUDE_DIRS} ) add_definitions( ${Qt5Widgets_DEFINITIONS} ) QT5_WRAP_UI( UI ${UI_FILES} ) QT5_WRAP_CPP(MOC ${MOC_FILES} ) QT5_ADD_RESOURCES( TRAY_RC_SRCS icon.qrc ) INCLUDE_DIRECTORIES( ${CMAKE_BINARY_DIR} ) add_executable( zuluMount-gui ${MOC} ${UI} ${SRC} ${TRAY_RC_SRCS} ) TARGET_LINK_LIBRARIES( zuluMount-gui sharedObject lxqt-wallet ${Qt5Widgets_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Widgets_LIBRARIES} ${Qt5Network_LIBRARIES} ${blkid} zuluCryptPluginManager ) set_target_properties( zuluMount-gui PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( zuluMount-gui PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pedantic " ) install( TARGETS zuluMount-gui RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) install ( FILES ${PROJECT_BINARY_DIR}/zuluMount.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications ) install( FILES zuluMount.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps/ ) install( FILES zuluMount.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons ) install( FILES zuluMount.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps ) install( FILES zuluMount.nicolas.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps/ ) install( FILES zuluMount.nicolas.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps ) install( FILES zuluMount.papirus.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps/ ) install( FILES zuluMount.papirus.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps ) install( FILES zuluMount.papirus.dark.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps/ ) install( FILES zuluMount.papirus.dark.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps ) #install ( FILES zuluMount.png DESTINATION share/icons/hicolor/32x32/apps ) # desktop file section file( WRITE ${PROJECT_BINARY_DIR}/zuluMount.desktop "[Desktop Entry] Comment[en_US]= Comment= Exec=${CMAKE_INSTALL_FULL_BINDIR}/zuluMount-gui -d %U GenericName[en_US]=Encrypted volume and Partition mounter GenericName=Encrypted volumes and partition mounter Icon=zuluMount Name[en_US]=ZuluMount Name=ZuluMount NoDisplay=false StartupNotify=true Terminal=false Type=Application MimeType=application/x-raw-disk-image; Categories=Security;Utility;Qt;X-MandrivaLinux-System-FileTools;\n") zuluCrypt-6.2.0/zuluMount-gui/events.cpp000066400000000000000000000124611425361753700203750ustar00rootroot00000000000000/* * * Copyright (c) 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include #include #include #include #include "bin_path.h" #include #include #include #include #include #include #include #include #include "../zuluCrypt-gui/utility.h" #include "events.h" #include "zulumounttask.h" #include /* * http://linux.die.net/man/7/inotify */ #define _startsWith( x,y ) strncmp( x,y,strlen( y ) ) == 0 #define _contains( x,y ) strstr( x,y ) != 0 #define _stringsAreEqual( x,y ) strcmp( x,y ) == 0 events::events( QObject * parent,std::function< void() > f ) : m_parent( parent ), m_function( std::move( f ) ) { } events::~events() { } void events::stop() { utility::stopTask( m_task,m_function ) ; } void events::start() { m_task = utility::startTask( [ this ](){ this->run() ; },m_function ) ; } void events::run() { connect( this,SIGNAL( volumeMiniProperties( volumeProperty * ) ), m_parent,SLOT( autoMountVolume( volumeProperty * ) ) ) ; connect( this,SIGNAL( volumeRemoved( QString ) ), m_parent,SLOT( volumeRemoved( QString ) ) ) ; utility::fileHandle f( inotify_init() ) ; int fd = f.handle() ; if( fd == -1 ){ utility::debug() << "Failed to initialize inotify_init(),trouble ahead!!!" ; return ; } int dev = inotify_add_watch( fd,"/dev",IN_CREATE|IN_DELETE ) ; int dm = inotify_add_watch( fd,"/dev/mapper",IN_CREATE|IN_DELETE ) ; int md = -1 ; if( utility::pathExists( "/dev/dm" ) ){ md = inotify_add_watch( fd,"/dev/md",IN_DELETE ) ; } auto _allowed_device = []( const char * device ){ /* * dont care about these devices. * /dev/sgX seem to be created when a usb device is plugged in * /dev/dm-X are dm devices we dont care about since we will be dealing with them differently */ bool s = _startsWith( device,"sg" ) || _startsWith( device,"dm-" ) || _contains( device,"dev/tmp" ) || _contains( device,"dev-tmp" ) || _contains( device,".tmp.md." ) || _contains( device,"md/md-device-map" ) ; return s == false ; } ; auto _device_action = [&]( const struct inotify_event * event ){ /* * /dev/md/ folder seem to be deleted when the last entry in it is removed and * created before the first entry is added.To account for this,monitor for the * folder creation to start monitoring its contents. */ if( event->wd == dev && event->mask & IN_CREATE ){ if( _stringsAreEqual( "md",event->name ) ){ md = inotify_add_watch( fd,"/dev/md",IN_DELETE ) ; return false ; } } if( event->wd == dev && event->mask & IN_DELETE ){ if( _stringsAreEqual( "md",event->name ) ){ inotify_rm_watch( md,dev ) ; return false ; } } return true ; } ; const char * currentEvent ; const char * end ; constexpr int BUFF_SIZE = 4096 ; char buffer[ BUFF_SIZE ] ; fd_set rfds ; FD_ZERO( &rfds ) ; int select_fd = fd + 1 ; auto _eventsReceived = [ & ](){ /* * we are blocking on select() and not on read() because QThread->terminate() does not seem to * be able to get out of a blocked read() on certain Qt versions. */ auto _gotEvents = [ & ](){ FD_SET( fd,&rfds ) ; return select( select_fd,&rfds,nullptr,nullptr,nullptr ) > 0 ; } ; if( _gotEvents() ){ auto s = read( fd,buffer,BUFF_SIZE ) ; if( s > 0 ){ end = buffer + s ; currentEvent = buffer ; return true ; } } return false ; } ; auto _processEvent = [ & ]( const struct inotify_event * event ){ if( _device_action( event ) && _allowed_device( event->name ) ){ auto _device = [ & ](){ if( event->wd == dm ){ return zuluMountTask::devices::dm_device ; }else if( event->wd == md ){ return zuluMountTask::devices::md_device ; }else{ return zuluMountTask::devices::device ; } } ; zuluMountTask::event e{ _device(),event->mask == IN_CREATE,event->name } ; Task::exec( [ this,e ](){ auto r = zuluMountTask::deviceProperties( e ) ; if( r.volumeRemoved ){ emit volumeRemoved( r.volumeName ) ; }else{ emit volumeMiniProperties( r.entry ) ; } } ) ; } } ; #define _cast( x ) reinterpret_cast< const struct inotify_event * >( currentEvent ) #define _eventSize sizeof( struct inotify_event ) while( true ){ if( _eventsReceived() ){ while( currentEvent < end ){ auto event = _cast( currentEvent ) ; if( event ){ _processEvent( event ) ; currentEvent += _eventSize + event->len ; }else{ currentEvent += _eventSize ; } } } } } zuluCrypt-6.2.0/zuluMount-gui/events.h000066400000000000000000000024611425361753700200410ustar00rootroot00000000000000/* * * Copyright (c) 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef AUTO_MOUNT_H #define AUTO_MOUNT_H #include #include #include "task.hpp" class QObject ; class events ; class volumeProperty ; class events : public QObject { Q_OBJECT public: explicit events( QObject * parent,std::function< void() > ) ; ~events() ; void stop( void ) ; void start( void ) ; signals: void volumeRemoved( QString ) ; void volumeMiniProperties( volumeProperty * ) ; private: void run() ; QObject * m_parent ; std::function< void() > m_function ; Task::future< void > * m_task = nullptr ; }; #endif // AUTO_MOUNT_H zuluCrypt-6.2.0/zuluMount-gui/file.png000066400000000000000000000262151425361753700200140ustar00rootroot00000000000000‰PNG  IHDR  Ûph IDATxœíݰÝu}ïû÷gí½W6;;!!á‡`áG±U‹ŽUàzlmO½ÇžéÅÞétÎt˜‰GÇ£ÇqÚ‡±ÁQˆHñÎ=wZÇŸ\‹b=È©£ØâÔRG!?™@PEHB~²Ù{}ï WcöN¾ßÏg­ïz£UU}âæ›o ŠÆÿu檪ªX¿~ý›6lØð½ªªþ¥ªª·=üŠÎÏ#äŠÒCfC€ÐWÖ¯_ÿ¦7þ(¥t{D¼²ô€Ñ©ªêëÖ­!@ß ô…-[¶œ½qãÆ/ÿ<<.,½`u"B„}O€PTUU±iÓ¦wNOO?PUÕï•Þ0àDÐ÷ÅlذañÆ¿\UÕ‡"b¼ô€–èDÄ'nºé¦?*=àPElذá”ҿ¦”<ëP¿NJé“"èG„ì6lØðš”Ò?GÄ¥·´X'"DÐwYmÚ´éwSJÿ?û©å4«Ÿ¼ñÆEÐ7Ùlܸñ5UU}>¥4Qz À餔DÐ7Yüü5wŠ€"DÐ7Û´iÓINçΈXXz À뤔>¹nݺÿ\z0ܪª*"âo#â´ÂSøÙOLÿôG>ò#@hÔæÍ›ß¾Õ.@ÿ褔DPŒ¡16lXkKïàWtRJŸ¾ñÆE¡1###ë"¢[z‡Ô‰d'@hÄ–-[Þ¯/½€#!@v„ÚUUÕ©ªÊ—^ †NUU"ÈF€P»Í›7¿%"V”ÞÀ¬=ÿݱÞRzÐ~„ZUU)¥÷–ÞÀœu"â³"hš¡V>øà%ñë¥wpTDÐ8B­z½ÞŸ”ÞÀ1éD„/Ç#@¨ÍC=4žRò€0øFC„  Ôæ¹çžû½ˆXXzµõÂt  „Ú¤”þCé Ôj´ªªOøÃ!@muº¬ôj7"¨¡[·n=9"V•Þ@#DPB-z½ÞËKo Q¾ ¨…¡½^oeé 4N„ÇL€P‹”Ò¹¥7…މ¡.g—@6£UU}úCúÐÿVz0xuñó?†ËhJé³"˜+B]Àð!Àœ ê"@†ÓhDˆ`Öp¬F#ÂkB€Y @º!B€Y @]ºñén¸A„‡%@€:‰àˆP7–š B€C @Sºñé믿þM¥‡ýC€Mꦔ>+B€ç  i"xrèFÄgo¸áCN€¹t«ª!0ä“!'@€ÜºUU}öúë¯cé!@~(¡[UÕm"†J!0„PR·ªªÛ®»î:CB€¥uSJ"†„ú!!@€~ÑM)Ývíµ×þÇÒC€æ ŸtSJŸ!Ð^è7"ZL€ý¨›Rúü?øA-#@€~Õ­ªJ„@Ë Ÿu{½ž @¿!Ð"Ý^¯÷ùk¯½ö÷JŽE7"n!0Ø0Hºqû_ÿõ_‹P4ÝN§#B`@ `uSJ"•$@€AÖM)Ý~íµ×þné!Àì`Ðu«ªúâ>ð@€mÐM)‰h @€m"B Ï  mDô1´Q7¥ôŵk׊è3h«nUU"úŒÚ¬ÛëõDô´>"@€aÐíõz·‹(O€Ãb¼×ëÝ~Í5׈(H€Ãd<¥tû>ð×—ÃJ€Ãf¼ªª/Š(C€ÃH„@!V"  À0!™†ÝxUU_|ÿûß/B 1ÞétDd @~f¼Óé|ñšk®!Ð ðÿ  ¿L„@ƒÀ¯¯ªêvõ ‡6!B ~àðDÔL€ÙDUU·¿ÿýïÿíÒC  À‹›H)}Q„À± ³#B `ö&"â‹kÖ¬!p”ÀÜL¤”D%0w"Ž’8:Ï¿&äß—ƒD€½‰ªª¾$B`öÀ±!0àØ‰˜%P‰ªª¾´fÍG @ê3"Ž@€Ôk""¾ôWõW—•ýH€Ôo"¥ôe¿J€4C„À!€æˆ8ˆhÖDJéËkÖ¬¹¬ôè y½^O„@€\D„Èi¢×ë}ù/ÿò//)=J yM¤”î! +Ÿah €2&"âÎ÷½ï}"„¡"@Ê™èt:"„¡"@Ê! Pžah€þ0‘R!´žè"„Ö ýåùoÑûÚÒC   ÿLTUu—¡@!´’è_UUÝõÞ÷¾W„Р¿Mt:;Em!@úߤ¡-À`!´‚“?ÿ‰é"„%@ËdUU"„%@a` €Á$BH`p‰Žl"„"@ßdUUw¾÷½ï}Mé!ðb@;LFÄ]"„~'@ÚC„Ð÷4`ff&Çcl/Ã5<"„¾&@ Ýnwa†ËìÎp ÓdDxM}I€@fffrÈ“®ÁàZè…éô#ÍX”á3\ƒÁ¶°ªª;ßóž÷ˆú†€TUÕø3 UUýkÓ× ¦”D}C€@3NÊp¯d¸í BèR:¯ék\}õÕ÷§”lú:´†¡/h@UUfºÎÍ9®CkˆŠ Ѐ”R–û±#ǵh…!B(F€@3^òw÷wM_äÊ+¯Ü×4}Zgaüì焼ºô†€†ìß¿ÿµ9®366öш¸/ǵh•…½^ï.Bnšó†¹òÊ+§SJoˆgr\VYØëõîz×»Þ%BÈF€@s~7×…®ºêªñ¿GD/×5i…NG„€æ¬ºõÖ[ÏÎu±«¯¾úŽ”ÒŸçº­²°ÓéÜõîw¿[„Ð8 ªªêM9¯÷¶·½íãUUý—ðLs·0"D Р”Ò©ª*ë5W¯^ý?ªªúˆx2ë…iBã4ëüüã—å¾èêÕ«¿ZUÕ+"âå¾6oaDÜõ®w½ëâÒCh'Í»ªÄEßþö·?²zõê߉ˆ?‰ˆŸ”ØÀÀZØétþQ„ÐÍ{Óºuë–•ºøêÕ«ÿ."^oˆ‡Kí`à,L)‰j'@ y£Ýn÷ÿ,9`õêÕS«W¯¾iÇŽ/Ÿý|’ÏDÄ®’› SJÿøîw¿[„P›Tzí°eË–mqÆÁ/´<Ü /÷«Çõó6ÇÕ{\?o›Ëqý¶gŽ›îõzüÅ_üÅæCÞ €[o½uôÀ¯éõz¯ˆWEÄ…qFDŒFôÕû®µÇõó¶ƒÞ¾;¥ô>øÁ~÷ÂŒ–ÃfÿþýñðÃÇž={bß¾}133‡ÿà°RÇõËŽ~?îXnßï÷­ŸÞW³9ndd$&&&bþüù±xñâH©ø¿¹v:µñŸJyÞ•W^9ÿôóÿ""âsŸû\çñÇ_6==½("ÆSJ‹žÿ½Ã½~ûôôô¬®Ÿë|Ïœ«Ã¯×›Ýw8>øö‡:ßÑÞ·Ãm;ÚóÍæ}Ô‡h ’¨…g@^ü¸­[·Æ7¿ùÍxøá‡gýàÔ£ÛíÆé§Ÿçž{nÌ›7ïÇäúøPUÕoýùŸÿù·f5 …µ ‡?nÿþýñ÷ÿ÷±eË–CžÈgdd$.¸à‚xéK_ú+¿—ëãCJiã¾}û~ãï|ç³³Ð"^„ zòÉ'ããÿ¸ø€>133?üáã¾ûî;æ/;ZUU­š˜˜X[äâ}@€@CöíÛŸúÔ§bçÎ¥§Ù¶m[<ðÀ%'ü×[o½õ²’J Ð;î¸#vìØQzp[¶l‰íÛ·—œð·7ÝtÓI%” @ [·nM›6•ž¼ˆûï¿¿ä—b166öùÏ}îsÝ"  Ѐ{î¹§ô`öíÛ>úhÉ —<õÔSÿOɹ ¨Ùó?ç …¿ +"âŠ[n¹å¿—‹šmÛ¶ÍÏù€òÓŸþ´ô„ˆˆµó7ó¶Ò#r P³Ý»w—žÌÁÔÔÔQÿ¤ì:UUµîæ›o~WéM P³½{÷–žÌÑJOˆˆˆ”ÒõûØÇ|9ÐjjæË¯€c´ö–[n¹qÍš5£¥‡4A€@Ÿ©ªjõÉ'Ÿ|×­·Þêç„­#@ ?ýû™™™ïÝrË-¿^z@ô¯—TUõí}ìcï\³fÇl |0€þ6^UÕ‡–,YòÍuëÖ­*=àX  ¯ît:ÿzóÍ7ÿ÷5kÖtK8ZÇxD¬=餓¶|ô£ýc_– "¸`ðœŸ8餓þuݺu¿[z À\øã0¸.J)ÝùÑ~ô‡)¥u£££ŸºòÊ+Ÿ)= àH<ƒï¢ªªþ¯©©©¯[·îºo¼qEéA‡ãhÅñîN§óîuëÖý ªªÏÏÌÌü¿ïxÇ;6–ð<íôëñë###×ÜtÓMSJ_­ªê›UU}ëíoû#¥ÇÃK€@û­ªªjUD¼-¥7Þxãö”Ò·ªªÚ[ªªÚÚëõ|Ç;Þ±=¥Tz+Ðr†Ï²ªªÞò‹oèt:qã7N}ä#y&"vEijUU=;ž?¦ªªCž¬×ëÍê¢ß>×ùf{þ¦Ï7›ûu¸k͹ær¾Ã9è:O\ýõoÕ áð¼îÏÿ[4—ü¬Él?¹Íu¾c½}]ç;Ô³KužëXÎ7ËÛùÒ=já»`٨ټyóJOæ¨Óñp‹¸P³ÉÉÉÒ€9H)ù‡€ŒÔ줓N*=˜ƒùóçöë騟švÚi1þüÒ3€YZºtié CE€@ÍRJqÁ”žÌBJ)Î8ãŒÒ3†Š\rÉ%ÑívKÏ^IJeËâøã/=`¨hÀääd\~ùå¥gG0oÞ¼¸ð KÏ:òªW½*^þò——žB§Ó‰ßüÍߌ‰‰‰ÒS†ŽýÁüA¼æ5¯)=øÝn7~ë·~+–,YRz ÀP-=Ú,¥¯ýëãÌ3ÏŒ»îº+vìØQz ­”R,_¾<.¸àÏ|$@ ƒ•+WÆŠ+býúõ±qãÆx衇â™gž)= Z¯ÓéÄÄÄD,[¶,N;í´X´hQTUUzÀP I§Ó‰ /¼0.¼ð¨ª*¦§§cïÞ½/|2tð'E‡û$i¶Ç½Øíæz¾£=n¶{†i_¿ÿ?›ë'èý²çàãFFFb||\pô…ŒŽŽÆ¢E‹^øu¿|Bî¸æëçms9®ßö €ÁàEè@6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À°™™™‰íÛ·ÇîÝ»ãÙgŸ}áíUUÍêöw´·›ëqM_g˜îGîCÎëíqN'æÍ›“““1þüY€æ ÈäñÇo}ë[±yóæ8pà@é90T,X§vZ¬\¹2:Oþ”$@ aSSSqçwÆ~ðƒ9ÿË2P={öĆ bëÖ­qÑEÅi§VzÀÐ Р={öÄ'?ùÉxüñÇKO"âÀñ½ï}/ž~úé8ÿüó#¥TzÀÐñ<44djj*>ñ‰OˆèC›7oŽÍ›7—ž0”4äK_úR<ñÄ¥g‡±aÆøéOZzÀÐ ЀG}4î¿ÿþÒ3€#¨ª*~ô£•ž0t4àßø†œÃxúé§cûöí¥g 5›ššŠ­[·–žÌ’ÈK€@Í~øá˜žž.=˜%¯ÕÈK€@ÍvïÞ]z0ˆ^¯WzÀÐ P³={ö”žÌÑJOj633Sz0G¾i@>ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² P³±±±Ò€9)=`h¨Ù‚ JOæ¨Ûí–ž04ÔlñâÅ¥'s011)¥Ò3††šqÆ1oÞ¼Ò3€Y:õÔSKO*jÖétâ‚ .(=˜¥åË——ž0T4à’K.‰ÑÑÑÒ3€±téÒ8ñÄKÏ*°hÑ¢xík_[zp£££qá…–ž0t4äÒK/U«V•žBJ)^ùÊWú®uhHJ)Þò–·ÄË^ö²ÒS€_022_|±Ÿâ‹Ô¡A£££ñæ7¿9N?ýôøú׿ûöí+= †Ú’%K⢋.Š… –ž0´dðŠW¼"~í×~-î»ï¾Ø´iSlÛ¶-ªª*= †B·ÛSO=5N;í´8å”SüÝ(L€@&Ýn7^ýêWÇ«_ýꘞžŽ½{÷ñ‘Ã}’tðÛg{Ül¯s¬×í÷£¾sõÓ}(yƒÝétb||ÜO9è3 ‰ã?>Ž?þøÞV÷'ŸŽëßãúyÛ\Žë·=Ç4äáEè@6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À0Ú¹sgìÙ³'öíÛUUò˜¹¾ýÅŽ;ÚÛ¹ný×mË}=ÖÛ»n\sX¯;66ccc1>>>«Ûõ ÉÓO?÷Þ{olذ!víÚUz1>>'œpB,]º4ÆÆÆJÏ¡ @ a½^/¾öµ¯Åw¾ó˜žž.=€_ðì³ÏÆc=ÿöoÿ§žzj,[¶,RJ¥gA« hÐþýûã¶Ûn‹­[·–žÀôz½xôÑGcÏž=±bÅŠõ)4ŋС!333ñ™Ï|F| Ý»wÇ–-[fýz`î4äÎ;ïŒmÛ¶•žÀíÙ³'yä‘Ò3 µ4à‰'žˆù—)=€£ôÄOÄþýûKÏ€V Ѐ»ï¾ÛÓ÷¬ªªØ¾}{éÐJj6==[¶l)=€c´k×®èõz¥g@ë¨ÙÃ?Ï=÷\é£^¯{÷î-=ZG€@Íž~úéÒ¨ÉJO€Ö P³={ö”ž@M¦¦¦JO€Ö P3?í =|C¨Ÿ² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€lÔltt´ôj’R*=ZG€@Í,XPz5év»¥'@ë¨Ù¢E‹JO &óæÍ+=ZG€@ÍÎ<óLÿbÐN'&''KÏ€Ö P³ÑÑÑX¹reé£N8!:Ÿ*AÝü­‚\z饴XJ)–-[Vz´’Ï K–,‰W½êU¥gp”N9å”/=ZI€@C~û·;Î:ë¬Ò3˜£… Æé§Ÿ^z´–†ŒŒŒÄýÑÅŠ+JO`–-ZçœsŽŸÿ  РyóæÅ[ßúÖ¸ì²Ë|g,€>ÖétbùòåqÎ9çÄÈÈHé9Ðj~d34,¥—^zi¼â¯ˆ{ï½76lØO=õTéYDÄqÇ'œpB,]º4FG}Z9ø›™LNNÆå—_—_~yìÞ½;ž~ú騷o_ÌÌÌòøªªæôö;îhoçºõ_·-÷õXoïºýqÍa¼nÄϾeúøøxŒÕí£'@ € Ä‚ ~ém³} uÜà×ÏÛær\¿íÄãúyÛ0äá5 @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À0šššŠ={öľ}ûbff&""ªªú¥cþõáÏ7ÛÛ;ßìÏ=¨š|_Íåºm8ß þùî÷óÊØØXŒÅÈÈȬoÔC€@&Ï>ûlÜwß}±~ýúؾ}ûœ(hÆääd,^¼8N>ùäèt|aä @ aUUŽ÷ÞßøÆ7bÿþý¥çð öîÝ{÷îíÛ·ÇòåËãä“OŽ”RéYÐj4==·ß~{<ðÀ¥§pÓÓÓ±mÛ¶Ø»woœuÖYž  hHUUqÛm·Å¦M›JO`–žz꩘™™‰sÎ9§ôh-y ¹ûî»ÅÀÚµkWlß¾½ô h- عsgÜsÏ=¥gp”{ì±8pà@éÐJp÷Ýw¿ðíu<½^ϳ Ð5›žžŽ7–žÀ1Ú¹s§o™  P³ÿøÇž¶h™™™Ø»woéÐ:j¶sçÎÒ¨‰P‚ú ¨Ùž={JO &SSS¥'@ë¨ÙsÏ=Wz5éõz¥'@ë d#@€l² @6ÈF€Ù d#@€l² @6ÈF€@ÍFGGKO &ŽO• nþVAÍ&''KO &þQ ê'@ fÇ|é ÔdÞ¼y¥'@ë¨Ù™gžé_ÌZ ÓéÄ‚ JÏ€Ö P³n·+V¬(=€ctüñÇ{ 4Àß*hÀ%—\)¥Ò38Ë–-+=ZI€@–-[/{ÙËJÏà(-Y²$&&&JÏ€V Ðßÿýß÷¯ghþüùqæ™g–ž­%@ Ä.n\ HIDAT!cccqÅWÄòåËKO`–&''cåÊ•^û ò· 499ú§_|±3€>–RŠSN9%V­Zccc¥ç@«ù^¡Ð°ÑÑÑxÃÞ¯|å+ãÛßþvlÚ´)žyæ™Ò³ˆŸ}Œ>á„âÔSOñññÒs`(ÈdÉ’%ñÆ7¾1ªªŠíÛ·ÇÞ½{cïÞ½/ü~UU³:ÏÁÇííæz\Óצûцûó:myËŸAºG:®ŸîÇØØXt»Ý˜˜˜xá»ÎõÏ>ptd–R:ä‹Ógû@ê¸Á?®Ÿ·Íå¸~Û3ˆÇõó¶a<ÈÃ¥Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€ÙŒ–ÃêÀñÌ3ϼð몪~é÷þõ\{±Û5uÝ£Ý3LûúýÿÙl÷õÛž~ê¸6þù”}ccc1222«=@½d233?úÑbãÆñÐCÅÔÔTéICmdd$.\‹/ŽO<±ô2xàâ«_ýjìÚµ«ô~nff&vîÜ;wüä'qúé§ÇâÅ‹KÏ‚Ö Р^¯_ùÊWâ»ßýné)ÁâÁŒ¥K—Æé§Ÿ)¥Ò“ µ4è _øBüð‡?,=€YzüñÇczz:Î>ûìÒS µ|,hÈ·¿ýmñ0€ž|òÉxì±ÇJÏ€Ö ЀݻwÇ×¾öµÒ38J>úh<÷Üs¥g@+ hÀ?ÿó?{à`½^/¶oß^z´’šUU÷ßé£;vÌùçâ/N€@Íy䑨¿é£éé騷o_éÐ:j¶cǎҨɳÏ>[z´ŽšíÞ½»ôj255Uz´Žšyñ9@{ôz½Ò u² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@ fŽ¿Vm‘R*=ZÇgJP³ÉÉÉ񬃯ØXé Ð:j¶páÂÒ¨I·Û-=ZG€@Í^ò’—ø2,€H)Å‚ JÏ€ÖñYÔl||<Î>ûìÒ38F .Œ‘‘‘Ò3 u4àu¯{]é £SO=µôh% 8óÌ3cÕªU¥gp”/^ì˯ !òæ7¿9N<ñÄÒ3˜£ñññ8묳JÏ€Ö ÐyóæÅÿñ‹€rÜqÇŹçžëµÐ  :á„âÏþìÏâüóÏ/=€±xñâ8ÿüócÞ¼y¥§@«–m7>>ø‡<òHÜsÏ=ñÐCÅôôtéYDD§Ó‰… ÆòåËcþüù¥çÀP ÉgœW\qELMMŶmÛb÷îݱgÏžb¤ªªY§Ôqý²£ß;–Û÷û}ë§÷U[Žó÷¯ÌŸ©”Rt»Ý˜7o^LNN¾ðåVÇz`vdÖívcÅŠ¿òöƒø÷@è¸Á?®Ÿ·Íå¸~Û3ˆÇõó¶a<ÈÃk@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l`6z¥Ð„ºì.=hÔÞÒhB]´›Çzj!@¨‹JÐb)¥]¥7Єºl-=hN¯×óXO-µH)m(½hŽÇzê"@¨Ëƒ¥ÍI)m.½v Ô¢ÓéÜWzМ^¯÷ÃÒhB-Î>ûì'"b}é@#î¿á†ž(=‚v ÔéîÒ€FÜ]zí!@¨MJéKoêç1ž: j322ò•ðó@ mvíß¿ÿ+¥GЄڜuÖYϦ”>WzP«Ï­[·nªôÚC€P·O”Ô§×ë}²ôÚE€P«+VüSDü ô ÷}èCú§Ò#hB­RJ‘Rú@é@-<¦S;BíV¬Xñ÷~Z* ¶ªª6Ο?ÿ ¥wÐ>„Ú¥”z½^ï=¥wG¯Óé¼gÍš5½Ò;hB#Î=÷Ü/TUå[öÀ`úŸ×]wÝ¥GÐN„ÆŒŽŽ^¾m –g;ÎÛK ½yéK_ú`UU¾ HUUÿíÚk¯}°ôÚK€Ð¨sÏ=÷#UUýCéÀ‹«ªêŽë¯¿þ£¥wÐn„F¥”¢ªª?‰ˆŸ”ÞÑ####Rzí'@hÜyç·£×ë½!"v•ÞÒ“###¿síµ×z¬¦q„,Î;ï¼ûSJ¿SUÕ3¥·¿ä™^¯÷ûk×®ÝXzÃA€ÍÊ•+¿ÿI„@ßx&"Þ|à 7|·ô†‡!«U«V}eddäòˆØQz ¹Nçß]wÝuÿ«ô†‹!»sÎ9ç;333¯‹ˆ‡Ko€!õp§ÓyÝÚµk=óAv„".¸à‚õóæÍûˆøBé-0d¾pàÀßX»víúÒCN£¥0¼Î:ë¬]UU½yÓ¦Mÿ5"ÖFÄxéMÐbÏTUõß®»îº•Âpó E¥”bÕªUI)~`!4㎑‘‘óÄýÀ3 ô…U«V=°aÆÿˆˆ‹Ê.€VøAJé}k×®ýŸ¥‡Àó}å¼óÎû‡ªªþaÓ¦Moìõz‹Ko€ASUÕw:Î5ƒ~$@è;)¥ˆˆ;"âŽõë׿<"þ”ÒUU\vô¯”Òã½^ï3Nço×®]ûƒÒ{àpRé0_ÿú×G—.]úÚªª.¯ªê²ˆxuüB@WUõKÇüëA8®Ÿ·9®ÞãúyÛ\Žë·=ƒx\?osÜ@ü˜ŠˆïFÄ×:Î×7mÚôO·Ýv[ï'€>"@H?þñÇŸ~úé•)¥•)¥U½^ïô”Ò¢^¯7Ïÿ÷+Žõ­ƒõz¿üqþX¬Žt«îáÎ?×ó ÓýhÃ}(yA|µá>ê:îÇìÎ?Ësí}þ¿^¯·+"¶¥”6OOOožššÚüáøÙY]ø¹ÿ‘iEtÄ\oIEND®B`‚zuluCrypt-6.2.0/zuluMount-gui/folder.png000066400000000000000000000026611425361753700203470ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÛNµ_¨1IDATXÃí—Ïk]EÇ?gî¼—ˆØÖj‰ZDP©]tç?P…ºRZ ºwãÎU…"è¿!‚ÐMb©+©ˆX¤Õ*T[±5©Mš&yMò’wï9.æÌ½“ÔBJ7<îܹgΜßó=óàA×Ož½oÙãœý×Ï€c'ϜߪëÃBE§Dç˜òþÒ©Gþ'y÷}óøQWjBP"P ÂÔ@ˆÍ˜¯¾¹¨UU‰J2.š*¶¿Ë޹ÁäPm·^þü£×¾ôõæ~[ei´‰“»•Ìîâà ‡Ä;A%§ˆ ¶&"xg~ÙšC•¥! zî»ß’m=aqiÄÊ­9šÓá…7¯¢§p&£9”’Þs$ý74ÀÀ9föìgßÞYZ˜àª¿^ú–S'޲6£;ÜOc±gç{3ÓÓ{ÿ3vz‘;+‹±3@cdme‰ž`åömÁ‰$e"æ¡ôór¨êÝsUË»²{ÏnÍ]á‘Ù§i&ãag@]×´Í$…«ª‘ýâ™Ç°rXaô‡™× hÔnU5¥í º~õ¦fö±±º:é ¯¯²1Zî¼Ûf@ŽPUŽsn2i•;ã¶Gj1œ-–XÈ#²ÉgNc ª¾²:zï¼X^^fþËL \:TA \ Ék“Èh½áÊõ QïÆ‰ì(¿ˆAaŽÎѹ«û·><}ícG´ A>ýþ/î‘^¨eme‹J”Ö”– ,KW‹ºÏß­:@+ÇúÚ¿¾Ñ¸ðÓmh·E4WB´<µÀ!ºD$ˆŠ˜rMPq$O½¤=¢%4÷KT¼Ú¢éJ§Õ¾®‘ôî$Õ?±ÿ¦@Œ=FÛH™F“.1™@¸­æ(Úb´_“Ç-¬–Ä`qUûŘtF­!ö!&£y«}”bLº+Óã£ÁµQí€SG¨\oD´ÐF‹L£=ÈÛ?p6·h`hºÄšZcÞéPð´Q;ϰÃZ³ÞYó º=ô¹@ :6=M®‚˜dÅR< à½T´7çÒæÖÚqe¥–1 6@\’i ô‹å:{œó-†f5e£TI :eK!S`!Ĩè•ù*ÉÅB“©ÍC1YçÒ<#"3>ÉF@ñªJÛ&ªT+¹Æ„Z`h¢f”´ý|@oD›ï95a{)çõ\Ò¢àªÊ!xÌP¦ ÅRpB&_qXNø6ЧÉO5š÷?\]àç_“{ȽZ©ì ') ’äURñN†ìä6–ðOîfÏ£³±ÇÍ%3WV,]—Ýæu>´²”Y é2§¦»À8Çb=AÙª[4Ä´¡ô¸è³*‰<2—%Ø5í7‹öÏVB®,@ÄÑ„€î©Ç8øì󨶵­)òµÂ@ŠÍ™óͨ Eº¬ÖKÙÜ5cQž-à]Åï­áoÞ^gvu“ZÛ®L|qï‹…c¾h@ª=º³ÌÀ*¨+M»àíï_^*nÜZÅG„ñdÌ–ö*I–Ob|«óÊÁ8¦Ã2˜R9Ázì˜ Þ*"ä,WÞÁ¦Ýgü°ró«K£Ç¥r‰±†ŒZ' %Ñr¦\j:¢ Æý»†°Y[ZÄ6}“Ÿ„Dtm4FÌýC3»÷_LÑzø™·qnphL×!UIª0<«Cq¶&DŠ ."– ‘€QE$µ'1]EqD¢ŽY¹ü1¼ôÿ˜¾Êÿƒ¿½%å¤ÙTbIEND®B`‚zuluCrypt-6.2.0/zuluMount-gui/icon.qrc000066400000000000000000000004571425361753700200260ustar00rootroot00000000000000 zuluCrypt.png zuluMount.png passphrase.png keyfile.png module.png folder.png file.png partition.png zuluCrypt-6.2.0/zuluMount-gui/keydialog.cpp000066400000000000000000000646541425361753700210540ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "keydialog.h" #include "ui_keydialog.h" #include #include #include #include #include #include #include "bin_path.h" #include "../zuluCrypt-gui/dialogmsg.h" #include "task.hpp" #include "../zuluCrypt-cli/constants.h" #include "plugin_path.h" #include "../zuluCrypt-gui/utility.h" #include "lxqt_wallet.h" #include "zulumounttask.h" #include "zulumounttask.h" #include "siritask.h" #include "veracryptpimdialog.h" #include "../zuluCrypt-gui/favorites2.h" #include "../zuluCrypt-gui/tcrypt.h" keyDialog::keyDialog( QWidget * parent, QTableWidget * table, secrets& s, const volumeProperty& e, std::function< void() > p, std::function< void( const QString& ) > q ) : QDialog( parent ), m_ui( new Ui::keyDialog ), m_secrets( s ), m_cancel( std::move( p ) ), m_success( std::move( q ) ) { m_ui->setupUi( this ) ; m_label.setOptions( m_ui->veraCryptWarning,m_ui->pushButton ) ; m_ui->lineEditKey->setMaxLength( 32767 ) ; m_ui->checkBoxShareMountPoint->setToolTip( utility::shareMountPointToolTip() ) ; m_table = table ; m_path = e.volumeName() ; m_working = false ; m_encryptedFolder = e.fileSystem() == "cryptfs" ; QString msg ; if( e.fileSystem() == "crypto_LUKS" ){ msg = tr( "Mount A LUKS volume in \"%1\"").arg( m_path ) ; }else{ msg = tr( "Mount An Encrypted Volume In \"%1\"").arg( m_path ) ; } m_ui->checkBoxVisibleKey->setToolTip( tr( "Check This Box To Make Password Visible" ) ) ; m_ui->checkBoxShareMountPoint->setChecked( utility::mountWithSharedMountPoint() ) ; this->setWindowTitle( msg ) ; m_ui->lineEditMountPoint->setText( m_path ) ; m_ui->pbOpenMountPoint->setIcon( QIcon( ":/folder.png" ) ) ; m_menu = new QMenu( this ) ; connect( m_menu,SIGNAL( triggered( QAction * ) ),this,SLOT( pbPluginEntryClicked( QAction * ) ) ) ; this->setFixedSize( this->size() ) ; this->setWindowFlags( Qt::Window | Qt::Dialog ) ; this->setFont( parent->font() ) ; m_ui->lineEditKey->setFocus() ; m_ui->checkBoxOpenReadOnly->setChecked( utility::getOpenVolumeReadOnlyOption( "zuluMount-gui" ) ) ; m_ui->pbkeyOption->setEnabled( false ) ; m_ui->lineEditKey->setEchoMode( QLineEdit::Password ) ; m_veraCryptVolumeType.setValues( m_ui->checkBoxVeraCryptVolume, m_ui->checkBoxVeraCryptSystemVolume, utility::autoSetVolumeAsVeraCrypt() ) ; if( m_encryptedFolder ){ m_ui->checkBoxVeraCryptVolume->setEnabled( false ) ; m_ui->checkBoxVeraCryptSystemVolume->setEnabled( false ) ; m_ui->lineEditPIM->setEnabled( false ) ; m_ui->labelVeraCryptPIM->setEnabled( false ) ; } connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->pbOpen,SIGNAL( clicked() ),this,SLOT( openVolume() ) ) ; connect( m_ui->pbkeyOption,SIGNAL( clicked() ),this,SLOT( pbkeyOption() ) ) ; connect( m_ui->pbOpenMountPoint,SIGNAL( clicked() ),this,SLOT( pbMountPointPath() ) ) ; connect( m_ui->checkBoxOpenReadOnly,SIGNAL( stateChanged( int ) ),this,SLOT( cbMountReadOnlyStateChanged( int ) ) ) ; connect( m_ui->cbKeyType,SIGNAL( currentIndexChanged( int ) ),this,SLOT( cbActicated( int ) ) ) ; connect( m_ui->checkBoxVisibleKey,SIGNAL( stateChanged( int ) ),this,SLOT( cbVisibleKeyStateChanged( int ) ) ) ; m_ui->pbOpenMountPoint->setVisible( false ) ; connect( m_ui->checkBoxShareMountPoint,&QCheckBox::stateChanged,[]( int s ){ utility::mountWithSharedMountPoint( s == Qt::Checked ) ; } ) ; const auto& m = e.mountPoint() ; if( m.isEmpty() || m == "Nil" ){ m_point = utility::mountPathPostFix( m_path.split( "/" ).last() ) ; }else{ m_point = utility::mountPathPostFix( m ) ; } m_ui->lineEditMountPoint->setText( m_point ) ; m_ui->pbOptions->setEnabled( !m_encryptedFolder ) ; m_ui->frame->setVisible( false ) ; connect( m_ui->pbOptions,&QPushButton::clicked,[ this ](){ m_ui->lineEditVolumeOffset->setText( m_deviceOffSet ) ; m_ui->lineEditFsOptions->setText( utility::fileSystemOptions( m_path ) ) ; m_ui->frame->setVisible( true ) ; } ) ; connect( m_ui->pbSet,&QPushButton::clicked,[ this ](){ m_ui->frame->setVisible( false ) ; auto e = m_ui->lineEditVolumeOffset->text() ; if( !e.isEmpty() ){ m_deviceOffSet = QString( " -o %1" ).arg( e ) ; } m_options = m_ui->lineEditFsOptions->text() ; } ) ; connect( m_ui->pbCancelOptions,&QPushButton::clicked,[ this ](){ m_ui->frame->setVisible( false ) ; } ) ; m_ui->cbKeyType->addItem( tr( "Key" ) ) ; m_ui->cbKeyType->addItem( tr( "KeyFile" ) ) ; m_ui->cbKeyType->addItem( tr( "Key+KeyFile" ) ) ; m_ui->cbKeyType->addItem( tr( "Plugin" ) ) ; if( m_encryptedFolder ){ m_ui->checkBoxShareMountPoint->setEnabled( false ) ; }else{ m_ui->cbKeyType->addItem( tr( "TrueCrypt/VeraCrypt Keys" ) ) ; } m_ui->cbKeyType->addItem( tr( "YubiKey Challenge/Response" ) ) ; m_veraCryptWarning.setWarningLabel( m_ui->veraCryptWarning ) ; m_ui->pbkeyOption->setVisible( false ) ; m_ui->checkBoxVisibleKey->setVisible( true ) ; this->installEventFilter( this ) ; } bool keyDialog::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->pbCancel() ; } ) ; } void keyDialog::cbMountReadOnlyStateChanged( int state ) { m_ui->checkBoxOpenReadOnly->setEnabled( false ) ; m_ui->checkBoxOpenReadOnly->setChecked( utility::setOpenVolumeReadOnly( this,state == Qt::Checked,QString( "zuluMount-gui" ) ) ) ; m_ui->checkBoxOpenReadOnly->setEnabled( true ) ; if( m_ui->lineEditKey->text().isEmpty() ){ m_ui->lineEditKey->setFocus() ; }else if( m_ui->lineEditMountPoint->text().isEmpty() ){ m_ui->lineEditMountPoint->setFocus() ; }else{ m_ui->pbOpen->setFocus() ; } } void keyDialog::pbMountPointPath() { auto msg = tr( "Select A Folder To Create A Mount Point In" ) ; auto Z = QFileDialog::getExistingDirectory( this,msg,utility::homePath(),QFileDialog::ShowDirsOnly ) ; if( !Z.isEmpty() ){ while( true ){ if( Z.endsWith( '/' ) ){ Z.truncate( Z.length() - 1 ) ; }else{ break ; } } Z = Z + "/" + m_ui->lineEditMountPoint->text().split( "/" ).last() ; m_ui->lineEditMountPoint->setText( Z ) ; } } void keyDialog::cbVisibleKeyStateChanged( int s ) { auto m = m_ui->cbKeyType->currentIndex() ; if( m == keyDialog::Key || m == keyDialog::yubikey ){ if( s == Qt::Checked ){ m_ui->lineEditKey->setEchoMode( QLineEdit::Normal ) ; }else{ m_ui->lineEditKey->setEchoMode( QLineEdit::Password ) ; } m_ui->lineEditKey->setFocus() ; } } void keyDialog::enableAll() { auto m = m_ui->cbKeyType->currentIndex() ; m_ui->checkBoxVisibleKey->setEnabled( m == keyDialog::Key || m == keyDialog::yubikey ) ; m_ui->checkBoxVeraCryptVolume->setEnabled( true ) ; m_ui->pbOptions->setEnabled( !m_encryptedFolder ) ; m_ui->label_2->setEnabled( true ) ; m_ui->lineEditMountPoint->setEnabled( true ) ; m_ui->pbOpenMountPoint->setEnabled( true ) ; m_ui->pbCancel->setEnabled( true ) ; m_ui->pbOpen->setEnabled( true ) ; m_ui->label->setEnabled( true ) ; m_ui->cbKeyType->setEnabled( true ) ; auto index = m_ui->cbKeyType->currentIndex() ; m_ui->lineEditKey->setEnabled( index == keyDialog::Key || index == keyDialog::yubikey ) ; m_ui->pbkeyOption->setEnabled( index == keyDialog::Key || index == keyDialog::yubikey || index == keyDialog::keyfile ) ; m_ui->checkBoxOpenReadOnly->setEnabled( true ) ; m_ui->checkBoxShareMountPoint->setEnabled( !m_encryptedFolder ) ; m_ui->checkBoxVeraCryptVolume->setEnabled( true ) ; m_ui->checkBoxVeraCryptSystemVolume->setEnabled( true ) ; m_ui->lineEditPIM->setEnabled( true ) ; m_ui->labelVeraCryptPIM->setEnabled( true ) ; } void keyDialog::disableAll() { m_ui->checkBoxVisibleKey->setEnabled( false ) ; m_ui->checkBoxVeraCryptVolume->setEnabled( false ) ; m_ui->cbKeyType->setEnabled( false ) ; m_ui->pbOptions->setEnabled( false ) ; m_ui->pbkeyOption->setEnabled( false ) ; m_ui->label_2->setEnabled( false ) ; m_ui->lineEditMountPoint->setEnabled( false ) ; m_ui->pbOpenMountPoint->setEnabled( false ) ; m_ui->lineEditKey->setEnabled( false ) ; m_ui->pbCancel->setEnabled( false ) ; m_ui->pbOpen->setEnabled( false ) ; m_ui->label->setEnabled( false ) ; m_ui->checkBoxOpenReadOnly->setEnabled( false ) ; m_ui->checkBoxShareMountPoint->setEnabled( false ) ; m_ui->checkBoxVeraCryptVolume->setEnabled( false ) ; m_ui->checkBoxVeraCryptSystemVolume->setEnabled( false ) ; m_ui->lineEditPIM->setEnabled( false ) ; m_ui->labelVeraCryptPIM->setEnabled( false ) ; } void keyDialog::KeyFile() { if( m_ui->cbKeyType->currentIndex() == keyDialog::keyfile ){ auto msg = tr( "Select A File To Be Used As A Keyfile" ) ; auto Z = QFileDialog::getOpenFileName( this,msg,utility::homePath() ) ; if( !Z.isEmpty() ){ m_ui->lineEditKey->setText( Z ) ; } } } void keyDialog::pbkeyOption() { auto keyType = m_ui->cbKeyType->currentIndex() ; if( keyType == keyDialog::plugin ){ this->Plugin() ; }else if( keyType == keyDialog::keyfile ){ this->KeyFile() ; } } void keyDialog::Plugin() { m_menu->clear() ; utility::addPluginsToMenu( *m_menu ) ; m_menu->setFont( this->font() ) ; m_menu->addSeparator() ; m_menu->addAction( tr( "Cancel" ) )->setObjectName( "Cancel" ) ; m_menu->exec( QCursor::pos() ) ; } void keyDialog::pbPluginEntryClicked( QAction * e ) { auto m = e->objectName() ; utility::setDefaultPlugin( m ) ; auto r = e->text() ; r.remove( "&" ) ; if( m != "Cancel" ){ m_ui->lineEditKey->setText( r ) ; } } void keyDialog::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbCancel() ; } void keyDialog::encryptedFolderMount() { if( m_key.isEmpty() ){ m_label.show( tr( "Atleast one required field is empty" ) ) ; return this->enableAll() ; } auto m = utility::mountPath( utility::mountPathPostFix( m_ui->lineEditMountPoint->text() ) ) ; auto ro = m_ui->checkBoxOpenReadOnly->isChecked() ; auto e = siritask::encryptedFolderMount( { m_path,m,m_key,QString(),QString(), QString(),ro,m_success } ).await() ; switch( e.status() ){ case siritask::status::success : return this->HideUI() ; case siritask::status::cryfs : m_label.show( tr( "Failed to unlock a cryfs volume.\nWrong password entered" ) ) ; break; case siritask::status::encfs : m_label.show( tr( "Failed to unlock an encfs volume.\nWrong password entered" ) ) ; break; case siritask::status::gocryptfs : m_label.show( tr( "Failed to unlock a gocryptfs volume.\nWrong password entered" ) ) ; break; case siritask::status::ecryptfs : m_label.show( tr( "Failed to unlock an ecryptfs volume.\nWrong password entered" ) ) ; break; case siritask::status::ecryptfsIllegalPath : m_label.show( tr( "A Space Character Is Not Allowed In Paths When Using Ecryptfs Backend And Polkit" ) ) ; break; case siritask::status::securefs : m_label.show( tr( "Failed to unlock a securefs volume.\nWrong password entered" ) ) ; break; case siritask::status::cryfsNotFound : m_label.show( tr( "Failed to unlock a cryfs volume.\ncryfs executable could not be found" ) ) ; break; case siritask::status::securefsNotFound : m_label.show( tr( "Failed to unlock a securefs volume.\nsecurefs executable could not be found" ) ) ; break; case siritask::status::gocryptfsNotFound : m_label.show( tr( "Failed to unlock a gocryptfs volume.\ngocryptfs executable could not be found" ) ) ; break; case siritask::status::encfsNotFound : m_label.show( tr( "Failed to unlock an encfs volume.\nencfs executable could not be found" ) ) ; break; case siritask::status::ecryptfs_simpleNotFound : m_label.show( tr( "Failed to unlock an ecryptfs volume.\necryptfs-simple executable could not be found" ) ) ; break; case siritask::status::failedToCreateMountPoint : m_label.show( tr( "Failed to create mount point" ) ) ; break; case siritask::status::unknown : m_label.show( tr( "Failed to unlock the volume.\nNot supported volume encountered" ) ) ; break; case siritask::status::ecrypfsBadExePermissions : m_label.show( tr( "This backend requires root's privileges and an attempt to acquire them has failed." ) ) ; break; case siritask::status::cryfsMigrateFileSystem : m_label.show( tr( "zuluMount Can Not Unlock This Volume Because Its FileSystem Has To Manually Be Converted To The Version Of Cryfs That Is Currently In Use.\n\nRun Cryfs With This Volume To Manually Update This Volume's FileSystem." ) ) ; break; case siritask::status::backendFail : default: m_label.show( e.msg() ) ; break; } auto mm = m_ui->cbKeyType->currentIndex() ; if( mm == keyDialog::Key || mm == keyDialog::yubikey ){ m_ui->lineEditKey->clear() ; } m_ui->lineEditKey->setFocus() ; this->enableAll() ; } bool keyDialog::errorNotFound( int r ) { DialogMsg msg( this ) ; switch ( r ){ case 0 : break ; case 1 : m_label.show( tr( "Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed?" ) ) ; break ; case 2 : m_label.show( tr( "There seem to be an open volume accociated with given address" ) ) ; break ; case 3 : m_label.show( tr( "No file or device exist on given path" ) ) ; break ; case 4 : m_label.show( tr( "Volume could not be opened with the presented key" ) ) ; break ; case 5 : m_label.show( tr( "Insufficient privilege to mount the device with given options" ) ) ; break ; case 6 : m_label.show( tr( "Insufficient privilege to open device in read write mode or device does not exist" ) ) ; break ; case 7 : m_label.show( tr( "Only root user can perform this operation" ) ) ; break ; case 8 : m_label.show( tr( "-O and -m options can not be used together" ) ) ; break ; case 9 : m_label.show( tr( "Could not create mount point, invalid path or path already taken" ) ) ; break ; case 10: m_label.show( tr( "Shared mount point path aleady taken" ) ) ; break ; case 11: m_label.show( tr( "There seem to be an opened mapper associated with the device" ) ) ; break ; case 12: m_label.show( tr( "Could not get a passphrase from the module" ) ) ; break ; case 13: m_label.show( tr( "Could not get passphrase in silent mode" ) ) ; break ; case 14: m_label.show( tr( "Insufficient memory to hold passphrase" ) ) ; break ; case 15: m_label.show( tr( "One or more required argument(s) for this operation is missing" ) ) ; break ; case 16: m_label.show( tr( "Invalid path to key file" ) ) ; break ; case 17: m_label.show( tr( "Could not get enought memory to hold the key file" ) ) ; break ; case 18: m_label.show( tr( "Insufficient privilege to open key file for reading" ) ) ; break ; case 19: m_label.show( tr( "Could not get a passphrase through a local socket" ) ) ; break ; case 20: m_label.show( tr( "Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered" ) ) ; break ; case 21: m_label.show( tr( "Could not create a lock on /etc/mtab" ) ) ; break ; case 22: m_label.show( tr( "Insufficient privilege to open a system volume.\n\nConsult menu->help->permission for more informaion\n" ) ) ; break ; case 113:m_label.show( tr( "A non supported device encountered,device is missing or permission denied\n\ Possible reasons for getting the error are:\n1.Device path is invalid.\n2.The device has LVM or MDRAID signature" ) ) ; break ; default: return true ; } return false ; } void keyDialog::openVolume() { this->disableAll() ; auto keyType = m_ui->cbKeyType->currentIndex() ; if( m_encryptedFolder ){ if( keyType == keyDialog::Key ){ m_key = m_ui->lineEditKey->text().toLatin1() ; }else if( keyType == keyDialog::keyfile ){ QFile f( m_ui->lineEditKey->text() ) ; f.open( QIODevice::ReadOnly ) ; m_key = f.readAll() ; }else if( keyType == keyDialog::keyKeyFile ){ if( utility::pluginKey( m_secrets.parent(),&m_key,"hmac" ) ){ return this->enableAll() ; } }else if( keyType == keyDialog::plugin ){ /* * m_key is already set */ }else if( keyType + 1 == keyDialog::yubikey ){ utility::debug() << "ssss" ; auto s = utility::yubiKey( m_ui->lineEditKey->text() ) ; if( s.has_value() ){ m_key = s.value() ; }else{ m_label.show( tr( "Failed To Locate Or Run Yubikey's \"ykchalresp\" Program." ) ) ; return this->enableAll() ; } } return this->encryptedFolderMount() ; } if( m_ui->lineEditKey->text().isEmpty() ){ if( keyType == keyDialog::plugin ){ m_label.show( tr( "Plug in name field is empty" ) ) ; m_ui->lineEditKey->setFocus() ; return this->enableAll() ; }else if( keyType == keyDialog::keyfile ){ m_label.show( tr( "Keyfile field is empty" ) ) ; m_ui->lineEditKey->setFocus() ; return this->enableAll() ; } } auto test_name = m_ui->lineEditMountPoint->text() ; if( test_name.contains( "/" ) ){ m_label.show( tr( "\"/\" character is not allowed in the mount name field" ) ) ; m_ui->lineEditKey->setFocus() ; return this->enableAll() ; } QString m ; if( keyType == keyDialog::yubikey ){ auto s = utility::yubiKey( m_ui->lineEditKey->text() ) ; if( s.has_value() ){ auto addr = utility::keyPath() ; m = QString( "-f %1" ).arg( addr ) ; utility::keySend( addr,s.value() ) ; }else{ m_label.show( tr( "Failed To Locate Or Run Yubikey's \"ykchalresp\" Program." ) ) ; return this->enableAll() ; } }else if( keyType == keyDialog::Key ){ auto addr = utility::keyPath() ; m = QString( "-f %1" ).arg( addr ) ; utility::keySend( addr,m_ui->lineEditKey->text() ) ; }else if( keyType == keyDialog::keyKeyFile ){ if( utility::pluginKey( m_secrets.parent(),&m_key,"hmac" ) ){ return this->enableAll() ; } auto addr = utility::keyPath() ; m = QString( "-f %1" ).arg( addr ) ; utility::keySend( addr,m_key ) ; }else if( keyType == keyDialog::keyfile ){ auto e = m_ui->lineEditKey->text().replace( "\"","\"\"\"" ) ; m = "-f \"" + utility::resolvePath( e ) + "\"" ; }else if( keyType == keyDialog::plugin ){ auto r = m_ui->lineEditKey->text() ; if( r == "hmac" || r == "gpg" || r == "keykeyfile" ){ if( utility::pluginKey( m_secrets.parent(),&m_key,r ) ){ return this->enableAll() ; } } if( m_key.isEmpty() ){ m = "-G " + m_ui->lineEditKey->text().replace( "\"","\"\"\"" ) ; }else{ auto addr = utility::keyPath() ; m = QString( "-f %1" ).arg( addr ) ; utility::keySend( addr,m_key ) ; } }else if( keyType == keyDialog::tcryptKeys ){ QEventLoop wait ; bool cancelled = false ; tcrypt::instance( this,false,[ this,&wait ]( const QString& key, const QStringList& keyFiles ){ m_key = key.toLatin1() ; m_keyFiles = keyFiles ; wait.exit() ; },[ this,&wait,&cancelled ](){ cancelled = true ; m_key.clear() ; m_keyFiles.clear() ; wait.exit() ; } ) ; wait.exec() ; if( cancelled ){ return this->enableAll() ; } auto addr = utility::keyPath() ; m = QString( "-f %1 " ).arg( addr ) ; utility::keySend( addr,m_key ) ; }else{ qDebug() << "ERROR: Uncaught condition" ; } auto volume = m_path ; if( !volume.startsWith( "/dev/" ) ){ auto m = utility::loopDevicePath( volume ) ; if( !m.isEmpty() ){ volume = m ; } } volume.replace( "\"","\"\"\"" ) ; QString exe = zuluMountPath ; if( m_ui->checkBoxShareMountPoint->isChecked() ){ exe += " -M -m -d \"" + volume + "\"" ; }else{ exe += " -m -d \"" + volume + "\"" ; } if( m_ui->checkBoxOpenReadOnly->isChecked() ){ exe += " -e ro" ; }else{ exe += " e rw" ; } auto mountPoint = m_ui->lineEditMountPoint->text() ; mountPoint.replace( "\"","\"\"\"" ) ; exe += " -z \"" + mountPoint + "\"" ; if( !m_deviceOffSet.isEmpty() ){ exe += m_deviceOffSet ; } if( !m_keyFiles.isEmpty() ){ for( const auto& it : m_keyFiles ){ auto e = it ; e.replace( "\"","\"\"\"" ) ; exe += " -F \"" + e + "\"" ; } } if( m_veraCryptVolumeType.veraCrypt() ){ auto pim = m_ui->lineEditPIM->text() ; if( !pim.isEmpty() ){ exe += " -t vcrypt." + pim + " " + m ; }else{ exe += " -t vcrypt " + m ; } }else if( m_veraCryptVolumeType.veraCryptSystem() ){ auto pim = m_ui->lineEditPIM->text() ; if( !pim.isEmpty() ){ exe += " -t vcrypt-sys." + pim + " " + m ; }else{ exe += " -t vcrypt-sys " + m ; } }else{ exe += " " + m ; } utility::setFileSystemOptions( exe,volume,mountPoint,m_options ) ; m_veraCryptWarning.show( m_veraCryptVolumeType.yes() ) ; m_working = true ; auto s = utility::Task::run( utility::appendUserUID( exe ) ).await() ; m_working = false ; m_veraCryptWarning.stopTimer() ; if( s.success() ){ m_success( utility::mountPath( mountPoint ) ) ; this->HideUI() ; }else{ m_veraCryptWarning.hide() ; auto keyType = m_ui->cbKeyType->currentIndex() ; int r = s.exitCode() ; if( r == 12 && keyType == keyDialog::plugin ){ /* * A user cancelled the plugin */ this->enableAll() ; }else{ if( this->errorNotFound( r ) ){ QString z = s.stdOut() ; z.replace( tr( "ERROR: " ),"" ) ; m_label.show( z ) ; } auto m = m_ui->cbKeyType->currentIndex() ; if( m == keyDialog::Key || m == keyDialog::yubikey ){ if( utility::clearPassword() ){ m_ui->lineEditKey->clear() ; } } this->enableAll() ; m_ui->lineEditKey->setFocus() ; if( keyType == keyDialog::keyKeyFile ){ m_ui->cbKeyType->setCurrentIndex( 0 ) ; this->key() ; } } } } void keyDialog::cbActicated( int e ) { if( e == keyDialog::Key || e == keyDialog::yubikey ){ m_ui->checkBoxVisibleKey->setVisible( true ) ; m_ui->pbkeyOption->setVisible( false ) ; }else { m_ui->checkBoxVisibleKey->setVisible( false ) ; m_ui->pbkeyOption->setVisible( true ) ; } auto _set_yubikey = [ this ](){ this->plugIn() ; m_ui->pbkeyOption->setEnabled( !m_encryptedFolder ) ; m_ui->lineEditKey->setText( tr( "YubiKey Challenge/Response" ) ) ; } ; switch( e ){ case keyDialog::Key : return this->key() ; case keyDialog::yubikey : return _set_yubikey() ; case keyDialog::keyfile : return this->keyFile() ; case keyDialog::keyKeyFile : return this->keyAndKeyFile() ; case keyDialog::plugin : return this->plugIn() ; case keyDialog::tcryptKeys : return this->tcryptGui() ; } } void keyDialog::keyAndKeyFile() { m_ui->pbkeyOption->setIcon( QIcon( ":/module.png" ) ) ; m_ui->lineEditKey->setEchoMode( QLineEdit::Normal ) ; m_ui->label->setText( tr( "Plugin name" ) ) ; m_ui->pbkeyOption->setEnabled( false ) ; m_ui->lineEditKey->setEnabled( false ) ; m_ui->lineEditKey->setText( tr( "Key+KeyFile" ) ) ; } void keyDialog::plugIn() { m_ui->pbkeyOption->setIcon( QIcon( ":/module.png" ) ) ; m_ui->lineEditKey->setEchoMode( QLineEdit::Normal ) ; m_ui->label->setText( tr( "Plugin name" ) ) ; m_ui->pbkeyOption->setEnabled( !m_encryptedFolder ) ; m_ui->lineEditKey->setEnabled( false ) ; if( m_encryptedFolder ){ m_ui->pbkeyOption->setEnabled( false ) ; m_ui->lineEditKey->clear() ; }else{ m_ui->pbkeyOption->setEnabled( true ) ; m_ui->lineEditKey->setText( utility::defaultPlugin() ) ; } } void keyDialog::key() { m_ui->pbkeyOption->setIcon( QIcon( ":/passphrase.png" ) ) ; m_ui->pbkeyOption->setEnabled( false ) ; m_ui->label->setText( tr( "Key" ) ) ; m_ui->lineEditKey->setEchoMode( QLineEdit::Password ) ; m_ui->lineEditKey->clear() ; m_ui->lineEditKey->setEnabled( true ) ; m_ui->lineEditKey->setFocus() ; } void keyDialog::keyFile() { m_ui->pbkeyOption->setIcon( QIcon( ":/keyfile.png" ) ) ; m_ui->lineEditKey->setEchoMode( QLineEdit::Normal ) ; m_ui->label->setText( tr( "Keyfile path" ) ) ; m_ui->pbkeyOption->setEnabled( true ) ; m_ui->lineEditKey->clear() ; m_ui->lineEditKey->setEnabled( true ) ; m_ui->lineEditKey->setFocus() ; } void keyDialog::tcryptGui() { m_ui->pbkeyOption->setIcon( QIcon( ":/module.png" ) ) ; m_ui->lineEditKey->setEchoMode( QLineEdit::Normal ) ; m_ui->label->setText( tr( "Plugin name" ) ) ; m_ui->pbkeyOption->setEnabled( false ) ; m_ui->lineEditKey->setEnabled( false ) ; m_ui->lineEditKey->setText( tr( "TrueCrypt/VeraCrypt Keys" ) ) ; } void keyDialog::pbCancel() { this->HideUI() ; m_cancel() ; } void keyDialog::ShowUI() { auto m = favorites2::settings().autoMountBackEnd() ; if( m.isValid() ){ auto e = utility::pathToUUID( m_path ) ; auto secret = m_secrets.walletBk( m.bk() ).getKey( e ) ; if( secret.notConfigured ){ DialogMsg msg( this ) ; msg.ShowUIOK( tr( "ERROR!" ),tr( "Internal wallet is not configured" ) ) ; }else{ m_ui->lineEditKey->setText( secret.key ) ; } } this->show() ; } void keyDialog::HideUI() { if( !m_working ){ this->hide() ; this->deleteLater() ; } } keyDialog::~keyDialog() { m_menu->deleteLater() ; delete m_ui ; } void keyDialog::veraCryptVolumeType::setValues( QCheckBox * vc,QCheckBox * sys,const QString& e ) { m_veraCrypt = vc ; m_veraCryptSystem = sys ; if( e == "veraCrypt" ){ m_veraCrypt->setChecked( true ) ; m_veraCryptSystem->setChecked( false ) ; }else if( e == "veraCryptSystem" ){ m_veraCrypt->setChecked( false ) ; m_veraCryptSystem->setChecked( true ) ; }else{ m_veraCrypt->setChecked( false ) ; m_veraCryptSystem->setChecked( false ) ; } connect( m_veraCrypt,&QCheckBox::stateChanged,[ this ]( int s ){ if( s == Qt::Checked ){ m_veraCryptSystem->setChecked( false ) ; } } ) ; connect( m_veraCryptSystem,&QCheckBox::stateChanged,[ this ]( int s ){ if( s == Qt::Checked ){ m_veraCrypt->setChecked( false ) ; } } ) ; } keyDialog::veraCryptVolumeType::~veraCryptVolumeType() { if( m_veraCrypt->isChecked() ){ utility::autoSetVolumeAsVeraCrypt( "veraCrypt" ) ; }else if( m_veraCryptSystem->isChecked() ){ utility::autoSetVolumeAsVeraCrypt( "veraCryptSystem" ) ; }else{ utility::autoSetVolumeAsVeraCrypt( "" ) ; } } bool keyDialog::veraCryptVolumeType::veraCrypt() { return m_veraCrypt->isChecked() ; } bool keyDialog::veraCryptVolumeType::veraCryptSystem() { return m_veraCryptSystem->isChecked() ; } bool keyDialog::veraCryptVolumeType::yes() { return m_veraCryptSystem->isChecked() || m_veraCrypt->isChecked() ; } zuluCrypt-6.2.0/zuluMount-gui/keydialog.h000066400000000000000000000064651425361753700205150ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef KEYDIALOG_H #define KEYDIALOG_H #include #include #include #include class QCloseEvent ; class QAction ; class QTableWidgetItem ; class QTableWidget ; #include "zulumount.h" #include "volumeproperty.h" #include "../zuluCrypt-gui/utility.h" #include "../zuluCrypt-gui/secrets.h" #include #include #include namespace Ui { class keyDialog; } class keyDialog : public QDialog { Q_OBJECT public: static keyDialog& instance( QWidget * parent, QTableWidget * table, secrets& s, const volumeProperty& v, std::function< void() > cancel, std::function< void( const QString& ) > success ) { return *( new keyDialog( parent,table,s,v,std::move( cancel ),std::move( success ) ) ) ; } keyDialog( QWidget * parent, QTableWidget *, secrets&, const volumeProperty&, std::function< void() >, std::function< void( const QString& ) > ) ; ~keyDialog() ; void ShowUI( void ) ; void HideUI( void ) ; signals: void mounted( QString ) ; void cryptoOpen( QString ) ; private slots: void cbVisibleKeyStateChanged( int ) ; void cbActicated( int ) ; void pbkeyOption( void ) ; void pbMountPointPath( void ) ; void pbPluginEntryClicked( QAction * ) ; void plugIn( void ) ; void key( void ) ; void keyFile( void ) ; void openVolume( void ) ; void pbCancel( void ) ; void Plugin( void ) ; void KeyFile( void ) ; void cbMountReadOnlyStateChanged( int ) ; void encryptedFolderMount( void ) ; private : class veraCryptVolumeType{ public: void setValues( QCheckBox * vc,QCheckBox * sys,const QString& opt ) ; ~veraCryptVolumeType() ; bool veraCrypt() ; bool veraCryptSystem() ; bool yes() ; private: QCheckBox * m_veraCrypt ; QCheckBox * m_veraCryptSystem ; } m_veraCryptVolumeType ; bool errorNotFound( int ) ; void keyAndKeyFile( void ) ; void tcryptGui( void ) ; void enableAll( void ) ; void disableAll( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::keyDialog * m_ui ; secrets& m_secrets ; QString m_path ; QString m_point ; QByteArray m_key ; QStringList m_keyFiles ; QString m_deviceOffSet ; QString m_options ; QMenu * m_menu ; QTableWidget * m_table ; utility::veraCryptWarning m_veraCryptWarning ; bool m_working ; bool m_encryptedFolder = false ; enum{ Key = 0,keyfile = 1,keyKeyFile = 2,plugin = 3,tcryptKeys = 4,yubikey = 5 } ; std::function< void() > m_cancel ; std::function< void( const QString& ) > m_success ; utility::label m_label ; }; #endif // KEYDIALOG_H zuluCrypt-6.2.0/zuluMount-gui/keydialog.ui000066400000000000000000000217551425361753700207020ustar00rootroot00000000000000 keyDialog 0 0 521 266 true unlock and mount a luks volume 210 230 101 31 &Open true 310 230 101 31 &Cancel 0 200 101 31 Key Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 110 200 301 31 410 200 31 31 0 0 101 51 Mount Name Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 410 10 31 31 110 10 301 31 140 40 271 31 Mount In &Read Only Mode 140 60 271 31 &Share Mount Point 110 230 101 31 O&ptions 110 170 301 31 140 80 271 31 &VeraCrypt Volume 410 200 31 31 140 100 271 31 VeraCrypt System Volume 140 130 61 31 QLineEdit::Password 210 130 201 31 VeraCrypt PIM Value 0 0 521 271 true Qt::AlignCenter true 210 222 101 31 &OK 10 10 501 251 true QFrame::StyledPanel QFrame::Raised 80 50 341 51 Enter Below The Offset Location Of The Volume About To Be Opened. Qt::AlignCenter true 80 130 341 51 Enter Comma Separated Volume's File System Options Below Qt::AlignCenter true 80 100 341 31 80 180 341 31 140 210 111 33 Set 250 210 111 33 Cancel lineEditMountPoint pbOpenMountPoint checkBoxOpenReadOnly checkBoxShareMountPoint checkBoxVeraCryptVolume cbKeyType lineEditKey pbkeyOption checkBoxVisibleKey pbOptions pbOpen pbCancel zuluCrypt-6.2.0/zuluMount-gui/keyfile-1.png000066400000000000000000000036141425361753700206610ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎébKGDÿÿÿ ½§“ pHYs¯¯^‘tIMEÚ ÷Ææë IDATXí—]h\ÇÇsï{W»+YÚ]}X’%Û)vâš’8µ yP ”Ò<…×ÐBí§búJk§¥PBÉCiñKÓCêÚPhÒ`h)¡-Ôýql7õ‡lË–¥H+íJ»{¿ïÜéÃ]m%[–T·.sïÌΞÿœùŸÿ™´­R©÷ÿ›‰5ïú±°¿¿²Z­¶6šxDÿ?¬õ÷M‡Ï­uj­yÏÔ––BdË!²B€ÖYŸad3Ò4kÛß©ÈS½tš°aqåÊú™››Ã–ÇqXY^&_(Ë僀J¥B£årò]ºr’]£9¼ FõîL „!=ÝÝHÛÞ„À‚‰‰‰NDÆÇÆ:¡†Ñ!cÆÃ”]†ÉØpžßŸ{Ô¨&N÷³”Ëe†0¥$]%ìv" $޳ ÕÞ?Ñfþjf¬šR Ë$_´ðš‹È‚C"ºpr†eÖë¹³tûe{¿ ÓDJÙé“Rv2Ų,,ËBë'ßE¡§ we)%‰Îxbš&†iþ'u·Š€‚‹~ˆ%%;wî¤^«‘jeY„aˆ”’ÞÞ^¤”ÌÌÌÐ××G,Þû+õ˜Ùk0þ³°$˜žÞEWW޳µÀNh­u†%€?;ý–>ø™Ãн}ƒúßü–¾zõšv]WÇq¬ƒ XUÂÏo×u¹yó&®ë244D³Ù¤Õj‘Ëå0 ß÷Éçó,..£££LMM‘&!½=Ù*‹Ise™¹¹YŠÅ½½½!6ŒÂ†B´ÿ~,ËZG²UulµZ …uDŸ~å+¼XýOê¡1Å݇9ÿ›IªŒíehçN=<< ødaaáÑJx§îéc^Ò7]íµš:I­”ÒI’h×uuÇ:ˆc=ñ¢þçoèé»wõ…¿þm3‘L§ï܉Û~©¿¿ßÜ’ãÁ£Ù×kÆ)I:£1†å©¥bDw7±ÖÔoÜ êûÙ‘7 ÑZgÄ Z­–n4¼ôòË_.‹¿«V«jË,@´Ïš«5ߟ…k?G'bþT? M­Û·8vŒê{ïáºnG’$! C|ß×Q‰¯?~¬V«½S«Õ’m¥a†¡-8i ùQÐ)´Á0ð£1î¾ùcºöì!cr{÷²|þ<´ÏQxžŽ¢H|õèÑã—/_>[¯×“GUÀ‡ODZ£E LC ÒˆpøKØ÷þ€.ì"72ÀîW_%p]Âf“î矧”¥Qáyž6LSœüΉï^ü裟zž§6+ÁEàvC±à§üñ^È‹1o^÷(”öBí*Tž%B”ç¡ãÒåûˆ¶`y­–6-Süòì[¯¿ýëw¿¿•ó #0V08ý\w¦Á©à¹AI£_@« ³×«Oš¦äóy-m[œxíÄ÷Μ9û:nç÷€HiâtµAîý ý©W@%뜫4%N†‡‡u³±,N~ûµ“gΜý Ø¦mÌ@ ‘«ã/¶§z¡”"IR¥ô'Ÿ{žxâëµÚÒOþçòÅâ?+n89UŠ(Šê£cc'ÇùEÅÉc_¥Ëår÷ÒÒÒS[\Ïõsp¿¯¯ï^½^Oy û7ÉK1¯õƒ IEND®B`‚zuluCrypt-6.2.0/zuluMount-gui/keyfile.png000066400000000000000000000262151425361753700205250ustar00rootroot00000000000000‰PNG  IHDR  Ûph IDATxœíݰÝu}ïû÷gí½W6;;!!á‡`áG±U‹ŽUàzlmO½ÇžéÅÞétÎt˜‰GÇ£ÇqÚ‡±ÁQˆHñÎ=wZÇŸ\‹b=È©£ØâÔRG!?™@PEHB~²Ù{}ï WcöN¾ßÏg­ïz£UU}âæ›o ŠÆÿu檪ªX¿~ý›6lØð½ªªþ¥ªª·=üŠÎÏ#äŠÒCfC€ÐWÖ¯_ÿ¦7þ(¥t{D¼²ô€Ñ©ªêëÖ­!@ß ô…-[¶œ½qãÆ/ÿ<<.,½`u"B„}O€PTUU±iÓ¦wNOO?PUÕï•Þ0àDÐ÷ÅlذañÆ¿\UÕ‡"b¼ô€–èDÄ'nºé¦?*=àPElذá”ҿ¦”<ëP¿NJé“"èG„ì6lØðš”Ò?GÄ¥·´X'"DÐwYmÚ´éwSJÿ?û©å4«Ÿ¼ñÆEÐ7Ùlܸñ5UU}>¥4Qz À餔DÐ7Yüü5wŠ€"DÐ7Û´iÓINçΈXXz À뤔>¹nݺÿ\z0ܪª*"âo#â´ÂSøÙOLÿôG>ò#@hÔæÍ›ß¾Õ.@ÿ褔DPŒ¡16lXkKïàWtRJŸ¾ñÆE¡1###ë"¢[z‡Ô‰d'@hÄ–-[Þ¯/½€#!@v„ÚUUÕ©ªÊ—^ †NUU"ÈF€P»Í›7¿%"V”ÞÀ¬=ÿݱÞRzÐ~„ZUU)¥÷–ÞÀœu"â³"hš¡V>øà%ñë¥wpTDÐ8B­z½ÞŸ”ÞÀ1éD„/Ç#@¨ÍC=4žRò€0øFC„  Ôæ¹çžû½ˆXXzµõÂt  „Ú¤”þCé Ôj´ªªOøÃ!@muº¬ôj7"¨¡[·n=9"V•Þ@#DPB-z½ÞËKo Q¾ ¨…¡½^oeé 4N„ÇL€P‹”Ò¹¥7…މ¡.g—@6£UU}úCúÐÿVz0xuñó?†ËhJé³"˜+B]Àð!Àœ ê"@†ÓhDˆ`Öp¬F#ÂkB€Y @º!B€Y @]ºñén¸A„‡%@€:‰àˆP7–š B€C @Sºñé믿þM¥‡ýC€Mꦔ>+B€ç  i"xrèFÄgo¸áCN€¹t«ª!0ä“!'@€ÜºUU}öúë¯cé!@~(¡[UÕm"†J!0„PR·ªªÛ®»î:CB€¥uSJ"†„ú!!@€~ÑM)Ývíµ×þÇÒC€æ ŸtSJŸ!Ð^è7"ZL€ý¨›Rúü?øA-#@€~Õ­ªJ„@Ë Ÿu{½ž @¿!Ð"Ý^¯÷ùk¯½ö÷JŽE7"n!0Ø0Hºqû_ÿõ_‹P4ÝN§#B`@ `uSJ"•$@€AÖM)Ý~íµ×þné!Àì`Ðu«ªúâ>ð@€mÐM)‰h @€m"B Ï  mDô1´Q7¥ôŵk׊è3h«nUU"úŒÚ¬ÛëõDô´>"@€aÐíõz·‹(O€Ãb¼×ëÝ~Í5׈(H€Ãd<¥tû>ð×—ÃJ€Ãf¼ªª/Š(C€ÃH„@!V"  À0!™†ÝxUU_|ÿûß/B 1ÞétDd @~f¼Óé|ñšk®!Ð ðÿ  ¿L„@ƒÀ¯¯ªêvõ ‡6!B ~àðDÔL€ÙDUU·¿ÿýïÿíÒC  À‹›H)}Q„À± ³#B `ö&"â‹kÖ¬!p”ÀÜL¤”D%0w"Ž’8:Ï¿&äß—ƒD€½‰ªª¾$B`öÀ±!0àØ‰˜%P‰ªª¾´fÍG @ê3"Ž@€Ôk""¾ôWõW—•ýH€Ôo"¥ôe¿J€4C„À!€æˆ8ˆhÖDJéËkÖ¬¹¬ôè y½^O„@€\D„Èi¢×ë}ù/ÿò//)=J yM¤”î! +Ÿah €2&"âÎ÷½ï}"„¡"@Ê™èt:"„¡"@Ê! Pžah€þ0‘R!´žè"„Ö ýåùoÑûÚÒC   ÿLTUu—¡@!´’è_UUÝõÞ÷¾W„Р¿Mt:;Em!@úߤ¡-À`!´‚“?ÿ‰é"„%@ËdUU"„%@a` €Á$BH`p‰Žl"„"@ßdUUw¾÷½ï}Mé!ðb@;LFÄ]"„~'@ÚC„Ð÷4`ff&Çcl/Ã5<"„¾&@ Ýnwa†ËìÎp ÓdDxM}I€@fffrÈ“®ÁàZè…éô#ÍX”á3\ƒÁ¶°ªª;ßóž÷ˆú†€TUÕø3 UUýkÓ× ¦”D}C€@3NÊp¯d¸í BèR:¯ék\}õÕ÷§”lú:´†¡/h@UUfºÎÍ9®CkˆŠ Ѐ”R–û±#ǵh…!B(F€@3^òw÷wM_äÊ+¯Ü×4}Zgaüì焼ºô†€†ìß¿ÿµ9®366öш¸/ǵh•…½^ï.Bnšó†¹òÊ+§SJoˆgr\VYØëõîz×»Þ%BÈF€@s~7×…®ºêªñ¿GD/×5i…NG„€æ¬ºõÖ[ÏÎu±«¯¾úŽ”ÒŸçº­²°ÓéÜõîw¿[„Ð8 ªªêM9¯÷¶·½íãUUý—ðLs·0"D Р”Ò©ª*ë5W¯^ý?ªªúˆx2ë…iBã4ëüüã—å¾èêÕ«¿ZUÕ+"âå¾6oaDÜõ®w½ëâÒCh'Í»ªÄEßþö·?²zõê߉ˆ?‰ˆŸ”ØÀÀZØétþQ„ÐÍ{Óºuë–•ºøêÕ«ÿ."^oˆ‡Kí`à,L)‰j'@ y£Ýn÷ÿ,9`õêÕS«W¯¾iÇŽ/Ÿý|’ÏDÄ®’› SJÿøîw¿[„P›Tzí°eË–mqÆÁ/´<Ü /÷«Çõó6ÇÕ{\?o›Ëqý¶gŽ›îõzüÅ_üÅæCÞ €[o½uôÀ¯éõz¯ˆWEÄ…qFDŒFôÕû®µÇõó¶ƒÞ¾;¥ô>øÁ~÷ÂŒ–ÃfÿþýñðÃÇž={bß¾}133‡ÿà°RÇõËŽ~?îXnßï÷­ŸÞW³9ndd$&&&bþüù±xñâH©ø¿¹v:µñŸJyÞ•W^9ÿôóÿ""âsŸû\çñÇ_6==½("ÆSJ‹žÿ½Ã½~ûôôô¬®Ÿë|Ïœ«Ã¯×›Ýw8>øö‡:ßÑÞ·Ãm;ÚóÍæ}Ô‡h ’¨…g@^ü¸­[·Æ7¿ùÍxøá‡gýàÔ£ÛíÆé§Ÿçž{nÌ›7ïÇäúøPUÕoýùŸÿù·f5 …µ ‡?nÿþýñ÷ÿ÷±eË–CžÈgdd$.¸à‚xéK_ú+¿—ëãCJiã¾}û~ãï|ç³³Ð"^„ zòÉ'ããÿ¸ø€>133?üáã¾ûî;æ/;ZUU­š˜˜X[äâ}@€@CöíÛŸúÔ§bçÎ¥§Ù¶m[<ðÀ%'ü×[o½õ²’J Ð;î¸#vìØQzp[¶l‰íÛ·—œð·7ÝtÓI%” @ [·nM›6•ž¼ˆûï¿¿ä—b166öùÏ}îsÝ"  Ѐ{î¹§ô`öíÛ>úhÉ —<õÔSÿOɹ ¨Ùó?ç …¿ +"âŠ[n¹å¿—‹šmÛ¶ÍÏù€òÓŸþ´ô„ˆˆµó7ó¶Ò#r P³Ý»w—žÌÁÔÔÔQÿ¤ì:UUµîæ›o~WéM P³½{÷–žÌÑJOˆˆˆ”ÒõûØÇ|9ÐjjæË¯€c´ö–[n¹qÍš5£¥‡4A€@Ÿ©ªjõÉ'Ÿ|×­·Þêç„­#@ ?ýû™™™ïÝrË-¿^z@ô¯—TUõí}ìcï\³fÇl |0€þ6^UÕ‡–,YòÍuëÖ­*=àX  ¯ît:ÿzóÍ7ÿ÷5kÖtK8ZÇxD¬=餓¶|ô£ýc_– "¸`ðœŸ8餓þuݺu¿[z À\øã0¸.J)ÝùÑ~ô‡)¥u£££ŸºòÊ+Ÿ)= àH<ƒï¢ªªþ¯©©©¯[·îºo¼qEéA‡ãhÅñîN§óîuëÖý ªªÏÏÌÌü¿ïxÇ;6–ð<íôëñë###×ÜtÓMSJ_­ªê›UU}ëíoû#¥ÇÃK€@û­ªªjUD¼-¥7Þxãö”Ò·ªªÚ[ªªÚÚëõ|Ç;Þ±=¥Tz+Ðr†Ï²ªªÞò‹oèt:qã7N}ä#y&"vEijUU=;ž?¦ªªCž¬×ëÍê¢ß>×ùf{þ¦Ï7›ûu¸k͹ær¾Ã9è:O\ýõoÕ áð¼îÏÿ[4—ü¬Él?¹Íu¾c½}]ç;Ô³KužëXÎ7ËÛùÒ=já»`٨ټyóJOæ¨Óñp‹¸P³ÉÉÉÒ€9H)ù‡€ŒÔ줓N*=˜ƒùóçöë騟švÚi1þüÒ3€YZºtié CE€@ÍRJqÁ”žÌBJ)Î8ãŒÒ3†Š\rÉ%ÑívKÏ^IJeËâøã/=`¨hÀääd\~ùå¥gG0oÞ¼¸ð KÏ:òªW½*^þò——žB§Ó‰ßüÍߌ‰‰‰ÒS†ŽýÁüA¼æ5¯)=øÝn7~ë·~+–,YRz ÀP-=Ú,¥¯ýëãÌ3ÏŒ»îº+vìØQz ­”R,_¾<.¸àÏ|$@ ƒ•+WÆŠ+býúõ±qãÆx衇â™gž)= Z¯ÓéÄÄÄD,[¶,N;í´X´hQTUUzÀP I§Ó‰ /¼0.¼ð¨ª*¦§§cïÞ½/|2tð'E‡û$i¶Ç½Øíæz¾£=n¶{†i_¿ÿ?›ë'èý²çàãFFFb||\pô…ŒŽŽÆ¢E‹^øu¿|Bî¸æëçms9®ßö €ÁàEè@6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À°™™™‰íÛ·ÇîÝ»ãÙgŸ}áíUUÍêöw´·›ëqM_g˜îGîCÎëíqN'æÍ›“““1þüY€æ ÈäñÇo}ë[±yóæ8pà@é90T,X§vZ¬\¹2:Oþ”$@ aSSSqçwÆ~ðƒ9ÿË2P={öĆ bëÖ­qÑEÅi§VzÀÐ Р={öÄ'?ùÉxüñÇKO"âÀñ½ï}/ž~úé8ÿüó#¥TzÀÐñ<44djj*>ñ‰OˆèC›7oŽÍ›7—ž0”4äK_úR<ñÄ¥g‡±aÆøéOZzÀÐ ЀG}4î¿ÿþÒ3€#¨ª*~ô£•ž0t4àßø†œÃxúé§cûöí¥g 5›ššŠ­[·–žÌ’ÈK€@Í~øá˜žž.=˜%¯ÕÈK€@ÍvïÞ]z0ˆ^¯WzÀÐ P³={ö”žÌÑJOj633Sz0G¾i@>ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² P³±±±Ò€9)=`h¨Ù‚ JOæ¨Ûí–ž04ÔlñâÅ¥'s011)¥Ò3††šqÆ1oÞ¼Ò3€Y:õÔSKO*jÖétâ‚ .(=˜¥åË——ž0T4à’K.‰ÑÑÑÒ3€±téÒ8ñÄKÏ*°hÑ¢xík_[zp£££qá…–ž0t4äÒK/U«V•žBJ)^ùÊWú®uhHJ)Þò–·ÄË^ö²ÒS€_022_|±Ÿâ‹Ô¡A£££ñæ7¿9N?ýôøú׿ûöí+= †Ú’%K⢋.Š… –ž0´dðŠW¼"~í×~-î»ï¾Ø´iSlÛ¶-ªª*= †B·ÛSO=5N;í´8å”SüÝ(L€@&Ýn7^ýêWÇ«_ýꘞžŽ½{÷ñ‘Ã}’tðÛg{Ül¯s¬×í÷£¾sõÓ}(yƒÝétb||ÜO9è3 ‰ã?>Ž?þøÞV÷'ŸŽëßãúyÛ\Žë·=Ç4äáEè@6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À0Ú¹sgìÙ³'öíÛUUò˜¹¾ýÅŽ;ÚÛ¹ný×mË}=ÖÛ»n\sX¯;66ccc1>>>«Ûõ ÉÓO?÷Þ{olذ!víÚUz1>>'œpB,]º4ÆÆÆJÏ¡ @ a½^/¾öµ¯Åw¾ó˜žž.=€_ðì³ÏÆc=ÿöoÿ§žzj,[¶,RJ¥gA« hÐþýûã¶Ûn‹­[·–žÀôz½xôÑGcÏž=±bÅŠõ)4ŋС!333ñ™Ï|F| Ý»wÇ–-[fýz`î4äÎ;ïŒmÛ¶•žÀíÙ³'yä‘Ò3 µ4à‰'žˆù—)=€£ôÄOÄþýûKÏ€V Ѐ»ï¾ÛÓ÷¬ªªØ¾}{éÐJj6==[¶l)=€c´k×®èõz¥g@ë¨ÙÃ?Ï=÷\é£^¯{÷î-=ZG€@Íž~úéÒ¨ÉJO€Ö P³={ö”ž@M¦¦¦JO€Ö P3?í =|C¨Ÿ² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€lÔltt´ôj’R*=ZG€@Í,XPz5év»¥'@ë¨Ù¢E‹JO &óæÍ+=ZG€@ÍÎ<óLÿbÐN'&''KÏ€Ö P³ÑÑÑX¹reé£N8!:Ÿ*AÝü­‚\z饴XJ)–-[Vz´’Ï K–,‰W½êU¥gp”N9å”/=ZI€@C~û·;Î:ë¬Ò3˜£… Æé§Ÿ^z´–†ŒŒŒÄýÑÅŠ+JO`–-ZçœsŽŸÿ  РyóæÅ[ßúÖ¸ì²Ë|g,€>ÖétbùòåqÎ9çÄÈÈHé9Ðj~d34,¥—^zi¼â¯ˆ{ï½76lØO=õTéYDÄqÇ'œpB,]º4FG}Z9ø›™LNNÆå—_—_~yìÞ½;ž~ú騷o_ÌÌÌòøªªæôö;îhoçºõ_·-÷õXoïºýqÍa¼nÄϾeúøøxŒÕí£'@ € Ä‚ ~ém³} uÜà×ÏÛær\¿íÄãúyÛ0äá5 @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6£¥À0šššŠ={öľ}ûbff&""ªªú¥cþõáÏ7ÛÛ;ßìÏ=¨š|_Íåºm8ß þùî÷óÊØØXŒÅÈÈȬoÔC€@&Ï>ûlÜwß}±~ýúؾ}ûœ(hÆääd,^¼8N>ùäèt|aä @ aUUŽ÷ÞßøÆ7bÿþý¥çð öîÝ{÷îíÛ·ÇòåËãä“OŽ”RéYÐj4==·ß~{<ðÀ¥§pÓÓÓ±mÛ¶Ø»woœuÖYž  hHUUqÛm·Å¦M›JO`–žz꩘™™‰sÎ9§ôh-y ¹ûî»ÅÀÚµkWlß¾½ô h- عsgÜsÏ=¥gp”{ì±8pà@éÐJp÷Ýw¿ðíu<½^ϳ Ð5›žžŽ7–žÀ1Ú¹s§o™  P³ÿøÇž¶h™™™Ø»woéÐ:j¶sçÎÒ¨‰P‚ú ¨Ùž={JO &SSS¥'@ë¨ÙsÏ=Wz5éõz¥'@ë d#@€l² @6ÈF€Ù d#@€l² @6ÈF€@ÍFGGKO &ŽO• nþVAÍ&''KO &þQ ê'@ fÇ|é ÔdÞ¼y¥'@ë¨Ù™gžé_ÌZ ÓéÄ‚ JÏ€Ö P³n·+V¬(=€ctüñÇ{ 4Àß*hÀ%—\)¥Ò38Ë–-+=ZI€@–-[/{ÙËJÏà(-Y²$&&&JÏ€V Ðßÿýß÷¯ghþüùqæ™g–ž­%@ Ä.n\ HIDAT!cccqÅWÄòåËKO`–&''cåÊ•^û ò· 499ú§_|±3€>–RŠSN9%V­Zccc¥ç@«ù^¡Ð°ÑÑÑxÃÞ¯|å+ãÛßþvlÚ´)žyæ™Ò³ˆŸ}Œ>á„âÔSOñññÒs`(ÈdÉ’%ñÆ7¾1ªªŠíÛ·ÇÞ½{cïÞ½/ü~UU³:ÏÁÇííæz\Óצûцûó:myËŸAºG:®ŸîÇØØXt»Ý˜˜˜xá»ÎõÏ>ptd–R:ä‹Ógû@ê¸Á?®Ÿ·Íå¸~Û3ˆÇõó¶a<ÈÃ¥Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€ÙŒ–ÃêÀñÌ3ϼð몪~é÷þõ\{±Û5uÝ£Ý3LûúýÿÙl÷õÛž~ê¸6þù”}ccc1222«=@½d233?úÑbãÆñÐCÅÔÔTéICmdd$.\‹/ŽO<±ô2xàâ«_ýjìÚµ«ô~nff&vîÜ;wüä'qúé§ÇâÅ‹KÏ‚Ö Р^¯_ùÊWâ»ßýné)ÁâÁŒ¥K—Æé§Ÿ)¥Ò“ µ4è _øBüð‡?,=€YzüñÇczz:Î>ûìÒS µ|,hÈ·¿ýmñ0€ž|òÉxì±ÇJÏ€Ö ЀݻwÇ×¾öµÒ38J>úh<÷Üs¥g@+ hÀ?ÿó?{à`½^/¶oß^z´’šUU÷ßé£;vÌùçâ/N€@Íy䑨¿é£éé騷o_éÐ:j¶cǎҨɳÏ>[z´ŽšíÞ½»ôj255Uz´Žšyñ9@{ôz½Ò u² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@ fŽ¿Vm‘R*=ZÇgJP³ÉÉÉ񬃯ØXé Ð:j¶páÂÒ¨I·Û-=ZG€@Í^ò’—ø2,€H)Å‚ JÏ€ÖñYÔl||<Î>ûìÒ38F .Œ‘‘‘Ò3 u4àu¯{]é £SO=µôh% 8óÌ3cÕªU¥gp”/^ì˯ !òæ7¿9N<ñÄÒ3˜£ñññ8묳JÏ€Ö ÐyóæÅÿñ‹€rÜqÇŹçžëµÐ  :á„âÏþìÏâüóÏ/=€±xñâ8ÿüócÞ¼y¥§@«–m7>>ø‡<òHÜsÏ=ñÐCÅôôtéYDD§Ó‰… ÆòåËcþüù¥çÀP ÉgœW\qELMMŶmÛb÷îݱgÏžb¤ªªY§Ôqý²£ß;–Û÷û}ë§÷U[Žó÷¯ÌŸ©”Rt»Ý˜7o^LNN¾ðåVÇz`vdÖívcÅŠ¿òöƒø÷@è¸Á?®Ÿ·Íå¸~Û3ˆÇõó¶a<ÈÃk@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l² @6ÈF€Ù d#@€l`6z¥Ð„ºì.=hÔÞÒhB]´›Çzj!@¨‹JÐb)¥]¥7Єºl-=hN¯×óXO-µH)m(½hŽÇzê"@¨Ëƒ¥ÍI)m.½v Ô¢ÓéÜWzМ^¯÷ÃÒhB-Î>ûì'"b}é@#î¿á†ž(=‚v ÔéîÒ€FÜ]zí!@¨MJéKoêç1ž: j322ò•ðó@ mvíß¿ÿ+¥GЄڜuÖYϦ”>WzP«Ï­[·nªôÚC€P·O”Ô§×ë}²ôÚE€P«+VüSDü ô ÷}èCú§Ò#hB­RJ‘Rú@é@-<¦S;BíV¬Xñ÷~Z* ¶ªª6Ο?ÿ ¥wÐ>„Ú¥”z½^ï=¥wG¯Óé¼gÍš5½Ò;hB#Î=÷Ü/TUå[öÀ`úŸ×]wÝ¥GÐN„ÆŒŽŽ^¾m –g;ÎÛK ½yéK_ú`UU¾ HUUÿíÚk¯}°ôÚK€Ð¨sÏ=÷#UUýCéÀ‹«ªêŽë¯¿þ£¥wÐn„F¥”¢ªª?‰ˆŸ”ÞÑ####Rzí'@hÜyç·£×ë½!"v•ÞÒ“###¿síµ×z¬¦q„,Î;ï¼ûSJ¿SUÕ3¥·¿ä™^¯÷ûk×®ÝXzÃA€ÍÊ•+¿ÿI„@ßx&"Þ|à 7|·ô†‡!«U«V}eddäòˆØQz ¹Nçß]wÝuÿ«ô†‹!»sÎ9ç;333¯‹ˆ‡Ko€!õp§ÓyÝÚµk=óAv„".¸à‚õóæÍûˆøBé-0d¾pàÀßX»víúÒCN£¥0¼Î:ë¬]UU½yÓ¦Mÿ5"ÖFÄxéMÐbÏTUõß®»îº•Âpó E¥”bÕªUI)~`!4㎑‘‘óÄýÀ3 ô…U«V=°aÆÿˆˆ‹Ê.€VøAJé}k×®ýŸ¥‡Àó}å¼óÎû‡ªªþaÓ¦Moìõz‹Ko€ASUÕw:Î5ƒ~$@è;)¥ˆˆ;"âŽõë׿<"þ”ÒUU\vô¯”Òã½^ï3Nço×®]ûƒÒ{àpRé0_ÿú×G—.]úÚªª.¯ªê²ˆxuüB@WUõKÇüëA8®Ÿ·9®ÞãúyÛ\Žë·=ƒx\?osÜ@ü˜ŠˆïFÄ×:Î×7mÚôO·Ýv[ï'€>"@H?þñÇŸ~úé•)¥•)¥U½^ïô”Ò¢^¯7Ïÿ÷+Žõ­ƒõz¿üqþX¬Žt«îáÎ?×ó ÓýhÃ}(yA|µá>ê:îÇìÎ?Ësí}þ¿^¯·+"¶¥”6OOOožššÚüáøÙY]ø¹ÿ‘iEtÄ\oIEND®B`‚zuluCrypt-6.2.0/zuluMount-gui/main.cpp000066400000000000000000000022271425361753700200140ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include "zulumount.h" #include "../zuluCrypt-gui/utility.h" int main( int argc,char * argv[] ) { QSettings m( "zuluCrypt","zuluMount" ) ; utility::setSettingsObject( &m ) ; utility::setHDPI( "zuluMount" ) ; QApplication a( argc,argv ) ; return utility::startApplication( "zuluMount",[ & ](){ zuluMount e ; utility::startApplication( &e,"Show" ) ; return a.exec() ; } ) ; } zuluCrypt-6.2.0/zuluMount-gui/module.png000066400000000000000000000024421425361753700203560ustar00rootroot00000000000000‰PNG  IHDRójœ sRGB®Îé pHYs „ „ªâcytIMEÚ ®böc÷PLTE ooopst·¹»¯´·±¶¸¼¾¾´¹»¾Âͼ¾»¿ÂÂÆÈ†„„‰ˆˆŒkf‘j“l––——o›v›w!œw! †¥}¥§°¦¥¥©ƒ ª‹¯Ž¯“°—±±±²”²•³³³´“´—´µµ´µ¶µ·Ã¶·Ã¶¹Ä¶¹Å¶¹Æ···¸š¸› º¸¹ºÀÀ¼¦T¼¼Å¾©b¾ÃÅ¿¿À¿ÀÁÁÆÉÂÂÁÂÅÎÃÂÂÄÅÅÄÉÌÆÆÆÆÚ¾ÈÈÈÉÌÎÊÓÝËÌÌͶiͶjÍ·iηjθjÏÓÕѽ:ÒµÒÇXÓÝÛÕäÃÖ××Öäñ×¹×ÅbظظØÛÜÙµ0Ù½ÙÅ;Ûàçݽ(ÝÞÞÝàéÝæâÞ¹1ÞÊ6Þäçß¹1ߺ0ß»1ßÄ@ßáâßâàßäçßåèàâòàâóàäóàêãáãäáåôáåöâÝxâæ÷âçöâç÷âèêâëõâìõãÕMãå÷ãèéãòæäË]äåæäçøäíßåêìåêøåîùæëûè܇èíîèïáéêìéíïêÜPêíóêîðêñøêñÿëºëÕ@ëÖ?ëÖ@ëÛOëÜPëñÿëøÝìÒbìÖ@ìÝOìÝPìïñíÒbíÒcíÖ@í×Bíéíé€íðñíóùíùâîé€îðñîóùïðñïññïñöïòóïôùïõúðÆ ðõúðöúòæòôõòôöóæóç‘óôõóõöóö÷óøýóþÿôæ‘ôç‘ôõúôö÷ôöøõÇõöúõ÷øõûê÷Í÷ùù÷ùú÷ÿÿøÈøÊøÊ øËøÍùÊýÜþËÿÒÿÔÿÙÿÚÿß ÿáÿâÿå&ÿé0ÿê'ÿî ÿî(ÿï)ÿï,ÿô7ÿõ*ÿ÷;ÿÿÿ0&\)tRNS !$(,.16. */ #include "monitor_mountinfo.h" #include #include #include #include "../zuluCrypt-gui/utility.h" #include "zulumounttask.h" monitor_mountinfo::monitor_mountinfo( QObject * parent,bool s,std::function< void() > f ) : m_parent( parent ), m_stop( std::move( f ) ), m_announceChanges( s ), m_announceEvents( true ) { } monitor_mountinfo::~monitor_mountinfo() { } std::function< void() > monitor_mountinfo::stop() { return [ this ](){ utility::stopTask( m_task,m_stop ) ; } ; } void monitor_mountinfo::announceEvents( bool s ) { m_announceEvents = s ; } void monitor_mountinfo::start() { m_task = utility::startTask( [ this ](){ this->run() ; },m_stop ) ; } void monitor_mountinfo::run() { if( m_announceChanges ){ connect( this,SIGNAL( volumeMiniProperties( volumeProperty * ) ), m_parent,SLOT( volumeMiniProperties( volumeProperty * ) ) ) ; connect( this,SIGNAL( volumeMiniProperties_0( volumeProperty * ) ), m_parent,SLOT( volumeMiniProperties_0( volumeProperty * ) ) ) ; connect( this,SIGNAL( volumeRemoved( QString ) ), m_parent,SLOT( volumeRemoved( QString ) ) ) ; } auto _unmountProperty = [ & ]( const QString& volume ){ Task::exec( [ &,volume ](){ auto r = zuluMountTask::volumeMiniProperties( volume ) ; if( r.volumeRemoved ){ emit volumeRemoved( r.volumeName ) ; }else{ emit volumeMiniProperties( r.entry ) ; } } ) ; } ; auto _mountProperty = [ & ]( const QString& volume ){ Task::exec( [ &,volume ](){ emit volumeMiniProperties_0( zuluMountTask::volumeMiniProperties( volume ).entry ) ; } ) ; } ; auto oldMountList = [ this ](){ if( m_announceChanges ){ return zuluMountTask::mountedVolumeList() ; }else{ return decltype( zuluMountTask::mountedVolumeList() )() ; } }() ; decltype( oldMountList ) newMountList ; auto _volumeWasUnMounted = [ & ](){ return oldMountList.size() > newMountList.size() ; } ; auto _volumeWasMounted = [ & ](){ return oldMountList.size() < newMountList.size() ; } ; auto _unmountedVolume = [ & ]( const QString& e ){ return !newMountList.contains( e ) ; } ; auto _mountedVolume = [ & ]( const QString& e ){ return !oldMountList.contains( e ) ; } ; utility::monitor_mountinfo monitor ; while( monitor.gotEvent() ){ if( m_announceEvents ){ emit gotEvent() ; } if( m_announceChanges ){ newMountList = zuluMountTask::mountedVolumeList() ; if( _volumeWasUnMounted() ){ for( const auto& it : oldMountList ){ if( _unmountedVolume( it ) ){ _unmountProperty( it ) ; } } }else if( _volumeWasMounted() ){ for( const auto& it : newMountList ){ if( _mountedVolume( it ) ){ _mountProperty( it ) ; } } }else{ /* * mount/unmount just happened but volume count remain the same, * possible reason is because of a bind mount */ } oldMountList = newMountList ; } } } zuluCrypt-6.2.0/zuluMount-gui/monitor_mountinfo.h000066400000000000000000000030651425361753700223230ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef MONITOR_MOUNTINFO_H #define MONITOR_MOUNTINFO_H #include #include #include #include #include "task.hpp" class QObject ; class volumeProperty ; class monitor_mountinfo : public QObject { Q_OBJECT public: monitor_mountinfo( QObject * parent,bool,std::function< void() > ) ; std::function< void() > stop() ; void announceEvents( bool ) ; void start( void ) ; ~monitor_mountinfo() ; signals: void gotEvent( void ) ; void volumeRemoved( QString ) ; void volumeMiniProperties( volumeProperty * ) ; void volumeMiniProperties_0( volumeProperty * ) ; private: void run( void ) ; QObject * m_parent ; std::function< void() > m_stop ; bool m_announceChanges ; bool m_announceEvents ; Task::future< void > * m_task = nullptr ; }; #endif // MONITOR_MOUNTINFO_H zuluCrypt-6.2.0/zuluMount-gui/mountpartition.cpp000066400000000000000000000241311425361753700221620ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "mountpartition.h" #include "ui_mountpartition.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "zulumounttask.h" #include "bin_path.h" #include "task.hpp" #include "../zuluCrypt-gui/dialogmsg.h" #include "../zuluCrypt-gui/tablewidget.h" #include "../zuluCrypt-gui/utility.h" mountPartition::mountPartition( QWidget * parent,QTableWidget * table,std::function< void() > p,std::function< void( const QString& ) > q ) : QWidget( parent ),m_ui( new Ui::mountPartition ),m_cancel( std::move( p ) ),m_success( std::move( q ) ) { m_ui->setupUi( this ) ; m_ui->checkBoxShareMountPoint->setToolTip( utility::shareMountPointToolTip() ) ; m_table = table ; m_Label.setOptions( m_ui->label,m_ui->pushButton ) ; this->setFixedSize( this->size() ) ; this->setWindowFlags( Qt::Window | Qt::Dialog ) ; this->setFont( parent->font() ) ; m_ui->pbMount->setFocus() ; m_ui->checkBoxMountReadOnly->setChecked( utility::getOpenVolumeReadOnlyOption( "zuluMount-gui" ) ) ; connect( m_ui->pbMount,SIGNAL( clicked() ),this,SLOT( pbMount() ) ) ; connect( m_ui->pbMountFolder,SIGNAL( clicked() ),this,SLOT( pbOpenMountPath() ) ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->checkBox,SIGNAL( stateChanged( int ) ),this,SLOT( stateChanged( int ) ) ) ; connect( m_ui->checkBoxMountReadOnly,SIGNAL( stateChanged(int) ),this,SLOT( checkBoxReadOnlyStateChanged( int ) ) ) ; m_ui->pbMountFolder->setIcon( QIcon( ":/folder.png" ) ) ; this->setFont( parent->font() ) ; m_ui->pbMountFolder->setVisible( false ) ; m_ui->frame->setVisible( false ) ; connect( m_ui->pbOptions,&QPushButton::clicked,[ this ](){ m_ui->lineEditFsOptions->setText( utility::fileSystemOptions( m_path ) ) ; m_ui->frame->setVisible( true ) ; } ) ; connect( m_ui->pbFrameCancel,&QPushButton::clicked,[ this ](){ m_ui->frame->setVisible( false ) ; } ) ; connect( m_ui->pbFrameSet,&QPushButton::clicked,[ this ](){ m_deviceOffSet = m_ui->lineEditVolumeOffset->text() ; m_key = m_ui->lineEditVolumePassword->text() ; m_options = m_ui->lineEditFsOptions->text() ; m_ui->frame->setVisible( false ) ; } ) ; this->installEventFilter( this ) ; } bool mountPartition::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->HideUI() ; } ) ; } void mountPartition::checkBoxReadOnlyStateChanged( int state ) { m_ui->checkBoxMountReadOnly->setEnabled( false ) ; m_ui->checkBoxMountReadOnly->setChecked( utility::setOpenVolumeReadOnly( this,state == Qt::Checked,"zuluMount-gui" ) ) ; m_ui->checkBoxMountReadOnly->setEnabled( true ) ; if( m_ui->lineEdit->text().isEmpty() ){ m_ui->lineEdit->setFocus() ; }else{ m_ui->pbMount->setFocus() ; } } void mountPartition::enableAll() { if( m_label != "Nil" ){ m_ui->checkBox->setEnabled( true ) ; } m_ui->checkBoxMountReadOnly->setEnabled( true ) ; m_ui->checkBoxShareMountPoint->setEnabled( true ) ; m_ui->labelMountPoint->setEnabled( true ) ; m_ui->lineEdit->setEnabled( true ) ; m_ui->pbCancel->setEnabled( true ) ; m_ui->pbMount->setEnabled( true ) ; m_ui->pbMountFolder->setEnabled( true ) ; m_ui->pbOptions->setEnabled( true ) ; } void mountPartition::disableAll() { m_ui->pbMount->setEnabled( false ) ; m_ui->checkBox->setEnabled( false ) ; m_ui->checkBoxMountReadOnly->setEnabled( false ) ; m_ui->checkBoxShareMountPoint->setEnabled( false ) ; m_ui->labelMountPoint->setEnabled( false ) ; m_ui->lineEdit->setEnabled( false ) ; m_ui->pbCancel->setEnabled( false ) ; m_ui->pbMountFolder->setEnabled( false ) ; m_ui->pbOptions->setEnabled( false ) ; } void mountPartition::pbCancel() { m_cancel() ; this->HideUI() ; } void mountPartition::reportError( utility::Task& e ) { switch ( e.exitCode() ){ case 0 : break ; case 112 : m_Label.show( tr( "Could not resolve path to device or device could not be opened in read write mode" ) ) ; break ; case 100 : m_Label.show( tr( "Insuffienct privileges to mount the volume with given mount options" ) ) ; break ; case 102 : m_Label.show( tr( "Device already mounted" ) ) ; break ; case 103 : m_Label.show( tr("Insuffienct privilege to manage a system volume.\nnecessary privileges can be acquired by:\n\ 1. Adding an entry for the volume in fstab with \"user\" mount option\n\2. Add yourself to \"zulumount\" group" ) ) ; break ; case 104 : m_Label.show( tr( "\"/etc/fstab\" entry for this volume requires it to be mounted read only" ) ) ; break ; case 113 : m_Label.show( tr( "\"/etc/fstab\" entry for this volume is malformed" ) ) ; break ; case 105 : m_Label.show( tr( "\"/etc/fstab\" entry for this volume does not allow you to mount it" ) ) ; break ; case 106 : m_Label.show( tr( "Could not create mount point path,path already taken" ) ) ; break ; case 114 : m_Label.show( tr( "Shared mount point path aleady taken" ) ) ; break ; case 108 : m_Label.show( tr( "Failed to mount a filesystem:invalid/unsupported mount option or unsupported file system encountered" ) ) ; break ; case 109 : m_Label.show( tr( "Failed to mount ntfs/exfat file system using ntfs-3g,is ntfs-3g/exfat package installed?" ) ) ; break ; case 110 : m_Label.show( tr( "Mount failed,no or unrecognized file system" ) ) ; break ; case 111 : m_Label.show( tr( "Mount failed,could not get a lock on /etc/mtab~" ) ) ; break ; case 115 : m_Label.show( tr("Failed to mount the partition" ) ) ; break ; default: { QString z = e.stdOut() ; z.replace( tr( "ERROR: " ),"" ) ; m_Label.show( z ) ; } } } void mountPartition::pbMount() { auto test_mount = m_ui->lineEdit->text() ; if( test_mount.contains( "/" ) ){ if( this->isVisible() ){ DialogMsg msg( this ) ; msg.ShowUIOK( tr( "ERROR" ),tr( "\"/\" character is not allowed in the mount name field" ) ) ; m_ui->lineEdit->setFocus() ; }else{ this->deleteLater() ; } return ; } this->disableAll() ; QString exe = zuluMountPath ; auto volume = m_path ; if( !volume.startsWith( "/dev/" ) ){ auto m = utility::loopDevicePath( volume ) ; if( !m.isEmpty() ){ volume = m ; } } volume.replace( "\"","\"\"\"" ) ; if( m_ui->checkBoxShareMountPoint->isChecked() ){ exe += " -M -m -d \"" + volume + "\"" ; }else{ exe += " -m -d \"" + volume + "\"" ; } QString m = m_ui->lineEdit->text().replace( "\"","\"\"\"" ) ; exe += " -z \"" + m + "\""; if( !m_deviceOffSet.isEmpty() ){ QString addr = utility::keyPath() ; utility::keySend( addr,m_key ) ; exe += " -o " + m_deviceOffSet + " -f " + addr ; } if( m_ui->checkBoxMountReadOnly->isChecked() ){ exe += " -e -ro" ; }else{ exe += " -e -rw" ; } utility::setFileSystemOptions( exe,volume,m,m_options ) ; auto s = utility::Task::run( utility::appendUserUID( exe ) ).await() ; if( s.success() ){ m_success( utility::mountPath( m_ui->lineEdit->text() ) ) ; this->HideUI() ; }else{ if( s.exitCode() == 103 ){ if( utility::enablePolkit( utility::background_thread::False ) ){ s = utility::Task::run( utility::appendUserUID( exe ) ).await() ; } } if( s.success() ){ m_success( utility::mountPath( m_ui->lineEdit->text() ) ) ; this->HideUI() ; }else{ if( this->isVisible() ){ this->reportError( s ) ; this->enableAll() ; }else{ this->deleteLater() ; } } } } void mountPartition::pbOpenMountPath() { auto p = tr( "Select Path To Mount Point Folder" ) ; auto Z = QFileDialog::getExistingDirectory( this,p,utility::homePath(),QFileDialog::ShowDirsOnly ) ; if( !Z.isEmpty() ){ while( true ){ if( Z.endsWith( '/' ) ){ Z.truncate( Z.length() - 1 ) ; }else{ break ; } } Z = Z + "/" + m_ui->lineEdit->text().split( "/" ).last() ; m_ui->lineEdit->setText( Z ) ; } } void mountPartition::ShowUI( const volumeProperty& e ) { m_path = e.volumeName() ; m_label = e.label() ; const auto& m = e.mountPoint() ; if( m.isEmpty() || m == "Nil" ){ m_point = utility::mountPathPostFix( m_path.split( "/" ).last() ) ; }else{ m_point = utility::mountPathPostFix( m ) ; } m_ui->lineEdit->setText( m_point ) ; bool r = m_label != "Nil" ; m_ui->checkBox->setEnabled( r ) ; m_ui->checkBox->setChecked( r && ( m.isEmpty() || m == "Nil" ) ) ; this->show() ; } void mountPartition::AutoMount( const volumeProperty& e ) { m_path = e.volumeName() ; const auto& label = e.label() ; const auto& m = e.mountPoint() ; if( m.isEmpty() || m == "Nil" ){ if( label != "Nil" ) { m_point = utility::mountPathPostFix( label ) ; }else{ m_point = utility::mountPathPostFix( m_path.split( "/" ).last() ) ; } }else{ m_point = m ; } m_ui->lineEdit->setText( m_point ) ; this->pbMount() ; } void mountPartition::stateChanged( int i ) { Q_UNUSED( i ) m_ui->checkBox->setEnabled( false ) ; if( m_ui->checkBox->isChecked() ){ m_ui->lineEdit->setText( utility::mountPathPostFix( m_label ) ) ; }else{ m_ui->lineEdit->setText( utility::mountPathPostFix( m_point ) ) ; } m_ui->checkBox->setEnabled( true ) ; } void mountPartition::HideUI() { this->hide() ; this->deleteLater() ; } void mountPartition::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbCancel() ; } mountPartition::~mountPartition() { delete m_ui ; } zuluCrypt-6.2.0/zuluMount-gui/mountpartition.h000066400000000000000000000045521425361753700216340ustar00rootroot00000000000000 /* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef MOUNTPARTITION_H #define MOUNTPARTITION_H #include #include #include "volumeproperty.h" #include "../zuluCrypt-gui/utility.h" #include #include class QTableWidget ; class QCloseEvent ; class QMenu ; class QAction ; namespace Ui { class mountPartition; } class mountPartition : public QWidget { Q_OBJECT public: static mountPartition& instance( QWidget * parent, QTableWidget * table, std::function< void() > cancel, std::function< void( const QString& ) > success ) { return *( new mountPartition( parent,table,std::move( cancel ),std::move( success ) ) ) ; } mountPartition( QWidget * parent, QTableWidget * table, std::function< void() >, std::function< void( const QString& ) > ) ; void ShowUI( const volumeProperty& ) ; void HideUI( void ) ; void AutoMount( const volumeProperty& ) ; ~mountPartition() ; signals: void cancel( void ) ; void openMountPoint( QString ) ; private slots: void stateChanged( int ) ; void pbMount( void ) ; void pbCancel( void ) ; void pbOpenMountPath( void ) ; void checkBoxReadOnlyStateChanged( int ) ; private: void reportError( utility::Task& ) ; void enableAll( void ) ; void disableAll( void ) ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::mountPartition * m_ui ; QString m_path ; QString m_label ; QString m_point ; QString m_deviceOffSet ; QString m_key ; QString m_options ; QTableWidget * m_table ; std::function< void() > m_cancel ; std::function< void( const QString& ) > m_success ; utility::label m_Label ; }; #endif // MOUNTPARTITION_H zuluCrypt-6.2.0/zuluMount-gui/mountpartition.ui000066400000000000000000000167571425361753700220340ustar00rootroot00000000000000 mountPartition 0 0 523 185 select mount point path 0 10 101 31 Mount Name Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 200 140 121 31 &Mount true true 410 10 31 31 180 40 231 31 Use La&bel 110 10 301 31 320 140 101 31 &Cancel true 180 70 161 41 Mount &Read Only 180 110 181 31 &Share Mount Point 100 140 101 31 &Options 10 10 501 171 true QFrame::StyledPanel QFrame::Raised 10 10 311 31 Set File System Options Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 20 40 301 51 Enter Below The Offset Location Of The Volume About To Be Opened Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 20 90 301 31 Enter The Password Below To A Volume At The Above Offset Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 330 10 151 31 330 50 151 31 330 90 151 31 QLineEdit::Password 140 130 111 33 Set 250 130 111 33 Cancel 10 0 501 181 true TextLabel Qt::AlignCenter true 200 140 121 31 &OK lineEdit pbMountFolder checkBox checkBoxMountReadOnly checkBoxShareMountPoint pbOptions pbMount pbCancel zuluCrypt-6.2.0/zuluMount-gui/oneinstance.cpp000066400000000000000000000051531425361753700213770ustar00rootroot00000000000000 /* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "oneinstance.h" #include #include "../zuluCrypt-gui/utility.h" #include #include oneinstance::oneinstance( QObject * parent, const QString& socketPath, const QString& argument, std::function< void( const QString& ) > start, std::function< void( int ) > exit, std::function< void( const QString& ) > event ) : QObject( parent ), m_serverPath( socketPath ), m_argument( argument ), m_start( std::move( start ) ), m_exit( std::move( exit ) ), m_event( std::move( event ) ) { if( QFile::exists( m_serverPath ) ){ connect( &m_localSocket,SIGNAL( connected() ),this,SLOT( connected() ) ) ; connect( &m_localSocket,SIGNAL( error( QLocalSocket::LocalSocketError ) ), this,SLOT( errorOnConnect( QLocalSocket::LocalSocketError ) ) ) ; m_localSocket.connectToServer( m_serverPath ) ; }else{ this->start() ; } } void oneinstance::start() { m_start( m_argument ) ; connect( &m_localServer,SIGNAL( newConnection() ),this,SLOT( gotConnection() ) ) ; m_localServer.listen( m_serverPath ) ; } void oneinstance::gotConnection() { std::unique_ptr< QLocalSocket > s( m_localServer.nextPendingConnection() ) ; s->waitForReadyRead() ; m_event( s->readAll() ) ; } void oneinstance::errorOnConnect( QLocalSocket::LocalSocketError e ) { Q_UNUSED( e ) utility::debug() << tr( "Previous instance seem to have crashed,trying to clean up before starting" ) ; QFile::remove( m_serverPath ) ; this->start() ; } void oneinstance::connected() { utility::debug() << tr( "There seem to be another instance running,exiting this one" ) ; if( !m_argument.isEmpty() ){ m_localSocket.write( m_argument.toLatin1() ) ; m_localSocket.waitForBytesWritten() ; } m_localSocket.close() ; m_exit( 255 ) ; } oneinstance::~oneinstance() { if( m_localServer.isListening() ){ m_localServer.close() ; QFile::remove( m_serverPath ) ; } } zuluCrypt-6.2.0/zuluMount-gui/oneinstance.h000066400000000000000000000036531425361753700210470ustar00rootroot00000000000000 /* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ONEINSTANCE_H #define ONEINSTANCE_H #include #include #include #include #include class oneinstance : public QObject { Q_OBJECT public: static void instance( QObject * a, const QString& b, const QString& c, std::function< void( const QString& ) > d, std::function< void( int ) > e, std::function< void( const QString& ) > f ) { new oneinstance( a,b,c,std::move( d ),std::move( e ),std::move( f ) ) ; } oneinstance( QObject *, const QString&, const QString&, std::function< void( const QString& ) >, std::function< void( int ) >, std::function< void( const QString& ) > ) ; ~oneinstance() ; private slots: void connected( void ) ; void gotConnection( void ) ; void errorOnConnect( QLocalSocket::LocalSocketError ) ; private: void start( void ) ; QLocalServer m_localServer ; QLocalSocket m_localSocket ; QString m_serverPath ; QString m_argument ; std::function< void( const QString& ) > m_start ; std::function< void( int ) > m_exit ; std::function< void( const QString& ) > m_event ; }; #endif // ONEINSTANCE_H zuluCrypt-6.2.0/zuluMount-gui/partition.png000066400000000000000000000026521425361753700211050ustar00rootroot00000000000000‰PNG  IHDR D¤ŠÆsBITÛáOà pHYsvv}Õ‚ÌtEXtSoftwarewww.inkscape.org›î<[PLTEÿÿÿ333MMM LLLKKKIIINNNhhhiiiTTTWWW|||PPPEEEHHHwwwyyy“““ 000EEE!!!!!!ŽŽŽ£££žžž   ­­­®®®žžžŸŸŸªªª¬¬¬­­­®®®¯¯¯±±±²²²µµµ¸¸¸´´´”””•••ÀÀÀÁÁÀÁÁÁÂÂÁ¸¸¸¹¹¹¼¼¼½½½ÁÁÁÃÃÃÁÁÁÂÂÂÊÊÊÆÆÆ»»»ÉÉÉÐÐÐ&&&---4_4999IIILLLRRR[[[]]]```ggghjhjjjkkkmmmpppssstttuuuu†uvvvwwwyyy~~~†††’’’˜˜˜™™™šššŸŸŸ¡¡¡¢¢¢£££¤¤¤¥¥¥¦¦¦§§§¨¨¨©©©ªªª«««¬¬¬®®®¯¯¯°°°±±±²²²³³³´´´µµµ¶¶¶···¸¸¸¹¹¹ººº»»»¼¼¼½½½¾¾¾¿¿¿ÀÀÀÁÁÁÂÂÂÃÃÃÄÄÄÅÅÅÆÆÆÇÇÇÈÈÈÉÉÉÊÊÊËËËÌÌÌÍÍÍÎÎÎÏÏÏÐÐÐÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝàààáááâââãããäääåååæææççåçççèèæèèèêêêëëëìììííëîîìïïîïïïððîðððñññóóóôôôõõõöööùùùúúúûûûüüû>Àç¨PtRNS  "$(,44EI[[cwzzƒƒˆŒŒŽ¡¢££¨¾¾ÁÁÄÄÓÓÓÓÓÓÓÖÙÛÜÜãããããääççððññùúþþþ¬n[eIDATxÚ…ÎÍnYÅñSuËÝí¯Ä JB€Ye1š'˜€-¼Ø<Éðh6,BH€€Lˆ¤ýQuÆ×F°Ä_-õâþîÑůåAç²™4”4pÁ`{ò¢ Þ÷öï\¹.0Õâͤ&Qwÿ>ajv{òòuRUQL7†{ ¿Û;aê+P4êѪˆ@àu·EËð(Ö@ªâ°[HåÞç§; ¤^ 2H©à¦‰ t»óñp§"ȆSJ+ ¥E ÛUýLvc“ F)kгÎdsPñüU£!-£÷ ˜œþV¿_”=¬¢ ¥Ú¨½ì_v+ÌÇùk…ÔŸ’šŽjN6„Œà²È¿vÍóÓõ‚J9ÙÁï nß¼ñÇc¡A,á3;³ø¡qäoßmþn!·_•|]êMÈÏù÷ßÔL<ìSÞ_´éî€ò§Eï+|YÛ0ÒM-ÇZ’ZñÃøaðñ’µ7Û2{ß÷ÙñÖQjQÊ„dH&6'ö îmŽjtk2#äÙ´6]ÑKýò~W@×b€ŽúöºöH¶™ “oÈ_ÀÏåwò;áã%f[ìáXÛ]Îy9·ïè>ßc н¢=éÙ*vÚï/º¹ÝÅ­k„nB.@ux-¯–Š*GUìejx¿ðxŽO³c³ÂÂ’ö6©2Y§ÆM·õ$÷‰ú–½Ô˜zéÖöëÇm¯ÛÒÚÌY’͹€¦¢æÒæRøøà/T ªÒk2Õ3Õ/ÜË8bb@ÈM‡°¿…™½U©‘~ðsõiBº¦vLïP>tð·ÖÞÞ—Ý–Iqìw¢ý­Ák€z×z—z iôr´Ú‚Eû¡ÿ÷wN7Œ tcqE¾JžBžÒ{û^H`ˆëP_ù­Ò)¥a„›OZ×Ç÷™wïåô\ÔŠ¼Yò;Úöxí™ú@ñG Ñ‘è  Ɔ:‚1þëÀÛœ5@ž]^N^^Éþ¿(‹(B2 “ù) C¤…Ûج=t¼ýˆhHteIèë]ýÉýª¢Ÿ„§„ú¬Æúuu‘u±ŒŠÿ›^*É*jYMÌË3j…8êIFÔRK½ÊRGÿØ™è“è,tzä™ðœxNÝ’À²çeÏÖ'-Hš¨öÖ — wB¢î„v„>y;³AP§_×EHÛÂTáãK;íÚÙíf‡²¬æZ­“Z‹7¡žîMýi"Σ‰ZõGjåjÅ©˜Ej¹èjj¥>¼ž ˆ£æ ­Ñ]è@fbFé opÿÉcÀc€5+À;$'$Àî¨C’CüÔ5…=¢‚ŽîÚÈMׯ]?CÈOCeûÊ*‡ðN$+:Ãï\ûùÚ 5=ópߟ=(i.¹Gr§Úl¬ä|êq®@¹âH¡™h3V@õÆ_©Ù•@Y„¶aîéh„ÃÄÚSOéÄùÝÁ¼RA>ÀÖ¡H–J~“ü6V=Õ/>(>€ßÇÛÅ;ö·Ô6U6ÿ@HÑ`a_‘¦±°êMåÊ0€ûGï±îmbŸ¬Õ{téQÕ‡æZ:üA™‘ˆ\´7N¤ Çsp\Hm@ýÙçú•Ì ñNÑ8€ÆŽ˜…ËÕaÁ0Ç·b)»Fv·ìîYá8JTÏÏl3Ýü%¹î¹^„ w§! ÔD?pªþšÊÆ»*ý{ róVJ¸§ºüìö†ý cw×Eq¬0P?cÂ<êÍí€*ãf" žú—Ö1ênXÙÔ’×ðú ƧŸQŸºAýePÖzB$B¢fˆÁ.Ë?ž¿9ßäáêh÷¡7ü†—¿Ô°Ô•á ~²pzÚwâÿ3°—ãx6°>k3Z ÄÐ0ÂÀ°a°ee]0ÐqXá[Ôò¡ŒÎa.ú4Ùˆç_p¢^¬âèý6²é¨º«^W½®T”û©~ióÓ>sý:S7õJj!IêQ­Q‰„<[&òox¾.ìËÃáÓ‘Kn,ŒžP2WRÊâ+Ãj1Æa€ëfRéc…l©Õnb¥—Ps¼@UF¡$õ–Úvõ±õØaŒÀY½#?¬ÃN­SôS¬V¬–½4RÉs†çƒÏiÄ,âÝàż²üÞ%H?Héýã»Gó½"ä©CCq£¯¿Û¬Sú9€è¸HËI lµáDÌøp ³±%DRoh¦þÄ+ëŸSq¦ Ñ;0pCCmµ‡4µ!úOáõ½€Aõ™ š4ÿ÷ŒŒs„¹z¹zéÑÙ§Òæ¦Í%¤2½Â»Â‹¶ßDmí:¾ŒÖöv»r<®Ñ²ØÔKúñ, laܦ¢‹Ñ³·1[càMxºã|- T£‘G›£æîÉÌd¿¹Û^¥^¥À“ÊŸ’?ÙÝë¸×KHyx‰w‰íÐ7­ü:Á9BZýùW„:ËVb%”9µœ*N£ëÇ`|Ó@œèp4Äa£fÅu©¿ÃßÌ8 PfŒ~]ÄBÊâ[‹oâ®ÆÅÇÅü`±'bðÎÆxGxGxôäzúË¿ºóîNô›BÃ’µë ´ yüªþJýmB„ñ­;D’~m¸y¥h:j~¡yrRïäàÉÂâ G*h8Ê ‡1ßé ÆšO¨¿Z†‰À¸ŒË(•q·ÆåŒËˆpEˆøòü¹ü¹µCujujìÁ§_5NlœP¼½¸«¸Ó¿§´£Ø»ø!w¯WL©`Ò6^ø‡h@øì¦mdÏÍ<ùÀÛìb«Ûý«ôlVÍ`¤` Ì@ F  “Em:‰‘ I´6~îÈH]Gù{£ù0J!J É&©!© =+Ã9Ùõ>­9ckÆV€d©”E) W8”Ÿ¼íw;ˆäÚgÍÉb ]|úyÃëÇñ„ü̽Ÿ_£¿³¹3ï™BW6_¢I…¿›Í(6íLØjcÒ³Õ˜H2÷1ªQ\q •á¯âœÏ¹Ès‘¾Ò¾;|wXÙ[Z‚nrihH\˜x4ѱ¼Škæ³Ëg !é“Z“§Rgú°³.;qãùàØÈøDSó‰üÑ*Âbtˆ:¶rˆƒ->ñ!µÆ6êy˜  PËÄ€8Ça¬$œOx‘ðàÒayy€À3W]=Ä¼Æ ‘ ‘¸`|±÷b¯íÙk½WW]]CH”Æu7–R{ñÑ–Z‡æù³²4žÿzIìâ/—xöN9³¢­/â[{1×&»Ęˆk[[ŠZ^ƒz½+õ®Ljãd\<üýNLØIæ“&¢c%8>x xÀLÛ|Ÿù>+›Õ6«ÁoŠÃLáL!À2 ½.½–ñ¼y©^©—ŸÚ†ÊÞ L$¤L¿˜Wâ@ÈÍú˜î؆­Õ™ 2ô³ÜòÂr%yò>°Ôà_–|“ƒ… >fMm²—zQ0õâ-ÔóÏ`âƒ8à¿E)O©I© à ß_Î_ Ï*ïDÞ €ìíÃ_¢Zræ•ê””mˆÚm}Ôë%Wӧݧ†Ôœÿ„nBÈTõ?¨ô1íÜÞ1¹Ë J+"4j‹D!P~°‡_ˆA6µßWÔÞï¨w˜c ¹ÔZ˜¯:jÅ0 82–Òvfb6zì]pôÝÑw.Z.e.ež gΰ”½+.{]öð¾ésØÇñs6§Ïœvo}73¢0â!í«…EísÂUÅ÷À‰OÖ¦¾¬C}¦‡úSƦ½ŠZj$>šÉ-táØvý±ÃAO{p>fãXúX¸½ª½*ûûcKíŒíÌÓ|säìæü@®¯Ìå÷„4èÔ&Öfï àùgûYÈÏ’û]îþ¬ü 0œZÿ £rÒŒ˜" +ÇåŒûüx´‡vEëíüÑBÛB`è$ê/×ÈÖÈ$ZG÷D?a×]×áÞãFœÝç¶ÜM=(«4¦°¿ÈôáœG˜¨Ÿ<ÉÚÃ:À²1¾>,aý“¿º‚ˆ z#Acè1L1¡Êøëg2±2ûevSÅëu¯¹¸JEÏiÒ†œWO2µŠ¦ýjÈ5RÞ€·ënÿÂ+r~,®i¹MØâCètôLœ.µä.¼¾35ç"Î#XƒVŠ3ZÆ†Ä jE#j‰ÔÚ˜©µ¾Ô_HRü œMqìÊù–óŽÓFLŒÞ§Û8[^›Ì¶éðW¬^áa~¿ƒÜÏncW³êâý{yõRuj­—Ôóñ}MGœÏtê™ذة*ýÔSݨ'ã˜x<‹Zú>&2ÃøúÕ‚KH/¤D­ú'H=ïsê…[©m€I  ‹ÿ†»õzÖO¬4VÚ’HÎJŽGé3'ü\#LeP^(±x‰zÎrjõG¨1K=½zÚ\j%C,˜=|ÆÄɰ°“œ0ðiÔ)Æ]bý?-´™­X#°"zTXtSoftwarexÚ+//×ËÌË.NN,HÕË/J6ØXSÊ\IEND®B`‚zuluCrypt-6.2.0/zuluMount-gui/siritask.cpp000066400000000000000000000334221425361753700207220ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "siritask.h" #include "bin_path.h" #include #include #include #include using cs = siritask::status ; static QString _makePath( const QString& e ) { return utility::Task::makePath( e ) ; } static bool _m( const QString& e ) { return utility::Task( utility::appendUserUID( e ) ).success() ; } static bool _delete_folder( const QString& m ) { return _m( QString( "%1 -b %2" ).arg( zuluMountPath,m ) ) ; } static bool _create_folder( const QString& m ) { return _m( QString( "%1 -B %2" ).arg( zuluMountPath,m ) ) ; } template< typename ... T > static bool _deleteFolders( const T& ... m ) { bool s = false ; for( const auto& it : { m ... } ){ s = _delete_folder( it ) ; } return s ; } template< typename T > static bool _ecryptfs( const T& e ) { return utility::equalsAtleastOne( e,"ecryptfs","ecryptfs-simple" ) ; } template< typename T > static utility::Task::USEPOLKIT _ecryptfs_1( const T& e ) { if( _ecryptfs( e ) ){ return utility::Task::USEPOLKIT::True ; }else{ return utility::Task::USEPOLKIT::False ; } } static bool _ecryptfs_illegal_path( const siritask::options& opts ) { if( _ecryptfs( opts.type ) && utility::useZuluPolkit() ){ return opts.cipherFolder.contains( " " ) || opts.plainFolder.contains( " " ) ; }else{ return false ; } } static QString _wrap_su( const QString& s ) { auto su = utility::executableFullPath( "su" ) ; if( su.isEmpty() ){ return s ; }else{ return QString( "%1 - -c \"%2\"" ).arg( su,QString( s ).replace( "\"","'" ) ) ; } } bool siritask::deleteMountFolder( const QString& m ) { if( utility::reUseMountPoint() ){ return false ; }else{ return _deleteFolders( m ) ; } } Task::future< bool >& siritask::encryptedFolderUnMount( const QString& cipherFolder, const QString& mountPoint, const QString& fileSystem ) { return Task::run( [ = ](){ auto ecryptfs = _ecryptfs( fileSystem ) ; auto cmd = [ & ](){ if( ecryptfs ){ auto exe = utility::executableFullPath( "ecryptfs-simple" ) ; auto s = exe + " -k " + _makePath( cipherFolder ) ; if( utility::useZuluPolkit() ){ return _wrap_su( s ) ; }else{ return s ; } }else{ if( utility::platformIsOSX() ){ return "umount " + _makePath( mountPoint ) ; }else{ return "fusermount -u " + _makePath( mountPoint ) ; } } } ; const int max_count = 5 ; if( ecryptfs ){ bool not_set = true ; auto exe = cmd() ; for( int i = 0 ; i < max_count ; i++ ){ auto s = utility::Task::run( exe,10000,utility::Task::USEPOLKIT::True ).get() ; if( s.success() ){ return true ; }else{ if( not_set && s.stdError().contains( "error: failed to set gid" ) ){ if( utility::enablePolkit( utility::background_thread::True ) ){ not_set = false ; exe = cmd() ; }else{ return false ; } }else{ utility::Task::waitForOneSecond() ; } } } }else{ for( int i = 0 ; i < max_count ; i++ ){ auto s = utility::Task::run( cmd(),10000,utility::Task::USEPOLKIT::False ).get() ; if( s.success() ){ return true ; }else{ utility::Task::waitForOneSecond() ; } } } return false ; } ) ; } static QString _args( const QString& exe,const siritask::options& opt, const QString& configFilePath, bool create ) { auto cipherFolder = _makePath( opt.cipherFolder ) ; auto mountPoint = _makePath( opt.plainFolder ) ; const auto& type = opt.type ; auto mountOptions = [ & ](){ if( !opt.mOpt.isEmpty() ){ if( type == "cryfs" ){ return QString( "--unmount-idle %1" ).arg( opt.mOpt ) ; }else if( type == "encfs" ){ return QString( "--idle=%1" ).arg( opt.mOpt ) ; } } return QString() ; }() ; auto separator = [ & ](){ if( type == "cryfs" ){ return "--" ; }else if( type == "encfs" ){ return "-S" ; }else{ return "" ; } }() ; auto configPath = [ & ](){ if( type.isOneOf( "cryfs","gocryptfs","securefs","ecryptfs" ) ){ if( !configFilePath.isEmpty() ){ return "--config " + _makePath( configFilePath ) ; } } return QString() ; }() ; if( type.isOneOf( "gocryptfs","securefs" ) ){ QString mode = [ & ](){ if( opt.ro ){ return "-o ro" ; }else{ return "-o rw" ; } }() ; if( type == "gocryptfs" ){ if( create ){ auto e = QString( "%1 --init %2 %3" ) ; return e.arg( exe,configPath,cipherFolder ) ; }else{ mode += ",fsname=gocryptfs@" + cipherFolder ; auto e = QString( "%1 %2 %3 %4 %5" ) ; return e.arg( exe,configPath,cipherFolder,mountPoint,mode ) ; } }else{ if( create ){ auto e = QString( "%1 create %2 %3" ) ; return e.arg( exe,configPath,cipherFolder ) ; }else{ auto e = QString( "%1 mount -b %2 %3 %4 %5,fsname=securefs@%6,subtype=securefs" ) ; return e.arg( exe,configPath,cipherFolder,mountPoint,mode,cipherFolder ) ; } } }else if( _ecryptfs( type ) ){ auto _options = []( const std::initializer_list< const char * >& e ){ QString q = "-o key=passphrase" ; for( const auto& it : e ){ q += it ; } return q ; } ; auto mode = [ & ](){ if( opt.ro ){ return "--readonly" ; }else{ return "" ; } }() ; auto e = QString( "%1 %2 %3 -a %4 %5 %6" ) ; auto s = [ & ]{ if( create ){ auto s = _options( { ",ecryptfs_passthrough=n", ",ecryptfs_enable_filename_crypto=y", ",ecryptfs_key_bytes=32", ",ecryptfs_cipher=aes" } ) ; return e.arg( exe,s,mode,configPath,cipherFolder,mountPoint ) ; }else{ return e.arg( exe,_options( {} ),mode,configPath,cipherFolder,mountPoint ) ; } }() ; if( utility::runningInMixedMode() ){ return _wrap_su( s ) ; }else{ return s ; } }else{ auto e = QString( "%1 %2 %3 %4 %5 %6 -o fsname=%7@%8,subtype=%9" ) ; auto opts = e.arg( exe,cipherFolder,mountPoint,mountOptions,configPath, separator,type.name(),cipherFolder,type.name() ) ; if( opt.ro ){ return opts + ",ro" ; }else{ return opts + ",rw" ; } } } enum class status_type{ exeName,exeNotFound } ; static siritask::status _status( const siritask::volumeType& app,status_type s ) { if( s == status_type::exeNotFound ){ if( app == "cryfs" ){ return cs::cryfsNotFound ; }else if( app == "encfs" ){ return cs::encfsNotFound ; }else if( app == "securefs" ){ return cs::securefsNotFound ; }else if( _ecryptfs( app ) ){ return cs::ecryptfs_simpleNotFound ; }else{ return cs::gocryptfsNotFound ; } }else{ if( app == "cryfs" ){ return cs::cryfs ; }else if( app == "encfs" ){ return cs::encfs ; }else if( app == "securefs" ){ return cs::securefs ; }else if( _ecryptfs( app ) ){ return cs::ecryptfs ; }else{ return cs::gocryptfs ; } } } static siritask::cmdStatus _status( const utility::Task& r,siritask::status s,bool stdOut ) { if( r.success() ){ return siritask::status::success ; } siritask::cmdStatus e = { r.exitCode(),stdOut ? r.stdOut() : r.stdError() } ; const auto msg = e.msg().toLower() ; /* * * When trying to figure out what error occured,check for status value * if the backend supports them and fallback to parsing output strings * if backend does not support error codes. * */ if( s == siritask::status::ecryptfs ){ if( msg.contains( "operation not permitted" ) ){ e = siritask::status::ecrypfsBadExePermissions ; }else if( msg.contains( "error: mount failed" ) ){ e = s ; } }else if( s == siritask::status::cryfs ){ const auto& m = e.msg() ; if( msg.contains( "password" ) ){ e = s ; }else if( m.contains( "This filesystem is for CryFS" ) && m.contains( "It has to be migrated" ) ){ e = siritask::status::cryfsMigrateFileSystem ; } }else if( s == siritask::status::encfs ){ if( msg.contains( "password" ) ){ e = s ; } }else if( s == siritask::status::gocryptfs ){ /* * This error code was added in gocryptfs 1.2.1 */ if( e.exitCode() == 12 ){ e = s ; }else{ if( msg.contains( "password" ) ){ e = s ; } } }else if( s == siritask::status::securefs ){ if( msg.contains( "password" ) ){ e = s ; } } return e ; } static siritask::cmdStatus _cmd( bool create,const siritask::options& opt, const QString& password,const QString& configFilePath ) { const auto& app = opt.type ; auto exe = app.executableFullPath() ; if( exe.isEmpty() ){ return _status( app,status_type::exeNotFound ) ; }else{ auto _run = [ & ](){ auto s = utility::Task( _args( exe,opt,configFilePath,create ), 20000, utility::systemEnvironment(), password.toLatin1(), [](){}, _ecryptfs_1( app ) ) ; return _status( s,_status( app,status_type::exeName ),app == "encfs" ) ; } ; auto e = _run() ; if( e == siritask::status::ecrypfsBadExePermissions ){ if( utility::enablePolkit( utility::background_thread::True ) ){ e = _run() ; } } if( e != siritask::status::success ){ auto s = QString::number( e.exitCode() ) ; auto m = e.msg() ; while( true ){ if( m.endsWith( '\n' ) ){ m.truncate( m.size() - 1 ) ; }else{ break ; } } utility::debug() << "-------------------------" ; utility::debug() << QString( "Backend Generated Output:\nExit Code: %1" ).arg( s ) ; utility::debug() << QString( "Exit String: \"%1\"" ).arg( m ) ; utility::debug() << "-------------------------" ; } return e ; } } static QString _configFilePath( const siritask::options& opt ) { if( opt.configFilePath.startsWith( "/" ) || opt.configFilePath.isEmpty() ){ return opt.configFilePath ; }else{ return utility::homePath() + "/" + opt.configFilePath ; } } Task::future< siritask::cmdStatus >& siritask::encryptedFolderMount( const options& opt,bool reUseMountPoint ) { return Task::run( [ opt,reUseMountPoint ]()->siritask::cmdStatus{ auto _mount = [ reUseMountPoint ]( const QString& app,const options& copt, const QString& configFilePath )->siritask::cmdStatus{ auto opt = copt ; opt.type = app ; if( _ecryptfs_illegal_path( opt ) ){ return cs::ecryptfsIllegalPath ; } if( _create_folder( opt.plainFolder ) || reUseMountPoint ){ auto e = _cmd( false,opt,opt.key,configFilePath ) ; if( e == cs::success ){ opt.openFolder( opt.plainFolder ) ; }else{ siritask::deleteMountFolder( opt.plainFolder ) ; } return e ; }else{ return cs::failedToCreateMountPoint ; } } ; if( opt.configFilePath.isEmpty() ){ if( utility::pathExists( opt.cipherFolder + "/cryfs.config" ) ){ return _mount( "cryfs",opt,QString() ) ; }else if( utility::pathExists( opt.cipherFolder + "/gocryptfs.conf" ) ){ return _mount( "gocryptfs",opt,QString() ) ; }else if( utility::pathExists( opt.cipherFolder + "/.securefs.json" ) ){ return _mount( "securefs",opt,QString() ) ; }else if( utility::pathExists( opt.cipherFolder + "/.ecryptfs.config" ) ){ return _mount( "ecryptfs",opt,opt.cipherFolder + "/.ecryptfs.config" ) ; }else{ auto encfs6 = opt.cipherFolder + "/.encfs6.xml" ; auto encfs5 = opt.cipherFolder + "/.encfs5" ; auto encfs4 = opt.cipherFolder + "/.encfs4" ; if( utility::atLeastOnePathExists( encfs6,encfs5,encfs4 ) ){ return _mount( "encfs",opt,QString() ) ; }else{ return cs::unknown ; } } }else{ auto e = _configFilePath( opt ) ; if( utility::pathExists( e ) ){ if( e.endsWith( "gocryptfs.conf" ) ){ return _mount( "gocryptfs",opt,e ) ; }else if( e.endsWith( "securefs.json" ) ){ return _mount( "securefs",opt,e ) ; }else if( e.endsWith( "ecryptfs.config" ) ){ return _mount( "ecryptfs",opt,e ) ; }else if( e.endsWith( "cryfs.config" ) ){ return _mount( "cryfs",opt,e ) ; }else{ return cs::unknown ; } }else{ return cs::unknown ; } } } ) ; } Task::future< siritask::cmdStatus >& siritask::encryptedFolderCreate( const options& opt ) { return Task::run( [ opt ]()->siritask::cmdStatus{ if( _create_folder( opt.cipherFolder ) ){ if( _create_folder( opt.plainFolder ) ){ auto e = _cmd( true,opt,[ & ]()->QString{ if( opt.type.isOneOf( "cryfs","gocryptfs" ) ){ return opt.key ; }else if( opt.type == "securefs" ){ return opt.key + "\n" + opt.key ; }else if( opt.type == "ecryptfs" ){ return opt.key ; }else{ return "p\n" + opt.key ; } }(),[ & ](){ auto e = _configFilePath( opt ) ; if( e.isEmpty() && opt.type == "ecryptfs" ){ return opt.cipherFolder + "/.ecryptfs.config" ; }else{ return e ; } }() ) ; if( e == cs::success ){ if( opt.type.isOneOf( "gocryptfs","securefs" ) ){ e = siritask::encryptedFolderMount( opt,true ).get() ; if( e != cs::success ){ _deleteFolders( opt.cipherFolder,opt.plainFolder ) ; } }else{ opt.openFolder( opt.plainFolder ) ; } }else{ _deleteFolders( opt.plainFolder,opt.cipherFolder ) ; } return e ; }else{ _deleteFolders( opt.cipherFolder ) ; return cs::failedToCreateMountPoint ; } }else{ return cs::failedToCreateMountPoint ; } } ) ; } zuluCrypt-6.2.0/zuluMount-gui/siritask.h000066400000000000000000000110361425361753700203640ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef SIRITASK_H #define SIRITASK_H #include "volumeproperty.h" #include "task.hpp" #include "../zuluCrypt-gui/utility.h" #include #include #include namespace siritask { class volumeType { public: volumeType() { } template< typename T > volumeType( const T& type ) : m_type( type ) { } template< typename T > volumeType& operator=( const T& e ) { m_type = e ; return *this ; } const QString& name() const { return m_type ; } template< typename T > bool startsWith( const T& e ) const { return m_type.startsWith( e ) ; } QString executableFullPath() const { return utility::executableFullPath( m_type ) ; } template< typename T > bool operator==( const T& type ) const { return m_type == type ; } template< typename T > bool operator!=( const T& type ) const { return m_type != type ; } template< typename ... T > bool isOneOf( const T& ... t ) const { return utility::equalsAtleastOne( m_type,t ... ) ; } private: QString m_type ; }; struct options { using function_t = std::function< void( const QString& ) > ; options( const QString& cipher_folder, const QString& plain_folder, const QString& volume_key, const QString& mount_options, const QString& config_file_path, const QString& volume_type, bool unlock_in_read_only, function_t folder_opener = []( const QString& e ){ Q_UNUSED( e ) } ) : cipherFolder( cipher_folder ), plainFolder( plain_folder ), key( volume_key ), mOpt( mount_options ), configFilePath( config_file_path ), type( volume_type ), ro( unlock_in_read_only ), openFolder( folder_opener ) { } QString cipherFolder ; QString plainFolder ; QString key ; QString mOpt ; QString configFilePath ; siritask::volumeType type ; bool ro ; function_t openFolder ; }; enum class status { success, cryfs, encfs, gocryptfs, securefs, ecryptfs, ecryptfsIllegalPath, ecrypfsBadExePermissions, gocryptfsNotFound, cryfsNotFound, encfsNotFound, securefsNotFound, ecryptfs_simpleNotFound, unknown, failedToCreateMountPoint, backendFail, cryfsMigrateFileSystem }; class cmdStatus { public: cmdStatus() { } template< typename T = QString > cmdStatus( const siritask::cmdStatus& s,const T& e = T() ) { m_status = s.status() ; m_exitCode = s.exitCode() ; if( e.isEmpty() ){ m_message = s.msg() ; }else{ m_message = e ; } } template< typename T = QString > cmdStatus( siritask::status s,const T& e = T() ) : m_status( s ),m_message( e ) { } template< typename T > cmdStatus( int s,const T& e ) : m_exitCode( s ),m_message( e ) { } siritask::status status() const { return m_status ; } bool operator==( siritask::status s ) const { return m_status == s ; } bool operator!=( siritask::status s ) const { return m_status != s ; } cmdStatus& setExitCode( int s ) { m_exitCode = s ; return *this ; } cmdStatus& setStatus( siritask::status s ) { m_status = s ; return *this ; } template< typename T > cmdStatus& setMessage( const T& e ) { m_message = e ; return *this ; } const QString& msg() const { return m_message ; } int exitCode() const { return m_exitCode ; } private: int m_exitCode = -1 ; siritask::status m_status = siritask::status::backendFail ; QString m_message ; }; bool deleteMountFolder( const QString& ) ; Task::future< bool >& encryptedFolderUnMount( const QString& cipherFolder, const QString& mountPoint, const QString& fileSystem ) ; Task::future< siritask::cmdStatus >& encryptedFolderMount( const options&,bool = false ) ; Task::future< siritask::cmdStatus >& encryptedFolderCreate( const options& ) ; } #endif // SIRITASK_H zuluCrypt-6.2.0/zuluMount-gui/veracryptpimdialog.cpp000066400000000000000000000044161425361753700227770ustar00rootroot00000000000000/* * * Copyright (c) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "veracryptpimdialog.h" #include "ui_veracryptpimdialog.h" #include "../zuluCrypt-gui/utility.h" #include "../zuluCrypt-gui/dialogmsg.h" VeraCryptPIMDialog::VeraCryptPIMDialog( QWidget * parent,std::function< void( int ) > function ) : QDialog( parent ),m_ui( new Ui::VeraCryptPIMDialog ),m_function( std::move( function ) ) { m_ui->setupUi( this ) ; this->setFixedSize( this->size() ) ; this->setWindowFlags( Qt::Window | Qt::Dialog ) ; this->setFont( parent->font() ) ; connect( m_ui->pbCancel,SIGNAL( clicked() ),this,SLOT( pbCancel() ) ) ; connect( m_ui->pbSet,SIGNAL( clicked() ),this,SLOT( pbSet() ) ) ; m_ui->label->setText( tr( "Set VeraCrypt dynamic mode magic number below." ) ) ; m_ui->lineEditPIM->setFocus() ; this->Show() ; } bool VeraCryptPIMDialog::eventFilter( QObject * watched,QEvent * event ) { return utility::eventFilter( this,watched,event,[ this ](){ this->pbCancel() ; } ) ; } void VeraCryptPIMDialog::closeEvent( QCloseEvent * e ) { e->ignore() ; this->pbCancel() ; } void VeraCryptPIMDialog::Show() { this->show() ; } void VeraCryptPIMDialog::Hide() { this->hide() ; this->deleteLater() ; } VeraCryptPIMDialog::~VeraCryptPIMDialog() { delete m_ui ; } void VeraCryptPIMDialog::pbSet() { bool ok ; auto e = m_ui->lineEditPIM->text().toInt( &ok ) ; if( ok ){ m_function( e ) ; this->Hide() ; }else{ DialogMsg msg( this ) ; msg.ShowUIOK( tr( "ERROR" ),tr( "Failed to convert the value to digits only " ) ) ; } } void VeraCryptPIMDialog::pbCancel() { m_function( 0 ) ; this->Hide() ; } zuluCrypt-6.2.0/zuluMount-gui/veracryptpimdialog.h000066400000000000000000000031151425361753700224370ustar00rootroot00000000000000/* * * Copyright (c) 2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef VERACRYPTPIMDIALOG_H #define VERACRYPTPIMDIALOG_H #include #include #include #include #include class QCloseEvent ; namespace Ui { class VeraCryptPIMDialog ; } class VeraCryptPIMDialog : public QDialog { Q_OBJECT public: static VeraCryptPIMDialog& instance( QWidget * parent,std::function< void( int ) > function ) { return *( new VeraCryptPIMDialog( parent,std::move( function ) ) ) ; } explicit VeraCryptPIMDialog( QWidget * parent,std::function< void( int ) > ) ; ~VeraCryptPIMDialog() ; private slots: void pbSet() ; void pbCancel() ; private: void Show() ; void Hide() ; void closeEvent( QCloseEvent * ) ; bool eventFilter( QObject * watched,QEvent * event ) ; Ui::VeraCryptPIMDialog * m_ui ; std::function< void( int ) > m_function ; }; #endif // VERACRYPTPIMDIALOG_H zuluCrypt-6.2.0/zuluMount-gui/veracryptpimdialog.ui000066400000000000000000000031131425361753700226230ustar00rootroot00000000000000 VeraCryptPIMDialog 0 0 480 182 VeraCrypt PIM value 139 150 101 31 &Set 239 150 101 31 &Cancel 20 10 451 91 TextLabel Qt::AlignCenter 20 110 441 31 QLineEdit::Password zuluCrypt-6.2.0/zuluMount-gui/volumeproperty.cpp000066400000000000000000000104131425361753700222000ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "volumeproperty.h" #if 0 static void setFsSize( const QString& path,QString * volumeSize,QString * usedPercentage ) { struct statfs vfs ; auto passed = Task::await< bool >( [ & ](){ return statfs( path.toLatin1().constData(),&vfs ) == 0 ; } ) ; if( passed ){ quint64 s = vfs.f_bsize * ( vfs.f_blocks - vfs.f_bavail ) ; *volumeSize = utility::prettyfySpaceUsage( s ) ; if( vfs.f_bfree == 0 ){ *usedPercentage = "100%" ; }else{ quint64 s = vfs.f_blocks - vfs.f_bavail ; auto e = double( s ) / double( vfs.f_blocks ) * 100 ; if( e < 0.01 ){ *usedPercentage = "0%" ; }else{ *usedPercentage = QString::number( e,'f',2 ) + "%" ; } } }else{ *usedPercentage = "Nil" ; } } #else static void setFsSize( const QString& path,QString * volumeSize,QString * usedPercentage ) { Q_UNUSED( path ) Q_UNUSED( volumeSize ) Q_UNUSED( usedPercentage ) } #endif bool volumeProperty::encryptedFolder( const QString& s,bool f ) { auto e = s.toLower() ; if( f ){ return utility::equalsAtleastOne( e,"nil","cryptfs","cryfs","encfs", "gocryptfs","securefs","ecryptfs" ) ; }else{ return utility::equalsAtleastOne( e,"cryptfs","cryfs","encfs", "gocryptfs","securefs","ecryptfs" ) ; } } volumeProperty::volumeProperty( const QStringList& l,bool isSystem ) { this->setValues( l,isSystem ) ; } volumeProperty::volumeProperty( const std::initializer_list& l,bool isSystem ) { this->setValues( l,isSystem ) ; } const QString& volumeProperty::volumeName() const { return m_volume ; } const QString& volumeProperty::mountPoint() const { return m_mountPoint ; } const QString& volumeProperty::fileSystem() const { return m_fileSystem ; } const QString& volumeProperty::label() const { return m_label ; } const QString& volumeProperty::volumeSize() const { return m_volumeSize ; } const QString& volumeProperty::spaceUsedPercentage() const { return m_usedSpacePercentage ; } bool volumeProperty::isSystem() const { return m_isSystem ; } bool volumeProperty::isEmpty() const { return m_volume.isEmpty() ; } bool volumeProperty::isNotEmpty() const { return !m_volume.isEmpty() ; } bool volumeProperty::isValid() const { if( m_volume.isEmpty() ){ return false ; } if( volumeProperty::encryptedFolder( m_fileSystem,true ) ){ return true ; } if( utility::equalsAtleastOne( m_volumeSize,"1.0 KB","1,0 KB","0 B","Nil" ) ){ return false ; } if( m_mountPoint == "/run/media/public/" ){ return false ; } return true ; } bool volumeProperty::encryptedVolume() const { return m_fileSystem.startsWith( "crypto" ) || volumeProperty::encryptedFolder( m_fileSystem,true ) ; } bool volumeProperty::mounted() const { return m_mountPoint != "Nil" ; } QStringList volumeProperty::entryList() const { return { m_volume,m_mountPoint,m_fileSystem,m_label, m_volumeSize,m_usedSpacePercentage } ; } volumeProperty& volumeProperty::setMountPoint( const QString& m ) { m_mountPoint = m ; return *this ; } void volumeProperty::setValues( const QStringList& l,bool isSystem ) { m_isSystem = isSystem ; if( l.size() >= 6 ){ m_volume = l.at( 0 ) ; m_mountPoint = l.at( 1 ) ; m_fileSystem = l.at( 2 ) ; m_label = l.at( 3 ) ; m_volumeSize = l.at( 4 ) ; m_usedSpacePercentage = l.at( 5 ) ; int index = m_fileSystem.indexOf( "/" ) ; if( index != -1 ){ m_fileSystem = m_fileSystem.replace( "/","\n(" ) + ")" ; } m_usedSpacePercentage.remove( '\n' ) ; if( m_fileSystem == "cryfs" ){ setFsSize( m_mountPoint,&m_volumeSize,&m_usedSpacePercentage ) ; } } } zuluCrypt-6.2.0/zuluMount-gui/volumeproperty.h000066400000000000000000000036421425361753700216530ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef VOLUMEENTRYPROPERTIES_H #define VOLUMEENTRYPROPERTIES_H #include #include #include #include #include "../zuluCrypt-gui/utility.h" class volumeProperty { public: static bool encryptedFolder( const QString& e,bool f ) ; volumeProperty( const QStringList& l = QStringList(),bool isSystem = false ) ; volumeProperty( const std::initializer_list& l,bool isSystem = false ) ; const QString& volumeName() const ; const QString& mountPoint() const ; const QString& fileSystem() const ; const QString& label() const ; const QString& volumeSize() const ; const QString& spaceUsedPercentage() const ; bool isSystem() const ; bool isEmpty() const ; bool isNotEmpty() const ; bool isValid() const ; bool encryptedVolume() const ; bool mounted() const ; QStringList entryList() const ; volumeProperty& setMountPoint( const QString& m ) ; private: void setValues( const QStringList& l,bool isSystem ) ; QString m_volume ; QString m_mountPoint ; QString m_fileSystem ; QString m_label ; QString m_volumeSize ; QString m_usedSpacePercentage ; bool m_isSystem = true ; }; #endif // VOLUMEENTRYPROPERTIES_H zuluCrypt-6.2.0/zuluMount-gui/zuluCrypt-1.png000066400000000000000000000053041425361753700212500ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs  šœtIMEà;Šuà QIDAThÞÍšYP[×€¿#‰UÆ€16l@Fb±ƒ—ØØ`³¸­Ý,vêÄÅK’6I'/M:“éC—§¼ô¡ÓN¦íLÛ—fZ'Ó6ìÔi:q=qZ›UÇ;›$À€ÙwB åž>dƒ»“þ/÷êêœsÿïœÿ?ÿιBJÉJeº Å寭HÐhp»P ШB­FÁj‰X Àt]évãt)¸p«4þ £VܨA F¨TV³l)%HɤÃͤKâBeD¨ü•<Š ÅÝ â{AÔ¬bÉÓåv‡Â„KHE­^ü §®*Å-ƒ5R¢h‚@€@<9€érn§ ›l)BýXïÊÇÔ“‹TF Ýh…ЩPiÔxC¬.€”©H¬vcŠ´K5¬®#ªVX(„6Tã5©Å˜Ö¼ÓÿÙÆŒL"G …˜Õã®Âû{¶ÁÈY÷s÷²JºYáÁB„„,ÀóH21ábp\‘#v‰S¥æIÉl5¥›ÈPAdˆAóƒÌ˜¾w9Ý Œ¹åÀ¸d\Q-Q£¹@å™#¦v³N«_§UkUjÕœ 3·›«ËÖg“¡Ã“bÊ\|_'YUð‹$•”¬ –DkÅÏ"ÖüZ*•Ê``ÐfìŸPïï—¸PÍߺ\L¯Ë©;áÇîåÆ#ýÎ@¸‰Ö 6†)"Lê ð·Kwäý.Ù;“ Y£·W„?(¿€+ó €ñ>*{*8ÏÑm¼E¼q¿µßÆÙ+µÜiê&{ÇVv§% 4Ä“ôVïù›¥$ç7ú®SÞ[AƒÕÂî˜×fÔöI\n7wÓÐÖKmcû2¶¢KŒ[š> µOE9ë:ýS¡vðU½Üº÷œï›3ór*’k÷[¨yÐ;í:öoK"2zÝ´•>~1#ÀJÂüé´¶P5PIU¿«{lÞ·ù¤ÄGò,_ÜjãVSŸk15w°û©dv§ë ^`$üôè >9çðÙ&‡¹5PAu펮Eu—€ðúátŽíÓQXb¢ðš™ÆÞšþsÓƒNö¤%¡OND¨U«æŠâ fè_Ub²Ö{áv¬×Ñ<Ú…Õa_<€¢HÆìN6®¼ó|*Ùi±–˜¹t£…»Í]4¶õ°³µ›i:b6ŬØ?Z¬µÜªàÞÈ—8p}Ä&Nês9’°›—ü‰[}‹0w óË¢œÊ3°;!Œ½ºpöêö’¾‰¿_m ¦e€Ššf,­]ìHM"#U‡6<|>1S†ìíÜ1rw¸’ae€µ¡œH>ÈIC[£—gB+›(¯íätžÓy¢µ‚ûâØkØHQ‰™¢R3½V;WªkizØÃö”$R’QÍã™tY©5R3RI‡ã!j¡â™„=è’ið–-l ×>¼t€¾;¿ÿô.U ݼ|(…çvŰ%RÃOާs`Û&ŠJL\¾ÙJs÷{hní"ÝÄæ„ÍsæRºi»Iݨ‘ÆñûÈ©"OoÐsRŸÃ‹q™Þ²“½[ÊøØRŽÕi_À´T›{¸ÓÜGEÖVNçx*^K¶>‚lCçÒb9wÕDCû5-´vö–ÜMJr"Ѽ#Ñc7Q?f¤a¬Ϋ©ßà¤>—(BS»(¶”Rl)¥y¤{ù&4[.…óe*ë:9“ŸÂéüÖ¸9s` Y©±–˜8_fÁjwR]×HK{)ÉIÄë"yàü“­’!eÈÛÞ¶¨ÞÙyœü¨4ï³KÝ·)²”bìª_Ò ¦YJáŽï}| c}?<šA¦.œÄ¨~þÒv²ÒbùÅGÕ´õYéµÑ{«íd¶µ3ÚÔò£Œc^åoY[)6—ò¯U8×’§`Íræí@š€Y ù¼´(þ¥¥­Ïú(09F|êèòÍèíœk+çýšË´õ/;†, @¬áµo¥óÆátƒæŠ!óIX@Gž Ÿñ+¿$€m[Öñæ³Ûy~W 0Sù¡ ÁÙ+uÜlì· ¡¤Fƃ†&Æž[q_@9zÞ8’ÎÖè Ÿÿ–a>¸RÇÕ{í ¾L-Th¼[1«#óį_Ãޤójn¢ï¼.Ô|ðßFÎ~^K÷Ð8_—ø8´#ž7¿½½:ß4¡¶cœ³Wêøôz3_·Ì™¾õ|¯I'<Ð×Q/\oçÃ/ê1µñÿ s®Þ>–F:f<ï¶*|øE=ù¼)¿åBÔØÝŽ¥›Ðìý›Û­V~{ñ6׺¿ÅŸÁ³ {øÈt»ýþMÕgUÒ5hã¢ñÁÌžÒ°!"µJ»Ó‰Ë-ù§±c}§óR8“ŸBTˆäľ8²Ò<É[Q‰™¡±É•;¡JÍѤL ô9ì]«ó>¿:PG¡©„úAÏš!Dh8žÉþ ©so-*(ØFí\¬h”çKÍT5zq3 9gàèӱފׇ9wͳ&ðëÔz3l~à q|rô]4IŸ´ñ~íev®×ñ\Ì.o™z{ÅæR>i2bsM ’phc:' 9KÎAÁ oî>lï—ÅeŠÊiœ @­â…ý:Nåعe7˜–? °ÄL}Ûà’f˰j’"s Åæ2ŽõyÒ—5±œÒçpÂ;¾~m”v®3?ÛëžgÕ5å…R3Wµ0æðÄ„Më´œ9”©\S ]ۋ¾\;sþZ$À'7¸`)§ºÇäÉ™4Z¾»õ†Òc’Å|‡ p¸Nþ]Õ,‹K-\¹ßåMãö§Æp:ÏÀs»íL¼ò›n˜{üDiùcþÛì ÷ØzÕHEæR.µT£HI *ŽmÙC>‡ü¤ÝBˆ…O2¹\ü)¥ôÀ4¶ôÊâ2 çËéõDÉ„ a¼°_GÉýŽ™Sì>nM>‡}›"c¦ÎøVùo¶YI)1Þi‘çË,\¬nÅî^Ü,ô¸D¨ƒ9¡Ëâ¤>—q©b!SY5€ÇAœ“>­ôL»×z‘³÷ãæÐ x&n'§ô¹ÖíbjiºÜÃn±Òo%¤”ô÷(ÊÌ¢¸ÌBm·Í/@fdú^ÒkBÃVå› !W)µ”RRgéòøGEýã./@Bp$É9©Ï%a}¼XI?1¯( Wo¶È ¥&®XË9žG>—ÌÍÛB¬ê—*«ð8ÈÄø=25v“ÐhV]ñiùƒ2©½íJûVIEND®B`‚zuluCrypt-6.2.0/zuluMount-gui/zuluCrypt.png000066400000000000000000000077471425361753700211270ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs  šœtIMEß . Îþ+tIDAThÞÅškŒ×uÇw^—ÏårW»ZIkYÇ–%ËŽŸ±Ýøç<êÆN´iSi‹ @Ñ EÛ}|H ýØ¢(ÐMšºHƒ¼àÀqâØ‰cK–l+¶I–¥•ä]í‹\î’\9ÃyÜÛªÔfåXã p13äàÎùßsî9ÿsÎ~}‡¸‚gÕ[1ɯJhq‚«_'±îZK®õ äP€L΃ãç@o³ð}ÁõäÝVr6’ßE"x”Œ0Ñå@ˆ·Yø¾Ði`È rlÒ¥4è…D~DHÚpqx@/jÊx›„×á `t¬Àø]y&÷ORËàätlÕDsC¼•c^R=8Gõ¥çýˆ`p„x›VÞ²@¥gûÃ{ÙùÑqv\Ýe8?Jd‰Ð5ŒÈÁ×{”ˆ º„;m0ÿµ*/=Yãh34PâmذVb.» nü‡ßä–¶Sh{˜ÇO1z®‰›è­v·‹JYXÙ3ob¼«Ët»1ÞÍrè+s<¶ès"ÑFøv˜¤lºeŒ[>?ÁÞwòå—{¦q¦Fêl•ÔRHÇ„±$–Ƙ [-ÌŠAú`•Òæò¾ £õâ¿#j݈öx«´¢) tÃÞÏïæþwMRyê Ñ×R>Û¡×ôidŠÖ[éìFF:gÎ1zx‰ÊSMj'5Ì]) ›„Laï­pçÓON·™Kæÿ9b}%‡Z·úC“«>=É{n)±åé…ÇW‘/,ã~ò&VÿðÝœ_ýÛ×zdª5¢óulSúiî,‘Yö‘ÿVgí™z~cµÇ°c‰Y^6òÓÚ@°y³ÂÇ(”œàæ·³ïDç;ó˜¯4™ÿëÛid7áü€kN®P:ÓÆèD¨n!R›@ŸÔÑ®ÍýIÿLŠÞØö\ˆ@ ~ÆÀËû‚§w—zN¬>ºIàq¦,¦î¶¹s¹ƒóE´Ã5ª~ ñýSÈ=Aá‘S”_o±Ðêq*†ª’„–Aþ¬`͎ۘ¥Ñ»†P;u„çaι(·w©¶u+ŸBPÞì°%§S"LÃ@ ¡4¤ "¥…hÒ!Ò#ŒØCb!â˜ÀiÔºÌGЊû‹¼cGž«Ž´p^XŽ« ï%ýå—È}yýt“ï¹=ó@A€Ù|+f‡+¹«sËn›¼#ˆ_ïÉ -ÞˆJh@öž {?>Áû'²Œ[Âq® ¨†nû!x:ZƦ­BTÖÁq›ˆ—q¿=Ïy± Ê·meÇJŒöÌ©ŽÏÂ= ª˜ßšFœmñu7àq`6‰¶a_v7báŒË¬²°Ôå–ÎØjÌ)_1Ÿhú¢ú×(¥(>´{ïáŽB½ÞÅpÛSÛX5Rø§^cdS™¶m³¶¸J®Õá<¾®pr&väšÉ1ôr@½lQºu‚±WNcÍù4wgwŒ"¿¹„s®ÃA7ä)`h&4aÐt€ŽTt{´z:5Kg§¼âIfÖ¸è5Ei´ÄÖt…øÑ92MqŒÓ N/@Ó–p Ñí’ZYÃjÌ1âèûJô*ŠXI®1$[®Ê3<9Œóè1ÄbHã×y:úË ü•ÅŠsQ5°k‘ÜG@)ü¦¤aH†„ Õ•Ôì¥&Ù¹ ö±ÔóuBC'B'V!½P¢£¡…½N@»Þà r- xoŽb'Æ‚‘qÅd³J¾#ƒ˜µ Âé&ù¹6¯x'“hÚ^­ófýáq ñ‚ &Z§­Kã@,æºàÌ’¹¯Œú`•N¡YŠ8Ž ‡G‰k«cü0ÆêD¸ÿx‚à ̧S)¨x ”`(§ØìF¤g]Âá¡çR:Ñ$ÝèñªTT× ¯6ðnjàÿh€jËÁçDí˜æq—ùFÀžM%b¬¢CÜr‘Ù4*>G`êâh ×°È_3J8Ù¢vsRŠÀ•+ÄöyOÃóñh=+=z]ÅÌÀ¦UoSú.Zn ¡KšþQ7fåh›ïOkŒ«¦„@H…ý¸ †£¡OÙDwN`9ñZx*Mææ<Å'æÉÍ÷˜µ5ÂɦB  ]Ñ1}‰Þ i+‰Ä«úFQ]\èÏí8V´çº£³õ†S[ò‡š¯{¿¿ oÍG?ÒA,D¼`jx#9¼Z€- ‚´ÂCÌPQ.púð2¦sE ýz ð"EÕq"q?Éi‚íïŸ`ô§Ðži ­£&¯bñcïDÿ«oQx­ÍKÃe“¢¿FAj˜RŽòQQ@7t70‹_Š1®ç2ÝĽՀ% šÜïp¨|x˜É¥ã`tOÑþâïQ{ò,›R£½Øãq gLŸr¹a\¥ˆÒ6 Í0‰”"|³ùPp?ÉECÀÈÁÄC%n«¤)X&²…ÿ;;©Æ äÿó•9Ÿçü˜€•Lš`(G7mÄšÍI]|Ë[šDì|5p­¶€±Ï\Ëí÷±ý„‡ù| yu–î{ÊÈ‚=‡«Ìµzü0†ó€”½Ð$ CDJ!} ‰¡ ôP½u ´7Ø0"áÝ÷—¸îƒã\ZÄG{ŸŸ!ÐçGz2oØüÑíÜøÙûØ_Ø6d2{ê,³n›Õ~^0¨> ¨||?·ÿåî~µFñÑe¢z—µ¿» ÷Ðy†ŸnXå¥H±ÔÏ¡"Pòɪ©„êŽFy2ÏžmY‚vLoº…5Y¡wÓ.V÷æ)Ÿ[dh¶{±ü˜IæÆJ;?µ›Ûÿì:nÝ1A% °j¥k¯úÌ$ûî’„ÆK1ö± ö¥S¤¿yŽáC«œû½´¢6›–"‰<Þ”)Œ*nÕu\ ô”@‹š¤D ¯*©?Qçù ¦öŒÇώ̱œòÙüáí¸S§ó£ Ó¤²Ë@üíµT^ì1òl•óMšB"lëö £÷gÙ±SQ Ö(<ùŽ&U!c Õ…4ÀzGŽMWÁäO^'xO)»†æV·• þtn¾@ª>Ë&G²Ú‰ØXn†\ÖÆ †#™Y㫘ڒϹ£ Ž¥yhgHú¡1Â>CV / wa¢Âöϼ‹RmT§N\¢à6)vÊW±Ï®a.öP÷Q®‹)×y¡Á=`¤åNáÙ&NÕg.“¢ýÔ,[¤FÊ[#7û å‚CØ èÊgÍc³.@ɤ%ù®Ù•¼»¨óƒNÌ’T,Ÿìðt¡ÎžbžS‚ö¿<Èò羋îU ç…®ÞUÇ7èD’Öá9ÆÏ®2\p–|ôŸ¶p÷åæÙ²\šG_’ÔK…µÔ" Q•<Á\›ð»gY+ilA¢kl!Êõ±´4ÝoÂD¿¾LPw)jM Éœkk¯mñ-k–OÞ7Iáîq´º÷‹ÇÉ^A»®€^Óp†Rd\‚Û!× H-G´>݇ËXoÃz¼Žµ¨Ñè^ȧà Ùh;"\í¢våé}é¬VˆåUÉÎÛÌ¶ê ™)Ë¢«bÄjŒf§‘‘GÊЇӨZDæL—n /z¥X©>Ú dÛü¶u„ʶ˜ð‘³ú\“îÿdüD ‚Ýë¡tEsÄÀoëÎͤC_Y@<]ǘö9Ô8Ÿƒ›X¡'XYŒ‰D›ô~InXflj}S/¬µ)lÝDCëÈËè&C¦ŽÑÐ0£6â´ªIºÑ…þV”¨º,Ìûüð™Eä’ϦFªfɦóÙ=¨á2kY‡°qãøYƽö|û»óXÇ:ˆÓ‚ÞBÇ;!_ë]Ð@зc zöf<^ªÆ+†âŽï·Ö¡¨¾nÊé(ÀLF=ì(ÄÔNÇÅ´RÐ `9$Z 8؉YàFhIÅLÕãûˆ¥y›{Nùl·Ùdb §Iç «u2¾"W÷±ç|Ä|¿rf-äG<JÎp¡îz±k9È;,]P.ZìS’w:£±ÀP „†B!%R¢„@C¦%¥4EEœ?ö"ŽË /ôr‰¯64ÆS:»³6»mÅ”©‘1 ì0BïEDR£íEÔº!'#É ©˜•RܵÄÿ÷©‹ä}THF°4 T’£‰äÉJ^´?\uAðµ‚ǺN¥ð™,ס(4rJ‘B¡¡(…«Mu!Aj'fè ôŒY€þ€9Ѐ¾’G¿žlÐÏ|G?Y2îe®ktÇëæ öÓú®ý% HÙ•¤}rà,/S Zd#ž¯Ö•å}j ~Á÷ Wz¨_Pz3ïSW2ç•~=òKó4/9þÍ"P@“Ì xIEND®B`‚zuluCrypt-6.2.0/zuluMount-gui/zuluMount.nicolas.png000066400000000000000000000070571425361753700225510ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs  šœtIMEà-BXÌ ¼IDAThÞÍšIp[Wv†¿{F’Áy¦%J´%Š–Ü’ìV»Ûmyìn·WÆÊ&•E’Ê2›^g•ì²I•Sm/œHv¬n»cË-G“5R´(‰â ÎH‚$bzïÞ, Ñ"MRR†» ÀùïùÏðŸû„Öš§¹´Rh¥P–FK‰€e!HÃ@ÆSý?ÛS3\k´¥0M…””€@hR€¥JaÓ ‰â©ü¯xRh­QJc¦-Ò–ÆDÒRî‚KN?°÷¡Ôi‡6»”â‰<€;†§,âiMZ‹ %r!ˆ£uÆôö>ðÊ-•š² ]á² ìw€ð˜@ €R ËRēЏ‰N“¡„xÈÔÍ—¡nC ·Cb³K¤”ÿ³´R˜–&žRÄRZ'•Dß1ü»Þ¹óó›ø„V8„"Ç!„Ëi`7b@¶@k9ñ”"šP:f Lîów«Î€Ð Y†Æã–Âe—Øl!ä“P–"ž²ˆ&”^NBJI~€/[ƒpæZ¯Ëy­4v©ð:Àã’"Ëidh%€VšdÚ"’P±¥5•7%)×!ºØvügìÿnœ‹;Ø´Æ%YBç¸ érJäÞX@*eIê KQ«s%-H+BfNñ¨ÁÛÞÍh%@Y»ÔxlŠ‚cÒ㔇íÇ=À´4ñ¤"1õB\“°äç.ß°í"Ó:ç.ßãÙ°ÙåúºúguBea:œ˜:“]„ÖwNXlɺõp> --1°°‰4RÎÑYS'Öm%~ýå-’ÒÍ®¦5"¤”hÊÒ¡¿[“žˆ&›mÖ¤”™³ÓÁÈ=á^V’£tÖüÍú½Ððì2ÝccÜ Î°¿­ŽæêRü…y)ЖFÝñ–x8î6ÏõÛD'„@"Q–f1¢¥ sß0¡Ô³q3çpD“inç™­ÒZ1IG[õU%dgg¥Õº^<†ƒÄ£o¥0M2e0ÒO÷ÂU®/ß`!¹ˆPel @vCâõ8ñ¸ì\˜dp&̞滫¨(/Âæ°ƒÎ´â)F­AJ¥˜Œ¹î¦;ÜÅÄÚE¶ÝMJ[›·ÓR v×ò‡‡›ùøü§®Oðû«ôα§µšæº Š †DiÍziXl£ $RXÚb!1ËÀÊ ®-]b<>NÔŠ‘ewòÃ@;R¾œèÞ€òs\üì…zÚëý´)ä·—ƒôŽ-2¾ÁÀØí-ÕÔT–áõæ€XJmÀ}ºb©0£ÑÛ\_b06Àª¹Š¥»›?k}™?mýßLßæÔÔõÍh­™ ǘE¨-Éå¯ßÜ;æŽääµqzF¦›[bGí,;k(--Âåv¡5™øØRK!‘Z’RkÌ®rså2}‘,¦C(m!„$e™ìôÕðG-?¤6·”kóÃëj‡GXZÓ\àW\âµ}5j p¸-@k¥ŽÆ>>?ÈžYÎÝ!8³È3u´ÔWá+ÈÇpØQJ±q%00°tšpr–þÕ.ú"]L''Hk3L÷roq#Eî¼LO¦ëý캒2ž´8qi„îáyŽÏóÖóu´Õúùã#-´×ûùøÜŸ_e`*ÌÜR„ñé-uTWWàñx@ÊLëû$“]VÒ ŒÅnq;r…Ñø µ–I›â¾V6•E¡ÛËsE dÙÛ×ÄB€Ò06¿Ê¿|q‹î¡oî¯å'{jØY]Hm±—ަþýì gnNqst†©Ð2õÓ 4ÕURZZ‚ÛíÎÔ -1„Áša.1D_ô #k7Y5—ÑB?døÝØHZižËk !¯ ›4OÔKI2mq¾wš©0Wæyë@Ÿ)畽մVùøüJãç†è .Ð=0ÊLh‘ÚŠ2êkª(,,BØ`.1Æpì CkÝÌ¥¦01±K;¹>дûkñgå"6I ¶Íó³@‚…ÕÇÏg }ãùZŽvÔÐZUÀ_üd»jý|za˜/ºÆ]%bzn‘êº2Œ’%FÓW™Jµ¢äÚspÙrˆ¦ãXZ=b ©, \^ž-ªÇãÈzzcC ´ÖÜ[d|>ÂÐô2ûV;­•>ö·”ÒȧܗÍ?þÇuV¢I&æÂ̧f@ ’ÌF`°ÓWË+U{ÍG§™Š-a€"wéÓVXCC^9Ni{zî6X6CPœï¦¾4l—ãÞg>‹çŠÉËv°K"ï¤B¬$¨Ê)æ¯ÚŽòvý ,ÄWY™a.x¥Õ=±r—>;|Õ<…„Q\vnÛÆ¼eõl)Ëiãp[€_½×É_m£ªÈóОñù‰”y™IEÆsÅÙyìö×á¶9är¤²¢¬<¬õˆ²Èwæð¬¿ŸËKÏb•dìû)¾%A¯þ\7p¨‘¿·ƒ×:kñfÝ?ý•X’Nð¯_õŽ&òÑÀSZ“Væ=`Êž¡£¸›0Pwb!e¥©ò󌯊„™âòÜ‘Tüñ)di]JZ+òyïÅf^ﬡ$?û¡=}K;7ısƒŒÏGR ·0¤ªôq¤¢ËsƒÌÄ‘B£–‚ êòJ\ž¦oi’TUúñXJãÉrðÒ®ïjäàŽr\ŽûÛ)“37¦øàT?goN±Kà0Œ-Øä^ølô2)ËÄëÈb·¿–Bw.¿¹È||ùñ‚Xå¾lÞ9ØÈ;¨/Ë{èT'CN\ òá×}ôO„QZã´mê\é-âHÅnºæ\ž¦>¯”…5¤•E×ü«Éئá£í4‚J÷ógyùÙ* <®FŠš®¡9>8ÕÇ—×&˜^ŒbH‰ÍØj.ÈX³_%ËîÂesp ¬•= Œ¬ÎRŸWFC^9c«sô-M°RÛ/dBš+òùåÁÆ{ÝŸÒšÐJœÓ=“|pªŸKý³¤L ‡m{cò»[¯/ɱ»Ù寡:·„C\ Ñæ«¦(+ߎ\dz-LŽÝyH Ö‡b[wœqç wW4žæd×ÿôé·ôŽ/á°Øíbïz`de†ùµe?¥Ùùt”4ñzm'{Š›ÐZÓa)!Ûæ¼Wè”Vh¡¿?¦Miiú&¼²—ùå5ÜNe¾š+ò)Ês£5¤MÅ㮸•âôÔM®‡†ÑZSå-æÝÆCì+ib2ºÀí¥qÖÌvi#a¦è[çüL/i¥H+kcørìe18³Ì?»Ê·#!~º·šì(çp[€ê/Ÿ]râbžà‰”‰Ý&1„Ø¢˜×÷è0²:ËÉñnö7àsçÒ”_!%ç¦o1 !¤TšÏ2¼2Í™©›¤Í>GöÆÞ=ÜŒCJ¾êatf•¿îçÛá¯v,ðZg-Í|þüågx®¡˜OÎs²{Œàì*¦8l[§”$n&93uƒŸVïáp  Ch­éYa~m»´3»æýÞ“¬&c8sx©|7¿h<¸1€CíÕ¢¡<_wöLrüì]£a.öÍ0ŠÒ=<ÏëµüøÙ*ö·”RWšKGS1ÇÎr¡o–¥H§ÝÀb Á,B\ãäx7íEõ¸Q\èegµO}}‚cç‡éŸYåÄÅ }“Ët †xsÏ·”ð³õì¨öñ»Ë£|ra˜É0¦Öbó‹ CHÖÌç§{¹:7@]nLJÎq}q”˜™Ä Å[Æ›Õû8RÙN[i£Èr¸I«ë²,—öæ2Ñð±»¾HÿîrϺ&èŸXbz1FÏhˆ£{k8ÚYKKEÂÚë‹øðT_^#þ@C·ÑøK0„Áxtžîù·ÍÁÕГ‘¥®<~\ÖÆ«uì+k¹˜—å}ÞØ@™m¬È¤Äëus¨½Z´TútGsŸžä¿zg8{cŠàl„KýsüüõÙ]Á‹»D).öÏKšßÄ™+XCHVŠó³·ˆ¥d~T²“·^à``'e^¿pØìO¦ì6ƒòâ<ñF~»k õî1ŽŸâêH˜—b N‡¹:0Ï{/5áÉrà´Ë kÀݾ?¥L´V!X3Ó­hóVðvÝ~^®ÙCƒ¯R¸lŽ-É- —ÃFcµ_”yØÛTªO|3ħ—‚Ü .0µãæèþ\7«k©ŒžþN^u k+[:Ë'Cß°œZ#e¥©pçójås¼Y€Åu‡½®œÓR<åK¾G:UK^Y›¸z{*ðogùâú$Ñ”&7ÛI*me¦J‚'}hß"ÅÎB*<~æãË -OãFr¸tï4âùÀü9ùb³ ÄS¿©7M‹™ÅˆþêJNpix-%»ë.€~ð-"µ´²H›iÚó«øeÃA^©ÛGù=žÿ/^tW±¥R&#“KúØ™Ž_a8Ãis ½Ê·@ÙúosÄJÆ` CIEND®B`‚zuluCrypt-6.2.0/zuluMount-gui/zuluMount.papirus.dark.png000066400000000000000000000015431425361753700235160ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYs)†)†"ìߌtEXtSoftwarewww.inkscape.org›î<àIDAThí™MkÔP†Ÿ£¶Xð\JÅŸàF\XliA¬ºèÆ­ZZÜÿAÔ?à²~l)‚Rª´µE\Ø•ÿ E\I¿V˜Ñã"IIîÜœL2“ÌæÉɹ'ï{“›ÜäB-!¾ ªöa`Ø_¥¨€OÀ°("57¡Á€ªî'K——M`VD¾Æƒ aÏß§ûÄGl·âgb“0N÷Š8Epiïà®NKa]'*R”Áø†k` B!EIht ì:v½}£<V0Ü0Ž]+À^`ÔʯÂÀc™m¿PÕÀÍ”ü‡"ò²Ùü*.¡·žØðÅß^yâkiÅK7 "ß<±:ðÜ“þ4ÜçæÿL«ßÉA¼Dò,lËy‹tÌ€ç,x{? kosÀºˆ|ÏSTU#ÀõŒÔ%àjø?wïƒm`ND^)*"?îYyuU}ý/r,ËÀû"–šÈ)ÔóU<LŠö|„5ˆ‡Z)2Ú†&–)UWÕcE «êi‚)@©X—Ð0Ì8ƒ±Ü‘i Cñ·þ6h4Éûè*ñÏ@׉‡æ Ô»í¯ª —¯/–E3"ñ놘"=É»œ£=m ,ñ“ª:¡ªÃß0™³†yÊ "+ñ˜ª"xŽLMûÂýVN&–'YâÓ‘_ÀBø&U*Ö%ÔÒ%d¥ 5LÊ~U=àUõhZß>+ß2ÐŽyÌÁ{Ë9£ÍOìlZ²5®i0‡X¶ÞI}¨êaà<á]EUÿニ`Ï‘¦Ã±M燀©´d÷óú›_|‰É\"Ò@ˆÚJÐ"z{©Tµí{Û?¢íKU*µ¢ªT!¤J Z¢¦Ü”‚Û‰s±cûØ9·™3·½ûàãʰ“8µ’?i4ÒÌž=ëÛkïµ¾µ`ëXÇ:Ö±Žÿcˆ/y^»;ì—M@Üp-±üú<–sãØIè/Òr ˜E\$9 nëqÔH–$–Ù‘Aâ,  .±±_–ñ©Ã¸çPŽÃªŸîØG6æÞ½Â{G'x¨Ü°¢ª˜¢ûÙ!ì/ò2´…ñ' œýÓ÷"®¬à¹/ž@ ùg»xf{ŠOJ s1b{•Òdž¨\»ÎG@¸l¼»%Í}j~QˆÙ[¹Ñ!Η˜>±ðþ¯ñZ=pÛg¤¦vØ9ܤøâ|\‹¨òÙº»ƒ÷8vô:£@´4¿+ÉïÊñ˜„}¿ŸäÂp Ïõ±eÀ¡ß„l ¹’ä-/[DU. (@aqê ©j„œó9ÞžáË5ÎXK¡?Ëý@qÙܪMÒ»ÓáÐXƒæTÂð\ÄÑŒbÒ€UÐv³E\É¢ Ü”¢ä ²´ äâ kA¨EçZ04ý˜j¢f –$=m䲋ýçÉÎÆx=yvot˜j2Õ:Øî`Žíl?UÃ?’gèa´ÙqýW$»-ÖBêž[žï♞"›‹#Û0QŒlS€ 6m¡Ü`áØÞü—Ç5‘aÚ ¿³ÎþªÀ›óIJ9†¶æÙ5Õd¸µ¯sOmä@S’-7©ßŸc³—"›XLè£Ìê;dEKqØùZ/‡¿:ÀO¯%tø¬Æ„1VIˆ,FúÄÈ4¨¡ ñ—¡“Mþ r$AD*²ÊEiE:ÓÌh:¶wrßÛ3¼Þò@ßÖvöOÕH„H оƒJYDƒ#WOb+°-:Œš iÿ¸ŒWiJ‘ "‹PilÍ'üpž©JHø­.ð-›\MgÜDº¡å¢û½2L^„êÜ»)ËÀÅÕC%ö:š¾KI·FWCäõ՟ǦS‹Û`-–ó˜´“Dƒ%29K›VXÆH(¤ÀÍ`KYêǧíJc>²DaB¨l”@"æ+ˆë1d-î\ ç²­×e×ÅsOnåA§8™ú<ÅɱUØ FˆÍÚ X zgWÏiJÉ ÷¶a@·)ŠÜÕKé³ ©§ºÙQ Ñç=Ά†i·DCb4BÄ‚G$4¢‘d$…¼åÁö×;»GgÐYƒI@ÙA»ƒÉ8$Êb’;ð€Ð‚¤sñRÌoX gHƒÏwñƒ¯ô°í³ø]watšÞ×Ï0|>äÏiÅBÚH#H3èL€§@*Mʇà®,ì„:ÃÐÙ •‡òdGk4BA“©s$Q½%:Öêx‘}ÐÊšK¹ ÷»ì{¢‡ƒÇ˨X2·§ƒâß&˜9uß§•¤×b V+ 6±TCCÒ¥¨4‰ú² bUŸRd)§ #5®îé$ M6I°JV·¦¿n&c—î™§ûyøÉ~¾=²aÂcöHùwÇ1§&y1„£@Õj Âu°Æ@*ƒ1šÊLÄxÑÅJ‡$ÛFêîw–‰wqÇ*D—=F´C-R-°¹Ö÷wB`9Úîé`Ïá­<·³ûô<å#[qGêè·.ój9à%`ˆ…L ÙôÚÁnìÆ8iª#>.tPSi’…€$•Ãñ ‡ 8c j×NµK’Œ@&12ŠÀMß!V L\oã›2æ‰×Ïã?ÞŠ^ãäÕ&/“KÍI3ã¤cG¶a¯VIœÞ… ç>»Æe¢¦<¼÷®â뀸|ìtÌ9-m‹Q'ª¢u HÝüÈU^ ÚQô>±“#»¶ðô1˜%jK(½6ÍØ•€_ç–‰-ے„´HkR×-“刑-Ü™€ËÇËœØV¿ÔDN4x##YCˆ#”•ˆÈ Ä-ì•%@á¾}g?,_eÃ\¯S‘ãsgª¼[†[+¿$öTÓ.j£”Â&`#CBŒf/5ø0ˆ¨}}€®ïí ³!OéB“©…ˆi…L`¥Ä¦$øáÚ2ñb³¤ûÓìýù£üèÊ<[?œe~O=1Ktbž7kÓ@ÐÝ x° º§ Aœ6Ø¢‹´q“ÔÙ,8˜Šé{»Š3æó0žqÙØ³$¨td1ŽK¢õr?{€oØ„}/R,13a§ÓEã—CìëˆØ¦ Q8ÆG65s¯Íñ—?^`Ô„¨F5‘DDÉeŸ³oÏð«“sœi&tE–‰zÌ_²NèÕ>Ò±H¯r#¤”ksÿ©¬Ú-;Ʀȫr¢3Gî|i<ò6$;c‘Ê ³ò] I¹¿šµH-q‹ƒmy©zÅã-àô²B¥ÄqŒõêˆ8Æ)¤ˆ´`nÖ•Xµ"›¸†ÜÞ‰ýþƒÜÕ(Ì\ ÜŠ€0†M¤ŠQô¦ ÅA; Ž' ú,±±˜Gùu–|NZ×oè>¨Ð s;Ùž4z¤Œò}‚ÅR{m*ç#>©Wy¤Çe‡›ÂÈ4Ö87 hDh™ ‹8S¥9q¶i¯Ì§šÇ7tÓùòfÇø¤e´Y!Z'uË™# LÔÈŽ4¸Zù´EÜÞnÍ+€tGŠ®æ«6‰´l‚k  R€1˜È0߈8îY>-HÚÅÝAÄ´s,°Œ¯bŒP-iö(8˜@1‚Ïj1ÿ40½ZQ/nò< d[w¹ÊxÓ*Ô-ý¤\ë´"Tx“ÎÜb? 2­ú:hÍ—¬¶Ä-õ·Úþ[Þ¿‘«¼»Ùÿì zì¶Û&_dëñÔýçþϲŽu¬cëXÇ:þGñoàÞ¹LüwÌIEND®B`‚zuluCrypt-6.2.0/zuluMount-gui/zuluMount.pro000066400000000000000000000033071425361753700211300ustar00rootroot00000000000000#------------------------------------------------- # # Project created by QtCreator 2012-08-03T05:17:03 # #------------------------------------------------- QT += core gui TARGET = zuluMount-gui TEMPLATE = app SOURCES += main.cpp\ zulumount.cpp\ keydialog.cpp \ ../zuluCrypt-gui/dialogmsg.cpp \ ../zuluCrypt-gui/userfont.cpp \ ../zuluCrypt-gui/tablewidget.cpp \ mountpartition.cpp \ ../zuluCrypt-gui/socketsendkey.cpp \ oneinstance.cpp \ ../zuluCrypt-gui/utility.cpp \ events.cpp \ monitor_mountinfo.cpp \ task.cpp \ deviceoffset.cpp \ mountoptions.cpp \ volumepropery.cpp \ zulumounttask.cpp \ veracryptpimdialog.cpp HEADERS += zulumount.h\ keydialog.h \ ../zuluCrypt-gui/dialogmsg.h\ ../zuluCrypt-gui/userfont.h \ ../zuluCrypt-gui/tablewidget.h \ mountpartition.h \ ../zuluCrypt-gui/socketsendkey.h \ oneinstance.h \ ../zuluCrypt-gui/utility.h \ events.h \ monitor_mountinfo.h \ task.h \ deviceoffset.h \ mountoptions.h \ volumepropery.h \ zulumounttask.h \ veracryptpimdialog.h TRANSLATIONS = ../translations/zuluMount/en_US.ts \ ../translations/zuluMount/fr_FR.ts \ ../translations/zuluMount/de_DE.ts \ ../translations/zuluMount/ar_SA.ts \ FORMS += zulumount.ui\ ../zuluCrypt-gui/dialogmsg.ui \ keydialog.ui \ mountpartition.ui \ deviceoffset.ui \ mountoptions.ui \ veracryptpimdialog.ui RESOURCES += \ icon.qrc INCLUDEPATH +=/home/ink/projects/build/zuluCrypt /home/local/KDE4/include /home/local/QT/include LIBS += -lzuluCryptPluginManager -lQtNetwork -lkwalletbackend -L/home/local/KDE4/lib -llxqtwallet zuluCrypt-6.2.0/zuluMount-gui/zuluMount.xcf000066400000000000000000001504451425361753700211160ustar00rootroot00000000000000gimp xcf fileåBB gimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) ƒå Drop shadowÿ     ?å[Ñ Ñå§·X  gAënƒX’Ó­…ÃCÐÍÐÝÐíÐý~ý 1ò  !*0ñ+9AISYULRWU/ð%7Qjx‰”—“–˜.ï$AYzœ±ÈÒÐÅÌÐÏÊ.ï=b~¨ÌÛÝ×ÏÌËÀÁÓ.ð *U€ªÇÙå×ÑÎÃÉÀ½Ì~ý1ò 1ò !!"(" +;0ñ *.--1/0Eb/ð "(-47::4;@[€/ð%/7<;>;34luhl.ð 1<==I>:82aiXS °-ý,ýý,+û(ø'õ  (î 'ç &ç  "#$$%ýë "&),./122%æ %*/37;>@BDF%æ #,4=DKQVZ\]_b#æ %0@irjeKC>3  à (;N]`\SLPS‹M+55aia_GDJI* ò2ALUWTKA=@ € ûü ýýüûüûþýþþ   øüó î þÜ  þì $$ì#"!  è !"322è0.-*'$   þÓ !$'*-.0FFEC@><961,'!  Ð #(-269<>@cb`^^YUQLF>60(   Ì !'/7?FLQVZ[…‡‡†…xqidWKB7+"  Ð #+6BO[itz}„…°´·¸¹²¤—‰vdXJ9,# ýË #-:K\o‚•¥®¯·ºàßáçñæÑ¾²š„tdM;-! Ë "-0#-ퟘ—œ ¡ž”–—Ž‚kVD/,ìÞÉÏÕÛàßÐÌÌÆ´œ}^G0 +ëãÝàáãååÒÏÏÌŹ mM-*êÙÚ×ÙÞàÙËÄÇÌ¿¾¯–Z8 )Aû9ð /î& $"-í5'%-0/.0//-' ,ìC7;FOQLMB96/+# +ëTQHJTZSG@<782'#9' *ëIQKJRXPC9:A45/)<) * €+ ý)ýý( ý'(þþ%  öþ$þô $ýð ý#þ#$$#î"  "þ122é1/-+)%" "äBEFFECA?=;73.)$ !ý]_``ç_]ZUQLC:2*"  ý…‡‰‰ç†ƒ‚~tlcUF:.$  ẻ¹º»»¹±´°¢—‹ycQ>/$  àòðâæéíòáäã×κ¤ŒnT>-! òâóññòóçîóìîìÙµŒhN9) àòóöôôö÷òóõöøõïÛ¬ƒaE1" 4øþ'è   'ì)877:3#ä "14-05,)41"/995-#ä "-,'',2/2;C:)"+>GD;1#ä !%&#!:BC@;-$)6>?9.%*-$å !! '+8<5' *6<60( -3%ü ì (,($,-'%"%)%ë ý&ï  ý &í    (è)õü+üù~þ=þ<ý:û '9ú '98ù !.7ø"2PZ7ø0Ejq6÷ '6Gda4õ %4BKK@4õ 4>@<8:;3ô-KXK81552ó :ekR82,*2ô ,H€pO91f$ 3û"ý !þú þ÷ î  ì ë  !!é "%()+,..//ã %)-157:Zƒ²Ûóôðò÷üùøøùøùûüøøùúøöõé  .C`‹Áæññòô÷üúúùûùùúúøùùýø÷ä !0FeËðòîóõ÷ùõôôóðïïùðîîððñã "1Gf’ÓøõðòöøøëâÞÝÜÙØØýÖÕÖÖÚ "1Ff”ÒôôõúúùûíæåäâááàßÝÞÞÝßÞÚ !0EcÍòööüú÷ù÷óñðòòñïìíððîðïå .C_ˆÃîúöøø÷øüüúùûû÷úöùúùøùùÚ+>Yµäüøô÷ýûúüüú÷÷úûùúöô÷öùî '8Qu¦Öö÷÷ýøûúúóüûø÷øõöøùùööÛ "0Fe¿êúüúøùúùøùýùøúúùùøøúúì ):Tv¡Ìèøýüûûúúôüúúüýüûúùûüæ #/C_€¡Áàñöøõ÷ùø÷÷øù÷øù÷õ÷ã &5I`{—¯ÂÐÚàååäåæçææåæä )6EWl~¥©­¯¯²³´´þ³´´µæ '1=KWclrux{|‚„æ #,3;BGKNQSUXYYZü[\]é $)-0379:;<==>ú?@@BDè  #%()*,,þ-..ú/0247è  !!ù"#$&)-ýï ù"'õ  ö%þþù  ÷ 'ûõ "* ô '2!ýô %/<"î #.:K#î !+6G\'ì  )5DYs)í (3BUn)î '2@Rj†§(ì %0>Pf¤Í(é $/p¤ÇÝàÉÉ¿®¥•‰Š-î@o£¸»³±¢”†vkigc-îDv¬¹¾À¸¤yiHAA<-î Gx²º¸¶ª˜€eL-$$"-î!Gu³¹¯¢—‡pQ&-îDr±º¸¶¥qP# -îAl¦¶½¼¤ŠoP%-î>j¥²³­›ƒhJ% -î=j¦®¨¡”fJ(  -î>l¤¬ª§˜„oV0 -î@oª³´´ª“~f; 5-î;f£°©›‘€oZ4  D-î/SŠ—“ˆteR0)T-î)Ix†‹Š{kX51f-è8d˜ªª ˜‰xc=9tûüýÅ4ZŽœš“„xf<A| ! ! ! Å0S€Œ’–wf<IBC?8/" Ä2T‘–“ra8Kƒ‚z€}†}z~‡ˆ€}}twxz|x~|rnuwvz†zrxzseP;, Ä9[‘±©Š’zhV0D}ÇÇò¼ÏÏÉÈÌÏÏÀ¿Å¿ÂÂÁ¿¹´³µ¶½Ã»ǿ»¾´«”tYE1î8]•³¦€ƒpdT. HyÖÖÖÈÇÏÎÕØÑÇÇÅÇÈÁ¹·½ÈƼº¿½ÌÔÖ×ÞÓÏÓ¼¶¦‘€aF- Â7\–¶§{€qeT/ HzÍÎÒʼ²¶ÉÐǶ´·¼½¶¦ž¤²»°®´±¿ÈÍÒÔËÊ㲪ž”xZ:$Â9^˜·§{„wjY4 J|¸»º¹¤”ž²¿¾³«¨¬³®ž”‘’¡šš¢£¤ª¯¯­«³¼©ª§”†iD,Âj™±žwƒyqb8J|{€‚‚|usrtwxx‰vwp`]\]_fUSYY_g~›—š–ŒƒydK0@o¨’kzhX1 R‹nqstutplijnpolighjg`YQJGI;:>;LWj„Š„wnaN0 >lˆ§dž~dR, W—][ZYZ]^^ø_ab^YUSUUÌWLIB85..-(7>Keƒ„…ƒrh^N/ 8d‰®—g¨„hU. Vš" !  ##ô$#""! ""€…# )Dz†ƒ|scZM- 1\“µžr«‰p_3 Q”GKNPOMNMIEAAHKIGC?><+)"  B{Ž‹~r^UJ/ 0Y—²˜qª‹vf7 OŒ‹— ¦¥¢œ•Œ†…‹•››˜“ŽŠ…dH1  €#MŒ’‚o[RG- 2Y™¥‰n§Švh; N‡³ÁÉÎÏÌĺ³±µ½ÄÉÊÈþº¸¼Ÿ}a>),Z˜˜„nYOC+ 5\™™|k¢„rg; Mƒ®·´±´¶°«¬°¶¼»»¼¾º¶´µ¶¸ªˆ[D1 9d”¡–‚pWJ>& â7`š™}l™|oe8 L¥¥ ››¡¦£™›¢¦¦¢å ˜–¡¦—kU="0QwžŸ•„mXG7 Â5eŸ®˜zukb3 J~„ƒ}{{}{yy„Œ“”–šœ†™…lY@"(Fu¢¯¦—dR@0Â3dŸ¶¡|Šzo_4 GzZ[[XVVUWWY\`lx‡‹–¢ŽŒsbU;=j𾹫”y[H8(Â3`œµ¤€Œr]5 Fx66744667:?FO[fowƒ‡ƒ|wjUK/'\±Â·¤‰lQ?/!í3^–±§Š“…t^6 FyØ ""'/7AFGIU{‡ˆŽ…nefM>V…Ÿ³¿©v^F6' Â3^Ž­¬”•†xc6 Eu"''&3Pz‡Š†€€_U`FIŒ Ÿ¥¬“zcM;, Ã1]­±žƒ{i8 I{ -Vƒ˜‘†|ula^Y0(e¢¦¢£¢ƒmV@.!Ä2f ®¯¦|uf4 H{ 8\‰ª¥–~mjYccG$S‡©¨¥¢—v^H3! î4m­¯«ªŽwm_1 EyÜ+Lr•¡Ÿ¢s_\WTD%K´­°£‘~_H5$ î5i©¯®«‘yo`2 G}Ü'Em¨«ª¦xcXVPA$4v¤°œžŒv_G5& î5ež®²¬•}q`2 H{Û0Nn‹¥¬ªcURSD4]’®®™ˆr[E4& î5aœ°µ¬”€uc2 EzÜ+Mw𭬝¡…lVLKH%6r{¥¹±”s[F2% î7_𳏫”vd2 CxÜ+Eh•¶Å²kYOG>.4{¥ˆ°Á¯‚bJ7& î:^”´¼¬–‚we3 DvÝ%Ce“¢¢ž›y`KLB( *s«¶‡¯³‘fU<& É8]”°¶©—Š~h5 G~(A[w”›˜‘Šx`LA8")eŸ±¡“£“nNF/ É;c ¶·§–‹€i6 K‚!=Zwš¡Ÿ”„kVH=&!\•¬«ŸœŒoP<4" Ê>g§¹´¢Ž„{f5 Nƒ$;Vy—¨§«¥’x`PF4K©¤¤©—sQ9."  Ë=f§¶­™…zr`3 O…#>^¤·³®£v\L?/;|²Ÿ–š›€[;(  Ì7\¤±§“sl]2 RŠ;f“Ãȵ¢–…q]UO< >‚¯³›•‚eH.  Í7X¡¯« Šyrd6 L^‹ÀϾ¢„teYQA$,u¦·¨˜‰{jO9%  Î6Z¦¹·«”‰n< Et¥ÌÌ´—‡yk`WG$'i ®§›xdQ?, Ð4[ªÂ½©•–q>DtŸ³¸Êº™obXL0 !i«¸¨•wfQ;1! Ñ2\¥À¸›Ž—m9 L²´«¤”€m^[Q4Z¦§ ”„iP=0Ò7`𽼡‘Œg6 HxÇǶ§v`_S6!Gv˜ ²ªoVB0  Ó;d–»¿¥‘€uc5NƒÃθ¡…l]V;Vz‘ž¡©šyWB2# Ó=h½Àª“ulc6 S®¼¤‡oaX<E„£¡‡nU@0! Ó/! Õ;f ¨£›xpg;S•rZcY=;o™±Á±‡eA.$ Ö7]Œ‘ˆ{sd:OaQ]P-&u¡³³¯™hI/ ×5ZˆŒŽ”Œ|sd9 N‡XRZ;i¤¼¹©¡‰nS8% ïCGJB?=5GME>.õ%55BP:C@77ü=;1-î ,*%"%" %00&-î%32025/(#-î):86762)  -ò )<930,*!.î (::884,".ï&9;:82(.ï%8962,%-î$761/*$.ï%4323/)!  .ï (:<=?;3*  -î-1-('"  .ï  !.ï ()'! ,-ç")021-( 3üÇ !##%$!4       à !#%# 3&"!"é Å ()$*'" .55- *:9,$%,1+&)2>KK9(20 75((3' *=/ Å 0L@- $ZT@(2KQIEB@CEB>@L[`SRA:??WSFGVA5AK<( Ä 7SD(WZPA;>EOQH::HJC?>CFF]=4HNWUOPTA;GC7& à :WE&QYXR>.8MUM;8GLE>4//5P3.GPLKMLE8:F80% Ä  ;XB% SVTJ5'2GTTLGIJGB93.,6,/?E?>@?4+2B3-&!!# Ä #=T>$    OLG8( '6FPROEBDC?<4$)/+40./0 %@:(#&$$ â *=N:)%" %:==<70,,05:=966å70 ! ") -C72( Ã49I61*  7.036861+*-3740-+-/,$#&671( í76F580  $@&""ò%()(),/0,'#!##Á !7*$"05E5<3  "?   Ä   *,% (6D4<3 9 ç  #+& à 8=-:1"1(4@A;4.'"!)7?>;4/-13# )'#  Ã=4 5/"+'4@KOI>5//6?GLNLE?>EN:(  *'$!  Ã!@-1+!'1456:=735;BHA@DFA;GC0$! #/-! Ä &>0 ,$#442,.6MB'.* ! Þ &+-6D+24( #-7>6.% í*>QF)6-" # Ú *0264)&( '.+4B3)  í+;TM.7*##Ú  #-30);+ )D5&,=-# è+?XQ24##%%Þ (10.-+0 (-F<*+9,$ î.KRRH*&%%Ø (6:4(&.!&( !5ED3.5*" î0RKQ["+' $Ý*-,/96%$!! 'AQUJ:0+ î,JHQY%*' "ß!625;0#  $MWSSB1$ î)BDT_(+' ß"-89( P^ZPH5' î(CFWc(,(Þ '02/32+"9rj`VC.  î*HL\e',) Ý *>PTA* /M€ui\E- ï .JRbg*,(Ý  .0..23-! ,Ib}sXB<)  Ë +ERcf5.+"$"%).+  (8Ldv`>(* Ë.KW_Z2(& %'053)  )=>H]fI(  Ì0PYWI( $ %,7>;1# ?BAITN3  Í-NUN=" & '38993( &K.?SN2"  Ð #FNI<'""+ 5OG2*+(",>?.;E=% Ñ #FNLB0*)%"2BK;%"&&""9@5532.  Ð(UYPD232)9IJB1""'('#  2A@35,%! Ï *baQA-98( MYOJ=.(('$ #:CLI6)'!Ð '__O=&86"(30*(+.+'(%'3:?<2( Ò *K[VA,/* UHD?8/'%! )ANRVTD)  Ò +BYZC/$   'eTOI<,! ":KTVUO; Ô +KZXG3  3QB<6/%-358;4+  Ö ,^]RJ963)&%$ 1)&)( ×-l]KJ=& 4.%# (GXE62*Ö $<:52)! $E%!"(:JXC2+" Ø"$%% #D 4B?9A2$ Ù !!$'" !=  YR9/4," ð+.15.)&! %@#ã )9Sw¥Óìðõ÷ôòöðòóð"ã !.B_‰¹Ùìôôõóò÷òõ÷ô"ã #3Jk—Íæñõó÷øùû÷÷ø÷"ã '7OqžÛóöô÷øúüýýûúý"ã ):Sv¤ä÷ø÷úùüûïëæäå"ã *X~¬áóõóõøúîη¨Ÿ™%ï  .?Z°èôñóúúùîʬ˜Œ…&ç !.@[±çôô÷ù÷úðťހy&ç !/A]‚°æõ÷øöôúðÁ¡ˆyuç "0B^ƒ¯ëøõôöøûí¿„yy   üç "0B]­èù÷õôøû쿜…| à  #0C]°éõóô÷÷ùë¾›ˆƒ‡ß $1C^ƒ²êõóõ÷÷úí¿›Œ‹•!! Þ$1C^ƒ²ê÷÷øöøüïÁœ•¥//.Û,+)(%"%2D_¯íùöø÷÷úíÁŸ•Ÿ±ABAABüABBA A@Ê><:851.*&!'3D_ƒ°è÷øúûúúíÄ¢›¨½WZ[ZZ[ZZYYZXYYZ\[Z[[\[ÏXUSQNIC=5.("!)4E_„±éùúúùúûíÆ¦¢¯Äy{}|~}|{{}z|}}|þ}~~€r~||~}|{yuqkcXMA7-&"!$+6F_ƒ³êø÷÷õùüîǪ¨·Í«§©«¬¬ª¨©«¬­®®«¤¥¦¦¨¨ª¨¤¢¤§¨¥«°«˜–o[I;0*'(.8G`„³ãìîööùýðɬ«¿ÝÚÝéèåäæãàÞÞÝÖØàâàÚÖÖÑåãÎÑÔÝßÔØçæÕÕɾ²›~eO=3--1:Ha„°ãïðôûýýîÉ­®ÄáìíôðêëôðîñóììíïòôëåéâìòìàåîñéìôòêìääàÇ©†eM=425=Jaƒ¯æïìñûùúïʯ±Æßíëìééìóííñóìòñëíôïëñëéòøäéðòðïïðñôðõ÷æÐ§}_H;68?Lbƒ­çíêñùöùð˱´Çàêìëîõúöñïîíìïíééðòôøöòôõëïñòóìíò÷øôóõõíÅ•pRB;JXk‚œºØìèïóôõøú÷éÒÈÎÛÝçëêçíõúøé¿–tXC5*#!)4E_€¦Ùèåæøö÷îÌ´µËè-6APby•±Ôêíñðò÷ùúùíÕÇÏÞèáêîëèð÷ùíÁ›x[F6+#&3D]~¦ÜèäçøøùïÌ´·Ìæ0:GZrެËçóîìòõöûûîÙÉÎÜéëàíòíèóýîÆž|`I9,#%2C\~¨áéãæúùúðË´·Ìæ5CTl‡©ÎäïòñïôøùùîÛÍÍÚèìæâëññîûí̤€dN<.$$1C]©âêâå÷øúð̳µÉã?Pfƒ£ÆæñððóòõùúðÝÏÍØãêêææìðóõñШ†gP>0%$1C]~¨âëäåøùúðÍ´µÊæMc~žÃâñóïîòõöøôáÐÎ×ãìéçéëðññ€IÔ®‰kR@1&#1C\}§Þêæèøùúðδ¶Ìê`|½ÞóòîíîñöøòåÓÍ×äìöêäëðîðìÖ°mTA3' "0B[|¦ÕçêìñöúðÌ´µÉåu”¸ÙæéòòóôöùòäÔÊÒáìîíìîñôóîÚ³‘pVC4) "0B[~©Óéïíïöùí̳¶Ëä°Þíîîô÷öö÷óæÕËÔçðññèìðòøôÞ»”tYD6*   "0B[~¨Ïåîïòô÷íË´·ÌæªÈîòóõö÷øøõçÖËÏâõôïòêíïðøç˜w\G7+!  "0B[}¨Òäëïõô÷îË´·ÌçÄØßëòôõó÷÷îØÈÌÞêðêçîòòðîìÈŸ{^I9-#  !0BZ}«ÜéêîõöøïͳµËæäèêíòöõôôëÙÇËÙåèïíëîö÷÷îÈ£€aJ:.#  !0B[~«ÕêððòõøîÌ´·ËâêðóñóöùøíÛÊËÒÝåçìííòôúðЧƒeM;/%  !0B[¬ÔéññôõùïÌ´¶ËåæññóôõúñßÏÊ×ßçêæìëìõ÷ñÖ¬‡hO=0&  !0B[®×éîðööùðÌ´¶ÊååñìôöõôáÐÌ×äìòòéïíìööذ‹kS@1' ƒ !0B[€°Ýêíðööøî̳¶Éâó÷÷øùôåÒÍÕãìïðññõôõöܵoVC4(  !0B\€­äðñõö÷øí̳µËåõùøùôçÔÌÒÞçñîîñóòöóẔsXE5)  ð !0B\±êõô÷÷Äúð̳´Çáõ÷÷õéØÌÔÞçîðîðôòðïâÀ˜v[F7*!  !0B\°éúú€‡üðÌ´´Æß÷õõëÚÍÏáéîòìíòöóîàÄœz^H8,"  !0B]‚°æúüúûüüïÍ´´Æßø÷ïÛÍÍÞèíðïèêñ÷õçÆŸ~bK:-$  !0B]ƒ²å÷÷ôö÷øíÍ´µÇÝíÈx‰’µº·ÂºÏÊ {Y9Þ )T‚·ÓÚÛÝÐÅÆ¸¶˜jZks™§«±ªÉÆœmE#Þ=o›ÌßÜÒij¥œ“ˆhJDSYx‰“žŸ½¾ ™yR1ÝRh|‚™¤›†g@&Ú ?w­ÇÆ¿µ£fQ=0&6Uqs…Ÿ±¥ˆiH/Ú 'N„´ÇÈÁ²‘qT:! *Nqq}›¸­’sS: Ù)Ku••™Ÿ˜uW:" %Dcqy˜¾·Ÿ†lD&Ù6b¯© “}^L5  7Rnt‘¹¹¦—K*×*Q‰ª¯¥—„lQG4 $&CjrŒ´¹¥œ‰M2 ×8gŸ®™’ˆ{iQF1 09DJ?-9fs²¹¡”€OA/×Ar˜‰†„|m[F+4BIWdkeN.)]t‹¤°œŒz\P8Ö )Nt“ª´ ‘€n_DA]jYny}~fH'OyŒ–¯ƒh^E'Õ5U‚›ª°š‡vgX/9m‡ˆxˆ”—qD:rŒ“­”Ž}gI-Ô %Gh™­±¨{mcK*c’¦™‰ª¨³šk="Z‡™¨†ŠŸ—pN5% Ó6_‡±Â½§Œtj`:Bˆ¯¶¨¤Š’¯¡±«ŽZ 7v›¤‚•³š‚fH2Ó!Iy§¼Å¹š‚odS"+g¤Àº¤®‘›¼ ­À²p+&^𡔢³¥’uV6Ó .Yˆ°¸¸«’zk^CB‰·Äµœ³•¥Å“™¾ÁJA’¥—–™“c;%Ñ:g«¬¨ˆrmZ5cžº»«™³ ­¿…°¶Ša)z¢ˆ‹ŒŠrE,Ï !Csš«¡™liM$4{Ÿ­¯›±´°¤ž¦œŽu8"R‘‘”™—”U1 Ð0K~¬½žŒƒ{iW.C}Ž—«…s£ šp“¡Ÿš™a-9Œ—”ª¤›„[5!Ï:]™ÇÇ£Ž~ohM#^‡’™¤€w¡¡”w™¦¤Ÿžu3x—•‘  œŽsG+Î!Iy¬ÍŦ’}fe? 4~‘”˜›r|œ¡¤¢§¦œ”y@Z•¡˜™Ÿ¡›‰[6  Î/X–ºÇ¼¢{b])U•—””‘c~–Ÿ©®£”Ÿ¨šŽZ+7Œ¬¦ ©«¥•j@  Ì?iª¿º«“‡ydO%rž–†[€ªÂ´«•µ®¥¡€@f›«¦°³«˜zK'  Ë#Iz©´£‰ux|n>G Œ…ƒw[„³Á´Ÿ”aƒ´¶³°˜`J‰¥›§±°¥šl?$ Ë4^w£©˜|~|b)&a™—Œ…}rbƒ¸¼±¡’Ty¯³°®¥ƒ(5r˜¡ª¬¦Ÿ{R. ËEs’¯¥“|ysT8t–Œ…who„¸¼º´¢[y¬¬¤£¨šL#T‘ž£¥¤z]9 É ,X‡³Á¦‡‰njdE QƒŽŠ‰ƒpVy‡µ¼¼¹ªg©¥›™ž™k1}Ÿ¤¤¢™‰|fD)È>m™°À¥}abX.)n‘ކƒkCz‡¦³±¥˜mw• ’Ž”—‚-'^…‹•ž¢—ŒsL/Ç *Fl‘¥»£|yg`EF‚—Œ~‚j9~ˆ­ªš‹yn|œ‹…‹—•M'?p}‹š¤ –}X4 Ç/S{›¥´ž}wlZ4^˜‡yzƒl6ƒŠœ¤£œŽŠfa•…‚‰—h)!azŠ–Ÿž–‚e:f‡’œ ›“^+4wƒ†Š…zkT9 (LŒº½¬•|lqZ&j–›’ˆyeS@& N|~ˆ“‘›—†hA4eˆŠŒŒ‰…m5]}‚|„„sJ(4X—¶§xrzO(<ŒŸšŒp\H3Q}|‹£­¬£qS6 *Smoop}—–G ]p|‡Ž‹Š†b"-_qlotux{]7q¡©¨Ê˜”˜Š_2( 7Xwvƒžfgl/NxuwscPLTT;H¯©¡‘{bI2 =s§ª¡½Šs…Ž…^4(1Lns‚ž”nrN/[lb`YL@AKI,bœ¬¦›ˆnV=) =m¤¡µ‡o|ˆ‚]6*×(;bq‡¢˜sv‡iBXVPG=6A<%*e„ƒƒzjVC- ùBrœ©¨íc.),OTPVCGSX9& ß *>884.*688E=BOVH:* ý  â   166@88DRHA3 Ü "$!  %+,112ASG;. Û'8::971+!  !01BYH3%Û +:=>>8($ 82?[M6& í&- ð =,6YS?2-(Ù *2()*%  ?)/SRD=:-Ù 0:6.+(!  @*/QNA?>* Ù., #"  + <-4TP<85#Ø #& 2?#. 0(3QS@5."& × #:-,)$  )+>61" Õ )2/& -2,6&Ab=E8#-=EU66KR3Õ$.9<2&%12,9#>fC=:11@U4A_W>-Ó *16><-# *0.'6#7U93DG%#=ZGK]^P;& Ó"-0263'*,(#-&8L0(KV()?eG:DRZG, Ò$,&)-) #&$#!-/;B*&EM%*6X8'/@QG. Ð &/*&''" !#%!995/$./)! (*-3997- Ñ):J.'1:' #9'+& (0223#12,.@@<0 Ñ#3DL1*./#%5(')(&!08:94% 093.7:;7+ Î .>HG0++$  '."$*284:>=5) %<@83:?@9" Î!9EH>,+*$!&'"%)7ED>@?2& :KI?GLJ@) Î '?HC2%***$!#>SUJE5?KG@:+)ERTYYQB*  Î,>E;!#.$#- %FMD3- 7PRPPC&9HHMSTOH1 Ë&!9:/.&03" %%$HG?5,2MNKOK8-@BEIKJJ;'  Ë ,.E9&5)-/!$GGHH=!0EA9>E@ "940))% É$0;ZE"&"$6?>4)&21"!)30!'/683) È"6S@!+! %.86*!)."04,8?9,È$+5N@&0%#"  "%*,00)( +$04!  *4:8- Ç $241.$50+# &0&('&(  '$ %#$%# à 1@KG9235-/4-)" ,5+$$)*! &,)%)01-' €# &H=J2/9*(.87*#',/1,  "/40*   2@U[L1+"2A>=4' .Q@,+%  '#(/+!  6GLQH52.% #7>92* )C6!  !#&'" '22.' $:LLIC:40!.30.)! %2&$($! +2)+ ,/120& ',1!#').1-&  (@PH<=G;, )1%%"('' "095'  ('%$##(!%$&160 ,GRG7:KC*=>,!($ (%+2=?9-   <7* &&(%"#'(?K><;@G>3RB+#,$  #$-04-   #)*)% #)  5Q<26AE/ '%   &6*!$" #+,#$# ",37+9P<-1>@CI7&  -C(%%$#$*($$2<@=- .AG5-283 +JD0(# "3O+&   # $$#! *-351( 2;$2929QA')* 1V&€ð  (! $12  &('(,8(2781#.6-%KY=!%  .X#&'))"  "&'063&-010.!3;5+('.( ?[S2  *U&8AA>8)  $2>@?:1$ -7;:3' 2<4*)%' O^G$#  'O=PUK:,  %3?FEB;535<:77:6*&>E;,#)#,IQ?-! $G#+1.$  ,)%   0>B@8(&#$494-)%:3BM( "@2896/(   #2@A<889/#5=@?9<>AKN<)&# F1BW. !?FPNC92( &9KOJGII>!%/6;;?DHKK7$$ &QBKR( #DIQPJB:. '?A?>AB?) (,'*040-% # .X[UB Ã)L@@AB?7+ /-*,046(  ###=XkZ1  ® -R_>,8HH, #/&'82$ 4;,))& +6=9+ $38=`21JN- – .76   09(%$!/9530,$ "34/O'-FJ,(57( '0831-& í,-,H)(@F) Ø #!)<3,0   ù".10àïòööîîëëðæîåȳ–sT=-! ä "->WwœÃä÷óñïñõù÷ðòõõòôôêìïèØØ­„dH5'Ç )6Jh·æ÷óùóöüúøú÷öö÷ùòôù÷íðêàè½’qV>.! Ä "/@Z|§Ûñøùøüýú÷ùùüýüûü÷óô÷ððêäñÒ¨cG4& ã (7Jhºîõõùùúúûýÿÿãäääåèï÷ñðëçñæÁ”rR;+  Ê !.?VužÌñóóøùùûùðì鸶¸»½ÃÓè÷ðïíëíôب]C1% ¾ &4Gb„°ßðóô÷úûûîÓÆ¿”“•š¡©¼ÚöîîïíìöèÁjM8) í +;Pm•ÆòõøøÚúûïØ¾¬¡€~ƒŒ˜«ÉêìíððêíëÓštV@/# à #1C[}©×öíôø÷ùÿèÆ«™Œutvz‚Œ¸ØèðóõðëîÞ§„cH5'  (7Lh½åùô÷ûú÷öÚ¶œŒ‚stx}„ˆ“©Çáð÷÷óîîẕpR<+ ï !->Uv›ÍñùùÔúûøêÊ©”‹…y}‚‰Ž‘ ¼ÖëõôîòíâÓ¢|]C1$ Ÿ &3E`…ªÚ÷÷óôöøûß¼¡–•’ƒ‹’–›š˜ž°Ñæïïðëðò㳊gK7(  *9Nl–ÇéùûùööøöÒ¯£¤ Ž›¢¤ª§§æ¨ÄáïðîäéôñŘrT>.! ƒ "/@X{¨Öñùöú÷øøëí¬¶¶µ¡­²¶¾¾¼µ¬»ÙîòíçèîïШaF3%  '5HdЏâóõóùùûöݸ³¿ÉÈǹ¿ÃÈÏØÒź·ÏèóìñîçãÙº“nO9* à ,UwŸÊðóöúûûýïÔÄÛðøõôëë÷õíêôòñóÙÆËàîôõóñçæÓ¨|[C1$  %3F`†¯ÖïõöøúûùæÏÑê÷ùöòì÷ûùôì÷ø÷úïÕÍÞöüûúûùõ์hL7(  *:Nl‘»àõüöñõúñÚËÛöü÷ôñòõûü÷êöüýýúâÑÕîööóó¢ëÒŸuU>-!  #/@Ww¢ËçîúøõùùêÕÎçöùø÷íóòùû÷ìöúùúùéÕÍç÷ú÷öõóòã­_E3%  '5Hb…µÚîñøø€úøãÓ×óùúúùìôó÷ø÷ñö÷÷øøðÜÍßôûøöóððèºkN9)   ,."$1BX{ Ââçìô÷øûïØÖíúùùûýøìúüøùùûùñóøûüûûøìÕÔåúöõõóõõÚ¬‚`G4'(6Jd‰¯Ïêíïô÷ùõåÑÛîúûûüþ÷éøúûøöúüõñôýüüú÷ößÔÞ÷øøöóö÷å¿‘kO;,!#.=Ro–¾ßèòóóùûîÛÐäôûûúûý÷è÷úøø÷ùýúðïüûûù÷ûèÕÔîøùöõõöïÕ¡xXA1& (4D[|£ÌêãóõñûûèÕÔîúüùúûý÷é÷ûñúüûûþðëûûüüûûî×Îäøùööóðöì´†cI8,$ %-:Mg‰±×íäòóðùøâÔÝõûûúýþüóê÷üö÷ùüûýíèþúú€¿øù÷äÓÛôúø÷óôøíÁ–qT?1)%%*3AVs–Ããîîóõöùï×Ðåôöøûüýöîìùúùùøúûýìæúúûüüûúê×ÓìøúøöóóîÒ§_H8/++1:JbªÐèïñôöøøåÓÖîö÷øûûýñèðúúöùùúùüìäòøúûüûûðÝÎãóù÷øòññ⸎jQ?6128BTmÂÝéððõöõöÜÓßö÷øúûûþíãóùøóøûû÷üîâéöùù€û÷æÐÚîøöùôóöðÈwZG=89?L_yžÖæéîîöõñïÕÕçúøúûûýýéàõø÷úýûùúÿðáãûþûùúøúòÙÔéúûöõôôõ×®†fRE@AFUkаÕåçèôöøôãÎÙîúûúûýþöâÞ÷ûùôûüúúþñàÚöúøùüûûôâÏÝòúó÷öòóæÂ–s\NHIP_y›¿×åêíôõ÷òÙÑå÷øøùûýüïÝÝ÷ùøôûüûúþñÝÓí÷ùùøúúöêÑ×êùôööóðñÒ¦gYRS[k…©ÒßêïîõóñèÒ×ìúù÷ùûýýéØÝõö÷õúûúûþñÜÍãõüú÷øùøòÚÕãøøööõïöÞ¶td]]gy“¶áéððìõôìÝÎßðøø÷ùûüúàÓÝõô÷ï÷ùùúüòÝÉÙðýýüúøùùãÔÛòûú÷ôïóæÇž‚pggr‡¥Çäòòìéó÷ë×Ðæóõò÷úûùïÖÎÝõòöúúøùúýòÜÇÑè÷ù÷÷úüúêÒÑæòòôôîðôà­|st~“²ËÖèïìéðóãÑ×ñø÷÷úùûúåÌÊÜòñóùúø÷÷ýñÚÄÇÜïöôö÷øøðÚÑßõ÷öõòðöç» Š€Œ¤ÈàÞçììëñíÚÍÝóøøûùùûöÚÃÆÚðóóöúúø÷ûðÙÁ¾Ðè÷ôööéåÕ×ò÷÷õôòôêί˜ŒŒ›¶×ìêìîîÝôçÔÎãóö÷ûùúùíлÂÙîôôõúûûøúðÙ¿¶Æâø÷øø€±÷ûíÙÐåñööóõôïâ½¥™™ªÈÝèîïòñïöáÒÕëôõöùûüôßŵ¿Øíòõô÷úü÷ûòÙ¼¯½Øñ÷üúøûûðÜÍßóúöóøöòê̳¥¦¹×éíìðóòîîØÐÛñõ÷øùûþðÓº°½Øññ÷óùúøøùïÖ¸¨²Êäöüûù÷ùùêÕÙîùùö÷÷ôíÛò²ÅãîììñòñîæÑÑãõóõ÷ô÷ùæÅ°«¹Öôòñöù÷öøøíÕµ¡§¼Ù÷üú÷ö÷ûòÝÑåõúùöõôðåϾ¾ÒêïëíñòòîÞÏÙìôò÷ùööðØ·¦¦¶Ôõôíù÷öø÷øîÔ²œž°Íóù÷öøøùôåÍÜðúùôòóóíÙÊÊÞîïíñðòòë×ÒàðñôùûúøæÈ«¡´ÒòöïöùúüûúíÒ®™˜¤½ßîõøùùûúïÕØêúöòðñôóãÔÔéñðñùðñðãÏÕáêï÷÷ôôúݺ •œ±ÏìöòñúüúüûìϬ–‘™®Ñóüø÷øøùõÜÓàô÷õôôõõêÞÛìïñóôô÷ðÜÎÛåêòóõ÷öñΫ•Œ˜¯ÎîöðöùùŸúüîÏ©’‰£Âéø÷÷ù÷øùåÑ×îù÷õôóöðçäôôõõñõöê×Óáëïõðõûö⽞Œ‡“«Îóùíùöõøöùìͦ‚†—²×ïööøôõ÷îÕÓæ÷÷öõôøõíêùöö’òõðàÑÛçíðñò÷üöÒ­’„‚ާËóùêóôôõôóæÉ¢ˆ}}ФÆçøñòñðòóÞÔÝïöøøöù÷ðìöññõ÷öéÖÌäëëééöùúòž‡|}‹¥ÉîóêòöõóõúëÊ¡…vu€–´Úõõöõôô¶åÕÓçïññðòõòïöôóöûúçÔÒéòñíí÷ùñÞ²‘|tx†¢ÌøöõõöôôøùéÇœqnv‰¦Íìñòô÷øôêÙÐàðóðñïññ€Ýõôöø÷óÞÒÚëîîíîôûðÌ¢…tns‚ Êòñ÷óõôóô÷èÅš}lhn}—¼ÝìëñõôôïßÑÚïõôóñóóòõòõùöëÕÑàìêìñïôú軓ylhnžÇïïóðõõñíöèÅ›zhbfr‰ªÍéèïñíôóæÖÒèõ÷ôõø÷ó÷òôùøãÐÒæïêïõîùôש†ncbj}›Æññïôöôóñ÷çÄ—wd\^h}œÃëñôöõööíÛÊßðöõõöö÷ù÷ö÷ôØÐÛîõððñíýêØwe]]g{›Çóðïððñô÷ûèÁ”taXX_q´ßîôõóóöòãÌÔæóöóõööõõù÷èÍÑæøø÷öõöüÞ±ˆm]VXbx˜Ãòôóïðïñö÷⽓r]SRXf£ÎíòïðòööìÓÌÜïõóõöóðôøòÛÇÖìøö÷øøúõÏŸzdVQT_u—ÆôøøðóòñðïÞ½“oZOMQ\r“¼éïìðòõøòÚÆÑåïó÷÷óîóòåÎÉÞñôôõöøúç½n[PMP\s—È÷øùïô÷÷ìíàÀ“nWKHKTg…¬ÛíñòñóõñßÅÅÕäïõøöññåÑÁÍéöóöõõ÷÷תeRJHLYq”Å÷ôõ깺·»ÃÆ¿¸¹¿Ã½¿¶£‰`>%)ê…ˆˆ‹’˜š™ª´±À¼²¤eC*)êOWX\dlrw€šœ¡šŒ„hJ.)ê5::>GR\hz §§¤”k\F*)ê#%%(/8COg‚˜¦£ŸeXB()í#.LoŽœš‘‚jU?()þ  î%Q¡¨¦š‚`I7%)ê (_ާª¦•yZG6$)ê.b‹£¥—„shQ:$)ê! 4bˆ ¡‘~tx\@&)êGE9' 6j’¨¨ Ž}]B()êlg\D&9s¢½¾¸§yU<&)ê‚|kT38gŒ¤§ €W7!)êŒ{fP50Y|”—v‚U4)ê’~hR: *Yž–‡{zN2 )ꞥ“wV-6i‘­±ª›ˆrK2 )ê›§“rQ+/cŒ¦«©›†oO6)ꙡŒlL)'\ˆ£¨§™„nU: )ꎔ‡pQ)&Y†¤¥ ‘|eQ9)êw…ˆ~],/X¥škOB3!)ꀋ‹],0Uw”ŽŠ|j^K5)ꎔ‘€\+ 0Qs‘‘‹}mcK4)ꘗ“\* .Pt–˜’…wnP5 )êš‘`, ,Oušœƒ\:)ê—„†ƒe/ *Lq•›ž”„zV7)ꂊ„f2(An¥–‚ssX=#)ꊃŒb2*r­–—gO7)ꇀedT.(Jv£‘˜‹rlQ7 )ꎅfcS.+Nvœ™˜‹wiN4)ê–‰hdR,,PyŸ£šŒ{bK4)êŸkdP**S€§ªœ{]J4)ꨘndO)(Zˆ©®¢’}bH1)꫘pcM((`‹¡««š~aK4)꣗p]L.&e £“w`I3)êš•mYL3%f“—˜‰o]F2)ê–’l\L/%f” ™šŠnZH5 )ꌉpdP, (g–¥Ÿœ‹p^J5 )ꊄriQ( )f”¥£ ŽpVE3)ê„vpT&*f”¥¥£pSC1)ê†|yY& +f”§¦¥“sZF2)ê~{yZ& )c“©²¬—x^H3)êš}|]))c’©´­–yeN7 )꧉‚€`**aŒ «§ueP9! )ꮃ_))^„“œ‰qdQ;")ê­†{uV% ([€”•†skV=#)ê©‚zsU%(a‹œ›Ÿ”}lS9 )ꡃ{rS& *h•¨³²¤ˆdJ3 )ê…xlP& ,h“«É¿¨‰bH2)ꡈodM( -aˆ¤Ì¼lQ7 )ê°™kiU* .e¥¹¯”znP6)깤lnZ, .g‘£¦¢yuW:!)ê½§qp\--i”¢”™|uY>$)ê¼£yr[. ,j˜¤…””€qW>&)ê´™ƒv[. +i˜¥}•™…y[?&)êŸ~w[- &]ŠŸ™Ÿ™ˆy[>$)ê”…upV) !T€˜žž”†xY;")ꕃsmS(Vƒœžž”„wY: )êžw[,$a”®°«›ˆ{]=)ê6@>=DIC:8=B9;727) )ê&*%%+20)9>3A=875, )ê #!"11# )ê &./02/#+! )ê (16330!' )ë !+1,'$$"*í (350( +ì +11,$ *í).-%!*ë (/-#1'*í -44-$"0%*ë#$! '9CB=4,)*ë#! &-/) !: *ë#  #&!B *ë% %01-%&; *ë*2.! .9<71/4*ë&,& ",/.)'.*ë%( ,21,',  *ë!%! "241)#$ *ê"+, 1& )ë-2- .& *ë)7:. -% *ë/:=0 +$ *ë/172#)&#3"*ê) /5)/..'#. )ë(%75+:3(*! *ë)+;1(B8! *ë(*6(!"F;!*ë%#'$F>& !*ë##C<*'( *ë!   "@:+,. *ë!&$  :6*-1 *ë$#&%!2,(+,*ë-+ &)%)& #*ë1/! %+,)%"$*ë54"!%44)%& *:í"# )=6+&%*ë?@&$! ->42-% *Aí'$ "0;+75% *ë>C,#/8/34,!*ë9C/!;?$>/! *ë3;'9?'=0" *ë$.%! ;D*>0# *ë$,%!=E*@2& *ë,0)' @F(@3' *ë2401'AH+?4)" *ê/+6:,?L7>:2)" )ë6.?D28D5360&! *ëC5DG4/7,*,( *ëO8AC0)/&'(# *ëU57:( (0+-1+ *ëZ789( *768;5'*ëZ;@;(,89EE;* *ëV=E7%,55PI9) *êP>A.*//QD0$  )ëQK6/$,43@8(# *ëUS30'.72--#) *êYR50%/;4&%' )ëYJ=/"/?8%-#"*ëW@E/.B= (5**  *ê<74,  ,+ ,214% )ê+)#"  "%)+.3$)ë(! "'%*++0#*ë,%"   .446303)*öâõôöùùøööø÷ðòîÇŸuQ9' àúøööøúøô÷ùöõïðïÛµ‡]A, ýúûüüäûúøùùö÷õ÷÷ëÓgG0" ÿãþýþþüùøøùùø÷É›qL4% ßçååääæéìòøûùûúùûΡvP7' ß»¸·¸º¾ÄÎâóûùùøùûÔ¦yS9) ß›–”–š ©¼Öëõ÷ôóöùÛ­|U;+ ß„€‡›±Ðìûøõ÷úõ׬~W<+ß|xuuzƒ’«ÏìøóøúùöجX=, ߀zusu}Œ§Íëõñùú÷÷Ú®X>-  ߌ…zvz‰£Èçö÷÷øøõܯY?-  ß›•‹ƒ|{‡¢Èæóö÷øùõá²Y?-  󱩟‘…ˆ¡Åæ÷ôööîôÞ°}X>-  ßý³£“‰Š¢Æç÷õ÷÷õñܯ~X>-  ßÑÐÆ¶¢’Ž¥ÊèõöùúöîݱY?-  ßÜàÝȯš‘¨Ìéöôö÷õðܰY?-  ßçïïÙ¼¢•«Îìûø÷øøñÞ±Y?-  ßëöùäÇ«™®Ïëùø÷øúóß±~Y?-  ßî÷ûêϲž°Ïéô÷÷ùû÷á±~Y?-  ßöúøìÔ·¤°Îèôøùùúüá²Z?-  ßùøöðØ¹§³Îêýüø÷øöà³Z?-  òûù÷ñÚ¼ª´Ìèüö÷øøïá²Y?-  ßüúöñÛ¾­µÌçùòöøùûâ²Y?-  ßûøõóÝ¿¯¶Ïêùõö÷ùúâ²€Z?-  ßùöõøáÀ¯¶Ïêúöùú÷óà³€Y?-  óöóøùâÀ¯¶Ñêõ÷øøîôÞ²€Y>-  ô÷õø÷á°·ÓêóøøîõÞ°Y?-  ßùøöõáñ¸Òéóøùø÷øß°~Y?-  ßúøõúä°ºÑèõööõöûâ±~Y?-  ßùøùüãÀ°ºÓìùõõ÷ùøà±Z?-  ßùúúüãÀ°»Ôíùõö÷øøá²€Z?-  û÷øûäÁ°»Õì÷÷öîøâ³€Z?-  ßüúùüå°ºÔëöûøõ÷øâ³Y?-  øâúãðºÔéñöûûúûß°€Z?-  øáù÷áðºÓëøöø÷öùâ³€Z?-  ÷áúöàðºÐêüøõóôùâ²~Z?-  õáùõàİ¹Îæøøõóöü߯~Y?-  ßôñ÷ôàñ·Ðæñôù÷ôùã´€Z?-  ßöôóôà±·Îçõóõö÷ùß±€Y?-  ß÷ôðõáÁ°¹ÏèùóóõøùಀY?-  ß÷òòöâ°ºÐéúôôöùùá²€Z?-  ßõðöùäð¹ÎçúööøúùݯY?-  óõøúⱺÌäöô÷÷îûâ³€Z?-  òòôùûâÀ±ºËâ÷òôööïà²Z?-  òáøùáÀ°¹Êâùòóõ÷÷Þ±€Z?-  ßóðöõÞÁ°¹Éâùôõöøþâ²€Z?-  ß÷òõôß°¹Éâûõø÷õûã³€Z?-  óóõðóà°¹Èáùõ÷÷îöÞ°Y?-  ßîôíòà°¹ÈáúööøùöÞ±€Y?-  ßíñíñÞÁ°¹Êãú÷öøúùá³Z?-  ßðòñïÜÁ°¹Îãñõ÷õöùÞ°€Z?-  ßïõñðÞ°ºÐãîöóóööà²Y?-  ßêòîñß°ºÐåññòôöøâ³Z?-  ßçðìðÞ°¹Ïæôïóö÷ùâ²€Z?-  ßéñíïÞ°¹Îåôóõ÷øöß±Y>-  ßóðíñß°ºÐæòòõö÷øâ²~Y?-  ß÷ñïòàðºÑçóòõöö÷ß±Z?-  òôððóáðºÐçõòõööïÞ±Z?-  òîðñôâݹÏçõóôööïß±Y?-  ßïñô÷âðºÓêõöôõ÷õÞ±€Z?-  ßóöøúäıºÔì÷õ÷÷öòØ­~Y?-  ÷áúûåı¼Öîúùùø÷ó׫~Y?-  ß÷öúüåı¼Öîúú÷÷øôØ«}Y?-  öáúüæÄ°»Óêõõóõ÷òÚ­}Y?-  2ò 'ScŒ«ž²«›ŽjW/ð x¾§—‘ƒ#ä@g«ÆÁÔà³q[G=3)n —“¢¯§š~#ä ,Ty¹ÑÃÃË—TJ8.#;€¯œ•š¡¡œˆ#ä8e•ÀοµµA=+! B‚­••—•˜"ã=j¢¾Æ½°§r;5! %BxŸ‰ŒŠމ"ã;f›¯¾Ä±¡p>0 '>i‰€|z|"ãAr¼¤·Ÿšp>/ $:Xnkrqnmfa"ã@k®¤¡³¤–tN6  *BXepkefb_"ã?g¡¢ž¤¥‘|fE$%8P\YTTYV"ã@i ˜ŠŠ\6%%+( .6985<9"ã<`Œ‰„¢¤¤›~ZUWR`NDHD60-$ "ã3OuŽ¥³³¨¦½¯”Œ¢¥‹ž¶¬’‡‘ih"ã1Ii‘§«¹¶¥§Óƪ©Çº¡¡¼àÎÀ»´‘•"ã1LiŒœ›¬¬ŸÉ´«·É¯œž´ÓÀÁ¾£’¡#ä/Jf}‚~—»¦²Àµ£¨¤ ºÆ·¥ … #ä 3Ckuhk{us–ƒ“•w’‘…ޤ˜‡‹wˆ#ä#.RZOP\TPpaihT_prhhvh\hdc#ä &8<8=A62ODBB=?JMGEJ>7EH>#ñ&&$*+! 3,(''õ,+&'*$".)&$å%æ     &÷û 1ý @1ñ )3Id{dH72/ð B\oyv]@10.ï%]vƒnY;*).ï+27lw}bS8#.ï%?HJemvtWK4"-î-O^Z^djeK@/! +ì -[m[RY\S>6*+ î!-_rR@JPF50% **ë23WkN-9GD5- =)ê -F=\kI'1>?7&3D(é$,268Tme?2,5>, /EE&ç /WkY54*/58EH=&ç *X`VE8>NJ-%(("DVQ;/%æ .)%æ)EwU7/350&& 4JTUK,&$å +H}lC''&'&  2NLIF@-*$å )AC8+#ä MdYFeG ,AOF?@G<4#ä .HVP=R4  .CPIC@A<8#ä1CSV?J- *>LFCA=95"ã  6SaEI,  #2E?-(#& "ã *:?C?5<_GaoI'OH*XVJBHL9"ã 2GHG@3P#ä**$11.;`=Vb9$HF2ZaQ?<1M#ä -0&,)/G.FL'*93'BWO?:*A$å&&"4#.0#//(/>5).,/$å  %$(!$&$å      %æ       &þö÷'ûúù=þ?#ã %/Z~¯Õçéîòô÷üôßŰ­¼Øìáæð÷õ÷óÚ "/Ec‰¾Ûêñððôùùäʳ¥¬½Ùíáèñöö÷öÚ %4Kj“ÍàéóññôöïÒ¹§Ÿª»Õêæðñðõ÷úÚ '6OqŸÝììðñô÷óÝ§µÍäèòðíðøøÚ (9Rv§àõñèöõùôÕ»§œš£°ÄÙåõöñóö÷Ú );Tz¬æúòçö÷øðÒ·¦šž¨·ÉØêôööúùÚ *;V{«æùôìöø÷íѹª¢ Ÿ£¬¹ÆÕãëíðñÚ *:Uy¦âöõñ÷øøïÓÀ´®¬«©«²ºÃÌÔÙÚÝÚ ):Tx¦èõíê÷õöñÝÍÆÂ¿Å¾¼ÀÄÅÇËÎÎÐÚ '8Pt¦àôñìöõööíçÜ×ÜÝÕ×âæäàßãÛâî %5LoŸ×ïóïõõïòöéãìëàäñõðîîëéíð #1Hh“ÌêôôíóòñöíèïðååïñíïðëðìÚ  ,A^†»ãøùôòóôòóîëîóðëêìîìíöòíÚ &7Qt¡Òðõñðóõòóîíõøðëìðïèèóøòì !0Ea‡²Øñ÷÷ööð÷õôöøòïñôñîîñôñÚ (9OlŒ³Øêóõ÷ùúûûùù÷ö÷ùõ÷ùôóóÚ !->Rk‡¥¿ÔâëïðòóóòòñòòïòôïîñÞ #.>Obw‹œ¨±¶·¸¸ºº¸¸¹¹¸¸¹¹þ¸â #.9FS`kt{‚„…‡‡†‡ˆ‡‡ˆþ‡æ !)19@GMRUX[]_``üa``aaþ`ã "(,047: ]ˆŸÃÉ«fG0" Ü3Zˆ”—–q]4 V Iš§¡ÀÀž{hO5# Ü5YŠ„vsg`T1 SŽ1¹µ ¨˜ƒjP6$ Ü5X‰”—™‘ƒ{l@Q‘*]§Á¸¢“xjX>$ Ý3Rz~І|vg< N’Y³¼±žˆgUE/ Þ3U‚}|xok_7 I†Œ®²£Ž|]E2! ß6]•Ÿ—Šupd: H‰œ„¤¥ŽrdL3  à9cŸµ½ºª–ŠxDM˜~–Œu\I5# á9cŸ³»»©’ƒoAPŒ“x€qeS5$ â1S•¨´¡ˆyg<PŒol]WL( !ã1R}‘§¶£‰zh<O“eaTK?# "ä>l¥¹Ãı•…qASu]]UG4! #ãBp©¸ÂÆ®“„rAU¥o^fR:$  ù ïÄ=i£²³¯¤zd:V¤qaZ>( %"!)42/055/0=;=>=?;1!Ä9d¯¬ œ‰u^5 V¡q]F96AXZVSWmnlmqe^coqtvvsy~~wrquzvun_M6Ã:fŸ±® ˜…u`4 Už^Ka{ˆ’¥“› ™£°µ¶¶žžª®´´µ·¯µµ¯¨ª²¸¶°¬¤–dF*Ã@r¬´¬¡“r]5 S—x{›¯°µË²§¯ÀÃľ¸·ÁÊËÔÅÀÍÓÞÐÂÊÄÁ¼¶µ¹¾´‹pZB ÂArª°¨ ›te6 N…¦²¶ºÃï®Ä¿¿¶ª«µÄȿ÷´½ÆÉÇÁ»»ÃÄÂÕÖÔ˵–tP.Ú@p©°¯¯ŸŠ~k; MŒƒ†“›¤¨¥À¬ °¨¨—¡¯¯ŸžžêŸ£ ©¬œ ¯·¹ËŸ±±”tP3Ú>l¦­¯²›k= Qxy}†ˆˆ£”‰“‡€~…Ž„ƒƒê„ˆŠ‡Š‰ˆ‰‰znebed[I0 €>;j ¦Ÿš—ƒxg9 V–bhfpjevyyup{ngjldbehgdehluspv|{‘“ŒŠ‹ŒwX;" =o¦­¯´¬šxFOŽ^bii_\klrrlqbclc\V]rmlmoqmpw}…Žœ©§¦¦¢™ƒe>%@p©¯ª§¡–ŽzFQ–SUa\SP[^bda^QWbSQLRd^^_`^W^ilkov‚“–›¡¢za:#@n¨¯©£ ™•GS›7:@A;63& à )Icx…Œ”œ¢¨ª¬ §™š•ŒˆŠŒ“‰Š|“|†‡usx‚upoqreYNA8/&à 7L`eafkpru•Šyxdhlifcaaflrrc^cg[gm^hicZW[dhcYUUVQG=4-("ë"2AFFJMNNQlcTR9=GC??Ú>AEGG>:=@9=@@EHGA=<;5.'# ë *27;<<:;C;34'*0)%%'Ü(*)$"#&""$#%()(')*+,)&%%  í(+*-.-+*)"ýôúø ß     ö    û õ   ò    þ ü øú þ÷ýþaë 5XM7-1) Û"6:;=;4.&*D %9K@1.0" Ü,15882,#+C &+,CL8(,, Ý #'(')%! (< C:.PT6!%" Ý$$  !4 +L?*:0*% ß$''&%##  !< 4KB-'!$ ß?7F>.&à ;)5@6),!á%(&! !#!73/9+'  â4=BB<62, <0+/" !ã#;DGGA81( (F,%$  "ä !)3=80)" (I'"  #å &3@;2,$&K!#  $æ /DMTWOC;1(P"%# %ã +?GQ[SF>5)T"*  ê Ç-3;C>5,$'R'"%      Å*/11.' %M*!-"#0.&#&)-0''(*))%"%$ Å%7:6-*$  $I$35:HH89:17@C@<51, "5A;3564.$Ä+=920)% #A)$5BIQ^ZRKIRB@JH;EH7=GLICM<,:<9668;><0' â,?<2,4&  60+57-$Û(<86;5.)" 31+*/?H;]B3I2340-,BG))ê+/&/5!!49/95.+,#Ã"3-0;*+)  7.) &04.B5-7+').-#,3+)''+1,!   Â+& %<'%!!&%*)!'!..""#% "'" Â#210460,& !1!"%"("+.&)#4(&"!#&' !(.,.0495442-*# ù&7522Ê/,% %:*"%"'+)% 1% !$&#'+$%)*+(*03($  '97200.,# $?      +   $7877841(8         .)')' Ã"378742/' !<02"GB,58:<:0/B (#(?5/'"*"",6:/(%%$ ø031//â) :EJPJE4VR@LRUUQF3J_+2-.=1.--ì!)54(% à*,+,-.*""M[ZTVEADC44:4 2:&$#"" ê D4"-0+'&'((Û+/22&!&*&-" ! Ù 6&"! î è    â     î    ü  ú þúý þñùþþý ðóøø ûhÝøðÜËÍÝíïñðëëîõøë˦ƒeM0%  !0B]‚±êöõöøúûð̳µÈâäÑÊ×èòóóïîóöõîØ¯‹lR?2' þ£ !0B]‚±ë÷öøúüüï̳´ÈâÓÊÖåîñóóððô÷õÚ±pU@3)  !0B]ƒµîúùûûýüïÌ´´ÈäÍÖèîî©õòòóóûÞ·‘sYD4)   !0B]ƒ³êøøùøûþòϵ·ÊàÓâðòðñôñó÷öå¾—w]I8+" É "0B]ƒ²ìûúøõøüñδ¶ÊãàíñòóôóñööèÅž|aL=<<;È:98753/+(#'3D]€°é÷ôòòöøìË´µÈäö÷öë׿«œ„ypic_\ZXWVV€ÀUTSSTTRQOMLIE?82+% !)4E^ƒ²çòó÷óôùñË´¶ÉáõñíÛʼ¯§ž”Œ‰‚~{ywutvxxvuuwxwurqpmhd]SH=3*%!!$+6E_„²èïðùõöúñÌ´·ÊàñêâÕÌÇ¿¶­¨«§¤¢¡›˜šŸ£¡  ž£¥¥£žžœ—“Ž…xgVE8/(%'-7G`ƒ±ìñðø÷ùûïε¶ÉáðèåäàÞßÖÕÓÍÏÒÔÕÔÆÄÍÖÓÐЋËÏ×ÚÕÔÏËË̳¡v^K;/+,1:Ia„²éðñú÷úüñ϶¶ÉâòôïðíëîåßàäâáäåÜÛàèìéàÞãæêëèäôñìëëçÚËÁ}aH9204Kb„³ëõô÷úú¹íÏ·¹Ìâùôõõóðìñìèìòòîìîèéíðóøùöòôøûûòîíîöòóøõè¿nP@9:@Mc†³éñòøøùùíй»Íã÷÷ùäöóöôñðòõñìðîò÷øú÷õõøùøö÷ùøøúúáùøúûݬ|ZG>=BNe‡´ëöôøöùûñÒ¼½Îä÷ùùôúùõö÷øöö÷ôñôôøöùúøööúüüÕûúúûûùúù÷øû滉eNC@DOd…²ìûø÷ùùüóÔ¿¿Ðèùûýúùúùùúð÷ø÷õ÷úùùüüûúûûüýýÖûýýûúùøö÷ùïÌ”kREBEOd…²íúùúûúüõ×ÄÃÒéññôñðñððñúîïïîïññóäôõôõööûúùø÷ùõÖ›pUGCEOd…±è÷÷ùùõûòÙÉÉÖêÞÞâààúÝÞßßàÞÞøßàááààãââÙäåæèïûûúú÷ù÷ÙžtWHCENbƒ¯ãôõóöøøðÜÑÐÛìÒÕÖÖþÔÕÕÔþÕÔÔÕ²ÖÕÔÖ××ÙÛÝÞáêú÷÷ùööøÜžsWGACL`€­èôòóûûùôåÝÙàïèçéæçéååäåèççååçææèêêìîîêíîîìîïñöüûûÑõóØ›qUE?AI\{§ßòöøøõøúóñìíöðòöîîóóðïðóñððñòññôöøøô÷øùùøùøøúüûùùÍ÷ñÑ–kQB<=EWt Ùñ÷÷öõøüùøõôøìó÷ïîó÷ñïðòñððòòñòõøú÷õõøøùãûø÷ùûøöõõûîÇŽdK=79@Pl–Ðð÷ôöøùùöÅ÷öìðòóôö÷ìèéíóðîïðïïõüùö÷ûúûüúöûýüûüüøõøüã´[D834;Haˆ»èúõôøø›ù÷ùùôííïõôóôêéìíñððô÷òòõùù÷øúúùøøùýûúüùûùøüøÑpQ<1..3?Vw¤Ôñ÷ù÷÷øø÷÷öóðôõøöóöîðòñóòô÷÷ñò÷úùøùûûúúûûüûùùÍüþýõÛ°‚^E4+((,7Id‰¶Ýõüûûüùö÷ø÷öûüüù÷úõöø÷ø÷÷øøóõúüûûüÈýþýüüûùú÷õí×±ŠgL9,$!"%.=Qn’¹Üëóøüü÷úûùóòòóòñòðïðñòñïïññòòüñðòóóÛòðíâÓ¾¢…hO;.$&0?Tn‹§ÁÔâìððòñ븹¹»»ý¹¸¹¹ô»º¹º»¹»»º»»ººÚ¹¸µ°¨›Šu_L;-#%0>Pdy©°´´µ´®†‡ˆ‰‰ˆ÷‡ˆˆ‡‡ˆˆ‰ˆˆü‰ˆˆ‰‰ˆÚ†„‚ztj_QD8,#$.:GS`ltz}~}z``aa`þa``þa``a`Ùa`_]ZXUQLF?80(! "*18@GMQSUUTRD DCDCDßBA><:73/+'! "',046899þ711ï0/.,+)&#  ô !$')**þ)##"!â   þñ ô þþ ÷ ö  þ   ÷ùþ"   ?€ô»šƒ‰…`8+Ù 4S_y¢©‚}†>%BD?810:7#V‘«©œ‹u]F-ì Bq¨¨»¦‘Œ‹†_6+Ù)Da„¦­‡€’S-20+(+6(%fŽŸ™iVD2  ì =gŒ”›±Ÿ‘’“„^8*Ù":\ ¦†ƒ–”d1"#"#'+E‚˜™u\I9%í :bˆ•œ¥Ž…“œ€]?(Ú !4DcŒœ„ˆšwL" !"-g©µ§“‡oVA)ì 9e•ª«ª†”›_B&Û-7U’ˆ‰’j6  Au¡¦’vcO;+ í7c”§¢¯‡“}cE'Û$-P|†›M 3lª·¯œƒmU>) í=j•¡”§ˆ‚‘†zbF)Ü %Grˆ‘˜›“¦›q5  Hƒ¶²§–iQ;$í @i‡œ€~w`D(Ý:b„œ¬ª«¯—X=1+(,1`“®§œŒv[E1 í @c{y{ ‰‡wxbA$Þ 0V…—¯´¦°®‰aZTLYY…³À¸©–~\@+ í B_liq¢ŒzycA"Þ'Ip~Œ›¢¨«³¹ž¬­ ¦Ÿ ¤œ}dK5% í "Kt‡§”‰Œ{bE&ß 9Z‡«²·Á¨³¸³»±¥™‹„xdJ5) í #Huœš™¯ž˜|bH&á +Dz~n¡®²µ¢ ¤ª±¡™uqgT<' í $Gx©¬¨¸°¡˜“}dG!á$7alim‚‘œ£Ÿ’“œš‚zs]ZUI7$ í %Nˆ¾ÁÁ¿¾§”y]C%ã -H[`Z]hv€wtwt_\ZJD?6)í "L‡½¼¾½º ‡ŽuZ>"ã#5FNI?FS[[SOPL>?@3-*$ í Dy¯³·°®–‚uY=!ã #196*/9=;3//-%(+ í?q¥­²¯¨wZ>$ì &"!'($ý í Bt¥¯²Ø³’‰vy_=) ò ùí 'N­¹ºÐŸ€‚t{c?) ç   í%N‚¯°¶Çt|rydB) üò í $J~­¯±Ãs}qwdD)+ì Cs£©¢Ã‘|†swbD*,í8g—–‹Ä{‹vwdE'+ì Bv¦©•¹”‰”}t^B&+ì #H¶¹±­žž£„s\C&,í #Fx©°´«¨±´ˆv`G&+ì >e‡“šÃµ·ºŽy`A%,í;b„‹”ˬ©¬}lT9!+ì ?fˆ“šÅž™™h]J2+ì !?c„“š³Ž‡†XPB,+ì ;[x‹“—xpnME9&,í5Slƒˆx[PO95) -î %@WmlS;5:)& -î 0BRS3""* -ð#.8=/ñ &'  1ò   2û ü5üôL6&):B(  Ø 7@%/:  0:<2,' í$124D8/2>E* Ù +A?)#-6  &-- í$&*90-7LJ- Ú-A>((69   #)($ í (*4($4[L. ï 2B(,CA$   î #=C=52) í &53@0%1YI- Ü ,=)'2,.$.-# î ,&I2&0HB. Ý )9.'#96(>A<1%" í &.#G+!-6;- Ý %40,*&DH1 *>;6-$# í ""A#,'6- ß 0+1>?GNB&.64/( í @)&/#5. à /"-EK?CC40)$$'-DVSSKA6% í C2.2(90 ß%&7?>;?JMIFHHGFC@>90% í !..$A5**H97?JLB8.&)% í2CB=NA3.3?0â +-&+101750045.'  î'B[\YUF3+;<.â %% "&+.+$"$&! í#=VSTU@0/59.ë#!û í .DEIN4(-04+ å   í!4:=S3#(.0)  î     þ ï 069|N--(81 ï  þ í,9=?oI6 ,í %C>KX=G6 -î  %G6CR1<. ,í (,1C/636>Md„±Üöïìñõòôܽ« žžº ­Çåïðóùùöô⯃`I<536@Pm’ÂóõõñôóóõïÞ½eK<4018EYwžÌóðïñòîóãÊ´£œ™™œ£´Îêôöö€.÷ùîΜsVB6004>Ok“Äõùûéñôôõîß¿dJ:1--3=OkŽºåïòòðîñê׿­¥¡ ¤¬¿Øíõöôòõû湊eL;2,-2=Nj’Åö÷úãïóòóìâËdI9/*).8G_¨ÒìòòðîòïáÌ»´°¯³¸ÌãïñòññõøÙ¦xYC5-)*0So•ÂçíñôîñïèÜËÅÂÁÆÉ×çììñôõôêÄ’kP<0)%(/:MhÁûöôíïïó÷ó⿌eI7,$#%,7Ha„¯àíóöóíééëàââßáàáäêëíðóøÚ®_F5*$"%-9LiÁôóøìíïóöïß½ŠeI6*# "'1?UtœÌëóïïë€äñæêëçêèçêïðòôö÷ËšqR=/& #,9Kh‘Âîòøíïðóóìß¾‰dH5)!"+7Je‰´ãñéêñïïòæëíéêèëñôôöø÷踇aF4)!"+8KgÀëðôóôôõñíῈcG4( %.?VtÐèêìîïñóéðóïëèíóóõö÷ðÉsR<-# *7KgŒ»éíîööòò÷ñß¼‰cG4' (5Ga…®Öñóðîïòîñôóïìñõñôûõܬƒ^C2&)7JfŠ·ãïíïôôèöóß¹‡cG3&!+:Nkµ×ðõõ€÷óõöõôñõúúþóÙ´‹hL7* (6Jg¿êôóìòôõ÷öงcF3&$/>Sq®Ñáêñ÷÷ùúùùöõôðéѯ‹lQ<,#'6Jh’Ãïõ÷ïïðôù÷ẊcF3&&1?Tl„ž´ÇÖâçêëëêæà×ɵƒiR?/#'6JgÂðòöñîð÷ôò༌cF2% &1>N`p‚›¤ª¬­­ª©¥‘o]L;/%'5Jg‘Ãñòôñóöøññß»ŒcE2% $.9COZdlswyy€¿xvtneYLA6+# &5Ig¾ðøöíòööðô㽌bE2% "(/7=CHMPQRQQOMID=5-' &5IfŽÂôøøìðòóòõæÁŒbE2$  "&*.1567887630.*%!  &5Jf‘Æôôøñòñò÷ðãÃbE1$  "%'()**Ä(&$"  %5Jh’ÂìòõðööôôñÞ»ŒbD1$  Ï  %4IfÂõùúòóööìíÞ»‹aD0#    $3GeÃóøúõóôöìëß¿Š`C/" ô   Ó  $2FdŽÂóöøööõõòíß¿Š^A/" øýÝ #1Eb‰¿ø÷÷óõøøíòจ]?,  Þ !/B`‡»ôúøô÷÷ôñîÚ³Y=*  Ý  -A\‚µìôöõõôóöðÖ¬zT9( þþÙ +=W}°åñõõóòôøòÒ¢sN5% ï '8Qu§Ûò÷óõõîöëÅ“hH1" ð $3Ii•ÈñùòööîùÙ®‚Z>+ Ü ,?[‚³äøøùüù従lL5% Ø %6Mm–Äè÷òîâ¾›wV=, Ù  -?WwÅâÔªuZB/# Ú $2DZw“§{gSA2% Ú &3CUjunbUH;/% Ú &1=JNIB:2*# Þ $+341-($ Þ $&$! å  å  üþí þ!îþ"þúþ"&û'úü)ý ú*ý .€ê¢—ˆc0 (g›¸º² ŒbB#)ꔂuoX, %gºº¯š†|cC$)ê‘ykeO("Y‡ ¡šˆxv`B#)꜇vlR("Ij…‡}rrZ>")ê—}oS("Yˆ¤©«¢mQ:$)ê…}tiO%O}™Ÿ£œ‡gJ7&)ê€}rhN&Ioˆ–}`C3&)ꃇwkR) $Sz—œ–]B1#)ê~…wrX,(m¤¿À¿´˜iL7")êŠwpX, *m£½¼¶§‘vW;!)ꔆocK%#g²­¨œˆsT:")êŸwfL$!hŸµ­©ž‰kO9%)꺪‘‚b. )r¬Æ¿¹¬‘iN;')ê»­—Šg1 +t­Â»¸¬‘iM<,)ê°šƒz^. (h›·µ¦˜‡hM<+)꤈toX- '`°¯žŒzdL;))꣈wqZ/ )a¬©¡ŒueN;))겡†}c3 (d£¤œ~tX>')ê´¥Š‚f4 '_­£¢”~tV;$)꬟‰e3 &gš²²®žˆrT:#)ê›”„|a2 %jœ¯¶¯Ÿ‹pV=#)ꈌ€y_1 &]Žª£¡”~kY@$)ê‘šŠ…i5 (l§Ä¾´©Ž\Q/m¡¹µ¨–aL7")ê ¤¦¬‡I';|¶ÎÀ¯™|YA1")ꚣ¯‘bW_ºÌ»¨ŽpS?1#)ꜥ®°®­¯¹¿¼¬vd]F3%)êž¡§­¼ÊËÈú­Ÿ„j\_F3%)ê™ ¦«µ¾¾¹µ°¥–iWT>.#)ꋚŸ¦««¨¦£šŠwcQB/$ )êikpu{…‚vjcXJ>76')ëNGFGJOSRKEA:1)%)*ë:1.-.0110/,(# *ì()**))('# +öû ,î  -ï  ¯ë2,)( $6?A@:57- *ë)#!  2=>;3.4/!*ë$  $..,&$0, *ê)   !",& )ë!$%!  !*.0.*' *ë#! #(,,&*í  ")*$*ë   #*12)*þ!!ï &:DEFC7!*ë,+"")>IGE>72(*ë-& "6@=:4/3$*ë71&#9B@>70/*ëVRE;*2LXURK>-!*êTMB:*3O\XVPA) )ëA1(%  %:DC<93#*ë3!  +31-)$*ë2'!$)0,,& *ê>:,)" *./)#'>. )ê9;0,$ +:-/($6) )ê45+)! !3;:92,/% )ê*+" !//:60-,' )ê$# # (+ )ê!.%! 0<;97.% )ë9:1.% /8;61* $ *ë>;89, /781("*ë,17=0'9A<1' *ð*-2:2# /<>6-"ý *ë0-/7<<988761#! *ë1/27?DA<853."' *ë-169=?=7785.&! *ë+06:;:88::8/' *í#"  *ù ö  *ì    +ö  ø +üø,û÷-þü²óüûûýçű¼Ôëöö÷÷îöݰY?-  ù÷øûåı»Ôëøøí÷ñÛ¯Y?-  ßøùøûåı»Ôíûúø÷öðÙ®Y?-  ßúüýþçű»ÖïûüøööôÛ¯Z?-  ßõøûýçű»Õì÷úûýý÷à°}Y?-  üáûýæÄ±¼Öëôöùúùôß±Y?-  õûúúþçı¼Õì÷÷íöôß±~Y>-  õôøüæÄ±ºÒìüúøööïá°|X>-  ßôõöùäݹÑëûùø÷÷õß®{X>-  ú÷þýæÅ±»ÑçóóìôõñÝ®{X>-  ßúøúýçű»ÔéòöõõôíÙ¬|X>-  õáöúåñ»Õêóù÷õôî׬}X>-  ßñööøâ±ºÒçñõóòôõÙ¬~Y?-  ßîóôõâŲ½ÓçñôóññðØ®Z?-  ßòõøøäŲ»ÔêññøöðîÛ¯~Y>-  ßøùøúåŲºÕìóóøøôñݰ~X>-  úáõøäų»Ôì÷øö÷ùõܯ~Y?-  óöøúû寳»Öíöøùùîñ×­Y?-  ßõøùúåÇ´½Õìúûø÷øòÛ¯~Y?-  ßø÷÷ùåǵ¾Õìúùôõöðݰ~Y>-  ßù÷øúæÈ¶¿×í÷÷óõ÷ïݰ~X>-  ßöøüþéʺÂÙìõ÷÷øùóܯ~Y>-  ùûãè̽ÆÚîù÷úúùúØ­€X>-  ùáûúéÐÁÉÝñûøûûùû׫W=,øúøêÔÈÎßðùøøíùúÚ¬~W<+øá÷ùìÙÐÔàíö÷óó÷øÛ­|V;* ßùûùùïâÞÝåòüùöøûöÔ¨zR9( ßùúõø÷òîðõøøôùúø÷Ò£vP6' ÷áöúûùøùúùöõùúøøÎpL3$ õãùüù÷ûú÷ö÷ùøùúõÇ”hG0"  à÷ø÷÷ööùúù÷÷øøúù깇]@+ àûùùøøùù÷÷øúøøýöÑ¢tP8& àúüûúúûúùúûüüÿøÜ±†aD0! ùáïôùûüýýéúöóñÛ´kN7' à¯ÇÛçíòöõñêß줉lQ<, á’¡¬²µ¶¶³®¦š‰vbM<-"  áWdnv{~}ztk^QD7,"  á;BINQTUUTQMG?70(   ú)-14799ë863/+'" "ú"%')**ì(&#  "ùë !ú ò ý#û  ô þ$þò%ü%(ý8ý9ý)¬ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @€r@9zuluCrypt-6.2.0/zuluMount-gui/zulumount.cpp000066400000000000000000001215131425361753700211520ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "zulumount.h" #include "ui_zulumount.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "keydialog.h" #include "../zuluCrypt-gui/dialogmsg.h" #include "../zuluCrypt-gui/tablewidget.h" #include "mountpartition.h" #include "oneinstance.h" #include "../zuluCrypt-gui/utility.h" #include "siritask.h" #include "zulumounttask.h" #include "task.hpp" #include "../zuluCrypt-gui/favorites2.h" #include "bin_path.h" #include static bool _encrypted_folder( const QString& e,bool f = true ) { return volumeProperty::encryptedFolder( e,f ) ; } zuluMount::zuluMount( QWidget * parent ) : QWidget( parent ), m_secrets( this ), m_mountInfo( this,true,[](){ QCoreApplication::quit() ; } ), m_events( this,m_mountInfo.stop() ), m_signalHandler( this ) { utility::mainWindowWidget( this ) ; m_signalHandler.setAction( [ this ]( systemSignalHandler::signal s ){ Q_UNUSED( s ) this->emergencyQuitApplication() ; } ) ; } void zuluMount::helperStarted( bool start,const QString& volume ) { if( !start ){ DialogMsg( this ).ShowUIOK( tr( "ERROR" ),utility::failedToStartzuluPolkit() ) ; return this->closeApplication() ; } this->setLocalizationLanguage( true ) ; m_ui = new Ui::zuluMount ; m_ui->setupUi( this ) ; m_ui->pbunlockcryptfs->setMinimumHeight( 31 ) ; m_ui->pbmenu->setMinimumHeight( 31 ) ; m_ui->pbmount->setMinimumHeight( 31 ) ; m_ui->pbupdate->setMinimumHeight( 31 ) ; m_ui->pbfavorites->setMinimumHeight( 31 ) ; auto f = utility::getWindowDimensions( "zuluMount" ) ; auto e = f.data() ; this->window()->setGeometry( *( e + 0 ),*( e + 1 ),*( e + 2 ),*( e + 3 ) ) ; auto table = m_ui->tableWidget ; table->setColumnWidth( 0,*( e + 4 ) ) ; table->setColumnWidth( 1,*( e + 5 ) ) ; table->setColumnWidth( 2,*( e + 6 ) ) ; table->setColumnWidth( 4,*( e + 7 ) ) ; table->setColumnWidth( 5,*( e + 8 ) ) ; m_ui->tableWidget->hideColumn( 3 ) ; #if QT_VERSION < QT_VERSION_CHECK( 5,0,0 ) m_ui->tableWidget->verticalHeader()->setResizeMode( QHeaderView::ResizeToContents ) ; #else m_ui->tableWidget->verticalHeader()->setSectionResizeMode( QHeaderView::ResizeToContents ) ; #endif m_ui->tableWidget->verticalHeader()->setMinimumSectionSize( 30 ) ; m_ui->tableWidget->setMouseTracking( true ) ; connect( m_ui->tableWidget,SIGNAL( itemEntered( QTableWidgetItem * ) ), this,SLOT( itemEntered( QTableWidgetItem * ) ) ) ; connect( m_ui->tableWidget,SIGNAL( currentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ), this,SLOT( slotCurrentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ) ) ; connect( m_ui->pbmount,SIGNAL( clicked() ), this,SLOT( pbMount() ) ) ; connect( m_ui->pbupdate,SIGNAL( clicked()), this,SLOT( pbUpdate() ) ) ; connect( m_ui->tableWidget,SIGNAL( itemClicked( QTableWidgetItem * ) ), this,SLOT( itemClicked( QTableWidgetItem * ) ) ) ; connect( m_ui->pbunlockcryptfs,SIGNAL( clicked() ), this,SLOT( unlockCryptFs() ) ) ; connect( this,SIGNAL( unlistVolume( QString ) ), this,SLOT( removeVolume( QString ) ) ) ; m_ui->tableWidget->setContextMenuPolicy( Qt::CustomContextMenu ) ; connect( m_ui->tableWidget,&QTableWidget::customContextMenuRequested,[ this ]( QPoint s ){ Q_UNUSED( s ) auto item = m_ui->tableWidget->currentItem() ; if( item ){ this->showContextMenu( item,true ) ; } } ) ; this->setUpShortCuts() ; this->setUpFont() ; const auto& icon = utility::getIcon( "zuluMount" ) ; this->setAcceptDrops( true ) ; this->setWindowIcon( icon ) ; m_trayIcon.setParent( this ) ; m_trayIcon.setIcon( icon ) ; auto trayMenu = new QMenu( this ) ; trayMenu->setFont( this->font() ) ; m_autoMount = this->autoMount() ; m_autoOpenFolderOnMount = this->autoOpenFolderOnMount() ; trayMenu->addAction( [ this ](){ auto ac = new QAction( tr( "Do Not Minimize To Tray" ),this ) ; m_actionPair.append( { ac,"Do Not Minimize To Tray" } ) ; ac->setCheckable( true ) ; ac->setChecked( utility::doNotMinimizeToTray() ) ; connect( ac,&QAction::triggered,[ ac ](){ auto s = !utility::doNotMinimizeToTray() ; ac->setChecked( s ) ; utility::setDoNotMinimizeToTray( s ) ; } ) ; m_autoMountAction = ac ; return ac ; }() ) ; trayMenu->addAction( [ this ](){ auto ac = new QAction( tr( "Automount Volumes" ),this ) ; m_actionPair.append( { ac,"Automount Volumes" } ) ; ac->setCheckable( true ) ; ac->setChecked( m_autoMount ) ; connect( ac,SIGNAL( toggled( bool ) ),this,SLOT( autoMountToggled( bool ) ) ) ; m_autoMountAction = ac ; return ac ; }() ) ; trayMenu->addAction( [ this ](){ auto ac = new QAction( tr( "Auto Open Mount Point" ),this ) ; m_actionPair.append( { ac,"Auto Open Mount Point" } ) ; ac->setCheckable( true ) ; ac->setChecked( m_autoOpenFolderOnMount ) ; connect( ac,SIGNAL( toggled( bool ) ),this,SLOT( autoOpenFolderOnMount( bool ) ) ) ; return ac ; }() ) ; trayMenu->addAction( [ this ](){ auto ac = new QAction( tr( "Clear Dead Mount Points" ),this ) ; m_actionPair.append( { ac,"Clear Dead Mount Points" } ) ; connect( ac,&QAction::triggered,[ this ](){ this->disableAll() ; utility::Task::run( zuluMountPath" --clear-dead-mount-points" ).await() ; this->enableAll() ; } ) ; return ac ; }() ) ; trayMenu->addAction( [ this ](){ auto ac = new QAction( tr( "Unmount All" ),this ) ; m_actionPair.append( { ac,"Unmount All" } ) ; connect( ac,SIGNAL( triggered() ),this,SLOT( unMountAll() ) ) ; return ac ; }() ) ; m_favorite_menu = [ this ](){ auto m = new QMenu( tr( "Favorites" ),this ) ; m_menuPair.append( { m,"Favorites" } ) ; m->setFont( this->font() ) ; connect( m,SIGNAL( triggered( QAction * ) ), this,SLOT( favoriteClicked( QAction * ) ) ) ; connect( m,SIGNAL( aboutToShow() ), this,SLOT( showFavorites() ) ) ; m_ui->pbfavorites->setMenu( m ) ; return m ; }() ; m_not_hidden_volume_menu = [ this,trayMenu ](){ auto m = trayMenu->addMenu( tr( "Hide Volume From View" ) ) ; m_menuPair.append( { m,"Hide Volume From View" } ) ; m->setFont( this->font() ) ; connect( m,SIGNAL( triggered( QAction * ) ), this,SLOT( removeVolumeFromVisibleVolumeList( QAction * ) ) ) ; connect( m,SIGNAL( aboutToShow() ), this,SLOT( showVisibleVolumeList() ) ) ; return m ; }() ; m_hidden_volume_menu = [ this,trayMenu ](){ auto m = trayMenu->addMenu( tr( "Unhide Volume From View" ) ) ; m_menuPair.append( { m,"Unhide Volume From View" } ) ; m->setFont( this->font() ) ; connect( m,SIGNAL( triggered( QAction * ) ), this,SLOT( removeVolumeFromHiddenVolumeList( QAction * ) ) ) ; connect( m,SIGNAL( aboutToShow() ), this,SLOT( showHiddenVolumeList() ) ) ; return m ; }() ; m_language_menu = [ this,trayMenu ](){ auto m = trayMenu->addMenu( tr( "Select Language" ) ) ; m_menuPair.append( { m,"Select Language" } ) ; connect( m,SIGNAL( triggered( QAction * ) ),this,SLOT( languageMenu( QAction * ) ) ) ; return m ; }() ; trayMenu->addMenu( [ this ](){ auto ac = new QAction( tr( "Select Icons" ),this ) ; m_actionPair.append( { ac,"Select Icons" } ) ; utility::setIconMenu( "zuluMount",ac,this,[ this ]( const QString& e ){ utility::setIcons( "zuluMount",e ) ; this->setIcons() ; } ) ; this->setIcons() ; return ac->menu() ; }() ) ; trayMenu->addAction( [ this ](){ auto ac = new QAction( tr( "About" ),this ) ; m_actionPair.append( { ac,"About" } ) ; connect( ac,SIGNAL( triggered() ),this,SLOT( licenseInfo() ) ) ; return ac ; }() ) ; auto _addQuitAction = [ this ](){ auto ac = new QAction( tr( "Quit" ),this ) ; m_actionPair.append( { ac,"Quit" } ) ; connect( ac,SIGNAL( triggered() ),this,SLOT( closeApplication() ) ) ; return ac ; } ; trayMenu->addAction( _addQuitAction() ) ; connect( &m_trayIcon,SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ), this,SLOT( slotTrayClicked( QSystemTrayIcon::ActivationReason ) ) ) ; m_trayIcon.setContextMenu( [ this,&_addQuitAction ](){ auto m = new QMenu( this ) ; m->addAction( [ this ](){ auto ac = new QAction( tr( "Show/Hide" ),this ) ; m_actionPair.append( { ac,"Show/Hide" } ) ; connect( ac,SIGNAL( triggered() ),this,SLOT( showTrayGUI() ) ) ; return ac ; }() ) ; m->addAction( _addQuitAction() ) ; return m ; }() ) ; m_ui->pbmenu->setMenu( trayMenu ) ; this->setLocalizationLanguage( false ) ; utility::showTrayIcon( nullptr,m_trayIcon,true ) ; m_powerOff = utility::powerOffCommand() ; this->disableAll() ; this->startAutoMonitor() ; this->updateVolumeList( zuluMountTask::updateVolumeList().await() ) ; if( volume.isEmpty() ) { this->enableAll() ; }else{ this->showMoungDialog( volume ) ; } if( !m_startHidden ){ this->raiseWindow() ; } auto debugWindowShortCut = new QShortcut( this ) ; debugWindowShortCut->setKey(Qt::CTRL | Qt::SHIFT | Qt::Key_D ) ; connect( debugWindowShortCut,&QShortcut::activated,[ this ](){ m_debugWindow.Show() ; } ) ; } void zuluMount::showTrayIcon( bool e ) { Q_UNUSED( e ) m_trayIcon.show() ; } void zuluMount::showTrayGUI() { this->slotTrayClicked( QSystemTrayIcon::Trigger ) ; } void zuluMount::setIcons() { const auto& icon = utility::getIcon( "zuluMount" ) ; m_trayIcon.setIcon( icon ) ; this->setWindowIcon( icon ) ; } void zuluMount::licenseInfo() { utility::licenseInfo( this ) ; } void zuluMount::removeVolumeFromHiddenVolumeList( QAction * ac ) { this->disableAll() ; auto e = ac->text() ; e.remove( "&" ) ; zuluMountTask::removeVolumeFromHiddenVolumeList( e ) ; this->updateList( zuluMountTask::getVolumeProperties( e ).await() ) ; this->enableAll() ; } static void _manage_volume_list( QMenu * menu,const QStringList& l ) { menu->clear() ; if( l.isEmpty() ){ menu->addAction( [ &menu ](){ auto ac = new QAction( QObject::tr( "List Is Empty" ),menu ) ; ac->setEnabled( false ) ; return ac ; }() ) ; }else{ for( const auto& it : l ){ menu->addAction( new QAction( it,menu ) ) ; } } } void zuluMount::showHiddenVolumeList() { _manage_volume_list( m_hidden_volume_menu,zuluMountTask::hiddenVolumeList() ) ; } void zuluMount::showVisibleVolumeList() { _manage_volume_list( m_not_hidden_volume_menu, tablewidget::columnEntries( m_ui->tableWidget ) ) ; } void zuluMount::removeVolumeFromVisibleVolumeList( QAction * ac ) { auto e = ac->text().remove( "&" ) ; auto table = m_ui->tableWidget ; zuluMountTask::addVolumeToHiddenVolumeList( e ) ; this->disableAll() ; tablewidget::selectRow( table,e ) ; utility::Task::suspendForOneSecond() ; tablewidget::deleteRow( table,e ) ; tablewidget::selectLastRow( table ) ; this->enableAll() ; } QString zuluMount::resolveFavoriteMountPoint( const QString& m ) { QString s ; favorites::instance().entries( [ & ]( const favorites::entry& e ){ if( e.volumePath == m ){ s = e.mountPointPath ; return true ; } return false ; } ) ; return s ; } void zuluMount::favoriteClicked( QAction * ac ) { auto e = ac->text() ; e.remove( "&" ) ; auto r = utility::favoriteClickedOption( e ) ; if( r == 1 ){ favorites2::instance( this,m_secrets,[](){} ) ; }else if( r == 2 ){ favorites::instance().entries( [ & ]( const favorites::entry& e ){ this->showMoungDialog( e.volumePath,e.mountPointPath ) ; } ) ; }else{ this->showMoungDialog( e,this->resolveFavoriteMountPoint( e ) ) ; } } void zuluMount::showFavorites() { utility::readFavorites( m_favorite_menu,true ) ; } void zuluMount::setLocalizationLanguage( bool translate ) { utility::setLocalizationLanguage( translate,m_language_menu,"zuluMount-gui" ) ; } void zuluMount::languageMenu( QAction * ac ) { utility::languageMenu( this,m_language_menu,ac,"zuluMount-gui" ) ; m_ui->retranslateUi( this ) ; for( auto& it : m_actionPair ){ it.first->setText( tr( it.second ) ) ; } for( auto& it : m_menuPair ){ it.first->setTitle( tr( it.second ) ) ; } } void zuluMount::autoOpenFolderOnMount( bool e ) { m_autoOpenFolderOnMount = e ; utility::autoOpenFolderOnMount( "zuluMount-gui",e ) ; } bool zuluMount::autoOpenFolderOnMount( void ) { return utility::autoOpenFolderOnMount( "zuluMount-gui" ) ; } void zuluMount::startAutoMonitor() { m_mountInfo.start() ; m_events.start() ; } /* * Below two functions should be the only functions that closes the application */ void zuluMount::closeApplication() { m_secrets.close() ; utility::quitHelper() ; m_events.stop() ; } void zuluMount::closeApplication( int s ) { m_secrets.close() ; Q_UNUSED( s ) m_events.stop() ; } void zuluMount::autoMountVolume( volumeProperty * q ) { std::unique_ptr< volumeProperty > r( q ) ; if( r && r->isValid() ){ auto& p = *r ; if( p.encryptedVolume() ){ this->addEntryToTable( true,p ) ; }else{ if( m_autoMount ){ this->disableAll() ; mountPartition::instance( this,m_ui->tableWidget,[](){},[ this ]( const QString& e ){ this->openMountPointPath( e ) ; } ).AutoMount( p.setMountPoint( this->resolveFavoriteMountPoint( p.volumeName() ) ) ) ; }else{ this->addEntryToTable( false,p ) ; } } } } void zuluMount::volumeRemoved( QString volume ) { if( !volume.isEmpty() ){ auto table = m_ui->tableWidget ; auto row = tablewidget::columnHasEntry( table,volume ) ; if( row != -1 ){ tablewidget::deleteRow( table,row ) ; /* * see if a user just removed the device without properly closing it/unmounting it * and try to do so for them */ Task::exec( [ volume ](){ zuluMountTask::checkUnMount( volume ) ; } ) ; this->enableAll() ; } } } void zuluMount::removeVolume( QString volume ) { if( volume.isEmpty() ){ tablewidget::selectLastRow( m_ui->tableWidget ) ; this->enableAll() ; }else{ tablewidget::deleteRow( m_ui->tableWidget,volume ) ; } } void zuluMount::itemEntered( QTableWidgetItem * item ) { auto row = item->row() ; auto table = item->tableWidget() ; auto m_point = table->item( row,1 )->text() ; using string_t = decltype( table->item( row,3 )->text() ) ; string_t x = table->item( row,3 )->text() ; string_t z ; string_t y ; if( m_point == "/" ){ /* * we dont check if root path is publicly shared because the path it will produce (/run/media/public/) * will always return true,a solution is to examine /proc/self/mountinfo and thats work for another day */ if( x == "Nil" ){ x.clear() ; } z += tr( "LABEL=\"%1\"" ).arg( x ) ; }else if( m_point == "Nil" ){ /* * volume is not mounted,cant know its LABEL value */ x.clear() ; z += tr( "LABEL=\"%1\"" ).arg( x ) ; }else{ if( x == "Nil" ){ x.clear() ; } y = utility::shareMountPointToolTip( m_point ) ; if( y.isEmpty() ){ z += tr( "LABEL=\"%1\"" ).arg( x ) ; }else{ z += tr( "LABEL=\"%1\"\n%2" ).arg( x,y ) ; } } item->setToolTip( z ) ; } void zuluMount::raiseWindow( const QString& volume ) { this->setVisible( true ) ; this->raise() ; this->show() ; this->setWindowState( Qt::WindowActive ) ; if( !volume.isEmpty() ){ this->showMoungDialog( volume ) ; } } void zuluMount::polkitFailedWarning() { DialogMsg( this ).ShowUIOK( tr( "ERROR" ),tr( "zuluMount Failed To Connect To zuluPolkit.\nPlease Report This Serious Bug." ) ) ; } void zuluMount::Show() { auto l = QCoreApplication::arguments() ; m_startHidden = l.contains( "-e" ) ; m_folderOpener = utility::cmdArgumentValue( l,"-m",utility::fileManager() ) ; auto s = utility::socketPath() ; if( utility::configDirectoriesAreNotWritable( this ) ){ return this->closeApplication() ; } utility::polkitFailedWarning( [ this ](){ QMetaObject::invokeMethod( this,"polkitFailedWarning",Qt::QueuedConnection ) ; } ) ; if( utility::libCryptSetupLibraryNotFound() ){ auto a = tr( "Cryptsetup library could not be found and zuluCrypt will most likely not work as expected." ) ; auto b = tr( "\n\nPlease recompile zuluCrypt to force it to re-discover the new library" ) ; DialogMsg( this ).ShowUIOK( tr( "ERROR" ),a + b ) ; } oneinstance::instance( this, s + "/zuluMount-gui.socket", utility::cmdArgumentValue( l,"-d" ), [ this ]( const QString& e ){ utility::startHelperExecutable( this, e, "zuluMount", "helperStarted", "closeApplication" ) ; }, [ this ]( int s ){ this->closeApplication( s ) ; }, [ this ]( const QString& e ){ this->raiseWindow( e ) ; } ) ; } void zuluMount::cryfsVolumeProperties() { this->disableAll() ; auto mountPath = [ this ](){ auto table = m_ui->tableWidget ; auto row = table->currentRow() ; if( row >= 0 ){ return table->item( row,1 )->text() ; }else{ return QString() ; } }() ; DialogMsg msg( this ) ; struct statfs vfs ; if( Task::await( [ & ](){ return statfs( mountPath.toLatin1().constData(),&vfs ) ; } ) ){ msg.ShowUIOK( tr( "ERROR" ),tr( "Failed To Read Volume Properties" ) ) ; return this->enableAll() ; } msg.ShowUIInfo( tr( "INFORMATION" ),true,[ & ](){ return QString( [ this ](){ auto l = { tr( "Block Size: %1" ), tr( "Used Blocks: %2" ), tr( "Free Blocks: %3" ), tr( "Total Blocks %4" ), tr( "Used Space: %5" ), tr( "Free Space: %6" ), tr( "Total Space: %7" ), tr( "Used %: %8" ) } ; QString e ; for( const auto& it : l ){ e += it + "\n\n" ; } e.truncate( e.size() - 2 ) ; return e ; }() ).arg( [ & ](){ return utility::prettyfySpaceUsage( vfs.f_bsize ) ; }(),[ & ](){ return QString::number( vfs.f_blocks - vfs.f_bavail ) ; }(),[ & ](){ return QString::number( vfs.f_bfree ) ; }(),[ & ](){ return QString::number( vfs.f_blocks ) ; }(),[ & ](){ auto s = vfs.f_bsize * ( vfs.f_blocks - vfs.f_bavail ) ; return utility::prettyfySpaceUsage( s ) ; }(),[ & ](){ return utility::prettyfySpaceUsage( vfs.f_bsize * vfs.f_bavail ) ; }(),[ & ](){ return utility::prettyfySpaceUsage( vfs.f_bsize * vfs.f_blocks ) ; }(),[ & ]()->QString{ if( vfs.f_bfree == 0 ){ return "100%" ; }else{ quint64 s = vfs.f_blocks - vfs.f_bavail ; auto e = double( s ) / double( vfs.f_blocks ) ; return QString::number( e * 100,'g',2 ) + "%" ; } }() ) ; }() ) ; this->enableAll() ; } static void _volume_properties( const QString& cmd,const QString& arg, QTableWidget * table,QWidget * w ) { auto exe = utility::executableFullPath( cmd ) ; auto path = [ table ](){ auto row = table->currentRow() ; if( row < 0 ){ return QString() ; }else{ return utility::Task::makePath( table->item( row,0 )->text() ) ; } }() ; if( exe.isEmpty() ){ DialogMsg( w ).ShowUIOK( QObject::tr( "ERROR" ), QObject::tr( "Failed To Find %1 Executable" ).arg( cmd ) ) ; }else{ auto e = utility::Task::run( exe + arg + path,utility::Task::USEPOLKIT::False ).await() ; if( e.success() ){ auto s = e.stdOut() ; if( cmd == "gocryptfs" ){ s.replace( "Creator: ","Creator: " ).replace( "\n","\n\n" ) ; } DialogMsg( w ).ShowUIInfo( QObject::tr( "INFORMATION" ),true,s ) ; }else{ DialogMsg( w ).ShowUIOK( QObject::tr( "ERROR" ), QObject::tr( "Failed To Get Volume Properties" ) ) ; } } } void zuluMount::encfsProperties() { this->disableAll() ; _volume_properties( "encfsctl"," ",m_ui->tableWidget,this ) ; this->enableAll() ; } void zuluMount::securefsProperties() { this->disableAll() ; _volume_properties( "securefs"," info ",m_ui->tableWidget,this ) ; this->enableAll() ; } void zuluMount::gocryptfsProperties() { this->disableAll() ; _volume_properties( "gocryptfs"," -info ",m_ui->tableWidget,this ) ; this->enableAll() ; } static QString _fs_properties( const QString& m ) { QFile f( "/proc/self/mountinfo" ) ; f.open( QIODevice::ReadOnly ) ; auto s = " " + m + " " ; for( const auto& it : utility::split( f.readAll() ) ){ if( it.contains( s ) ){ return utility::split( it,' ' ).last() ; } } return QString() ; } void zuluMount::ecryptfsProperties() { this->disableAll() ; auto s = [ this ](){ auto table = m_ui->tableWidget ; auto item = table->currentItem() ; if( item ){ return table->item( item->row(),1 )->text() ; }else{ return QString() ; } }() ; DialogMsg( this ).ShowUIInfo( tr( "INFORMATION" ),true,[ & ](){ auto e = _fs_properties( s ) ; e.replace( ",","\n\n" ) ; e.replace( "ro\n\n","mode=read only\n\n" ) ; e.replace( "rw\n\n","mode=read and write\n\n" ) ; e.replace( "="," = " ) ; return e ; }() ) ; this->enableAll() ; } void zuluMount::showContextMenu( QTableWidgetItem * item,bool itemClicked ) { QMenu m ; m.setFont( this->font() ) ; auto _text = [ this ]( int row,int column ){ return m_ui->tableWidget->item( row,column )->text() ; } ; auto row = item->row() ; auto device = _text( row,0 ) ; auto mt = _text( row,1 ) ; auto fs = _text( row,2 ) ; auto _properties_menu = [ & ]( const QString& ff,bool addSeparator ){ auto fs = ff.toLower() ; if( _encrypted_folder( fs ) ){ if( fs == "cryfs" ){ connect( m.addAction( tr( "Properties" ) ),SIGNAL( triggered() ), this,SLOT( cryfsVolumeProperties() ) ) ; }else if( fs == "gocryptfs" ){ connect( m.addAction( tr( "Properties" ) ),SIGNAL( triggered() ), this,SLOT( gocryptfsProperties() ) ) ; }else if( fs == "securefs" ){ connect( m.addAction( tr( "Properties" ) ),SIGNAL( triggered() ), this,SLOT( securefsProperties() ) ) ; }else if( fs == "encfs" ){ connect( m.addAction( tr( "Properties" ) ),SIGNAL( triggered() ), this,SLOT( encfsProperties() ) ) ; }else if( fs == "ecryptfs" ){ connect( m.addAction( tr( "Properties" ) ),SIGNAL( triggered() ), this,SLOT( ecryptfsProperties() ) ) ; }else{ m.addAction( tr( "Properties" ) )->setEnabled( false ) ; } }else{ auto ac = m.addAction( tr( "Properties" ) ) ; //ac->setEnabled( fs != "crypto_BitLocker" ) ; connect( ac,SIGNAL( triggered() ), this,SLOT( volumeProperties() ) ) ; } if( addSeparator ){ m.addSeparator() ; } } ; if( mt == "Nil" ){ connect( m.addAction( tr( "Mount" ) ),SIGNAL( triggered() ),this,SLOT( slotMount() ) ) ; }else{ auto mp = QString( "/run/media/private/%1/" ).arg( utility::userName() ) ; auto mp_1 = QString( "/home/%1/" ).arg( utility::userName() ) ; if( mt.startsWith( mp ) || mt.startsWith( mp_1 ) ){ m_sharedFolderPath = utility::sharedMountPointPath( mt ) ; if( m_sharedFolderPath.isEmpty() ){ connect( m.addAction( tr( "Open Folder" ) ),SIGNAL( triggered() ), this,SLOT( slotOpenFolder() ) ) ; }else{ connect( m.addAction( tr( "Open Private Folder" ) ),SIGNAL( triggered() ), this,SLOT( slotOpenFolder() ) ) ; connect( m.addAction( tr( "Open Shared Folder" ) ),SIGNAL( triggered() ), this,SLOT( slotOpenSharedFolder() ) ) ; } m.addSeparator() ; _properties_menu( fs,true ) ; connect( m.addAction( tr( "Unmount" ) ),SIGNAL( triggered() ),this,SLOT( pbUmount() ) ) ; if( !m_powerOff.isEmpty() && !_encrypted_folder( fs ) && ( device.startsWith( "/dev/sd" ) || device.startsWith( "/dev/hd" ) ) ){ connect( m.addAction( tr( "Unmount + Power Down" ) ),SIGNAL( triggered() ),this,SLOT( pbUmount_powerDown() ) ) ; } }else{ m_sharedFolderPath = utility::sharedMountPointPath( mt ) ; if( m_sharedFolderPath.isEmpty() ){ if( utility::pathIsReadable( mt ) ){ connect( m.addAction( tr( "Open Folder" ) ),SIGNAL( triggered() ), this,SLOT( slotOpenFolder() ) ) ; m.addSeparator() ; _properties_menu( fs,false ) ; }else{ _properties_menu( fs,false ) ; } }else{ connect( m.addAction( tr( "Open Shared Folder" ) ),SIGNAL( triggered() ), this,SLOT( slotOpenSharedFolder() ) ) ; m.addSeparator() ; _properties_menu( fs,true ) ; } } } m.addSeparator() ; m.addAction( tr( "Close Menu" ) ) ; if( itemClicked ){ m.exec( QCursor::pos() ) ; }else{ auto p = this->pos() ; auto x = p.x() + 100 + m_ui->tableWidget->columnWidth( 0 ) ; auto y = p.y() + 50 + m_ui->tableWidget->rowHeight( 0 ) * item->row() ; p.setX( x ) ; p.setY( y ) ; m.exec( p ) ; } } void zuluMount::itemClicked( QTableWidgetItem * item ) { this->showContextMenu( item,true ) ; } void zuluMount::defaultButton() { auto table = m_ui->tableWidget ; if( table->rowCount() > 0 ){ auto row = m_ui->tableWidget->currentRow() ; auto mt = m_ui->tableWidget->item( row,1 )->text() ; if( mt == "Nil" ){ this->slotMount() ; }else{ this->showContextMenu( m_ui->tableWidget->currentItem(),false ) ; } } } void zuluMount::slotOpenSharedFolder() { this->openMountPoint( m_sharedFolderPath ) ; } void zuluMount::slotOpenFolder() { auto item = m_ui->tableWidget->currentItem() ; auto path = m_ui->tableWidget->item( item->row(),1 )->text() ; this->openMountPoint( path ) ; } void zuluMount::openMountPoint( const QString& m_point ) { auto x = tr( "Warning" ) ; auto y = tr( "Could not open mount point because \"%1\" tool does not appear to be working correctly").arg( m_folderOpener ) ; utility::openPath( m_point,m_folderOpener,this,x,y ) ; } void zuluMount::openMountPointPath( QString m ) { if( m_autoOpenFolderOnMount ){ this->openMountPoint( m ) ; } } void zuluMount::volumeProperties() { this->disableAll() ; auto volume = m_ui->tableWidget->item( m_ui->tableWidget->currentRow(),0 )->text() ; auto volumeType = m_ui->tableWidget->item( m_ui->tableWidget->currentRow(),2 )->text() ; auto r = zuluMountTask::volumeProperties( volume,volumeType ).await() ; DialogMsg msg( this ) ; if( r.isEmpty() ){ msg.ShowUIOK( tr( "ERROR" ), tr( "Could not get volume properties.\nvolume is not open or was opened by a different user" ) ) ; }else{ auto i = r.indexOf( "\n" ) ; if( i != -1 ){ msg.ShowUIVolumeProperties( tr( "Volume Properties" ),r.mid( i + 1 ) ) ; }else{ msg.ShowUIOK( tr( "ERROR" ), tr( "Could not get volume properties.\nvolume is not open or was opened by a different user" ) ) ; } } this->enableAll() ; } void zuluMount::setUpShortCuts() { auto _addAction = [ this ]( std::initializer_list s,const char * slot ){ auto ac = new QAction( this ) ; ac->setShortcuts( s ) ; connect( ac,SIGNAL( triggered() ),this,slot ) ; return ac ; } ; this->addAction( _addAction( { Qt::Key_Enter,Qt::Key_Return },SLOT( defaultButton() ) ) ) ; this->addAction( _addAction( { Qt::Key_M },SLOT( pbMount() ) ) ) ; this->addAction( _addAction( { Qt::Key_U },SLOT( pbUmount() ) ) ) ; this->addAction( _addAction( { Qt::Key_R },SLOT( pbUpdate() ) ) ) ; this->addAction( _addAction( { Qt::Key_C },SLOT( closeApplication() ) ) ) ; } void zuluMount::setUpFont() { this->setFont( utility::getFont( this ) ) ; } void zuluMount::closeEvent( QCloseEvent * e ) { e->ignore() ; this->hide() ; if( utility::doNotMinimizeToTray() ){ this->closeApplication() ; } } void zuluMount::slotTrayClicked( QSystemTrayIcon::ActivationReason e ) { if( e == QSystemTrayIcon::Trigger ){ if( this->isVisible() ){ this->hide() ; }else{ this->show() ; } } } void zuluMount::autoMountToggled( bool opt ) { m_autoMount = opt ; } void zuluMount::dragEnterEvent( QDragEnterEvent * e ) { e->accept() ; } void zuluMount::dropEvent( QDropEvent * e ) { for( const auto& it : e->mimeData()->urls() ){ this->showMoungDialog( it.path() ) ; } } void zuluMount::mount( const volumeProperty& entry ) { this->disableAll() ; if( entry.encryptedVolume() ){ keyDialog::instance( this,m_ui->tableWidget,m_secrets,entry,[ this ](){ this->enableAll() ; },[ this ]( const QString& e ){ this->openMountPointPath( e ) ; } ).ShowUI() ; }else{ mountPartition::instance( this,m_ui->tableWidget,[ this ](){ this->enableAll() ; },[ this ]( const QString& e ){ this->openMountPointPath( e ) ; } ).ShowUI( entry ) ; } } void zuluMount::slotMount() { auto table = m_ui->tableWidget ; auto row = table->currentRow() ; this->mount( tablewidget::rowEntries( table,row ) ) ; } void zuluMount::showMoungDialog( const volumeProperty& v ) { if( v.isEmpty() ){ DialogMsg msg( this ) ; msg.ShowUIOK( tr( "ERROR" ), tr( "Permission to access the volume was denied\nor\nthe volume is not supported\n(LVM/MDRAID signatures found)" ) ) ; this->enableAll() ; }else{ this->mount( v ) ; } } void zuluMount::showMoungDialog( const QString& volume,const QString& m_point ) { if( !volume.isEmpty() ){ if( utility::pathPointsToAFolder( volume ) ){ this->mount( { volume,m_point,"cryptfs","Nil","Nil","Nil" } ) ; }else{ this->disableAll() ; this->showMoungDialog( zuluMountTask::getVolumeProperties( volume ).await().setMountPoint( m_point ) ) ; } } } void zuluMount::pbMount() { this->disableAll() ; auto path = QFileDialog::getOpenFileName( this,tr( "Select An Image File To Mount" ),utility::homePath() ) ; if( path.isEmpty() ){ this->enableAll() ; }else{ this->showMoungDialog( path ) ; } } void zuluMount::unlockCryptFs() { this->disableAll() ; auto path = QFileDialog::getExistingDirectory( this,tr( "Select An Encrypted Volume Directory" ), utility::homePath(),QFileDialog::ShowDirsOnly ) ; if( path.isEmpty() ){ this->enableAll() ; }else{ while( true ){ if( path.endsWith( '/' ) ){ path.truncate( path.length() - 1 ) ; }else{ break ; } } this->showMoungDialog( path ) ; } } QFont zuluMount::getSystemVolumeFont() { auto f = this->font() ; f.setItalic( !f.italic() ) ; f.setBold( !f.bold() ) ; return f ; } void zuluMount::addEntryToTable( bool systemVolume,const QStringList& l ) { if( systemVolume ){ tablewidget::addRow( m_ui->tableWidget,l,this->getSystemVolumeFont() ) ; }else{ tablewidget::addRow( m_ui->tableWidget,l ) ; } } void zuluMount::addEntryToTable( bool systemVolume,const volumeProperty& e ) { this->addEntryToTable( systemVolume,e.entryList() ) ; } void zuluMount::removeEntryFromTable( QString volume ) { auto table = m_ui->tableWidget ; auto r = tablewidget::columnHasEntry( table,volume ) ; if( r != -1 ){ tablewidget::deleteRow( table,r ) ; this->enableAll() ; }else{ this->pbUpdate() ; } } void zuluMount::volumeMiniProperties( bool valid,volumeProperty * e ) { std::unique_ptr< volumeProperty > volumeInfo( e ) ; this->disableAll() ; if( valid ){ this->updateList( *volumeInfo ) ; this->enableAll() ; }else{ this->pbUpdate() ; } } void zuluMount::volumeMiniProperties( volumeProperty * volumeInfo ) { this->volumeMiniProperties( volumeInfo,volumeInfo ) ; } void zuluMount::volumeMiniProperties_0( volumeProperty * volumeInfo ) { this->volumeMiniProperties( volumeInfo && volumeInfo->mounted(),volumeInfo ) ; } void zuluMount::updateList( const volumeProperty& entry ) { if( entry.isValid() ){ auto table = m_ui->tableWidget ; auto row = tablewidget::columnHasEntry( table,entry.volumeName() ) ; if( row == -1 ){ row = tablewidget::addRow( table ) ; } if( entry.isSystem() ){ tablewidget::updateRow( table,entry.entryList(),row,this->getSystemVolumeFont() ) ; }else{ tablewidget::updateRow( table,entry.entryList(),row,this->font() ) ; } tablewidget::selectRow( table,row ) ; } } bool zuluMount::errorNotFound( int r ) { DialogMsg m( this ) ; switch ( r ) { case 0 :break ; case 1 :m.ShowUIOK( tr( "ERROR!" ),tr( "Volume is not open or was opened by a different user" ) ) ; break ; case 2 :m.ShowUIOK( tr( "ERROR!" ),tr( "One or more files in the volume are in use." ) ) ; break ; case 3 :m.ShowUIOK( tr( "ERROR!" ),tr( "Volume does not have an entry in /etc/mtab" ) ) ; break ; case 4 :m.ShowUIOK( tr( "ERROR!" ),tr( "Could not get a lock on /etc/mtab~" ) ) ; break ; case 5 :m.ShowUIOK( tr( "ERROR!" ),tr( "Volume is unmounted but could not close mapper,advice to close it manually" ) ) ; break ; case 6 :m.ShowUIOK( tr( "ERROR!" ),tr( "Could not resolve full path of device\n" ) ) ; break ; case 7 :m.ShowUIOK( tr( "ERROR!" ),tr( "Shared mount point appear to be busy\n" ) ) ; break ; case 8 :m.ShowUIOK( tr( "ERROR!" ),tr( "Shared mount point appear to belong to a different user or multiple mount points detected\n" ) ) ; break ; case 9 :m.ShowUIOK( tr( "ERROR!" ),tr( "Shared mount point appear to be in an ambiguous state,advice to unmount manually" ) ) ; break ; case 10:m.ShowUIOK( tr( "ERROR!" ),tr( "Multiple mount points for the volume detected" ) ) ; break ; case 100 :m.ShowUIOK( tr( "ERROR!" ),tr( "Device does not appear to be mounted" ) ) ; break ; case 101 :m.ShowUIOK( tr( "ERROR!" ),tr( "Only root user of members of group \"zulumount\" can unmount this volume" ) ) ; break ; case 107 :m.ShowUIOK( tr( "ERROR!" ),tr( "Shared mount point appear to be busy" ) ) ; break ; case 108 :m.ShowUIOK( tr( "ERROR!" ),tr( "Shared mount point appear to belong to a different user" ) ) ; break ; case 109 :m.ShowUIOK( tr( "ERROR!" ),tr( "Shared mount point appear to be in an ambiguous state,advice to unmount manually" ) ) ; break ; case 103 :m.ShowUIOK( tr( "ERROR!" ),tr( "Device does not exist" ) ) ; break ; case 104 :m.ShowUIOK( tr( "ERROR!" ),tr( "Failed to unmount,the mount point and/or one or more files are in use" ) ) ; break ; case 105 :m.ShowUIOK( tr( "ERROR!" ),tr( "Failed to unmount,could not get a lock on /etc/mtab~" ) ) ; break ; case 106 :m.ShowUIOK( tr( "ERROR!" ),tr( "Failed to unmount the partition" ) ) ; break ; case 111 :m.ShowUIOK( tr( "ERROR!" ),tr( "Failed to unmount,multiple mount points for the volume detected" ) ) ; break ; case 110 :m.ShowUIOK( tr( "ERROR!" ),tr( "Close failed, could not find any partition with the presented UUID" ) ) ; break ; default: return true ; } return false ; } void zuluMount::unmount( const QString& e ) { this->disableAll() ; auto row = m_ui->tableWidget->currentRow() ; auto path = m_ui->tableWidget->item( row,0 )->text() ; auto mountPath = m_ui->tableWidget->item( row,1 )->text() ; auto type = m_ui->tableWidget->item( row,2 )->text() ; if( !type.startsWith( "crypto_" ) ){ utility::Task::suspendForOneSecond() ; } if( _encrypted_folder( type ) ){ if( siritask::encryptedFolderUnMount( path,mountPath,type ).await() ){ siritask::deleteMountFolder( mountPath ) ; }else{ DialogMsg( this ).ShowUIOK( tr( "ERROR" ),tr( "Failed to unmount volume" ) ) ; this->enableAll() ; } }else{ auto r = zuluMountTask::unmountVolume( path,type,e ).await() ; if( r.failed() ){ if( this->errorNotFound( r.exitCode() ) ){ DialogMsg m( this ) ; QString z = r.stdOut() ; z.replace( tr( "ERROR: " ),"" ) ; z.replace( "ERROR: ","" ) ; m.ShowUIOK( tr( "ERROR" ),z ) ; } this->enableAll() ; } } } void zuluMount::pbUmount() { this->unmount() ; } void zuluMount::pbUmount_powerDown() { this->unmount( m_powerOff ) ; } void zuluMount::emergencyQuitApplication() { this->hide() ; auto table = m_ui->tableWidget ; m_removeAllVolumes = true ; auto paths = tablewidget::columnEntries( table,0 ) ; auto mountPoints = tablewidget::columnEntries( table,1 ) ; auto fileSystems = tablewidget::columnEntries( table,2 ) ; auto mountPath = utility::mountPath( QString() ) ; auto homeMountPath = utility::homeMountPath( QString() ) ; for( int i = 0 ; i < paths.size() ; i++ ){ const auto& a = paths.at( i ) ; const auto& b = mountPoints.at( i ) ; const auto& c = fileSystems.at( i ) ; if( utility::startsWithAtLeastOne( b,mountPath,homeMountPath ) ){ if( _encrypted_folder( c ) ){ if( siritask::encryptedFolderUnMount( a,b,c ).await() ){ siritask::deleteMountFolder( b ) ; } }else{ zuluMountTask::unmountVolume( a,c ).await() ; } } } this->closeApplication() ; } void zuluMount::unMountAll() { this->disableAll() ; auto table = m_ui->tableWidget ; m_removeAllVolumes = true ; auto paths = tablewidget::columnEntries( table,0 ) ; auto mountPoints = tablewidget::columnEntries( table,1 ) ; auto fileSystems = tablewidget::columnEntries( table,2 ) ; auto mountPath = utility::mountPath( QString() ) ; auto homeMountPath = utility::homeMountPath( QString() ) ; int r = paths.size() - 1 ; if( r < 0 ){ utility::Task::suspendForOneSecond() ; }else{ do{ const auto& a = paths.at( r ) ; const auto& b = mountPoints.at( r ) ; const auto& c = fileSystems.at( r ) ; if( utility::startsWithAtLeastOne( b,mountPath,homeMountPath ) ){ if( _encrypted_folder( c ) ){ if( siritask::encryptedFolderUnMount( a,b,c ).await() ){ siritask::deleteMountFolder( b ) ; } }else{ zuluMountTask::unmountVolume( a,c ).await() ; } utility::Task::suspendForOneSecond() ; } r-- ; }while( r >= 0 ) ; utility::Task::suspendForOneSecond() ; } this->enableAll_1() ; } void zuluMount::pbUpdate() { this->disableAll() ; auto r = zuluMountTask::updateVolumeList().await() ; this->updateVolumeList( r ) ; this->removeDisappearedEntries( r ) ; } void zuluMount::updateVolumeList( const QVector< volumeProperty >& r ) { if( r.isEmpty() ){ DialogMsg msg( this ) ; msg.ShowUIOK( tr( "ERROR" ), tr( "Reading partition properties took longer than expected and operation was terminated,click refresh to try again" ) ) ; this->enableAll() ; }else{ for( const auto& it : r ){ if( it.isValid() ){ this->updateList( it ) ; } } } } void zuluMount::removeDisappearedEntries( const QVector< volumeProperty >& entries ) { /* * Below routine removes an entries from the table if they are found not to be * present on the the list of volumes we just received.This is necessary * for example to remove no longer valid options like a removed cdrom */ if( entries.isEmpty() ){ return this->enableAll() ; } auto table = m_ui->tableWidget ; auto l = tablewidget::columnEntries( table,0 ) ; auto _hasNoEntry = [ & ]( const QString& volume ){ for( const auto& it : entries ){ if( it.volumeName() == volume ){ if( _encrypted_folder( it.fileSystem(),false ) ){ return false ; } if( it.volumeSize() == "Nil" ){ return true ; }else{ return false ; } } } return true ; } ; decltype( l ) z ; for( const auto& it : l ){ if( _hasNoEntry( it ) ){ z.append( it ) ; } } auto _done = [ this ](){ tablewidget::selectLastRow( m_ui->tableWidget ) ; this->enableAll() ; } ; if( z.isEmpty() ){ _done() ; }else{ for( const auto& e : z ){ tablewidget::selectRow( table,e ) ; utility::Task::suspendForOneSecond() ; tablewidget::deleteRow( table,e ) ; } utility::Task::suspendForOneSecond() ; _done() ; } } void zuluMount::slotCurrentItemChanged( QTableWidgetItem * current,QTableWidgetItem * previous ) { tablewidget::selectRow( current,previous ) ; } void zuluMount::disableAll() { m_ui->pbmenu->setEnabled( false ) ; m_ui->pbmount->setEnabled( false ) ; m_ui->pbupdate->setEnabled( false ) ; m_ui->tableWidget->setEnabled( false ) ; m_ui->pbunlockcryptfs->setEnabled( false ) ; m_ui->pbfavorites->setEnabled( false ) ; } void zuluMount::enableAll() { if( m_removeAllVolumes ){ return ; } m_ui->pbmenu->setEnabled( true ) ; m_ui->pbupdate->setEnabled( true ) ; m_ui->tableWidget->setEnabled( true ) ; m_ui->pbmount->setEnabled( true ) ; m_ui->tableWidget->setFocus() ; m_ui->pbunlockcryptfs->setEnabled( true ) ; m_ui->pbfavorites->setEnabled( true ) ; } void zuluMount::enableAll_1() { m_removeAllVolumes = false ; this->enableAll() ; } bool zuluMount::autoMount() { auto& e = utility::settingsObject() ; if( !e.contains( "AutoMountVolumes" ) ){ e.setValue( "AutoMountVolumes",true ) ; } return e.value( "AutoMountVolumes" ).toBool() ; } zuluMount::~zuluMount() { if( !m_ui ){ return ; } if( m_autoMountAction ){ utility::settingsObject().setValue( "AutoMountVolumes",m_autoMountAction->isChecked() ) ; } auto q = m_ui->tableWidget ; const auto& r = this->window()->geometry() ; utility::setWindowDimensions( "zuluMount",{ r.x(), r.y(), r.width(), r.height(), q->columnWidth( 0 ), q->columnWidth( 1 ), q->columnWidth( 2 ), q->columnWidth( 4 ), q->columnWidth( 5 ) } ) ; delete m_ui ; } zuluCrypt-6.2.0/zuluMount-gui/zulumount.h000066400000000000000000000120271425361753700206160ustar00rootroot00000000000000/* * * Copyright (c) 2012-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include "volumeproperty.h" #include "../zuluCrypt-gui/secrets.h" #include "events.h" #include "monitor_mountinfo.h" #include "../zuluCrypt-gui/systemsignalhandler.h" #include "../zuluCrypt-gui/debugwindow.h" class QCloseEvent ; class QAction ; class QTableWidgetItem ; class events ; class monitor_mountinfo ; namespace Ui { class zuluMount ; } class zuluMount : public QWidget { Q_OBJECT public: explicit zuluMount( QWidget * parent = 0 ) ; ~zuluMount() ; signals: void result( int,QString ) ; void unlistVolume( QString ) ; private slots: void showTrayIcon( bool ) ; void polkitFailedWarning( void ) ; void helperStarted( bool,const QString& ) ; void Show( void ) ; void raiseWindow( const QString& = QString() ) ; void showTrayGUI( void ) ; void cryfsVolumeProperties( void ) ; void closeApplication( void ) ; void closeApplication( int ) ; void unlockCryptFs( void ) ; void showVisibleVolumeList( void ) ; void showHiddenVolumeList( void ) ; void removeVolumeFromHiddenVolumeList( QAction * ) ; void removeVolumeFromVisibleVolumeList( QAction * ) ; void volumeMiniProperties( bool,volumeProperty * ) ; void volumeMiniProperties( volumeProperty * ) ; void volumeMiniProperties_0( volumeProperty * ) ; void showMoungDialog( const volumeProperty& ) ; void showMoungDialog( const QString&,const QString& = QString() ) ; void autoMountVolume( volumeProperty * ) ; void mount( const volumeProperty& ) ; void defaultButton( void ) ; void volumeProperties( void ) ; void itemClicked( QTableWidgetItem * ) ; void pbUpdate( void ) ; void pbMount( void ) ; void slotMount( void ) ; void unMountAll( void ) ; void emergencyQuitApplication( void ) ; void pbUmount( void ) ; void pbUmount_powerDown( void ) ; void unmount( const QString& = QString() ) ; void slotTrayClicked( QSystemTrayIcon::ActivationReason ) ; void slotCurrentItemChanged( QTableWidgetItem *,QTableWidgetItem * ) ; void enableAll( void ) ; void enableAll_1( void ) ; void slotOpenFolder( void ) ; void slotOpenSharedFolder( void ) ; void itemEntered( QTableWidgetItem * ) ; void volumeRemoved( QString ) ; void removeVolume( QString ) ; void addEntryToTable( bool,const QStringList& ) ; void addEntryToTable( bool,const volumeProperty& ) ; void autoMountToggled( bool ) ; void autoOpenFolderOnMount( bool ) ; void removeEntryFromTable( QString ) ; void showFavorites( void ) ; void favoriteClicked( QAction * ) ; void openMountPointPath( QString ) ; void licenseInfo( void ) ; void languageMenu( QAction * ac ) ; void encfsProperties( void ) ; void securefsProperties( void ) ; void gocryptfsProperties( void ) ; void ecryptfsProperties( void ) ; private: void setIcons( void ) ; bool errorNotFound( int ) ; QString resolveFavoriteMountPoint( const QString& ) ; void updateVolumeList( const QVector< volumeProperty >& ) ; void openMountPoint( const QString& ) ; QFont getSystemVolumeFont( void ) ; void setLocalizationLanguage( bool ) ; bool autoOpenFolderOnMount( void ) ; void dragEnterEvent( QDragEnterEvent * ) ; void removeDisappearedEntries( const QVector< volumeProperty >& ) ; void dropEvent( QDropEvent * ) ; void showContextMenu( QTableWidgetItem *,bool ) ; void startAutoMonitor( void ) ; bool autoMount( void ) ; void updateList( const volumeProperty& ) ; Ui::zuluMount * m_ui = nullptr ; QString m_folderOpener ; void disableAll( void ) ; void closeEvent( QCloseEvent * e ) ; void setUpFont( void ) ; void setUpShortCuts( void ) ; void setUpApp( const QString& ) ; QAction * m_autoMountAction = nullptr ; QMenu * m_favorite_menu = nullptr ; QMenu * m_hidden_volume_menu = nullptr ; QMenu * m_not_hidden_volume_menu = nullptr ; QMenu * m_language_menu = nullptr ; secrets m_secrets ; bool m_startHidden ; bool m_autoMount ; QString m_sharedFolderPath ; bool m_autoOpenFolderOnMount ; bool m_removeAllVolumes = false ; QString m_env ; QString m_powerOff ; QVector< std::pair< QAction *,const char * > > m_actionPair ; QVector< std::pair< QMenu *,const char * > > m_menuPair ; QSystemTrayIcon m_trayIcon ; monitor_mountinfo m_mountInfo ; events m_events ; systemSignalHandler m_signalHandler ; debugWindow m_debugWindow ; }; #endif // MAINWINDOW_H zuluCrypt-6.2.0/zuluMount-gui/zulumount.ui000066400000000000000000000106551425361753700210110ustar00rootroot00000000000000 zuluMount Qt::NonModal 0 0 910 477 zuluMount :/zuluMount.png:/zuluMount.png 0 0 0 0 QAbstractItemView::NoEditTriggers QAbstractItemView::NoSelection false Qt::NoPen Volume Path AlignCenter Mount Point Path AlignCenter File System AlignCenter Label AlignCenter Size AlignCenter %Used AlignCenter QLayout::SetFixedSize Mount F&older &Mount File false false &Refresh &Favorites Men&u pbmenu zuluCrypt-6.2.0/zuluMount-gui/zulumounttask.cpp000066400000000000000000000301701425361753700220330ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "bin_path.h" #include "zulumounttask.h" #include #include #include #include #include static QString _convert_lvm_path( const QString& dev ) { auto volume = dev ; auto e = dev.toLatin1() ; char * begin = e.data() ; char * end = begin + e.size() ; char * k ; char * c ; char * d ; for( auto it = begin + 3 ; it < end ; it++ ){ k = it - 2 ; c = it - 1 ; d = it ; if( *k != '-' && *c == '-' && *d != '-' ){ *c = '/' ; volume = e ; while( volume.contains( "--" ) ){ volume.replace( "--","-" ) ; } break ; } } return volume ; } static QString _convert_md_raid_path( const QString& dev,bool wait ) { auto volume = dev ; decltype( volume ) dev_1 ; QDir f ; if( wait ){ /* * wait for a while because things dont always happen as expected if we check too soon. */ utility::Task::wait( 4 ) ; } if( utility::pathExists( "/dev/md/" ) ){ auto l = utility::directoryList( "/dev/md/" ) ; for( const auto& it : l ){ dev_1 = "/dev/md/" + it ; f.setPath( dev_1 ) ; if( f.canonicalPath() == dev ){ volume = dev_1 ; break ; } } } return volume ; } static QString _device( const QString& device ) { if( device.startsWith( "UUID" ) ){ return device ; }else{ auto d = device ; return d.replace( "\"","\"\"\"" ) ; } } static bool _volumeIsSystemVolume( const QString& e ) { return utility::Task( utility::appendUserUID( "%1 -S" ).arg( zuluMountPath ) ).splitOutput( '\n' ).contains( e ) ; } QStringList zuluMountTask::mountedVolumeList( void ) { return utility::Task( utility::appendUserUID( "%1 -E" ).arg( zuluMountPath ) ).splitOutput( '\n' ) ; } volumeProperty _getVolumeProperties( const QString& e ) { auto device = _device( e ) ; auto r = utility::Task( utility::appendUserUID( "%1 -L -d \"%2\"" ).arg( zuluMountPath,device ) ) ; if( r.success() ) { return volumeProperty( r.splitOutput( '\t' ),_volumeIsSystemVolume( device ) ) ; }else{ return volumeProperty() ; } } Task::future< volumeProperty >& zuluMountTask::getVolumeProperties( const QString& e ) { return Task::run( [ e ](){ return _getVolumeProperties( e ) ; } ) ; } Task::future< QString >& zuluMountTask::volumeProperties( const QString& v,const QString& volumeType ) { return Task::run( [ = ](){ if( v.isEmpty() ){ return QString() ; } auto volume = _device( v ) ; auto r = utility::Task( utility::appendUserUID( "%1 -s -d \"%2\"" ).arg( zuluMountPath,volume ) ) ; if( r.ok() ){ return QString( r.stdOut() ) ; }else{ if( volumeType.contains( "crypto_PLAIN\n" ) ){ /* * this could be a plain volume opened with an offset */ auto e = utility::appendUserUID( "%1 -s -o bogusNecessaryArgument -d \"%2\"" ) ; r = utility::Task( e.arg( zuluMountPath,volume ) ) ; if( r.ok() ){ return QString( r.stdOut() ) ; }else{ return QString() ; } }else{ return QString() ; } } } ) ; } utility::Task zuluMountTask::volumeUnmount( const QString& volumePath,const QString& volumeType,const QString& powerOffCommand ) { auto _run = []( const QString& exe ){ auto e = utility::Task( exe ) ; QString output = e.stdOut() ; int index = output.indexOf( QChar( ':' ) ) ; e.stdOut( output.mid( index + 1 ).toLatin1() ) ; return e ; } ; auto volume = _device( volumePath ) ; auto r = _run( utility::appendUserUID( "%1 -u -d \"%2\"" ).arg( zuluMountPath,volume ) ) ; if( r.failed() ){ if( volumeType.contains( "crypto_PLAIN\n" ) ){ /* * we could be trying to unmount a volume with an offset */ r = _run( utility::appendUserUID( "%1 -o bogusNecessaryArgument -u -d \"%2\"" ).arg( zuluMountPath,volume ) ) ; } } if( r.success() && !powerOffCommand.isEmpty() ){ auto v = volumePath ; if( utility::startsWithAtLeastOne( v,"/dev/sd","/dev/hd","/dev/vd","/dev/xvd" ) ){ for( char i = '0' ; i < '9' ; i++ ){ v.remove( i ) ; } } utility::Task( powerOffCommand.arg( v ) ) ; } return r ; } Task::future< utility::Task >& zuluMountTask::unmountVolume( const QString& volumePath,const QString& volumeType,const QString& powerOffCommand ) { return Task::run( [ = ](){ return zuluMountTask::volumeUnmount( volumePath,volumeType,powerOffCommand ) ; } ) ; } struct deviceList { QString deviceName ; QString uniqueName ; }; static QVector< deviceList > _getDevices() { auto p = "/dev/disk/by-id/" ; auto l = utility::directoryList( p ) ; decltype( _getDevices() ) devices ; if( l.isEmpty() ){ return devices ; }else{ auto _not_present = [ &devices ]( const QString& e ){ for( const auto& it : devices ){ if( it.deviceName == e ){ return false ; } } return true ; } ; auto _device_path = []( const QString& dev ){ if( dev.startsWith( "/dev/dm-" ) ){ QFile file( "/sys/block/" + dev.split( '/' ).last() + "/dm/name" ) ; if( file.open( QIODevice::ReadOnly ) ){ QString e = file.readAll() ; e.truncate( e.size() - 1 ) ; return _convert_lvm_path( "/dev/" + e ) ; }else{ return dev ; } }else if( dev.startsWith( "/dev/md" ) ){ return _convert_md_raid_path( dev,false ) ; }else{ return dev ; } } ; QDir e ; for( const auto& it : l ){ e.setPath( p + it ) ; if( !it.startsWith( "edd-int13_dev" ) ){ const auto& q = _device_path( e.canonicalPath() ) ; if( _not_present( q ) ){ devices.append( { q,it } ) ; } } } } return devices ; } static QString _getUniqueName( const QString& device ) { for( const auto& it : _getDevices() ){ if( it.deviceName == device ){ return it.uniqueName ; } } return QString() ; } void zuluMountTask::addVolumeToHiddenVolumeList( const QString& e ) { auto& settings = utility::settingsObject() ; QStringList s ; if( settings.contains( "ListOfHiddenVolumes" ) ){ s = settings.value( "ListOfHiddenVolumes" ).toStringList() ; } auto a = _getUniqueName( e ) ; if( !a.isEmpty() ){ s.append( a ) ; settings.setValue( "ListOfHiddenVolumes",s ) ; } } QStringList zuluMountTask::hiddenVolumeList() { auto& settings = utility::settingsObject() ; if( settings.contains( "ListOfHiddenVolumes" ) ){ auto l = _getDevices() ; QStringList e ; auto g = settings.value( "ListOfHiddenVolumes" ).toStringList() ; for( const auto& it : l ){ if( g.contains( it.uniqueName ) ){ e.append( it.deviceName ) ; } } return e ; }else{ return QStringList() ; } } void zuluMountTask::removeVolumeFromHiddenVolumeList( const QString& e ) { auto& settings = utility::settingsObject() ; auto _get_hidden_volume_list = [ & ](){ if( settings.contains( "ListOfHiddenVolumes" ) ){ return settings.value( "ListOfHiddenVolumes" ).toStringList() ; }else{ return QStringList() ; } } ; auto _remove_entry = []( QStringList l,const QString& e ){ if( !l.isEmpty() ){ l.removeAll( _getUniqueName( e ) ) ; } return l ; } ; auto _update_list = [ & ]( const QStringList& l ){ settings.setValue( "ListOfHiddenVolumes",l ) ; } ; _update_list( _remove_entry( _get_hidden_volume_list(),e ) ) ; } Task::future< QVector< volumeProperty > >& zuluMountTask::updateVolumeList() { return Task::run( [](){ auto l = zuluMountTask::hiddenVolumeList() ; auto _validEntry = [ & ]( const QString& e ){ if( e.startsWith( "/dev/md/md-device-map" ) ){ return false ; } if( e.contains( "\tswap\t" ) || e.contains( "member\t" ) || e.contains( "\t/run/media/public" ) ){ return false ; } if( !l.isEmpty() ){ for( const auto& it : l ){ if( e.startsWith( it + '\t' ) ){ return false ; } } } return true ; } ; QVector< volumeProperty > list ; auto all = utility::Task( utility::appendUserUID( "%1 -l" ).arg( zuluMountPath ),10000 ) ; if( all.finished() ){ auto system = utility::Task( utility::appendUserUID( "%1 -S" ).arg( zuluMountPath ),10000 ) ; if( system.finished() ){ auto a = all.splitOutput( '\n' ) ; auto s = system.splitOutput( '\n' ) ; for( const auto& it : a ){ if( _validEntry( it ) ){ const auto& e = utility::split( it,'\t' ) ; list.append( volumeProperty( e,s.contains( e.first() ) ) ) ; } } } } return list ; } ) ; } void zuluMountTask::checkUnMount( const QString& volume ) { utility::Task( utility::appendUserUID( "%1 -c -d \"%2\"" ).arg( zuluMountPath,_device( volume ) ) ) ; } volumeStatus zuluMountTask::volumeMiniProperties( const QString& volume ) { auto _loopDeviceIsGone = []( const QString& device ){ QFile f ; auto dev = QString( "%1\n" ).arg( device ) ; auto _match = [ & ]( const QString& path ){ f.setFileName( QString( "/sys/block/%1/loop/backing_file" ).arg( path ) ) ; auto r = false ; if( f.open( QIODevice::ReadOnly ) ){ r = f.readAll() == dev ; } f.close() ; return r ; } ; for( const auto& it : utility::directoryList( "/sys/block" ) ){ if( it.startsWith( "loop" ) && _match( it ) ){ return false ; } } return true ; } ; volumeStatus s{ volume,false,nullptr } ; if( !volume.startsWith( "UUID" ) && !volume.startsWith( "/dev/" ) ){ /* * There is some sort of a race condition here and things do not always work as expected * try to sleep for a second to see if it will help */ utility::Task::waitForOneSecond() ; if( _loopDeviceIsGone( volume ) ){ /* * we were just asked to find properties of a loop device * that no longer exists,remove it from the list in the GUI window */ s.volumeRemoved = true ; return s ; } } auto r = utility::Task( utility::appendUserUID( "%1 -L -d \"%2\"" ).arg( zuluMountPath,volume ) ) ; if( r.success() ){ s.entry = new volumeProperty( r.splitOutput( '\t' ),_volumeIsSystemVolume( volume ) ) ; } return s ; } volumeStatus zuluMountTask::deviceProperties( const zuluMountTask::event& deviceProperty ) { auto _mdRaidDevice = [ & ]( const QString& device ){ auto d = _convert_md_raid_path( device,true ) ; volumeStatus s{ d,false,nullptr } ; if( deviceProperty.added ){ s.entry = new volumeProperty( _getVolumeProperties( d ) ) ; }else{ s.volumeRemoved = true ; } return s ; } ; auto _dmDevice = [ & ]( const QString& device ){ auto d = _convert_lvm_path( device ) ; volumeStatus s{ d,false,nullptr } ; if( deviceProperty.added ){ s.entry = new volumeProperty( _getVolumeProperties( d ) ) ; }else{ s.volumeRemoved = true ; } return s ; } ; auto _normalDevice = [&]( const QString& device ){ auto _allowed_device = []( const QString& device ){ return utility::startsWithAtLeastOne( device, "/dev/sd", "/dev/hd", "/dev/vd", "/dev/mmc", "/dev/xvd" ) ; } ; volumeStatus s{ QString(),false,nullptr } ; if( _allowed_device( device ) ){ s.volumeName = device ; if( deviceProperty.added ){ s.entry = new volumeProperty( _getVolumeProperties( device ) ) ; }else{ s.volumeRemoved = true ; } } return s ; } ; auto _shouldNotGetHere = [](){ return volumeStatus{ QString(),false,nullptr } ; } ; auto device = QString( "/dev/%1" ).arg( deviceProperty.volumeName ) ; switch( deviceProperty.deviceType ){ case zuluMountTask::devices::device : return _normalDevice( device ) ; case zuluMountTask::devices::md_device : return _mdRaidDevice( device ) ; case zuluMountTask::devices::dm_device : return _dmDevice( device ) ; default : return _shouldNotGetHere() ; } } zuluCrypt-6.2.0/zuluMount-gui/zulumounttask.h000066400000000000000000000042141425361753700215000ustar00rootroot00000000000000/* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #ifndef ZULUMOUNTTASK_H #define ZULUMOUNTTASK_H #include "volumeproperty.h" #include "task.hpp" #include "../zuluCrypt-gui/utility.h" #include #include #include struct volumeStatus { QString volumeName ; bool volumeRemoved ; volumeProperty * entry ; }; namespace zuluMountTask { enum class devices { device,dm_device,md_device }; struct event { zuluMountTask::devices deviceType ; bool added ; QString volumeName ; }; Task::future< QString >& volumeProperties( const QString& volume,const QString& volumeType ) ; Task::future< QVector< volumeProperty > >& updateVolumeList( void ) ; Task::future< volumeProperty >& getVolumeProperties( const QString& e ) ; Task::future< utility::Task >& unmountVolume( const QString& volumePath, const QString& volumeType, const QString& powerOffCommand = QString() ) ; utility::Task volumeUnmount( const QString& volumePath, const QString& volumeType, const QString& powerOffCommand = QString() ) ; void checkUnMount( const QString& ) ; volumeStatus volumeMiniProperties( const QString& volume ) ; volumeStatus deviceProperties( const zuluMountTask::event& ) ; QStringList mountedVolumeList( void ) ; QStringList hiddenVolumeList( void ) ; void addVolumeToHiddenVolumeList( const QString& ) ; void removeVolumeFromHiddenVolumeList( const QString& ) ; } #endif // ZULUMOUNTTASK_H zuluCrypt-6.2.0/zuluPolkit/000077500000000000000000000000001425361753700157375ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluPolkit/CMakeLists.txt000066400000000000000000000041531425361753700205020ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0.2) add_definitions( -D_FILE_OFFSET_BITS=64 -Wextra -Wall -pedantic -I${PROJECT_BINARY_DIR}/zuluPolkit/ ) include_directories( ${PROJECT_BINARY_DIR}/zuluPolkit/ ) if( CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0.0) set( CMAKE_CXX_STANDARD 20 ) MESSAGE( STATUS "Setting C++ version to C++20" ) else() set( CMAKE_CXX_STANDARD 14 ) MESSAGE( STATUS "Setting C++ version to C++14" ) endif() set( CMAKE_CXX_STANDARD_REQUIRED ON ) set( CMAKE_CXX_EXTENSIONS OFF) set( MOC_FILES zulupolkit.h ) set( SRC main.cpp zulupolkit.cpp ../zuluCrypt-gui/executablesearchpaths.cpp ) Qt5_WRAP_CPP( MOC ${MOC_FILES} ) INCLUDE_DIRECTORIES( ${CMAKE_BINARY_DIR} ) add_executable( zuluPolkit ${MOC} ${SRC} ) set_target_properties( zuluPolkit PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" ) set_target_properties( zuluPolkit PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIC -pedantic" ) if( QT5 ) target_link_libraries( zuluPolkit ${Qt5Core_LIBRARIES} ${Qt5Network_LIBRARIES} mhogomchungu_task ) else() target_link_libraries( zuluPolkit ${QT_LIBRARIES} mhogomchungu_task ) endif() file( WRITE ${PROJECT_BINARY_DIR}/org.zulucrypt.zulupolkit.policy " Authentication is required to complete requested operation. zuluCrypt auth_admin auth_admin auth_admin ${CMAKE_INSTALL_PREFIX}/bin/zuluPolkit ") install( FILES ${PROJECT_BINARY_DIR}/org.zulucrypt.zulupolkit.policy DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/actions ) install( TARGETS zuluPolkit RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) zuluCrypt-6.2.0/zuluPolkit/main.cpp000066400000000000000000000024001425361753700173630ustar00rootroot00000000000000/* * * Copyright ( c ) 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include "zulupolkit.h" int main( int argc,char * argv[] ) { QCoreApplication a( argc,argv ) ; auto s = QCoreApplication::arguments() ; if( s.last().startsWith( "fork" ) ){ s.removeLast() ; auto exe = s.first() ; s.removeFirst() ; if( QProcess::startDetached( exe,s ) ){ return 0 ; }else{ return 1 ; } }else{ zuluPolkit e( s ) ; QMetaObject::invokeMethod( &e,"start",Qt::QueuedConnection ) ; return a.exec(); } } zuluCrypt-6.2.0/zuluPolkit/zulupolkit.cpp000066400000000000000000000140351425361753700206700ustar00rootroot00000000000000/* * * Copyright ( c ) 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include "zulupolkit.h" #include "task.hpp" #include "bin_path.h" #include "../zuluCrypt-gui/executablesearchpaths.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace utility { QString executableFullPath( const QString& e ) { QString exe ; for( const auto& it : executableSearchPaths::values() ){ exe = it + e ; if( QFile::exists( exe ) ){ return exe ; } } return QString() ; } } static bool _terminalEchoOff( struct termios * old,struct termios * current ) { if( tcgetattr( 1,old ) != 0 ){ return false ; } *current = *old ; current->c_lflag &= ~ECHO ; if( tcsetattr( 1,TCSAFLUSH,current ) != 0 ){ return false ; }else{ return true ; } } #if QT_VERSION > QT_VERSION_CHECK( 5,0,0 ) #include #define zuluPermission QFileDevice #else #define zuluPermission QFile #endif static QByteArray _zulupolkit( const QString& cmd,const QString& path,const QString& data ) { QFile e( path ) ; QDir().mkpath( "/etc/zuluCrypt" ) ; auto q = zuluPermission::ReadOwner | zuluPermission::WriteOwner ; QFile().setPermissions( "/etc/zuluCrypt",q | zuluPermission::ExeOwner ) ; QByteArray s ; if( cmd == "Read" ){ if( e.open( QIODevice::ReadOnly ) ){ s = e.readAll() ; } }else if( cmd == "Write" ){ if( e.open( QIODevice::WriteOnly | QIODevice::Truncate ) ){ e.write( data.toLatin1() ) ; } } e.setPermissions( q ) ; return s ; } zuluPolkit::zuluPolkit( const QStringList& s ) : m_arguments( s ) { connect( &m_server,SIGNAL( newConnection() ),this,SLOT( gotConnection() ) ) ; } zuluPolkit::~zuluPolkit() { QDir().remove( m_socketPath ) ; } static void _set_path_writable_by_others( const QString& e ) { QFile f( e ) ; for( decltype( umask( 0 ) ) i = 0 ; i < 1000 ; i++ ){ umask( i ) ; f.open( QIODevice::WriteOnly ) ; auto s = f.permissions() ; f.close() ; f.remove() ; if( s & zuluPermission::WriteOther ){ break ; } } } void zuluPolkit::start() { if( m_arguments.size() > 1 ){ m_cookie = this->readStdin() ; m_socketPath = m_arguments.at( 1 ) ; QFile::remove( m_socketPath ) ; auto s = umask( 0 ) ; _set_path_writable_by_others( m_socketPath ) ; m_server.listen( m_socketPath ) ; umask( s ) ; } } static void _respond( QLocalSocket& s,const QByteArray& e ) { QJsonObject obj ; obj.insert( "stdOut",e.constData() ) ; obj.insert( "stdError",e.constData() ) ; obj.insert( "exitCode",0 ) ; obj.insert( "exitStatus",0 ) ; obj.insert( "finished",true ) ; s.write( QJsonDocument( obj ).toJson( QJsonDocument::JsonFormat::Indented ) ) ; s.waitForBytesWritten() ; } static void _respond( QLocalSocket& s,const Task::process::result& e = Task::process::result() ) { QJsonObject obj ; obj.insert( "stdOut",e.std_out().constData() ) ; obj.insert( "stdError",e.std_error().constData() ) ; obj.insert( "exitCode",e.exit_code() ) ; obj.insert( "exitStatus",e.exit_status() ) ; obj.insert( "finished",e.finished() ) ; s.write( QJsonDocument( obj ).toJson( QJsonDocument::JsonFormat::Indented ) ) ; s.waitForBytesWritten() ; } static bool _correct_cmd( const QString& cmd ) { auto a = ZULUCRYPTzuluCrypt" " ; auto b = zuluMountPath" " ; auto su = utility::executableFullPath( "su" ) ; auto e = su + " - -c \"" + utility::executableFullPath( "ecryptfs-simple" ) ; auto f = su + " - -c \"'" + utility::executableFullPath( "ecryptfs-simple" ) ; return cmd.startsWith( a ) || cmd.startsWith( b ) || cmd.startsWith( e ) || cmd.startsWith( f ) ; } void zuluPolkit::gotConnection() { std::unique_ptr< QLocalSocket > m( m_server.nextPendingConnection() ) ; auto& s = *m ; s.waitForReadyRead() ; QJsonParseError error ; auto doc = QJsonDocument::fromJson( s.readAll(),&error ) ; if( error.error != QJsonParseError::NoError ){ return _respond( s,"zuluPolkit: Booooooooo!!!!" ) ; } auto obj = doc.object() ; auto path = obj.value( "path" ).toString() ; auto data = obj.value( "data" ).toString() ; auto password = obj.value( "password" ).toString() ; auto cookie = obj.value( "cookie" ).toString() ; auto command = obj.value( "command" ).toString() ; if( cookie == m_cookie ){ if( command == "exit" ){ return QCoreApplication::quit() ; }else if( command == "Read" || command == "Write" ){ return _respond( s,_zulupolkit( command,path,data ) ) ; }else if( _correct_cmd( command ) ){ #if QT_VERSION < QT_VERSION_CHECK( 5,15,0 ) return _respond( s,Task::process::run( command,{},password.toLatin1() ).get() ) ; #else auto ss = QProcess::splitCommand( command ) ; auto ee = ss.first() ; ss.removeFirst() ; return _respond( s,Task::process::run( ee,ss,password.toLatin1() ).get() ) ; #endif } } _respond( s,"zuluPolkit: Booooooooo!!!!" ) ; } QString zuluPolkit::readStdin() { std::cout << "Token: " << std::flush ; struct termios old ; struct termios current ; _terminalEchoOff( &old,¤t ) ; QString s ; int e ; int m = 1024 ; for( int i = 0 ; i < m ; i++ ){ e = std::getchar() ; if( e == '\n' || e == -1 ){ break ; }else{ s += static_cast< char >( e ) ; } } tcsetattr( 1,TCSAFLUSH,&old ) ; std::cout << std::endl ; return s ; } zuluCrypt-6.2.0/zuluPolkit/zulupolkit.h000066400000000000000000000023361425361753700203360ustar00rootroot00000000000000#ifndef ZULUPOLKIT_H #define ZULUPOLKIT_H /* * * Copyright ( c ) 2017 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include #include class zuluPolkit : public QObject { Q_OBJECT public: zuluPolkit( const QStringList& ) ; ~zuluPolkit() ; private slots: void start() ; void gotConnection() ; private: QStringList m_arguments ; QString readStdin() ; QString m_cookie ; QLocalServer m_server ; QString m_socketPath ; }; #endif // ZULUPOLKIT_H zuluCrypt-6.2.0/zuluSafe-cli.1000066400000000000000000000032471425361753700162100ustar00rootroot00000000000000 .TH zuluSafe-cli 1 .br .SH NAME zuluSafe-cli - command line tool that manages encrypted and unencrypted volumes .SH DESCRIPTION This is a simple tool for secure storage of files in a wallet.Added files to the wallet will be stored in a secured file located at \"~/.config/lxqt/wallets/zuluSafe/YYY.lwt\" where YYY is\n\ wallet name" .br .SH USAGE usage: see examples below .br options: .br To add a file to a wallet,run : zuluSafe-cli --add .br To delete a file in a wallet,run : zuluSafe-cli --delete .br To get a file from the wallet,run : zuluSafe-cli --get .br To add all files in a folder,run : zuluSafe-cli --add-all .br To get a list of files in the wallet,run : zuluSafe-cli --list .br To get all files from the wallet,run : zuluSafe-cli --get-all .br To get a list of wallets,run : zuluSafe-cli --wallets .br .SH COPYRIGHT Copyright (c) 2011-2014 .br name : Francis Banyikwa .br email: mhogomchungu@gmail.com .br .br 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, see . .br .SH LAST EDIT Sun Jan 19 14:59:24 EST 2014 zuluCrypt-6.2.0/zuluSafe/000077500000000000000000000000001425361753700153535ustar00rootroot00000000000000zuluCrypt-6.2.0/zuluSafe/CMakeLists.txt000066400000000000000000000016001425361753700201100ustar00rootroot00000000000000 cmake_minimum_required(VERSION 3.0.2) include_directories( ${PROJECT_BINARY_DIR} ) include_directories( ${PROJECT_SRC_DIR}/zuluSafe ) add_executable( zuluSafe-cli zuluSafe.c zuluwallet.c ) find_file( GCRYPT_INCLUDE_FILE gcrypt.h ) find_library( GCRYPT_LIBRARY gcrypt ) if( NOT GCRYPT_INCLUDE_FILE ) MESSAGE( FATAL_ERROR "could not find gcrypt header file" ) else() MESSAGE( STATUS "found gcrypt header file: ${GCRYPT_INCLUDE_FILE}" ) endif() set_target_properties( zuluSafe-cli PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64 -Wextra -Wall -s -fPIE -pthread -pedantic " ) set_target_properties( zuluSafe-cli PROPERTIES LINK_FLAGS "-pie" ) TARGET_LINK_LIBRARIES( zuluSafe-cli "${GCRYPT_LIBRARY}" ) install(TARGETS zuluSafe-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) zuluCrypt-6.2.0/zuluSafe/zuluSafe.c000066400000000000000000000246261425361753700173270ustar00rootroot00000000000000 /* * * Copyright (c) 2014-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * 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, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "zuluwallet.h" #include "version.h" #define PASSWORD_SIZE 512 #define WALLET_NAME_SIZE 512 #define APPLICATION_NAME "zuluSafe" #define _file( x ) x,strlen( x ) + 1 #define StringsAreEqual( x,y ) strcmp( x,y ) == 0 #define StringsAreNotEqual( x,y ) strcmp( x,y ) != 0 static void _write( int x,const void * y,size_t z ) { if( write( x,y,z ) ){;} } static void _read( int x,void * y,size_t z ) { if( read( x,y,z ) ){;} } static void _help( void ) { const char * help2 ; const char * help1 ; help1 = gettext( "\n\n\ This is a simple tool for secure storage of files in a wallet.Added files to the wallet\n\ will be stored in a secured file located at \"~/.config/lxqt/wallets/zuluSafe/YYY.lwt\" where YYY is\n\ wallet name\n\n" ) ; help2 = gettext( "\ To add a file to a wallet,run : zuluSafe-cli --add \n\ To delete a file in a wallet,run : zuluSafe-cli --delete \n\ To get a file from the wallet,run : zuluSafe-cli --get \n\ To add all files in a folder,run : zuluSafe-cli --add-all \n\ To get a list of files in the wallet,run : zuluSafe-cli --list\n\ To get all files from the wallet,run : zuluSafe-cli --get-all\n\ To get a list of wallets,run : zuluSafe-cli --wallets\n" ) ; printf( "\n%s%s\n%s",VERSION_STRING,help1,help2 ) ; } static void _clearKeyBoardBuffer( void ) { int c ; while( 1 ){ c = getchar() ; if( c == '\n' || c == EOF ){ break ; } } } static void _getInputFromUser( char * buffer,size_t size,size_t * len ) { char c ; char * e = buffer ; const char * f = e + size ; while( e != f ){ c = getchar() ; if( c == '\n' || c == EOF ){ break ; }else{ *e++ = c ; } } *e = '\0' ; if( len != NULL ){ *len = e - buffer ; } } static int _terminalEchoOff( struct termios * old,struct termios * new ) { if( tcgetattr ( 1,old ) != 0 ){ return 1 ; } *new = *old; new->c_lflag &= ~ECHO; if( tcsetattr ( 1,TCSAFLUSH,new ) != 0 ){ return 1 ; }else{ return 0 ; } } static int _getPassWordFromUser( char * password,size_t size,size_t * len ) { struct termios old ; struct termios new ; if( _terminalEchoOff( &old,&new ) == 1 ){ puts( gettext( "failed to read password" ) ) ; return 1 ; }else{ _getInputFromUser( password,size,len ) ; tcsetattr( 1,TCSAFLUSH,&old ); return 0 ; } } static int _open_wallet( lxqt_wallet_t * wallet,const char * password,size_t password_length,const char * wallet_name ) { lxqt_wallet_error r = lxqt_wallet_open( wallet,password,password_length,wallet_name,APPLICATION_NAME ) ; if( r != lxqt_wallet_no_error ){ puts( gettext( "wrong password,failed to open wallet" ) ) ; return 1 ; }else{ return 0 ; } } static int _openWallet( lxqt_wallet_t * wallet ) { size_t password_length = 0 ; lxqt_wallet_error r ; int c ; char password[ PASSWORD_SIZE + 1 ] ; char password_1[ PASSWORD_SIZE + 1 ] ; char wallet_name[ WALLET_NAME_SIZE + 1 ] ; printf( gettext( "enter wallet name: " ) ) ; _getInputFromUser( wallet_name,WALLET_NAME_SIZE,NULL ) ; if( lxqt_wallet_exists( wallet_name,APPLICATION_NAME ) != 0 ){ printf( gettext( "wallet \"%s\" does not exist,do you want to create it?(y/n): " ),wallet_name ) ; c = getchar() ; _clearKeyBoardBuffer() ; if( c == 'y' ){ printf( gettext( "enter wallet password: " ) ) ; _getPassWordFromUser( password,PASSWORD_SIZE,&password_length ) ; puts( "" ) ; printf( gettext( "re enter wallet password: " ) ) ; _getPassWordFromUser( password_1,PASSWORD_SIZE,NULL ) ; puts( "" ) ; if( StringsAreNotEqual( password,password_1 ) ){ puts( gettext( "passwords did not match" ) ) ; return 1 ; }else{ r = lxqt_wallet_create( password,password_length,wallet_name,APPLICATION_NAME ) ; if( r != lxqt_wallet_no_error ){ puts( gettext( "failed to create wallet" ) ) ; return 1 ; } } }else{ puts( gettext( "volume not created per user request" ) ) ; return 1 ; } }else{ printf( gettext( "enter wallet password: " ) ) ; _getPassWordFromUser( password,PASSWORD_SIZE,&password_length ) ; puts( "" ) ; } return _open_wallet( wallet,password,password_length,wallet_name ) ; } static int _printListOfManagedFiles( lxqt_wallet_t wallet ) { lxqt_wallet_iterator_t iter ; memset( &iter,'\0',sizeof( iter ) ) ; while( lxqt_wallet_iter_read_value( wallet,&iter ) ){ puts( iter.entry.key ) ; } return 0 ; } static const char * _fileName( const char * filePath ) { const char * e = strrchr( filePath,'/' ) ; if( e == NULL ){ return filePath ; }else{ return e + 1 ; } } static int _addFileToWallet_1( lxqt_wallet_t wallet,int fd,const char * filePath,const struct stat * st ) { lxqt_wallet_error r ; char * e ; const char * fileName = _fileName( filePath ) ; e = malloc( st->st_size ) ; if( e == NULL ){ puts( gettext( "failed to allocate memory" ) ) ; return 1 ; }else{ _read( fd,e,st->st_size ) ; r = lxqt_wallet_add_key( wallet,_file( fileName ),e,st->st_size ) ; free( e ) ; if( r != lxqt_wallet_no_error ){ puts( gettext( "failed to add file to the wallet" ) ) ; return 1 ; }else{ return 0 ; } } } static int _addFileToWallet( lxqt_wallet_t wallet,const char * filePath ) { lxqt_wallet_error r ; struct stat st ; int fd ; void * map ; int k = 1 ; const char * fileName = _fileName( filePath ) ; if( lxqt_wallet_wallet_has_key( wallet,_file( fileName ) ) ){ printf( gettext( "wallet already has \"%s\" entry\n" ),fileName ) ; return 1 ; }else{ fd = open( filePath,O_RDONLY ) ; if( fd == -1 ){ puts( gettext( "failed to open file for reading" ) ) ; return 1 ; }else{ fstat( fd,&st ) ; map = mmap( 0,st.st_size,PROT_READ,MAP_PRIVATE,fd,0 ) ; if( map == MAP_FAILED ){ k = _addFileToWallet_1( wallet,fd,fileName,&st ) ; }else{ r = lxqt_wallet_add_key( wallet,_file( fileName ),map,st.st_size ) ; munmap( map,st.st_size ) ; if( r != lxqt_wallet_no_error ){ puts( gettext( "failed to add file to the wallet" ) ) ; k = 1 ; }else{ k = 0 ; } } close( fd ) ; return k ; } } } static int _deleteFileFromWallet( lxqt_wallet_t wallet,const char * filePath ) { const char * fileName = _fileName( filePath ) ; lxqt_wallet_delete_key( wallet,_file( fileName ) ) ; return 0 ; } static int _getFileFromWallet( lxqt_wallet_t wallet,const char * filePath ) { int fd ; int r ; struct stat st ; lxqt_wallet_key_values_t k ; const char * fileName = _fileName( filePath ) ; r = lxqt_wallet_read_key_value( wallet,_file( fileName ),&k ) ; if( r != 1 ){ puts( gettext( "file not found in the wallet" ) ) ; return 1 ; }else{ if( stat( filePath,&st ) == 0 ){ printf( gettext( "path ./\"%s\" already occupied\n" ),fileName ) ; return 1 ; }else{ fd = open( filePath,O_WRONLY|O_CREAT,0644 ) ; if( fd == -1 ){ puts( gettext( "failed to open file for writing" ) ) ; return 1 ; }else{ _write( fd,k.key_value,k.key_value_size ) ; close( fd ) ; return 0 ; } } } } static int _getAllFilesFromWallet( lxqt_wallet_t wallet ) { lxqt_wallet_iterator_t iter ; memset( &iter,'\0',sizeof( iter ) ) ; while( lxqt_wallet_iter_read_value( wallet,&iter ) ){ _getFileFromWallet( wallet,iter.entry.key ) ; } return 0 ; } static int _addAllFilesToTheWallet( lxqt_wallet_t wallet,const char * path ) { struct stat st ; DIR * dir = opendir( path ) ; struct dirent * entry ; char path_1[ PATH_MAX ] ; if( dir == NULL ){ puts( gettext( "failed to open directory for reading" ) ) ; return 1 ; }else{ while( ( entry = readdir( dir ) ) != NULL ){ snprintf( path_1,PATH_MAX,"%s/%s",path,entry->d_name ) ; if( stat( path_1,&st ) == 0 && S_ISREG( st.st_mode ) ){ _addFileToWallet( wallet,path_1 ) ; } } return 0 ; } } static int _printWalletList( void ) { int len = 0 ; int k ; char * c ; char ** e = lxqt_wallet_wallet_list( APPLICATION_NAME,&len ) ; for( k = 0 ; k < len ; k++ ){ c = *( e + k ) ; puts( c ) ; free( c ) ; } free( e ) ; return 0 ; } int main( int argc,char * argv[] ) { lxqt_wallet_t wallet = 0 ; const char * path ; const char * action ; int r = 1 ; if( argc == 1 ){ _help() ; return 0 ; } action = argv[ 1 ] ; if( argc == 2 ){ if( StringsAreEqual( action,"-h" ) || StringsAreEqual( action,"--help" ) || StringsAreEqual( action,"-help" ) || StringsAreEqual( action,"-v" ) || StringsAreEqual( action,"--version" ) ){ _help() ; return 0 ; }else if( StringsAreEqual( action,"--wallets" ) ){ return _printWalletList() ; }else if( StringsAreEqual( action,"--list" ) || StringsAreEqual( action,"--get-all" ) ){ ; }else{ _help() ; return 1 ; } } if( _openWallet( &wallet ) ){ return 1 ; }else{ if( StringsAreEqual( action,"--list" ) ){ r = _printListOfManagedFiles( wallet ) ; }else if( StringsAreEqual( action,"--get-all" ) ){ r = _getAllFilesFromWallet( wallet ) ; }else{ if( argc != 3 ){ _help() ; }else{ path = argv[ 2 ] ; if( StringsAreEqual( action,"--add" ) ){ r = _addFileToWallet( wallet,path ) ; }else if( StringsAreEqual( action,"--delete" ) ){ r = _deleteFileFromWallet( wallet,path ) ; }else if( StringsAreEqual( action,"--get" ) ){ r = _getFileFromWallet( wallet,path ) ; }else if( StringsAreEqual( action,"--add-all" ) ){ r = _addAllFilesToTheWallet( wallet,path ) ; }else{ puts( "unknown command" ) ; r = 1 ; } } } lxqt_wallet_close( &wallet ) ; return r ; } } zuluCrypt-6.2.0/zuluSafe/zuluwallet.c000066400000000000000000001071651425361753700177410ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "zuluwallet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include #pragma GCC diagnostic warning "-Wdeprecated-declarations" #define VERSION 200 #define VERSION_SIZE sizeof( short ) /* * below string MUST BE 11 bytes long */ #define MAGIC_STRING "lxqt_wallet" #define MAGIC_STRING_SIZE 11 #define MAGIC_STRING_BUFFER_SIZE 16 #define PASSWORD_SIZE 32 #define BLOCK_SIZE 16 #define IV_SIZE 16 #define SALT_SIZE 16 #define FILE_BLOCK_SIZE 1024 #define PBKDF2_ITERATIONS 10000 #define NODE_HEADER_SIZE ( 2 * sizeof( u_int32_t ) ) #define WALLET_EXTENSION ".lwt" struct lxqt_wallet_struct{ char * application_name ; char * wallet_name ; char key[ PASSWORD_SIZE ] ; char salt[ SALT_SIZE ] ; char * wallet_data ; u_int64_t wallet_data_size ; u_int64_t wallet_data_entry_count ; int wallet_modified ; }; /* * Encrypted file documentation. * * A newly created file or an empty one takes 64 bytes. * * The first 16 bytes are used for pbkdf2 salt. * This salt is obtained from "/dev/urandom" and will not change when the wallet is updated. * * The second 16 bytes are used to store AES Initialization Vector. * The IV is initially obtained from "/dev/urandom". * The IV is stored unencrypted and will change on every wallet update. * * Everything from 32nd byte onward is store encrypted. * * The third 16 bytes are "magic string" bytes. * The first 11 bytes are used to store a known data aka "magic string" to be used to check if decryption key is correct or not. * The remaining 5 bytes are used to store file version number. * * The fourth 16 bytes are used to store information about the contents of the load. * The first 8 bytes are a u_int64_t data type and are used to store the load size * The second 8 bytes are a u_int64_t data type and are used to store the number of entries in the wallet. * * The load starts at 64th byte. * * The file is encrypted using CBC mode of 256 bit AES and hence may be padded to a file size larger than file contents to * accomodate CBC mode demanding data sizes that are divisible by 16. * * Key-Pair entries are stored as singly linked list nodes in an array. * Interesting video on why traditional linked lists are bad: http://www.youtube.com/watch?v=YQs6IC-vgmo * * A node of a linked list has 4 properties. * First 4 bytes of the node are a u_int32_t data type and are used to store the size of the key. * Second 4 bytes of the node are a u_int32_t data type and used to stores the size of the value. * The 8th byte of the node will be the beginning of the key. * The 8th byte of the node plus the size of the key will be the beginning of the value. * * The sum of the two 4 bytes plus the length of the key plus the length of the value will * point to the next node in the list. * * An empty node takes 8 bytes.A key is not allowed to be empty necessitating it having at least one character * making the minimum allowed size for the node to be 9 bytes. * * The size of the key in the node is managed by a u_int32_t data type. * The size of the value in the node is managed by a u_int32_t data type. * The above two data types means a node can occupy upto 8 bytes + 8 GiB of memory. * */ static void _write( int x,const void * y,size_t z ) { if( write( x,y,z ) ){} } static void _close( int x ) { if( close( x ) ){} } static void _read( int x,void * y,size_t z ) { if( read( x,y,z ) ){} } static char * _wallet_full_path( char * path_buffer,u_int32_t path_buffer_size,const char * wallet_name,const char * application_name ) ; static void _create_application_wallet_path( const char * application_name ) ; static gcry_error_t _create_key( const char salt[ SALT_SIZE ],char output_key[ PASSWORD_SIZE ],const char * input_key,u_int32_t input_key_length ) ; static gcry_error_t _create_temp_key( char * output_key,u_int32_t output_key_size,const char * input_key,u_int32_t input_key_length ) ; static void _get_iv_from_wallet_header( char iv[ IV_SIZE ],int fd ) ; static void _get_salt_from_wallet_header( char salt[ SALT_SIZE ],int fd ) ; static void _get_volume_info( char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ],int fd ) ; static void _get_random_data( char * buffer,size_t buffer_size ) ; static void _create_magic_string_header( char magic_string[ MAGIC_STRING_BUFFER_SIZE ] ) ; static int _wallet_is_compatible( const char * ) ; static int _password_match( const char * buffer ) ; static int _volume_version( const char * buffer ) ; static void _get_load_information( lxqt_wallet_t,const char * buffer ) ; static lxqt_wallet_error _lxqt_wallet_open( const char * password,u_int32_t password_length, const char * wallet_name,const char * application_name,char * buffer, int * ffd,struct lxqt_wallet_struct ** ww,gcry_cipher_hd_t * h ) ; int lxqt_wallet_library_version( void ) { return VERSION ; } char * _lxqt_wallet_get_wallet_data( lxqt_wallet_t wallet ) { if( wallet == NULL ){ return NULL ; }else{ return wallet->wallet_data ; } } static int _failed( gcry_error_t r ) { return r != GPG_ERR_NO_ERROR ; } static int _passed( gcry_error_t r ) { return r == GPG_ERR_NO_ERROR ; } inline static void _get_header_components( u_int32_t * first,u_int32_t * second,const char * str ) { memcpy( first,str,sizeof( u_int32_t ) ) ; memcpy( second,str + sizeof( u_int32_t ),sizeof( u_int32_t ) ) ; } u_int64_t lxqt_wallet_wallet_size( lxqt_wallet_t wallet ) { if( wallet == NULL ){ return 0 ; }else{ return wallet->wallet_data_size ; } } u_int64_t lxqt_wallet_wallet_entry_count( lxqt_wallet_t wallet ) { if( wallet == NULL ){ return 0 ; }else{ return wallet->wallet_data_entry_count ; } } static lxqt_wallet_error _exit_create( lxqt_wallet_error r,gcry_cipher_hd_t handle ) { if( handle != 0 ){ gcry_cipher_close( handle ) ; } return r ; } static lxqt_wallet_error lxqt_wallet_create_1( gcry_cipher_hd_t * h,const char * password, u_int32_t password_length,char * key,char * iv, char * salt ) { gcry_error_t r ; gcry_cipher_hd_t handle ; if( gcry_control( GCRYCTL_INITIALIZATION_FINISHED_P ) == 0 ){ gcry_check_version( NULL ) ; gcry_control( GCRYCTL_INITIALIZATION_FINISHED,0 ) ; } r = gcry_cipher_open( h,GCRY_CIPHER_AES256,GCRY_CIPHER_MODE_CBC,0 ) ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_open_failed ; } handle = *h ; _get_random_data( salt,SALT_SIZE ) ; r = _create_key( salt,key,password,password_length ) ; if( _failed( r ) ){ return lxqt_wallet_failed_to_create_key_hash ; } r = gcry_cipher_setkey( handle,key,PASSWORD_SIZE ) ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_setkey_failed ; } _get_random_data( iv,IV_SIZE ) ; r = gcry_cipher_setiv( handle,iv,IV_SIZE ) ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_setiv_failed ; }else{ return r ; } } lxqt_wallet_error lxqt_wallet_create( const char * password,u_int32_t password_length, const char * wallet_name,const char * application_name ) { int fd ; char path[ PATH_MAX ] ; char iv[ IV_SIZE ] ; char key[ PASSWORD_SIZE ] ; char salt[ SALT_SIZE ] ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] = { '\0' } ; gcry_cipher_hd_t handle = 0 ; gcry_error_t r ; if( password == NULL || wallet_name == NULL || application_name == NULL ){ return _exit_create( lxqt_wallet_invalid_argument,handle ) ; } if( lxqt_wallet_exists( wallet_name,application_name ) == 0 ){ return _exit_create( lxqt_wallet_wallet_exists,handle ) ; } r = lxqt_wallet_create_1( &handle,password,password_length,key,iv,salt ) ; if( _failed( r ) ){ return _exit_create( lxqt_wallet_gcry_cipher_encrypt_failed,handle ) ; }else{ _create_magic_string_header( buffer ) ; r = gcry_cipher_encrypt( handle,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE,NULL,0 ) ; _create_application_wallet_path( application_name ) ; _wallet_full_path( path,PATH_MAX,wallet_name,application_name ) ; fd = open( path,O_WRONLY|O_CREAT,0600 ) ; if( fd == -1 ){ return _exit_create( lxqt_wallet_failed_to_open_file,handle ) ; }else{ /* * first 16 bytes are for PBKDF2 salt */ _write( fd,salt,SALT_SIZE ) ; /* * second 16 bytes are for AES IV */ _write( fd,iv,IV_SIZE ) ; /* * third 16 bytes are for the magic string */ _write( fd,buffer,MAGIC_STRING_BUFFER_SIZE ) ; /* * fourth 16 bytes block that holds information about data load sizes */ _write( fd,buffer + MAGIC_STRING_BUFFER_SIZE,BLOCK_SIZE ) ; _close( fd ) ; return _exit_create( lxqt_wallet_no_error,handle ) ; } } } lxqt_wallet_error lxqt_wallet_create_encrypted_file( const char * password,u_int32_t password_length, const char * source,const char * destination,int(*function)( int,void * ),void * v ) { gcry_error_t r ; int fd_dest ; int fd_src ; char iv[ IV_SIZE ] ; char key[ PASSWORD_SIZE ] ; char salt[ SALT_SIZE ] ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] = { '\0' } ; char file_buffer[ FILE_BLOCK_SIZE ] ; u_int64_t size ; u_int64_t i ; u_int64_t j ; u_int64_t l ; int k ; gcry_cipher_hd_t handle = 0 ; struct stat st ; if( password == NULL || source == NULL || destination == NULL ){ return lxqt_wallet_invalid_argument ; } if( stat( destination,&st ) == 0 ){ return lxqt_wallet_failed_to_open_file ; } r = lxqt_wallet_create_1( &handle,password,password_length,key,iv,salt ) ; if( _failed( r ) ){ return _exit_create( lxqt_wallet_gcry_cipher_encrypt_failed,handle ) ; }else{ fd_dest = open( destination,O_WRONLY|O_CREAT,0600 ) ; if( fd_dest == -1 ){ return _exit_create( lxqt_wallet_failed_to_open_file,handle ) ; } fd_src = open( source,O_RDONLY ) ; if( fd_src == -1 ){ _close( fd_dest ) ; return _exit_create( lxqt_wallet_failed_to_open_file,handle ) ; } /* * first 16 bytes are for PBKDF2 salt */ _write( fd_dest,salt,SALT_SIZE ) ; /* * second 16 bytes are for AES IV */ _write( fd_dest,iv,IV_SIZE ) ; fstat( fd_src,&st ) ; size = (unsigned long)st.st_size ; _create_magic_string_header( buffer ) ; memcpy( buffer + MAGIC_STRING_BUFFER_SIZE,&size,sizeof( u_int64_t ) ) ; gcry_cipher_encrypt( handle,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE,NULL,0 ) ; /* * write third 16 byte and fourth 16 to the header */ _write( fd_dest,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ) ; i = 0 ; j = 0 ; l = 0 ; while( 1 ){ k = (int)read( fd_src,file_buffer,FILE_BLOCK_SIZE ) ; if( k == 0 ){ break ; } r = gcry_cipher_encrypt( handle,file_buffer,FILE_BLOCK_SIZE,NULL,0 ) ; _write( fd_dest,file_buffer,FILE_BLOCK_SIZE ) ; if( k < FILE_BLOCK_SIZE ){ break ; } i += FILE_BLOCK_SIZE ; j = ( i * 100 / size ) ; if( j > l ){ if( function( (int)j,v ) ){ break ; } l = j ; } } function( 100,v ) ; _close( fd_dest ) ; _close( fd_src ) ; return _exit_create( lxqt_wallet_no_error,handle ) ; } } lxqt_wallet_error lxqt_wallet_change_wallet_password( lxqt_wallet_t wallet,const char * new_key,u_int32_t new_key_size ) { char key[ PASSWORD_SIZE ] ; gcry_error_t r ; if( wallet == NULL || new_key == NULL ){ return lxqt_wallet_invalid_argument ; }else{ r = _create_key( wallet->salt,key,new_key,new_key_size ) ; if( _failed( r ) ){ return lxqt_wallet_failed_to_create_key_hash ; }else{ memcpy( wallet->key,key,PASSWORD_SIZE ) ; wallet->wallet_modified = 1 ; return lxqt_wallet_no_error ; } } } static lxqt_wallet_error _exit_open( lxqt_wallet_error st, struct lxqt_wallet_struct * w,gcry_cipher_hd_t handle,int fd ) { if( handle != 0 ){ gcry_cipher_close( handle ) ; } if( fd != -1 ){ _close( fd ) ; } if( w != NULL ){ free( w->wallet_name ) ; free( w->application_name ) ; free( w ) ; } return st ; } static lxqt_wallet_error _lxqt_wallet_open_0( gcry_cipher_hd_t * h,struct lxqt_wallet_struct * w, const char * password,u_int32_t password_length,int fd,char * buffer ) { gcry_error_t r ; gcry_cipher_hd_t handle ; char iv[ IV_SIZE ] ; if( gcry_control( GCRYCTL_INITIALIZATION_FINISHED_P ) == 0 ){ gcry_check_version( NULL ) ; gcry_control( GCRYCTL_INITIALIZATION_FINISHED,0 ) ; } r = gcry_cipher_open( h,GCRY_CIPHER_AES256,GCRY_CIPHER_MODE_CBC,0 ) ; handle = *h ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_open_failed ; } _get_salt_from_wallet_header( w->salt,fd ) ; r = _create_key( w->salt,w->key,password,password_length ) ; if( _failed( r ) ){ return lxqt_wallet_failed_to_create_key_hash ; } r = gcry_cipher_setkey( handle,w->key,PASSWORD_SIZE ) ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_setkey_failed ; } _get_iv_from_wallet_header( iv,fd ) ; r = gcry_cipher_setiv( handle,iv,IV_SIZE ) ; if( _failed( r ) ){ return lxqt_wallet_gcry_cipher_setiv_failed ; }else{ _get_volume_info( buffer,fd ) ; return gcry_cipher_decrypt( handle,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE,NULL,0 ) ; } } lxqt_wallet_error lxqt_wallet_create_decrypted_file( const char * password,u_int32_t password_length, const char * source,const char * destination,int( *function )( int,void * ),void * v ) { gcry_error_t r ; int fd_dest ; int fd_src ; struct stat st ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] = { '\0' } ; char file_buffer[ FILE_BLOCK_SIZE ] ; u_int64_t size ; u_int64_t i ; u_int64_t j ; u_int64_t l ; u_int64_t n ; u_int64_t t ; gcry_cipher_hd_t handle = 0 ; struct lxqt_wallet_struct * w ; if( password == NULL || source == NULL || destination == NULL ){ return lxqt_wallet_invalid_argument ; } if( stat( destination,&st ) == 0 ){ return lxqt_wallet_failed_to_open_file ; } w = malloc( sizeof( struct lxqt_wallet_struct ) ) ; if( w == NULL ){ return _exit_open( lxqt_wallet_failed_to_allocate_memory,NULL,handle,-1 ) ; } memset( w,'\0',sizeof( struct lxqt_wallet_struct ) ) ; fd_src = open( source,O_RDONLY ) ; if( fd_src == -1 ){ return _exit_open( lxqt_wallet_failed_to_open_file,w,handle,-1 ) ; } r = _lxqt_wallet_open_0( &handle,w,password,password_length,fd_src,buffer ) ; if( _failed( r ) ){ _close( fd_src ) ; return _exit_open( lxqt_wallet_failed_to_open_file,w,handle,-1 ) ; } if( _password_match( buffer ) && _wallet_is_compatible( buffer ) ){ fd_dest = open( destination,O_WRONLY|O_CREAT,0600 ) ; if( fd_dest == -1 ){ _close( fd_src ) ; return _exit_open( lxqt_wallet_failed_to_open_file,w,handle,-1 ) ; } _get_load_information( w,buffer ) ; size = w->wallet_data_size ; i = 0 ; j = 0 ; l = 0 ; n = size / FILE_BLOCK_SIZE ; for( t = 0 ; t < n ; t++ ){ _read( fd_src,file_buffer,FILE_BLOCK_SIZE ) ; gcry_cipher_decrypt( handle,file_buffer,FILE_BLOCK_SIZE,NULL,0 ) ; _write( fd_dest,file_buffer,FILE_BLOCK_SIZE ) ; i += FILE_BLOCK_SIZE ; j = ( i * 100 / size ) ; if( j > l ){ if( function( (int)j,v ) ){ break ; } l = j ; } } size = size - i ; if( size > 0 ){ _read( fd_src,file_buffer,FILE_BLOCK_SIZE ) ; gcry_cipher_decrypt( handle,file_buffer,FILE_BLOCK_SIZE,NULL,0 ) ; _write( fd_dest,file_buffer,size ) ; } _close( fd_src ) ; _close( fd_dest ) ; function( 100,v ) ; return _exit_open( lxqt_wallet_no_error,w,handle,-1 ) ; }else{ _close( fd_src ) ; return _exit_open( lxqt_wallet_wrong_password,w,handle,-1 ) ; } } static lxqt_wallet_error _lxqt_wallet_open( const char * password,u_int32_t password_length, const char * wallet_name,const char * application_name,char * buffer, int * ffd,struct lxqt_wallet_struct ** ww,gcry_cipher_hd_t * h ) { gcry_error_t r ; gcry_cipher_hd_t handle = 0 ; char path[ PATH_MAX ] ; int fd ; size_t len ; struct lxqt_wallet_struct * w ; _wallet_full_path( path,PATH_MAX,wallet_name,application_name ) ; fd = open( path,O_RDONLY ) ; if( fd == -1 ){ return _exit_open( lxqt_wallet_failed_to_open_file,NULL,handle,fd ) ; } w = malloc( sizeof( struct lxqt_wallet_struct ) ) ; if( w == NULL ){ return _exit_open( lxqt_wallet_failed_to_allocate_memory,NULL,handle,fd ) ; } memset( w,'\0',sizeof( struct lxqt_wallet_struct ) ) ; len = strlen( wallet_name ) ; w->wallet_name = malloc( sizeof( char ) * ( len + 1 ) ) ; if( w->wallet_name == NULL ){ return _exit_open( lxqt_wallet_failed_to_allocate_memory,w,handle,fd ) ; }else{ memcpy( w->wallet_name,wallet_name,len + 1 ) ; } len = strlen( application_name ) ; w->application_name = malloc( sizeof( char ) * ( len + 1 ) ) ; if( w->application_name == NULL ){ return _exit_open( lxqt_wallet_failed_to_allocate_memory,w,handle,fd ) ; }else{ memcpy( w->application_name,application_name,len + 1 ) ; } r = _lxqt_wallet_open_0( &handle,w,password,password_length,fd,buffer ) ; if( _failed( r ) ){ return _exit_open( lxqt_wallet_gcry_cipher_decrypt_failed,w,handle,fd ) ; }else{ *ww = w ; *ffd = fd ; *h = handle ; return lxqt_wallet_no_error ; } } lxqt_wallet_error lxqt_wallet_open( lxqt_wallet_t * wallet,const char * password,u_int32_t password_length, const char * wallet_name,const char * application_name ) { struct stat st ; u_int64_t len ; char * e ; int fd ; struct lxqt_wallet_struct * w = 0 ; gcry_cipher_hd_t handle = 0 ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] ; gcry_error_t r ; if( wallet_name == NULL || application_name == NULL || wallet == NULL ){ return lxqt_wallet_invalid_argument ; } r = _lxqt_wallet_open( password,password_length,wallet_name,application_name,buffer,&fd,&w,&handle ) ; if( r != lxqt_wallet_no_error ){ return r ; } if( _password_match( buffer ) ){ if( _wallet_is_compatible( buffer ) ){ fstat( fd,&st ) ; len = (unsigned long)st.st_size - ( SALT_SIZE + IV_SIZE + MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ) ; if( len <= 0 ){ /* * empty wallet */ *wallet = w ; return _exit_open( lxqt_wallet_no_error,NULL,handle,fd ) ; }else{ _get_load_information( w,buffer ) ; e = malloc( len ) ; if( e != NULL ){ mlock( e,len ) ; _read( fd,e,len ) ; r = gcry_cipher_decrypt( handle,e,len,NULL,0 ) ; if( _passed( r ) ){ w->wallet_data = e ; *wallet = w ; return _exit_open( lxqt_wallet_no_error,NULL,handle,fd ) ; }else{ free( e ) ; return _exit_open( lxqt_wallet_gcry_cipher_decrypt_failed,w,handle,fd ) ; } }else{ return _exit_open( lxqt_wallet_failed_to_allocate_memory,w,handle,fd ) ; } } }else{ return _exit_open( lxqt_wallet_incompatible_wallet,w,handle,fd ) ; } }else{ return _exit_open( lxqt_wallet_wrong_password,w,handle,fd ) ; } } int lxqt_wallet_volume_version( const char * wallet_name,const char * application_name,const char * password,u_int32_t password_length ) { int fd ; int version ; struct lxqt_wallet_struct * w = 0 ; gcry_cipher_hd_t handle = 0 ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] ; gcry_error_t r ; if( wallet_name == NULL || application_name == NULL ){ return -1 ; }else{ r = _lxqt_wallet_open( password,password_length,wallet_name,application_name,buffer,&fd,&w,&handle ) ; if( r != lxqt_wallet_no_error ){ return -1 ; }else{ if( _password_match( buffer ) ){ version = _volume_version( buffer ) ; _exit_open( lxqt_wallet_no_error,w,handle,fd ) ; return version ; }else{ _exit_open( lxqt_wallet_wrong_password,w,handle,fd ) ; return -1 ; } } } } int lxqt_wallet_read_key_value( lxqt_wallet_t wallet,const char * key,u_int32_t key_size,lxqt_wallet_key_values_t * key_value ) { const char * e ; const char * z ; u_int64_t k = 0 ; u_int64_t i = 0 ; u_int32_t key_len ; u_int32_t key_value_len ; if( key == NULL || wallet == NULL || key_value == NULL ){ }else{ e = wallet->wallet_data ; z = e ; k = wallet->wallet_data_size ; while( i < k ){ _get_header_components( &key_len,&key_value_len,e ) ; if( key_len == key_size && memcmp( key,e + NODE_HEADER_SIZE,key_size ) == 0 ){ key_value->key = e + NODE_HEADER_SIZE ; key_value->key_size = key_len ; key_value->key_value = e + NODE_HEADER_SIZE + key_len ; key_value->key_value_size = key_value_len ; return 1 ; }else{ i = i + NODE_HEADER_SIZE + key_len + key_value_len ; e = z + i ; } } } return 0 ; } int lxqt_wallet_wallet_has_key( lxqt_wallet_t wallet,const char * key,u_int32_t key_size ) { lxqt_wallet_key_values_t key_value ; return lxqt_wallet_read_key_value( wallet,key,key_size,&key_value ) ; } int lxqt_wallet_wallet_has_value( lxqt_wallet_t wallet,const char * value,u_int32_t value_size,lxqt_wallet_key_values_t * key_value ) { const char * e ; const char * z ; u_int64_t k = 0 ; u_int64_t i = 0 ; u_int32_t key_len ; u_int32_t key_value_len ; if( key_value == NULL || wallet == NULL ){ return 0 ; }else{ e = wallet->wallet_data ; z = e ; k = wallet->wallet_data_size ; while( i < k ){ _get_header_components( &key_len,&key_value_len,e ) ; if( key_value_len == value_size && memcmp( value,e + NODE_HEADER_SIZE + key_len,value_size ) == 0 ){ key_value->key = e + NODE_HEADER_SIZE ; key_value->key_size = key_len ; key_value->key_value = e + NODE_HEADER_SIZE + key_len ; key_value->key_value_size = key_value_len ; return 1 ; }else{ i = i + NODE_HEADER_SIZE + key_len + key_value_len ; e = z + i ; } } return 0 ; } } lxqt_wallet_error lxqt_wallet_add_key( lxqt_wallet_t wallet,const char * key,u_int32_t key_size, const char * value,u_int32_t key_value_length ) { char * e ; char * f ; u_int64_t len ; if( key == NULL || wallet == NULL ){ return lxqt_wallet_invalid_argument ; }else{ if( key_size == 0 ){ return lxqt_wallet_invalid_argument ; }else{ if( value == NULL || key_value_length == 0 ){ key_value_length = 0 ; value = "" ; } len = NODE_HEADER_SIZE + key_size + key_value_length ; f = realloc( wallet->wallet_data,wallet->wallet_data_size + len ) ; if( f != NULL ){ mlock( f,wallet->wallet_data_size + len ) ; e = f + wallet->wallet_data_size ; memcpy( e,&key_size,sizeof( u_int32_t ) ) ; memcpy( e + sizeof( u_int32_t ),&key_value_length,sizeof( u_int32_t ) ) ; memcpy( e + NODE_HEADER_SIZE,key,key_size ) ; memcpy( e + NODE_HEADER_SIZE + key_size,value,key_value_length ) ; wallet->wallet_data_size += len ; wallet->wallet_modified = 1 ; wallet->wallet_data = f ; wallet->wallet_data_entry_count++ ; return lxqt_wallet_no_error ; }else{ return lxqt_wallet_failed_to_allocate_memory ; } } } } int lxqt_wallet_iter_read_value( lxqt_wallet_t wallet,lxqt_wallet_iterator_t * iter ) { u_int32_t key_len ; u_int32_t key_value_len ; const char * e ; if( wallet == NULL || iter->iter_pos >= wallet->wallet_data_size ){ return 0 ; }else{ e = wallet->wallet_data + iter->iter_pos ; _get_header_components( &key_len,&key_value_len,e ) ; iter->entry.key = e + NODE_HEADER_SIZE ; iter->entry.key_size = key_len ; iter->entry.key_value = e + NODE_HEADER_SIZE + key_len ; iter->entry.key_value_size = key_value_len ; iter->iter_pos += NODE_HEADER_SIZE + key_len + key_value_len ; return 1 ; } } int lxqt_wallet_read_value_at( lxqt_wallet_t wallet,u_int64_t pos,lxqt_wallet_key_values_t * key_value ) { char * e ; char * z ; u_int64_t k = 0 ; u_int64_t i = 0 ; u_int32_t key_len = 0 ; u_int32_t key_value_len = 0 ; if( wallet == NULL || wallet->wallet_data_entry_count == 0 || pos > wallet->wallet_data_entry_count ){ return 0 ; }else{ e = wallet->wallet_data ; z = e ; while( 1 ){ _get_header_components( &key_len,&key_value_len,e ) ; if( k == pos ){ key_value->key = e + NODE_HEADER_SIZE ; key_value->key_size = key_len ; key_value->key_value = e + NODE_HEADER_SIZE + key_len ; key_value->key_value_size = key_value_len ; break ; }else{ i = i + NODE_HEADER_SIZE + key_len + key_value_len ; e = z + i ; k++ ; } } return 1 ; } } lxqt_wallet_error lxqt_wallet_delete_key( lxqt_wallet_t wallet,const char * key,u_int32_t key_size ) { char * e ; char * z ; u_int64_t k = 0 ; u_int64_t i = 0 ; u_int32_t key_len ; u_int32_t key_value_len ; u_int64_t block_size ; if( key == NULL || wallet == NULL ){ return lxqt_wallet_invalid_argument ; }else{ e = wallet->wallet_data ; z = e ; k = wallet->wallet_data_size ; while( i < k ){ _get_header_components( &key_len,&key_value_len,e ) ; if( key_len == key_size && memcmp( key,e + NODE_HEADER_SIZE,key_size ) == 0 ){ if( wallet->wallet_data_entry_count == 1 ){ memset( wallet->wallet_data,'\0',wallet->wallet_data_size ) ; free( wallet->wallet_data ) ; wallet->wallet_data_size = 0 ; wallet->wallet_modified = 1 ; wallet->wallet_data = NULL ; wallet->wallet_data_entry_count = 0 ; }else{ block_size = NODE_HEADER_SIZE + key_len + key_value_len ; memmove( e,e + block_size,wallet->wallet_data_size - ( i + block_size ) ) ; memset( z + wallet->wallet_data_size - block_size,'\0',block_size ) ; wallet->wallet_data_size -= block_size ; wallet->wallet_modified = 1 ; wallet->wallet_data_entry_count-- ; } break ; }else{ i = i + NODE_HEADER_SIZE + key_len + key_value_len ; e = z + i ; } } } return lxqt_wallet_no_error ; } lxqt_wallet_error lxqt_wallet_delete_wallet( const char * wallet_name,const char * application_name ) { char path[ PATH_MAX ] ; _wallet_full_path( path,PATH_MAX,wallet_name,application_name ) ; unlink( path ) ; return lxqt_wallet_no_error ; } static lxqt_wallet_error _close_exit( lxqt_wallet_error err,lxqt_wallet_t * w,gcry_cipher_hd_t handle ) { lxqt_wallet_t wallet = *w ; *w = NULL ; if( handle != 0 ){ gcry_cipher_close( handle ) ; } if( wallet->wallet_data_size > 0 ){ memset( wallet->wallet_data,'\0',wallet->wallet_data_size ) ; munlock( wallet->wallet_data,wallet->wallet_data_size ) ; free( wallet->wallet_data ) ; } free( wallet->wallet_name ) ; free( wallet->application_name ) ; free( wallet ) ; return err ; } lxqt_wallet_error lxqt_wallet_close( lxqt_wallet_t * w ) { gcry_cipher_hd_t handle ; int fd ; char iv[ IV_SIZE ] ; char path[ PATH_MAX ] ; char path_1[ PATH_MAX + 16 ] ; char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ] ; lxqt_wallet_t wallet ; u_int64_t k ; char * e ; gcry_error_t r ; if( w == NULL || *w == NULL ){ return lxqt_wallet_invalid_argument ; } wallet = *w ; if( wallet->wallet_modified == 0 ){ return _close_exit( lxqt_wallet_no_error,w,0 ) ; } gcry_control( GCRYCTL_INITIALIZATION_FINISHED,0 ) ; r = gcry_cipher_open( &handle,GCRY_CIPHER_AES256,GCRY_CIPHER_MODE_CBC,0 ) ; if( _failed( r ) ){ return _close_exit( lxqt_wallet_gcry_cipher_open_failed,w,0 ) ; } r = gcry_cipher_setkey( handle,wallet->key,PASSWORD_SIZE ) ; if( _failed( r ) ){ return _close_exit( lxqt_wallet_gcry_cipher_setkey_failed,w,handle ) ; } _get_random_data( iv,IV_SIZE ) ; r = gcry_cipher_setiv( handle,iv,IV_SIZE ) ; if( _failed( r ) ){ return _close_exit( lxqt_wallet_gcry_cipher_setiv_failed,w,handle ) ; } _create_magic_string_header( buffer ) ; memcpy( buffer + MAGIC_STRING_BUFFER_SIZE,&wallet->wallet_data_size,sizeof( u_int64_t ) ) ; memcpy( buffer + MAGIC_STRING_BUFFER_SIZE + sizeof( u_int64_t ),&wallet->wallet_data_entry_count,sizeof( u_int64_t ) ) ; r = gcry_cipher_encrypt( handle,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE,NULL,0 ) ; if( _failed( r ) ){ return _close_exit( lxqt_wallet_gcry_cipher_encrypt_failed,w,handle ) ; } _wallet_full_path( path,PATH_MAX,wallet->wallet_name,wallet->application_name ) ; snprintf( path_1,sizeof(path_1),"%s.tmp",path ) ; k = wallet->wallet_data_size ; if( k == 0 ){ fd = open( path_1,O_WRONLY|O_CREAT,0600 ) ; if( fd == -1 ){ return _close_exit( lxqt_wallet_gcry_cipher_open_failed,w,handle ) ; }else{ _write( fd,wallet->salt,SALT_SIZE ) ; _write( fd,iv,IV_SIZE ) ; _write( fd,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ) ; _close( fd ) ; rename( path_1,path ) ; return _close_exit( lxqt_wallet_no_error,w,handle ) ; } }else{ while( k % 32 != 0 ){ k++ ; } e = realloc( wallet->wallet_data,k ) ; if( e != NULL ){ wallet->wallet_data = e ; r = gcry_cipher_encrypt( handle,wallet->wallet_data,k,NULL,0 ) ; if( _failed( r ) ){ return _close_exit( lxqt_wallet_gcry_cipher_encrypt_failed,w,handle ) ; }else{ fd = open( path_1,O_WRONLY|O_CREAT,0600 ) ; if( fd == -1 ){ return _close_exit( lxqt_wallet_gcry_cipher_open_failed,w,handle ) ; }else{ _write( fd,wallet->salt,SALT_SIZE ) ; _write( fd,iv,IV_SIZE ) ; _write( fd,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ) ; _write( fd,wallet->wallet_data,k ) ; _close( fd ) ; rename( path_1,path ) ; return _close_exit( lxqt_wallet_no_error,w,handle ) ; } } }else{ return _close_exit( lxqt_wallet_failed_to_allocate_memory,w,handle ) ; } } } char ** lxqt_wallet_wallet_list( const char * application_name,int * size ) { char path[ PATH_MAX ] ; char ** result = NULL ; char ** result_1 ; char * e ; int count = 0 ; u_int32_t len ; struct dirent * entry ; DIR * dir ; if( application_name == NULL || size == NULL ){ return NULL ; } lxqt_wallet_application_wallet_path( path,PATH_MAX,application_name ) ; dir = opendir( path ) ; if( dir == NULL ){ return NULL ; } while( ( entry = readdir( dir ) ) != NULL ){ if( strcmp( entry->d_name,"." ) == 0 || strcmp( entry->d_name,".." ) == 0 ){ continue ; } len = (u_int32_t)strlen( entry->d_name ) - strlen( WALLET_EXTENSION ) ; if( len > 0 ){ result_1 = realloc( result,sizeof( char * ) * (unsigned long)( count + 1 ) ) ; if( result_1 != NULL ){ e = malloc( len + 1 ) ; if( e!= NULL ){ memcpy( e,entry->d_name,len ) ; *( e + len ) = '\0' ; result_1[ count ] = e ; result = result_1 ; count++ ; } } } } *size = count ; closedir( dir ) ; return result ; } int lxqt_wallet_exists( const char * wallet_name,const char * application_name ) { struct stat st ; char path[ PATH_MAX ] ; if( wallet_name == NULL || application_name == NULL ){ return lxqt_wallet_invalid_argument ; }else{ _wallet_full_path( path,PATH_MAX,wallet_name,application_name ) ; return stat( path,&st ) ; } } void lxqt_wallet_application_wallet_path( char * path,u_int32_t path_buffer_size,const char * application_name ) { struct passwd * pass = getpwuid( getuid() ) ; snprintf( path,path_buffer_size,"%s/.config/lxqt/wallets/%s/",pass->pw_dir,application_name ) ; } static char * _wallet_full_path( char * path_buffer,u_int32_t path_buffer_size,const char * wallet_name,const char * application_name ) { char path_1[ PATH_MAX - 16 ] ; lxqt_wallet_application_wallet_path( path_1,sizeof( path_1 ),application_name ) ; snprintf( path_buffer,path_buffer_size,"%s/%s%s",path_1,wallet_name,WALLET_EXTENSION ) ; return path_buffer ; } static void _create_application_wallet_path( const char * application_name ) { char path[ PATH_MAX ] ; char * e ; lxqt_wallet_application_wallet_path( path,PATH_MAX,application_name ) ; for( e = path + 1 ; *e != '\0' ; e++ ){ if( *e == '/' ){ *e = '\0' ; mkdir( path,0755 ) ; *e = '/' ; } } } static gcry_error_t _create_temp_key( char * output_key,u_int32_t output_key_size,const char * input_key,u_int32_t input_key_length ) { gcry_md_hd_t md ; unsigned char * digest ; gcry_error_t r = gcry_md_open( &md,GCRY_MD_SHA256,GCRY_MD_FLAG_SECURE ) ; if( _passed( r ) ){ gcry_md_write( md,input_key,input_key_length ) ; gcry_md_final( md ) ; digest = gcry_md_read( md,0 ) ; if( digest == NULL ){ r = !GPG_ERR_NO_ERROR ; }else{ memcpy( output_key,digest,output_key_size ) ; } gcry_md_close( md ) ; } return r ; } /* * gcry_kdf_derive() doesnt seem to work with empty passphrases,to work around it,we create a temporary passphrases * based on provided passphrase and then feed the temporary key to gcry_kdf_derive() */ static gcry_error_t _create_key( const char salt[ SALT_SIZE ], char output_key[ PASSWORD_SIZE ],const char * input_key,u_int32_t input_key_length ) { char temp_key[ PASSWORD_SIZE ] ; gcry_error_t r = _create_temp_key( temp_key,PASSWORD_SIZE,input_key,input_key_length ) ; if( _passed( r ) ){ return gcry_kdf_derive( temp_key,PASSWORD_SIZE,GCRY_KDF_PBKDF2,GCRY_MD_SHA256, salt,SALT_SIZE,PBKDF2_ITERATIONS,PASSWORD_SIZE,output_key ) ; }else{ return r ; } } static void _get_iv_from_wallet_header( char iv[ IV_SIZE ],int fd ) { lseek( fd,SALT_SIZE,SEEK_SET ) ; _read( fd,iv,IV_SIZE ) ; } static void _get_salt_from_wallet_header( char salt[ SALT_SIZE ],int fd ) { lseek( fd,0,SEEK_SET ) ; _read( fd,salt,SALT_SIZE ) ; } static void _get_volume_info( char buffer[ MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ],int fd ) { lseek( fd,IV_SIZE + SALT_SIZE,SEEK_SET ) ; _read( fd,buffer,MAGIC_STRING_BUFFER_SIZE + BLOCK_SIZE ) ; } static void _get_load_information( lxqt_wallet_t w,const char * buffer ) { buffer = buffer + MAGIC_STRING_BUFFER_SIZE ; memcpy( &w->wallet_data_size,buffer,sizeof( u_int64_t ) ) ; memcpy( &w->wallet_data_entry_count,buffer + sizeof( u_int64_t ),sizeof( u_int64_t ) ) ; } static void _get_random_data( char * buffer,size_t buffer_size ) { int fd ; fd = open( "/dev/urandom",O_RDONLY ) ; if( fd != -1 ){ _read( fd,buffer,buffer_size ) ; _close( fd ) ; }else{ gcry_create_nonce( buffer,buffer_size ) ; } } static int _password_match( const char * buffer ) { return memcmp( buffer,MAGIC_STRING,MAGIC_STRING_SIZE ) == 0 ; } static void _create_magic_string_header( char magic_string[ MAGIC_STRING_BUFFER_SIZE ] ) { u_int16_t version = VERSION ; /* * write 11 bytes of magic string */ memcpy( magic_string,MAGIC_STRING,MAGIC_STRING_SIZE ) ; /* * write version information in the remaining 5 bytes of the 16 byte buffer */ memcpy( magic_string + MAGIC_STRING_SIZE,&version,sizeof( u_int16_t ) ) ; } static int _wallet_is_compatible( const char * buffer ) { u_int16_t version ; memcpy( &version,buffer + MAGIC_STRING_SIZE,sizeof( u_int16_t ) ) ; /* * This source file should be able to guarantee it can open volumes that have the same major version number */ return version >= VERSION && version < ( VERSION + 100 ) ; } static int _volume_version( const char * buffer ) { u_int16_t version ; memcpy( &version,buffer + MAGIC_STRING_SIZE,sizeof( u_int16_t ) ) ; return ( int )version ; } zuluCrypt-6.2.0/zuluSafe/zuluwallet.h000066400000000000000000000342671425361753700177500ustar00rootroot00000000000000/* * copyright: 2013-2015 * name : Francis Banyikwa * email: mhogomchungu@gmail.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LXQTWALLET_H #define LXQTWALLET_H #ifdef __cplusplus extern "C" { #endif #include /* * NOTE: For documentation on how to use this API,look at the end of this header file. * * NOTE: This API takes anything of any size,most arguments takes "char *" or "const char *" for convenience * since most typical use case will be storage of strings and these argument types will aleviate this use case * from casting if the API was using "void *" or "const void *" as some would expect. */ typedef struct lxqt_wallet_struct * lxqt_wallet_t ; /* * error values */ typedef enum{ lxqt_wallet_no_error = 0, lxqt_wallet_wrong_password, lxqt_wallet_wallet_exists, lxqt_wallet_gcry_cipher_open_failed, lxqt_wallet_gcry_cipher_setkey_failed, lxqt_wallet_gcry_cipher_setiv_failed, lxqt_wallet_gcry_cipher_encrypt_failed, lxqt_wallet_gcry_cipher_decrypt_failed, lxqt_wallet_failed_to_open_file, lxqt_wallet_failed_to_allocate_memory, lxqt_wallet_invalid_argument, lxqt_wallet_incompatible_wallet, lxqt_wallet_failed_to_create_key_hash, lxqt_wallet_libgcrypt_version_mismatch }lxqt_wallet_error; /* * key can not be NULL, * a NULL value or a non NULL value of size 0 will be taken as an empty value. */ lxqt_wallet_error lxqt_wallet_add_key( lxqt_wallet_t,const char * key,u_int32_t key_size,const char * key_value,u_int32_t key_value_length ) ; /* * open "wallet_name" wallet of application "application_name" using a password of size password_length. * * The rest of the API except lxqt_wallet_create() are undefined if this function returns a non zero number */ lxqt_wallet_error lxqt_wallet_open( lxqt_wallet_t *,const char * password,u_int32_t password_length, const char * wallet_name,const char * application_name ) ; /* * create a new wallet named "wallet_name" owned by application "application_name" using a password "password" of size "password_length". */ lxqt_wallet_error lxqt_wallet_create( const char * password,u_int32_t password_length,const char * wallet_name,const char * application_name ) ; /* * give a list of all wallets that belong to a program * Returned value is a NULL terminated array of strings with names of program wallets. * size argument will contain the number of wallets managed by the program * The caller of this function is expected to free() the returned value. * The caller of this function is expected to free() all individual entries in the returned array */ char ** lxqt_wallet_wallet_list( const char * application_name,int * size ) ; /* * return the version of the library used to create the volume. * -1 is returned on error */ int lxqt_wallet_volume_version( const char * wallet_name,const char * application_name,const char * password,u_int32_t password_length ) ; /* * return the version of this library. * return value will be something like 200 for version 2.0.0 */ int lxqt_wallet_library_version( void ) ; /* * delete a key. */ lxqt_wallet_error lxqt_wallet_delete_key( lxqt_wallet_t,const char * key,u_int32_t key_size ) ; /* * delete a wallet named "wallet_name" of an application named "application_name" exists */ lxqt_wallet_error lxqt_wallet_delete_wallet( const char * wallet_name,const char * application_name ) ; /* * close a wallet handle. */ lxqt_wallet_error lxqt_wallet_close( lxqt_wallet_t * ) ; /* * Check if a wallet named "wallet_name" of an application named "application_name" exists * returns 0 if the wallet exist */ int lxqt_wallet_exists( const char * wallet_name,const char * application_name ) ; /* * returns a path to where the wallet file is stored. * on return path_buffer will contain something like "/home/$USER/.local/application_name/wallets" */ void lxqt_wallet_application_wallet_path( char * path_buffer,u_int32_t path_buffer_size,const char * application_name ) ; /* * returns the amount of memory managed data consumes. */ u_int64_t lxqt_wallet_wallet_size( lxqt_wallet_t ) ; /* * returns the number of elements in the wallet */ u_int64_t lxqt_wallet_wallet_entry_count( lxqt_wallet_t ) ; typedef struct{ const char * key ; u_int32_t key_size ; const char * key_value ; u_int32_t key_value_size ; }lxqt_wallet_key_values_t ; typedef struct{ u_int64_t iter_pos ; lxqt_wallet_key_values_t entry ; }lxqt_wallet_iterator_t ; /* * iterate over the internal data structure and return an entry at the current interator position. * Any operation that modifies the internal data structure invalidates the iterator. * * 0 is returned when the end of the list is reached or on error * 1 is returned otherwise and the info at the current iterator position is returned through the "lxqt_wallet_key_values_t" * structure in the iterator. * * Loot at the example at the end of this header file to see how to use this function. */ int lxqt_wallet_iter_read_value( lxqt_wallet_t,lxqt_wallet_iterator_t * ) ; /* * 1 is returned if a matching key was found and key_value structure was filled up. * 0 is returned if a matching key was not found. * Content of the key_value returned are undefined after an entry is added or removed from the list */ int lxqt_wallet_read_key_value( lxqt_wallet_t,const char * key,u_int32_t key_size,lxqt_wallet_key_values_t * key_value ) ; /* * returns 1 if a wallet has a key and 0 otherwise */ int lxqt_wallet_wallet_has_key( lxqt_wallet_t,const char * key,u_int32_t key_size ) ; /* * returns 1 if value was found in one of the entries. * returns 0 otherwise. * If an entry is found,key_value argument will be filled up * Content of the key_value returned are undefined after an entry is added or removed from the list */ int lxqt_wallet_wallet_has_value( lxqt_wallet_t,const char * value,u_int32_t value_size,lxqt_wallet_key_values_t * key_value ) ; /* * change the wallet password */ lxqt_wallet_error lxqt_wallet_change_wallet_password( lxqt_wallet_t,const char * new_password,u_int32_t new_password_size ) ; /* * get a file given by argument "source" and create an encrypted version of the file given by argument "destination" using * a password "password" of length "password_length" * * function is an argument pointer to a function that takes an interger and returns an integer.The input argument will * show progress in percentage.If the return value of the function is non zero,the process will terminate. */ lxqt_wallet_error lxqt_wallet_create_encrypted_file( const char * password,u_int32_t password_length, const char * source,const char * destination,int( *function )( int,void * ),void * ) ; /* * get an encrypted file given by argument "source" and create an un encrypted version of the file given by argument "destination" using * a password "password" of length "password_length" * * function is an argument pointer to a function that takes an interger and returns an integer.The input argument will * show progress in percentage.If the return value of the function is non zero,the process will terminate. */ lxqt_wallet_error lxqt_wallet_create_decrypted_file( const char * password,u_int32_t password_length, const char * source,const char * destination,int( *function )( int,void * ),void * ) ; /* * undocumented API */ char * _lxqt_wallet_get_wallet_data( lxqt_wallet_t wallet ) ; /* * below is a complete program that tests the library functionality,it may be useful as a * source of how the use the API */ #if 0 #include "lxqtwallet.h" #include #include #include /* * This source file shows how the library can be used */ static const char * wallet_name = "wallet_name" ; static const char * application_name = "application_name" ; #define stringsAreEqual( x,y ) strcmp( x,y ) == 0 int main( int argc,char * argv[] ) { lxqt_wallet_t wallet ; lxqt_wallet_error r = lxqt_wallet_no_error ; const char * f ; const char * z ; const char * command ; char ** p ; lxqt_wallet_key_values_t value ; lxqt_wallet_iterator_t iter ; int a ; int b ; if( argc < 2 ){ printf( "wrong number of arguments\n" ) ; return lxqt_wallet_invalid_argument ; } command = argv[ 1 ] ; if( stringsAreEqual( command,"create" ) ){ /* * create a new wallet * additional arguments: password * eg ./wallet create xxx */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_create( f,strlen( f ),wallet_name,application_name ) ; } }else if( stringsAreEqual( command,"add" ) ){ /* * add an entry to the wallet * additional arguments: password key key_value * eg ./wallet add xxx alicia abc */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r != lxqt_wallet_no_error ){ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occured" ) ; } }else{ f = argv[ 3 ] ; z = argv[ 4 ] ; r = lxqt_wallet_add_key( wallet,f,strlen( f ) + 1,z,strlen( z ) + 1 ) ; lxqt_wallet_close( &wallet ) ; } }else if( stringsAreEqual( command,"read" ) ){ /* * read an value in a wallet through its key * additional arguments: password key key_value * eg ./wallet read xxx alicia */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r != lxqt_wallet_no_error ){ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occured" ) ; } }else{ f = argv[ 3 ] ; if( lxqt_wallet_read_key_value( wallet,f,strlen( f ) + 1,&value ) ){ printf( "key=%s:value=%s\n",value.key,value.key_value ) ; }else{ printf( "key=%s:value=(NULL)\n",f ) ; } lxqt_wallet_close( &wallet ) ; } }else if( stringsAreEqual( command,"print" ) ){ /* * print all entries in the wallet * additional arguments: password * eg ./wallet print xxx */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r == lxqt_wallet_no_error ){ iter.iter_pos = 0 ; while( lxqt_wallet_iter_read_value( wallet,&iter ) ){ printf( "key=%s\tkey value=\"%s\"\n",iter.entry.key,iter.entry.key_value ) ; } lxqt_wallet_close( &wallet ) ; }else{ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occured" ) ; } } }else if( stringsAreEqual( command,"delete" ) ){ /* * delete a key from a wallet * additional arguments: password key * eg ./wallet delete xxx alicia */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r == lxqt_wallet_no_error ){ f = argv[ 3 ] ; r = lxqt_wallet_delete_key( wallet,f,strlen( f ) + 1 ) ; lxqt_wallet_close( &wallet ) ; }else{ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occured" ) ; } } }else if( stringsAreEqual( command,"change" ) ){ /* * replace wallet key * additional arguments: old_password new_password * eg ./wallet replace xxx zzz */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r == lxqt_wallet_no_error ){ f = argv[ 3 ] ; r = lxqt_wallet_change_wallet_password( wallet,f,strlen( f ) ) ; lxqt_wallet_close( &wallet ) ; }else{ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occured" ) ; } } }else if( stringsAreEqual( command,"value" ) ){ /* * returns a key with a particular value * additional arguments: password value * eg ./wallet value xxx zzz */ if( argc < 3 ){ r = lxqt_wallet_invalid_argument ; }else{ f = argv[ 2 ] ; r = lxqt_wallet_open( &wallet,f,strlen( f ),wallet_name,application_name ) ; } if( r == lxqt_wallet_no_error ){ f = argv[ 3 ] ; if( lxqt_wallet_wallet_has_value( wallet,f,strlen( f ) + 1,&value ) ){ printf( "key=\"%s\"\nkey size=%d\n",value.key,value.key_size ) ; }else{ printf( "key=\"\"\n" ) ; } lxqt_wallet_close( &wallet ) ; }else{ if( r == lxqt_wallet_wrong_password ){ puts( "wrong password" ) ; }else{ puts( "general error has occured" ) ; } } }else if( stringsAreEqual( command,"version" ) ){ /* * return the version of the library used to create the volume * additional argument: password * example ./wallet version zzz */ if( argc < 3 ){ printf( "wrong number of arguments\n" ) ; }else{ f = argv[ 2 ] ; printf( "%d\n",lxqt_wallet_volume_version( wallet_name,application_name,f,strlen( f ) ) ) ; } }else{ puts( "unknown option" ) ; } return r ; } #endif #ifdef __cplusplus } #endif #endif