[vlc-devel] [PATCH 09/13] memory_file: encrypt/decrypt password via AndroidKeyStore

Thomas Guillem thomas at gllm.fr
Wed Feb 24 14:25:18 CET 2016


This works only on Android M, the used cipher is AES/CBC/PKCS7Padding, the IV
(Initialisation Vector) is generated by Android, and the key is stored by
Android.
---
 modules/keystore/Makefile.am      |   3 +
 modules/keystore/memory-android.c | 620 ++++++++++++++++++++++++++++++++++++++
 modules/keystore/memory-crypt.h   |   7 +-
 3 files changed, 624 insertions(+), 6 deletions(-)
 create mode 100644 modules/keystore/memory-android.c

diff --git a/modules/keystore/Makefile.am b/modules/keystore/Makefile.am
index 99eed83..9c09d91 100644
--- a/modules/keystore/Makefile.am
+++ b/modules/keystore/Makefile.am
@@ -2,6 +2,9 @@ keystoredir = $(pluginsdir)/keystore
 
 libmemory_file_keystore_plugin_la_SOURCES = keystore/memory-file.c
 	keystore/memory-crypt.h
+if HAVE_ANDROID
+libmemory_file_keystore_plugin_la_SOURCES += keystore/memory-android.c
+endif
 keystore_LTLIBRARIES = libmemory_file_keystore_plugin.la
 
 libsecret_plugin_la_SOURCES = keystore/secret.c
diff --git a/modules/keystore/memory-android.c b/modules/keystore/memory-android.c
new file mode 100644
index 0000000..cabfd66
--- /dev/null
+++ b/modules/keystore/memory-android.c
@@ -0,0 +1,620 @@
+/*****************************************************************************
+ * memory-android.c: Crypt using AndroidKeyStore
+ *****************************************************************************
+ * Copyright © 2016 VLC authors, VideoLAN and VideoLabs
+ *
+ * This program 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.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <vlc_common.h>
+#include <vlc_memory.h>
+#include <vlc_keystore.h>
+
+#include "memory-crypt.h"
+
+#include <jni.h>
+
+JNIEnv * android_getEnv(vlc_object_t *, const char *);
+#define GET_ENV() android_getEnv(VLC_OBJECT(p_keystore), "android keystore")
+
+static struct
+{
+    struct
+    {
+        jmethodID toString;
+    } Object;
+    struct
+    {
+        jclass clazz;
+        jmethodID getInstance;
+        jmethodID load;
+        jmethodID getEntry;
+        struct
+        {
+            jmethodID getSecretKey;
+        } SecretKeyEntry;
+    } KeyStore;
+    struct
+    {
+        jint PURPOSE_ENCRYPT;
+        jint PURPOSE_DECRYPT;
+        jstring BLOCK_MODE_CBC;
+        jstring ENCRYPTION_PADDING_PKCS7;
+        jstring KEY_ALGORITHM_AES;
+    } KeyProperties;
+    struct
+    {
+        jclass clazz;
+        jmethodID getInstance;
+        jmethodID init;
+        jmethodID generateKey;
+    } KeyGenerator;
+    struct
+    {
+        struct
+        {
+            jclass clazz;
+            jmethodID ctor;
+            jmethodID setKeySize;
+            jmethodID setBlockModes;
+            jmethodID setEncryptionPaddings;
+            jmethodID build;
+        } Builder;
+    } KeyGenParameterSpec;
+    struct
+    {
+        jclass clazz;
+        jmethodID ctor;
+    } IvParameterSpec;
+    struct
+    {
+        jclass clazz;
+        jmethodID getInstance;
+        jmethodID init;
+        jmethodID doFinal;
+        jmethodID getIV;
+        jint ENCRYPT_MODE;
+        jint DECRYPT_MODE;
+    } Cipher;
+    jstring VLC_CIPHER;
+} fields;
+static jobject s_jkey = NULL;
+
+#define CALL(caller, obj, method, ...) \
+    (*p_env)->caller(p_env, obj, fields.method, ##__VA_ARGS__)
+
+#define CALL_VOID(obj, method, ...) \
+    CALL(CallVoidMethod, obj, method, ##__VA_ARGS__)
+
+#define CALL_OBJ(obj, method, ...) \
+    CALL(CallObjectMethod, obj, method, ##__VA_ARGS__)
+
+#define CALL_STATICOBJ(obj, method, ...) \
+    CALL(CallStaticObjectMethod, fields.obj.clazz, method, ##__VA_ARGS__)
+
+#define CALL_INT(obj, method, ...) \
+    CALL(CallIntMethod, obj, method, ##__VA_ARGS__)
+
+#define CALL_BOOL(obj, method, ...) \
+    CALL(CallBooleanMethod, obj, method, ##__VA_ARGS__)
+
+#define NEW_OBJECT(arg, ...) \
+    (*p_env)->NewObject(p_env, fields.arg.clazz, fields.arg.ctor, ##__VA_ARGS__)
+
+#define NEW_GREF(obj) \
+    (*p_env)->NewGlobalRef(p_env, obj)
+
+#define DEL_GREF(obj) \
+    (*p_env)->DeleteGlobalRef(p_env, obj)
+
+#define DEL_LREF(obj) \
+    (*p_env)->DeleteLocalRef(p_env, obj)
+
+#define NEW_STR(str) \
+    (*p_env)->NewStringUTF(p_env, str)
+
+static bool
+check_expection(vlc_keystore *p_keystore, JNIEnv *p_env)
+{
+    jthrowable jex = (*p_env)->ExceptionOccurred(p_env);
+    if (jex != NULL)
+    {
+        (*p_env)->ExceptionClear(p_env);
+        if (fields.Object.toString != NULL)
+        {
+            const char *psz_str = NULL;
+            jstring jstr = NULL;
+
+            jstr = (jstring) CALL_OBJ(jex, Object.toString);
+            if (jstr != NULL)
+                psz_str = (*p_env)->GetStringUTFChars(p_env, jstr, NULL);
+            if (psz_str != NULL)
+            {
+                msg_Err(p_keystore, "%s", psz_str);
+                (*p_env)->ReleaseStringUTFChars(p_env, jstr, psz_str);
+            }
+            DEL_LREF(jstr);
+        }
+        else
+            msg_Err(p_keystore, "unknown exception");
+        DEL_LREF(jex);
+        return true;
+    }
+    return false;
+}
+#define CHECK_EXCEPTION() check_expection(p_keystore, p_env)
+
+#define GET_CLASS(str) do { \
+    if (clazz != NULL) \
+        DEL_LREF(clazz); \
+    clazz = (*p_env)->FindClass(p_env, (str)); \
+    if (CHECK_EXCEPTION()) \
+        return VLC_EGENERIC; \
+} while (0)
+#define GET_GLOBAL_CLASS(id) do { \
+    fields.id.clazz = (jclass) NEW_GREF(clazz); \
+} while (0)
+#define GET_ID(get, id, str, args) do { \
+    fields.id = (*p_env)->get(p_env, clazz, (str), (args)); \
+    if (CHECK_EXCEPTION()) \
+        return VLC_EGENERIC; \
+} while (0)
+#define GET_CONST_INT(id, str) do { \
+    jfieldID field = (*p_env)->GetStaticFieldID(p_env, clazz, (str), "I"); \
+    if (!CHECK_EXCEPTION()) \
+    { \
+        fields.id = (*p_env)->GetStaticIntField(p_env, clazz, field); \
+        if (CHECK_EXCEPTION()) \
+            return VLC_EGENERIC; \
+    } else { \
+        return VLC_EGENERIC; \
+    } \
+} while(0)
+#define GET_CONST_OBJ(id, str, type) do { \
+    jfieldID field = (*p_env)->GetStaticFieldID(p_env, clazz, (str), type); \
+    if (!CHECK_EXCEPTION()) \
+    { \
+        jobject jobj = (*p_env)->GetStaticObjectField(p_env, clazz, field); \
+        if (CHECK_EXCEPTION()) \
+            return VLC_EGENERIC; \
+        fields.id = NEW_GREF(jobj); \
+        DEL_LREF(jobj); \
+    } else { \
+        return VLC_EGENERIC; \
+    } \
+} while(0)
+
+/*
+ * Init JNI fields that will be used to fetch the key and crypt/encrypt
+ */
+static int
+InitJni(vlc_keystore *p_keystore, JNIEnv *p_env)
+{
+    jclass clazz = NULL;
+
+    GET_CLASS("java/lang/Object");
+    GET_ID(GetMethodID, Object.toString, "toString", "()Ljava/lang/String;");
+
+    GET_CLASS("java/security/KeyStore");
+    GET_GLOBAL_CLASS(KeyStore);
+    GET_ID(GetStaticMethodID, KeyStore.getInstance, "getInstance",
+           "(Ljava/lang/String;)Ljava/security/KeyStore;");
+    GET_ID(GetMethodID, KeyStore.load, "load",
+           "(Ljava/security/KeyStore$LoadStoreParameter;)V");
+    GET_ID(GetMethodID, KeyStore.getEntry, "getEntry",
+           "(Ljava/lang/String;Ljava/security/KeyStore$ProtectionParameter;)"
+           "Ljava/security/KeyStore$Entry;");
+
+    GET_CLASS("java/security/KeyStore$SecretKeyEntry");
+    GET_ID(GetMethodID, KeyStore.SecretKeyEntry.getSecretKey, "getSecretKey",
+           "()Ljavax/crypto/SecretKey;");
+
+
+    GET_CLASS("javax/crypto/spec/IvParameterSpec");
+    GET_GLOBAL_CLASS(IvParameterSpec);
+    GET_ID(GetMethodID, IvParameterSpec.ctor, "<init>", "([B)V");
+
+    GET_CLASS("javax/crypto/Cipher");
+    GET_GLOBAL_CLASS(Cipher);
+    GET_ID(GetStaticMethodID, Cipher.getInstance, "getInstance",
+           "(Ljava/lang/String;)Ljavax/crypto/Cipher;");
+    GET_ID(GetMethodID, Cipher.init, "init",
+           "(ILjava/security/Key;Ljava/security/spec/AlgorithmParameterSpec;)V");
+    GET_ID(GetMethodID, Cipher.doFinal, "doFinal", "([B)[B");
+    GET_ID(GetMethodID, Cipher.getIV, "getIV", "()[B");
+    GET_CONST_INT(Cipher.ENCRYPT_MODE, "ENCRYPT_MODE");
+    GET_CONST_INT(Cipher.DECRYPT_MODE, "DECRYPT_MODE");
+
+    DEL_LREF(clazz);
+
+    jstring VLC_CIPHER = NEW_STR("AES/CBC/PKCS7Padding");
+    if (CHECK_EXCEPTION())
+        return VLC_EGENERIC;
+    fields.VLC_CIPHER = NEW_GREF(VLC_CIPHER);
+    DEL_LREF(VLC_CIPHER);
+
+    return VLC_SUCCESS;
+}
+
+/*
+ * Init JNI fields that will be used by generateKey()
+ */
+static int
+InitJniGenKey(vlc_keystore *p_keystore, JNIEnv *p_env)
+{
+    jclass clazz = NULL;
+
+    GET_CLASS("android/security/keystore/KeyProperties");
+    GET_CONST_INT(KeyProperties.PURPOSE_ENCRYPT, "PURPOSE_ENCRYPT");
+    GET_CONST_INT(KeyProperties.PURPOSE_DECRYPT, "PURPOSE_DECRYPT");
+    GET_CONST_OBJ(KeyProperties.BLOCK_MODE_CBC,
+                  "BLOCK_MODE_CBC", "Ljava/lang/String;");
+    GET_CONST_OBJ(KeyProperties.ENCRYPTION_PADDING_PKCS7,
+                  "ENCRYPTION_PADDING_PKCS7", "Ljava/lang/String;");
+    GET_CONST_OBJ(KeyProperties.KEY_ALGORITHM_AES,
+                  "KEY_ALGORITHM_AES", "Ljava/lang/String;");
+
+    GET_CLASS("android/security/keystore/KeyGenParameterSpec$Builder");
+    GET_GLOBAL_CLASS(KeyGenParameterSpec.Builder);
+    GET_ID(GetMethodID, KeyGenParameterSpec.Builder.ctor, "<init>",
+           "(Ljava/lang/String;I)V");
+    GET_ID(GetMethodID, KeyGenParameterSpec.Builder.setKeySize, "setKeySize",
+           "(I)Landroid/security/keystore/KeyGenParameterSpec$Builder;");
+    GET_ID(GetMethodID, KeyGenParameterSpec.Builder.setBlockModes, "setBlockModes",
+           "([Ljava/lang/String;)"
+           "Landroid/security/keystore/KeyGenParameterSpec$Builder;");
+    GET_ID(GetMethodID, KeyGenParameterSpec.Builder.setEncryptionPaddings,
+           "setEncryptionPaddings", "([Ljava/lang/String;)"
+           "Landroid/security/keystore/KeyGenParameterSpec$Builder;");
+    GET_ID(GetMethodID, KeyGenParameterSpec.Builder.build, "build",
+           "()Landroid/security/keystore/KeyGenParameterSpec;");
+
+    GET_CLASS("javax/crypto/KeyGenerator");
+    GET_GLOBAL_CLASS(KeyGenerator);
+    GET_ID(GetStaticMethodID, KeyGenerator.getInstance, "getInstance",
+           "(Ljava/lang/String;Ljava/lang/String;)Ljavax/crypto/KeyGenerator;");
+    GET_ID(GetMethodID, KeyGenerator.init, "init",
+           "(Ljava/security/spec/AlgorithmParameterSpec;)V");
+    GET_ID(GetMethodID, KeyGenerator.generateKey, "generateKey",
+           "()Ljavax/crypto/SecretKey;");
+
+    DEL_LREF(clazz);
+    return VLC_SUCCESS;
+}
+
+/*
+ * Encrypt or Decrypt
+ */
+static size_t
+Process(vlc_keystore *p_keystore, JNIEnv *p_env, jobject jcipher,
+        const uint8_t *p_src, size_t i_src_len,
+        const uint8_t *p_iv, uint32_t i_iv_len, uint8_t **pp_dst)
+{
+    size_t i_dst_size = 0;
+    uint8_t *p_dst;
+    jbyteArray jsrcArray = NULL, jdstArray = NULL;
+
+    jsrcArray = (*p_env)->NewByteArray(p_env, i_src_len);
+    if (CHECK_EXCEPTION())
+        goto end;
+    (*p_env)->SetByteArrayRegion(p_env, jsrcArray, 0, i_src_len, (jbyte *)p_src);
+
+    jdstArray = (jbyteArray) CALL_OBJ(jcipher, Cipher.doFinal, jsrcArray);
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    if (jdstArray == NULL)
+        goto end;
+
+    jsize dstSize = (*p_env)->GetArrayLength(p_env, jdstArray);
+
+    if (dstSize == 0)
+        goto end;
+
+    jbyte *p_bytes = (*p_env)->GetByteArrayElements(p_env, jdstArray, 0);
+
+    p_dst = i_iv_len > 0 ? malloc(dstSize + i_iv_len + sizeof(uint32_t))
+                         : malloc(dstSize);
+    if (p_dst == NULL)
+    {
+        (*p_env)->ReleaseByteArrayElements(p_env, jdstArray, p_bytes, 0);
+        free(p_dst);
+        goto end;
+    }
+
+    if (i_iv_len > 0)
+    {
+        /* Store the IV just before the encrypted password */
+        memcpy(p_dst, &i_iv_len, sizeof(uint32_t));
+        memcpy(p_dst + sizeof(uint32_t), p_iv, i_iv_len);
+        memcpy(p_dst + sizeof(uint32_t) + i_iv_len, p_bytes, dstSize);
+        i_dst_size = dstSize + i_iv_len + sizeof(uint32_t);
+    }
+    else
+    {
+        memcpy(p_dst, p_bytes, dstSize);
+        i_dst_size = dstSize;
+    }
+    (*p_env)->ReleaseByteArrayElements(p_env, jdstArray, p_bytes, 0);
+
+    *pp_dst = p_dst;
+
+end:
+    if (jsrcArray != NULL)
+        DEL_LREF(jsrcArray);
+    if (jdstArray != NULL)
+        DEL_LREF(jdstArray);
+    return i_dst_size;
+}
+
+static size_t
+AndroidEncrypt(vlc_keystore *p_keystore, void *p_ctx, const uint8_t *p_src,
+               size_t i_src_len, uint8_t **pp_dst)
+{
+    (void) p_ctx;
+    JNIEnv *p_env = GET_ENV();
+    if (p_env == NULL)
+        return 0;
+
+    jobject jcipher = NULL;
+    jcipher = CALL_STATICOBJ(Cipher, Cipher.getInstance, fields.VLC_CIPHER);
+    if (CHECK_EXCEPTION())
+        return 0;
+
+    size_t i_dst_len = 0;
+    CALL_VOID(jcipher, Cipher.init, fields.Cipher.ENCRYPT_MODE, s_jkey, NULL);
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    /* Get the IV (Initialization Vector) initialized by Android that will be
+     * used to decrypt this secret. This IV will be stored with the encrypted
+     * secret */
+    jarray jivArray = (jarray) CALL_OBJ(jcipher, Cipher.getIV);
+    if (jivArray == NULL)
+        goto end;
+
+    jsize i_iv_len = (*p_env)->GetArrayLength(p_env, jivArray);
+    if (i_iv_len == 0)
+        goto end;
+    jbyte *p_iv_bytes = (*p_env)->GetByteArrayElements(p_env, jivArray, 0);
+
+    i_dst_len = Process(p_keystore, p_env, jcipher, p_src, i_src_len,
+                        (const uint8_t *)p_iv_bytes, i_iv_len, pp_dst);
+
+    (*p_env)->ReleaseByteArrayElements(p_env, jivArray, p_iv_bytes, 0);
+    DEL_LREF(jivArray);
+
+end:
+
+    DEL_LREF(jcipher);
+    return i_dst_len;
+}
+
+static size_t
+AndroidDecrypt(vlc_keystore *p_keystore, void *p_ctx, const uint8_t *p_src,
+               size_t i_src_len, uint8_t **pp_dst)
+{
+    (void) p_ctx;
+    JNIEnv *p_env = GET_ENV();
+    if (p_env == NULL)
+        return 0;
+
+    jobject jivArray = NULL, jiv = NULL, jcipher = NULL;
+
+    jcipher = CALL_STATICOBJ(Cipher, Cipher.getInstance, fields.VLC_CIPHER);
+    if (CHECK_EXCEPTION())
+        return 0;
+
+    /* Get the IV located at the beginning of the secret */
+    size_t i_dst_len = 0;
+    uint32_t i_iv_len;
+    if (i_src_len < sizeof(uint32_t))
+        goto end;
+
+    memcpy(&i_iv_len, p_src, sizeof(uint32_t));
+    if (i_iv_len == 0 || i_src_len < (sizeof(uint32_t) + i_iv_len))
+        goto end;
+
+    jivArray = (*p_env)->NewByteArray(p_env, i_iv_len);
+    if (CHECK_EXCEPTION())
+        goto end;
+    (*p_env)->SetByteArrayRegion(p_env, jivArray, 0, i_iv_len,
+                                 (jbyte *)(p_src + sizeof(uint32_t)) );
+
+    jiv = NEW_OBJECT(IvParameterSpec, jivArray);
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    /* Use the IV to initialize the decrypt Cipher */
+    CALL_VOID(jcipher, Cipher.init, fields.Cipher.DECRYPT_MODE, s_jkey, jiv);
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    i_dst_len = Process(p_keystore, p_env, jcipher,
+                        p_src + sizeof(uint32_t) + i_iv_len,
+                        i_src_len - sizeof(uint32_t) - i_iv_len,
+                        NULL, 0, pp_dst);
+
+end:
+    DEL_LREF(jcipher);
+    if (jivArray != NULL)
+        DEL_LREF(jivArray);
+    if (jiv != NULL)
+        DEL_LREF(jiv);
+    return i_dst_len;
+}
+
+/*
+ * Generate a AES/CBC/PKCS7Padding key that will be stored by the Android
+ * Keystore
+ */
+static jobject
+GenerateKey(vlc_keystore *p_keystore, JNIEnv *p_env, jstring jstringAlias,
+            jstring jstringProvider)
+{
+    if (InitJniGenKey(p_keystore, p_env) != VLC_SUCCESS)
+        return NULL;
+
+    jobject jkey = NULL, jbuilder = NULL, jspec = NULL,
+            jkeyGen = NULL;
+    jclass jstringClass = NULL;
+    jobjectArray jarray = NULL;
+
+    jbuilder = NEW_OBJECT(KeyGenParameterSpec.Builder, jstringAlias,
+                          fields.KeyProperties.PURPOSE_ENCRYPT |
+                          fields.KeyProperties.PURPOSE_DECRYPT);
+    CALL_OBJ(jbuilder, KeyGenParameterSpec.Builder.setKeySize, 256);
+
+    jstringClass = (*p_env)->FindClass(p_env, "java/lang/String");
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    jarray = (*p_env)->NewObjectArray(p_env, 1, jstringClass, NULL);
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    (*p_env)->SetObjectArrayElement(p_env, jarray, 0,
+                                    fields.KeyProperties.BLOCK_MODE_CBC);
+    CALL_OBJ(jbuilder, KeyGenParameterSpec.Builder.setBlockModes, jarray);
+
+    (*p_env)->SetObjectArrayElement(p_env, jarray, 0,
+                                    fields.KeyProperties.ENCRYPTION_PADDING_PKCS7);
+    CALL_OBJ(jbuilder, KeyGenParameterSpec.Builder.setEncryptionPaddings, jarray);
+    jspec = CALL_OBJ(jbuilder, KeyGenParameterSpec.Builder.build);
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    jkeyGen = CALL_STATICOBJ(KeyGenerator, KeyGenerator.getInstance,
+                             fields.KeyProperties.KEY_ALGORITHM_AES,
+                             jstringProvider);
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    CALL_VOID(jkeyGen, KeyGenerator.init, jspec);
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    jkey = CALL_OBJ(jkeyGen, KeyGenerator.generateKey);
+    CHECK_EXCEPTION();
+
+end:
+    if (jbuilder != NULL)
+        DEL_LREF(jbuilder);
+    if (jstringClass != NULL)
+        DEL_LREF(jstringClass);
+    if (jarray != NULL)
+        DEL_LREF(jarray);
+    if (jspec != NULL)
+        DEL_LREF(jspec);
+    if (jkeyGen != NULL)
+        DEL_LREF(jkeyGen);
+
+    return jkey;
+}
+
+/*
+ * Init JNI fields, fetch the key stored by Android or generate a new one
+ */
+static void
+AndroidInit(vlc_keystore *p_keystore)
+{
+    JNIEnv *p_env = GET_ENV();
+    if (p_env == NULL)
+        return;
+
+    if (InitJni(p_keystore, p_env) != VLC_SUCCESS)
+        return;
+
+    jobject jkeystore = NULL, jentry = NULL, jkey = NULL;
+    jstring jstringAlias = NULL, jstringProvider = NULL;
+
+    jstringAlias = NEW_STR("LibVLCAndroid");
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    jstringProvider = NEW_STR("AndroidKeyStore");
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    jkeystore = CALL_STATICOBJ(KeyStore, KeyStore.getInstance, jstringProvider);
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    CALL_VOID(jkeystore, KeyStore.load, NULL);
+    if (CHECK_EXCEPTION())
+        goto end;
+
+    jentry = CALL_OBJ(jkeystore, KeyStore.getEntry, jstringAlias, NULL);
+    if (CHECK_EXCEPTION())
+        goto end;
+    if (jentry != NULL)
+    {
+        jkey = CALL_OBJ(jentry, KeyStore.SecretKeyEntry.getSecretKey);
+        if (CHECK_EXCEPTION())
+            goto end;
+    }
+    else
+    {
+        jkey = GenerateKey(p_keystore, p_env, jstringAlias, jstringProvider);
+        if (jkey == NULL)
+            goto end;
+    }
+
+    s_jkey = NEW_GREF(jkey);
+
+end:
+    if (jstringAlias != NULL)
+        DEL_LREF(jstringAlias);
+    if (jstringProvider != NULL)
+        DEL_LREF(jstringProvider);
+    if (jkeystore != NULL)
+        DEL_LREF(jkeystore);
+    if (jentry != NULL)
+        DEL_LREF(jentry);
+    if (jkey != NULL)
+        DEL_LREF(jkey);
+}
+
+int
+CryptInit(vlc_keystore *p_keystore, struct crypt *p_crypt)
+{
+    static vlc_mutex_t s_lock = VLC_STATIC_MUTEX;
+    static bool s_init = false;
+
+    vlc_mutex_lock(&s_lock);
+    if (!s_init)
+    {
+        AndroidInit(p_keystore);
+        s_init = true;
+    }
+    if (s_jkey == NULL)
+    {
+        vlc_mutex_unlock(&s_lock);
+        return VLC_EGENERIC;
+    }
+    vlc_mutex_unlock(&s_lock);
+
+    p_crypt->pf_encrypt = AndroidEncrypt;
+    p_crypt->pf_decrypt = AndroidDecrypt;
+
+    return VLC_SUCCESS;
+}
diff --git a/modules/keystore/memory-crypt.h b/modules/keystore/memory-crypt.h
index 4b4b815..be88626 100644
--- a/modules/keystore/memory-crypt.h
+++ b/modules/keystore/memory-crypt.h
@@ -18,13 +18,8 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-#if 0
-#if defined(__ANDROID__) || defined(_WIN32)
+#if defined(__ANDROID__) /* TODO || defined(_WIN32) */
 # define CRYPTFILE
-#endif
-#endif
-
-#ifdef CRYPTFILE
 
 struct crypt
 {
-- 
2.7.0



More information about the vlc-devel mailing list