#include "androidkeystore_p.h" #if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) #include "private/qjni_p.h" #endif #include using namespace QKeychain; using namespace android::content; using namespace android::security; using namespace java::io; using namespace java::lang; using namespace java::math; using namespace java::util; using namespace java::security; using namespace java::security::spec; using namespace javax::crypto; using namespace javax::security::auth::x500; using namespace javax::security::cert; const BigInteger BigInteger::ONE = BigInteger::getStaticObjectField("java/math/BigInteger", "ONE", "Ljava/math/BigInteger;"); const int Calendar::YEAR = Calendar::getStaticField("java/util/Calendar", "YEAR"); const int Cipher::DECRYPT_MODE = Cipher::getStaticField("javax/crypto/Cipher", "DECRYPT_MODE"); const int Cipher::ENCRYPT_MODE = Cipher::getStaticField("javax/crypto/Cipher", "ENCRYPT_MODE"); namespace { #if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) struct JNIObject { JNIObject(QSharedPointer d): d(d) {} static JNIObject fromLocalRef(jobject o) { return JNIObject(QSharedPointer::create(QJNIObjectPrivate::fromLocalRef(o))); } jobject object() const { return d->object(); } QSharedPointer d; }; #else using JNIObject = QAndroidJniObject; #endif QByteArray fromArray(const jbyteArray array) { QAndroidJniEnvironment env; jbyte *const bytes = env->GetByteArrayElements(array, Q_NULLPTR); const QByteArray result(reinterpret_cast(bytes), env->GetArrayLength(array)); env->ReleaseByteArrayElements(array, bytes, JNI_ABORT); return result; } JNIObject toArray(const QByteArray &bytes) { QAndroidJniEnvironment env; const int length = bytes.length(); JNIObject array = JNIObject::fromLocalRef(env->NewByteArray(length)); env->SetByteArrayRegion(static_cast(array.object()), 0, length, reinterpret_cast(bytes.constData())); return array; } } bool Object::handleExceptions() { QAndroidJniEnvironment env; if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); return false; } return true; } KeyPairGenerator KeyPairGenerator::getInstance(const QString &algorithm, const QString &provider) { return handleExceptions(callStaticObjectMethod("java/security/KeyPairGenerator", "getInstance", "(Ljava/lang/String;Ljava/lang/String;)Ljava/security/KeyPairGenerator;", fromString(algorithm).object(), fromString(provider).object())); } KeyPair KeyPairGenerator::generateKeyPair() const { return handleExceptions(callObjectMethod("generateKeyPair", "()Ljava/security/KeyPair;")); } bool KeyPairGenerator::initialize(const AlgorithmParameterSpec &spec) const { callMethod("initialize", "(Ljava/security/spec/AlgorithmParameterSpec;)V", spec.object()); return handleExceptions(); } bool KeyStore::containsAlias(const QString &alias) const { return handleExceptions(callMethod("containsAlias", "(Ljava/lang/String;)Z", fromString(alias).object())); } bool KeyStore::deleteEntry(const QString &alias) const { callMethod("deleteEntry", "(Ljava/lang/String;)Z", fromString(alias).object()); return handleExceptions(); } KeyStore KeyStore::getInstance(const QString &type) { return handleExceptions(callStaticObjectMethod("java/security/KeyStore", "getInstance", "(Ljava/lang/String;)Ljava/security/KeyStore;", fromString(type).object())); } KeyStore::Entry KeyStore::getEntry(const QString &alias, const KeyStore::ProtectionParameter ¶m) const { return handleExceptions(callObjectMethod("getEntry", "(Ljava/lang/String;Ljava/security/KeyStore$ProtectionParameter;)Ljava/security/KeyStore$Entry;", fromString(alias).object(), param.object())); } bool KeyStore::load(const KeyStore::LoadStoreParameter ¶m) const { callMethod("load", "(Ljava/security/KeyStore$LoadStoreParameter;)V", param.object()); return handleExceptions(); } Calendar Calendar::getInstance() { return handleExceptions(callStaticObjectMethod("java/util/Calendar", "getInstance", "()Ljava/util/Calendar;")); } bool Calendar::add(int field, int amount) const { callMethod("add", "(II)V", field, amount); return handleExceptions(); } Date Calendar::getTime() const { return handleExceptions(callObjectMethod("getTime", "()Ljava/util/Date;")); } KeyPairGeneratorSpec::Builder::Builder(const Context &context) : Object(QAndroidJniObject("android/security/KeyPairGeneratorSpec$Builder", "(Landroid/content/Context;)V", context.object())) { handleExceptions(); } KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setAlias(const QString &alias) const { return handleExceptions(callObjectMethod("setAlias", "(Ljava/lang/String;)Landroid/security/KeyPairGeneratorSpec$Builder;", fromString(alias).object())); } KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setSubject(const X500Principal &subject) const { return handleExceptions(callObjectMethod("setSubject", "(Ljavax/security/auth/x500/X500Principal;)Landroid/security/KeyPairGeneratorSpec$Builder;", subject.object())); } KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setSerialNumber(const BigInteger &serial) const { return handleExceptions(callObjectMethod("setSerialNumber", "(Ljava/math/BigInteger;)Landroid/security/KeyPairGeneratorSpec$Builder;", serial.object())); } KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setStartDate(const Date &date) const { return handleExceptions(callObjectMethod("setStartDate", "(Ljava/util/Date;)Landroid/security/KeyPairGeneratorSpec$Builder;", date.object())); } KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setEndDate(const Date &date) const { return handleExceptions(callObjectMethod("setEndDate", "(Ljava/util/Date;)Landroid/security/KeyPairGeneratorSpec$Builder;", date.object())); } KeyPairGeneratorSpec KeyPairGeneratorSpec::Builder::build() const { return handleExceptions(callObjectMethod("build", "()Landroid/security/KeyPairGeneratorSpec;")); } X500Principal::X500Principal(const QString &name) : Object(QAndroidJniObject("javax/security/auth/x500/X500Principal", "(Ljava/lang/String;)V", fromString(name).object())) { handleExceptions(); } Certificate KeyStore::PrivateKeyEntry::getCertificate() const { return handleExceptions(callObjectMethod("getCertificate", "()Ljava/security/cert/Certificate;")); } PrivateKey KeyStore::PrivateKeyEntry::getPrivateKey() const { return handleExceptions(callObjectMethod("getPrivateKey", "()Ljava/security/PrivateKey;")); } PublicKey Certificate::getPublicKey() const { return handleExceptions(callObjectMethod("getPublicKey", "()Ljava/security/PublicKey;")); } ByteArrayInputStream::ByteArrayInputStream(const QByteArray &bytes) : InputStream(QAndroidJniObject("java/io/ByteArrayInputStream", "([B)V", toArray(bytes).object())) { } ByteArrayOutputStream::ByteArrayOutputStream() : OutputStream(QAndroidJniObject("java/io/ByteArrayOutputStream")) { handleExceptions(); } QByteArray ByteArrayOutputStream::toByteArray() const { const QAndroidJniObject wrapper = callObjectMethod("toByteArray"); if (!handleExceptions()) return QByteArray(); return fromArray(static_cast(wrapper.object())); } int InputStream::read() const { return handleExceptions(callMethod("read"), -1); } bool OutputStream::write(const QByteArray &bytes) const { callMethod("write", "([B)V", toArray(bytes).object()); return handleExceptions(); } bool OutputStream::close() const { callMethod("close"); return handleExceptions(); } bool OutputStream::flush() const { callMethod("flush"); return handleExceptions(); } Cipher Cipher::getInstance(const QString &transformation) { return handleExceptions(callStaticObjectMethod("javax/crypto/Cipher", "getInstance", "(Ljava/lang/String;)Ljavax/crypto/Cipher;", fromString(transformation).object())); } bool Cipher::init(int opMode, const Key &key) const { callMethod("init", "(ILjava/security/Key;)V", opMode, key.object()); return handleExceptions(); } CipherOutputStream::CipherOutputStream(const OutputStream &stream, const Cipher &cipher) : FilterOutputStream(QAndroidJniObject("javax/crypto/CipherOutputStream", "(Ljava/io/OutputStream;Ljavax/crypto/Cipher;)V", stream.object(), cipher.object())) { handleExceptions(); } CipherInputStream::CipherInputStream(const InputStream &stream, const Cipher &cipher) : FilterInputStream(QAndroidJniObject("javax/crypto/CipherInputStream", "(Ljava/io/InputStream;Ljavax/crypto/Cipher;)V", stream.object(), cipher.object())) { handleExceptions(); }