Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QCA on Android



  • Hi
    I need OpenPGP to encrypt password, so I've choosend QCA (Qt Cryptographic Architecture)
    https://github.com/KDE/qca
    On Linux there is no problem, for Android I did cross compiled it with command:

    cmake . -DCMAKE_SYSTEM_NAME=Android -DCMAKE_TOOLCHAIN_FILE=/opt/Android/Ndk/android-ndk-r20/build/cmake/android.toolchain.cmake -DQt5_DIR=/opt/Felgo/Felgo/android_armv7/lib/cmake/Qt5/ -DQt5Core_DIR=/opt/Felgo/Felgo/android_armv7/lib/cmake/Qt5Core/ -DQt5Test_DIR=/opt/Felgo/Felgo/android_armv7/lib/cmake/Qt5Test/ -DQt5Network_DIR=/opt/Felgo/Felgo/android_armv7/lib/cmake/Qt5Network/ -DANDROID_PLATFORM=android-29 -DCMAKE_INSTALL_PREFIX=/usr/local/android -DUSE_RELATIVE_PATHS=ON
    

    Config says the package relocatable

    -- Check for working C compiler: /opt/Android/Ndk/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
    -- Check for working C compiler: /opt/Android/Ndk/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Check for working CXX compiler: /opt/Android/Ndk/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++
    -- Check for working CXX compiler: /opt/Android/Ndk/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    CMake Deprecation Warning at CMakeLists.txt:19 (cmake_policy):
      The OLD behavior for policy CMP0042 will be removed from a future version
      of CMake.
    
      The cmake-policies(7) manual explains that the OLD behaviors of all
      policies are deprecated and that a policy should be set to OLD only under
      specific short-term circumstances.  Projects should be ported to the NEW
      behavior and not rely on setting a policy to OLD.
    
    
    -- Found Doxygen: /usr/bin/doxygen (found version "1.8.13") found components:  doxygen dot 
    -- Installed package is relocatable
    -- Checking for certstore..
    -- Found system certstore
    -- certstore path: /etc/ssl/certs/ca-certificates.crt
    -- Looking for include file sys/filio.h
    -- Looking for include file sys/filio.h - not found
    -- Performing Test MLOCK_TAKES_VOID
    -- Performing Test MLOCK_TAKES_VOID - Success
    -- Found PkgConfig: /usr/bin/pkg-config (found version "0.29") 
    -- Checking for module 'botan-2'
    --   No package 'botan-2' found
    -- Checking for module 'nss'
    --   No package 'nss' found
    -- Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR (missing: OPENSSL_CRYPTO_LIBRARY OPENSSL_INCLUDE_DIR) (Required is at least version "1.1.1")
    -- Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR (missing: OPENSSL_CRYPTO_LIBRARY OPENSSL_INCLUDE_DIR) 
    -- Checking for one of the modules 'libpkcs11-helper-1'
    
    Plugins:
      qca-botan off
      qca-cyrus-sasl off
      qca-gcrypt off
      qca-gnupg on
      qca-logger on
      qca-nss off
      qca-ossl off
      qca-pkcs11 off
      qca-softstore on
    
    QCA prefix is /usr/local/android
    Plugins will be installed to /usr/local/android/lib/qca-qt5
    Binary will be installed to /usr/local/android/bin
    Library will be installed to /usr/local/android/lib
    Public headers will be installed to /usr/local/android/include/Qca-qt5
    Private headers will be installed to /usr/local/android/include/Qca-qt5
    Feature file will be installed to /usr/local/android/mkspecs/features
    Documentation will be installed to /usr/local/android/share/doc/qca-qt5/html
    Man page will be installed to /usr/local/android/share/man
    Pkg-config file will be installed to /usr/local/android/lib/pkgconfig
    
    -- Configuring done
    -- Generating done
    

    I have copied libraries into android/libs/armeabi-v7a/ linking and installing into Android device works fine, there are 3 plugins in crypto directory, visible in android-build directory:

    libqca-gnupg.so
    libqca-logger.so
    libqca-softstore.so
    

    But when app starts is does not support any of these plugins

        QCA::Initializer init;
        if(QCA::isSupported("logger")) {
            qDebug()<<"BackEnd::encrypt logger supported";
        }
        else {
            qDebug()<<"BackEnd::encrypt logger NOT supported";
        }
        if(QCA::isSupported("softstore")) {
            qDebug()<<"BackEnd::encrypt softstore supported";
        }
        else {
            qDebug()<<"BackEnd::encrypt softstore NOT supported";
        }
        if(QCA::isSupported("openpgp")) {
            qDebug()<<"BackEnd::encrypt openpgp supported";
        }
        else {
            qDebug()<<"BackEnd::encrypt openpgp NOT supported, return";
            return;
        }
    

    result is:

    BackEnd::encrypt logger NOT supported
    BackEnd::encrypt softstore NOT supported
    BackEnd::encrypt openpgp NOT supported, return
    

    Can someone give me some hint ? What is worying me is this sentence from QCA changes list

     - qca-gnupg: try both gpg and gpg2 to find gnupg executable
    

    if it is using command from OS then it will not work on Android ?

    Best Regards
    Marek



  • When I unzip APK file I can see that in lib/armeabi-v7a/ there is file libqca-qt5.so

    file lib/armeabi-v7a/libqca-qt5.so 
    lib/armeabi-v7a/libqca-qt5.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=70b166ed2526bff0c5c8c365f2ef585ec73a6440, stripped
    

    But there is no subdirectory "crypto" or any other that I have placed in android/libs/armeabi-v7a
    How to tell QtCreator to include subdirectories from armeabi-v7a into APK ?

    Best Regards
    Marek


  • Lifetime Qt Champion

    Hi,

    The Androïd deployment process is described here.



  • @SGaist thanks, somehow I can't make it work
    There is some issue with gradle here
    "fileTree() does not import the subdirectory"
    https://github.com/gradle/gradle/issues/2394
    So maybe it is not possible to include subdirectories ?

    Best
    Marek


  • Lifetime Qt Champion

    @Marek said in QCA on Android:

    So maybe it is not possible to include subdirectories ?

    That I do not know sorry.

    It looks like it should be somehow possible. See this git gist.



  • @SGaist It looks like they are creating files instead of directories like this:
    libplugins_crypto_libqca-ossl.so
    So I created mine in the same manner
    libplugins_crypto_libqca-gnupg.so
    But QCA still says OpenPGP is not supported. Maybe it needs some underlying package like gnuPG to work. I have filed bug report to ask for this
    https://bugs.kde.org/show_bug.cgi?id=432142

    Thanks for help
    Marek



  • Hi,

    thanks a lot for asking this question and providing the cmake command.
    For me, the cmake command had been the missing link while trying to resurrect one of my old applications.

    I realize the thread is a bit older but I hope my notes can still be helpful for some.

    Regarding getting the QCA plug-in to work.
    I am not sure if you looked at that already but just in case.

    For debugging QCA, e.g., seeing which plug-ins get loaded etc., I use the following code:

        QCA::scanForPlugins();
        qDebug("QCA Plugin Diagnostics Context: %s", QCA::pluginDiagnosticText().toUtf8().constData());
    
        QStringList capabilities;
        capabilities = QCA::supportedFeatures();
        qDebug("QCA supports: %s", capabilities.join(",").toUtf8().constData());
    

    In my case, the output looks like this (this already uses the second "hack" solution below):

    D MeePasswords: Preparing QCA plug-in...
    D MeePasswords: Initializing QCA...
    D MeePasswords: QCA initialized.
    W qtMainLoopThrea: type=1400 audit(0.0:40594): avc: granted { execute } for path="/data/data/com.ruedigergad.MeePasswords/crypto/libqca-ossl_armeabi-v7a.so" dev="mmcblk0p62" ino=661675 scontext=u:r:untrusted_app_27:s0:c231,c256,c512,c768 tcontext=u:object_r:app_data_file:s0:c231,c256,c512,c768 tclass=file
    D MeePasswords: QCA Plugin Diagnostics Context: Checking Qt static plugins:
    D MeePasswords:   (none)
    D MeePasswords: Checking Qt Library Path: /data/data/com.ruedigergad.MeePasswords
    D MeePasswords:   libqca-ossl_armeabi-v7a.so: (class: opensslPlugin) loaded as qca-ossl
    D MeePasswords: Checking Qt Library Path: /data/app/com.ruedigergad.MeePasswords-e3TV3HWpyXAxUPgO-5Zp7Q==/lib/arm
    D MeePasswords:   (No 'crypto' subdirectory)
    05-09 10:38:51.644 13166 13263 D MeePasswords:
    D MeePasswords: QCA supports: random,md5,sha1,keystorelist,ripemd160,md4,sha224,sha256,sha384,sha512,whirlpool,hmac(md5),hmac(sha1),hmac(sha224),hmac(sha256),hmac(sha384),hmac(sha512),hmac(ripemd160),aes128-ecb,aes128-cfb,aes128-cbc,aes128-cbc-pkcs7,aes128-ofb,aes192-ecb,aes192-cfb,aes192-cbc,aes192-cbc-pkcs7,aes192-ofb,aes256-ecb,aes256-cbc,aes256-cbc-pkcs7,aes256-cfb,aes256-ofb,blowfish-ecb,blowfish-cbc-pkcs7,blowfish-cbc,blowfish-cfb,blowfish-ofb,tripledes-ecb,tripledes-cbc,des-ecb,des-ecb-pkcs7,des-cbc,des-cbc-pkcs7,des-cfb,des-ofb,cast5-ecb,cast5-cbc,cast5-cbc-pkcs7,cast5-cfb,cast5-ofb,pbkdf1(sha1),pbkdf2(sha1),hkdf(sha256),pkey,dlgroup,rsa,dsa,dh,cert,csr,crl,certcollection,pkcs12,tls,cms,ca
    

    At least in my case, getting QCA to load the plug-in I needed, took a bit of effort.
    From what I can tell, the background is as follows:

    • QCA searches dynamically loaded plug-ins as follows:
      • Go through the paths defined in the environment variable QCA_PLUGIN_PATH and QCoreApplication::libraryPaths().
      • For each directory, check if there is a "crypto" sub-directory. The "crypto" name is hard-coded.
      • For all *.so files in */crypto, try to load them as plug-in. (It does some further checks regarding versions etc. but I'll leave that out here.)
    • As you already observed, Qt Android packaging is a bit odd regarding including sub-directories and removing files it does not consider "valid" or so.

    I ended up with two hacks as solution:

    • Include the QCA plug-in as static plug-in.
    • Package the QCA plug-in along with the Android libraries and at application startup, create the "crypto" sub-directory, copy the QCA plug-in there, and add the parent directory of "crypto" to the QCoreApplication library path.

    The first hack, statically linked plug-in, worked roughly as follows:

    // Include plug-in statically in main.cpp
    #ifdef ANDROID
    #include <QtPlugin>
    Q_IMPORT_PLUGIN(opensslPlugin)
    #endif
    
    # Add dynamic & static linking in project file
        LIBS += \
            -L$$PWD/lib/qt5/build/android/android-24/qca \
            -l:libqca-qt5_armeabi-v7a.so \
            -L$$PWD/lib/qt5/build/android/android-24/qca/qca-qt5/crypto \
            -l:libqca-ossl.a \
            -L$$PWD/lib/qt5/build/android/android-24/openssl \
            -l:libcrypto.so \
            -l:libssl.so
    

    As you see my quick hack uses a mix of dynamic linking (for QCA and OpenSSL libs) and static linking (for the ossl QCA plug-in).

    The alternative hack, copying the file etc., looks as follows:

        qDebug("Preparing QCA plug-in...");
        QDir dir("../");
        dir.mkdir("crypto");
        QFile::copy("../lib/libqca-ossl_armeabi-v7a.so", "../crypto/libqca-ossl_armeabi-v7a.so");
        QCoreApplication::addLibraryPath("../");
    

    Overall, both approaches are somewhat "hackish" but I couldn't spend more time on this and at least it got me unblocked.

    Just in case, the project, for which I use this is: https://github.com/ruedigergad/meepasswords
    There I also have some more notes and pre-compiled builds of OpenSSL and QCA.

    Cheers,

    Ruediger


Log in to reply