public class AES { public static int KEY_SIZE = 16; public static int IV_SIZE = 16; static public class CBC { private byte[] __key; private byte[] __iv; public CBC(byte[] key, byte[] iv) { __key = key; __iv = iv; } public CBC() { __key = GenerateKey(); __iv = GenerateIV(); } public native byte[] Encrypt(byte[] data); public native byte[] Decrypt(byte[] data); public byte[] GetKey() { return __key; } public byte[] GetIV() { return __iv; } } public static native byte[] GenerateIV(); public static native byte[] GenerateKey(); static { try { System.loadLibrary("nativecryptowrapper"); } catch (Exception e) { e.printStackTrace(); } } }
native
keyword.System.loadLibrary
surrounded by a try-catch
. It should be noted that the argument of the call to the loadLibrary
method is the name of the library WITHOUT the lib prefix and the extension!%PRJ%/bin/%NativePrjName%
%PRJ%/jni/nativecryptowrapper
folder in the console and from there start the javah –classpath ../../bin/classes com.cryptodroid.AES
. The -classpath
parameter specifies where to look for compiled class files. Inside the %PRJ%/bin/classes
class files are arranged according to the packages in which they are located, so it’s not necessary to specify a specific path to the class file. The second parameter is the full name of the class for which the header file * .h will be created. JNIEXPORT jbyteArray JNICALL Java_com_cryptodroid_crypto_AES_00024CBC_Encrypt(JNIEnv* env, jobject obj, jbyteArray source) { try { std::vector<jbyte> key = to_vector(env, get_field_value<jbyteArray>(env, obj, "__key")); std::vector<jbyte> iv = to_vector(env, get_field_value<jbyteArray>(env, obj, "__iv" )); CryptoPP::CBC_Mode< CryptoPP::AES >::Encryption e; e.SetKeyWithIV( reinterpret_cast<byte*>(&key.front()), KEY_SIZE, reinterpret_cast<byte*>(&iv.front()) ); CryptoPP::StreamTransformationFilter filter (e); jbytearray_holder data_holder(source, env); filter.Put(reinterpret_cast<byte*>(&*data_holder.begin()), data_holder.size()); filter.MessageEnd(); jbyteArray result = env->NewByteArray(filter.MaxRetrievable()); if (!result) throw std::runtime_error("No memory!"); jbytearray_holder result_holder(result, env); filter.Get(reinterpret_cast<byte*>(&*result_holder.begin()), result_holder.size()); return result; } catch (std::exception& e) { throw_jni_exception(env, e); } return NULL; } JNIEXPORT jbyteArray JNICALL Java_com_cryptodroid_crypto_AES_00024CBC_Decrypt(JNIEnv* env, jobject obj, jbyteArray source) { try { std::vector<jbyte> key = to_vector(env, get_field_value<jbyteArray>(env, obj, "__key")); std::vector<jbyte> iv = to_vector(env, get_field_value<jbyteArray>(env, obj, "__iv" )); CryptoPP::CBC_Mode< CryptoPP::AES >::Decryption d; d.SetKeyWithIV( reinterpret_cast<byte*>(&key.front()), KEY_SIZE, reinterpret_cast<byte*>(&iv.front()) ); CryptoPP::StreamTransformationFilter filter (d); jbytearray_holder data_holder(source, env); filter.Put(reinterpret_cast<byte*>(&*data_holder.begin()), data_holder.size()); filter.MessageEnd(); jbyteArray result = env->NewByteArray(filter.MaxRetrievable()); if (!result) throw std::runtime_error("No memory!"); jbytearray_holder result_holder(result, env); filter.Get(reinterpret_cast<byte*>(&*result_holder.begin()), result_holder.size()); return result; } catch (std::exception& e) { throw_jni_exception(env, e); } return NULL; }
to_vector
is a function that allows you to convert jbyteArray
(jni-array) to a regular std::vector<jbyte>
jbytearray_holder
- a class that encapsulates, in accordance with the RAII paradigm, memory management of a managed arraythrow_jni_exception
- throws an exception for managed codeget_field_value
is a template function. While there is only a specialization for getting fields of the byte[]
tapa, later, if necessary, other specializations will be added. const size_t KEY_SIZE = 16; const size_t IV_SIZE = 16; std::vector<jbyte> to_vector(JNIEnv* env, jbyteArray data) { size_t data_len = env->GetArrayLength(data); std::vector<jbyte> result(data_len); if (data_len) { env->GetByteArrayRegion(data, 0, data_len, &*result.begin()); } return result; } class jbytearray_holder { public: typedef jbyte* iterator; jbytearray_holder(jbyteArray& ar, JNIEnv* env): m_env(env), m_ar(ar) { jboolean is_copy; m_data = m_env->GetByteArrayElements(m_ar, &is_copy); } template<typename T> T get_as() { return reinterpret_cast<T>(m_data); } iterator begin() { return reinterpret_cast<iterator>(m_data); } iterator end() { return begin() + size(); } size_t size() { return m_env->GetArrayLength(m_ar); } ~jbytearray_holder() { m_env->ReleaseByteArrayElements(m_ar, m_data, 0); } private: JNIEnv* m_env; jbyte* m_data; jbyteArray& m_ar; jbytearray_holder(jbytearray_holder&); jbytearray_holder& operator= (jbytearray_holder&); }; void throw_jni_exception(JNIEnv* env, const std::exception& e) { jclass excClass = env->FindClass("java/lang/IllegalArgumentException"); if (excClass) { std::string message = "Exception from native code: "; message += e.what(); env->ThrowNew(excClass, message.c_str()); } } template<typename T> T get_field_value(JNIEnv* env, jobject obj, const std::string& field_name); template<> jbyteArray get_field_value<jbyteArray>(JNIEnv* env, jobject obj, const std::string& field_name) { jclass clazz = env->GetObjectClass(obj); if (!clazz) throw std::runtime_error("No class!"); jfieldID fld = env->GetFieldID(clazz, field_name.c_str(), "[B"); jbyteArray result = static_cast<jbyteArray>(env->GetObjectField(obj, fld)); return result; } JNIEXPORT jbyteArray JNICALL Java_com_cryptodroid_crypto_AES_00024CBC_Encrypt(JNIEnv* env, jobject obj, jbyteArray source) { try { std::vector<jbyte> key = to_vector(env, get_field_value<jbyteArray>(env, obj, "__key")); std::vector<jbyte> iv = to_vector(env, get_field_value<jbyteArray>(env, obj, "__iv" )); CryptoPP::CBC_Mode< CryptoPP::AES >::Encryption e; e.SetKeyWithIV( reinterpret_cast<byte*>(&key.front()), KEY_SIZE, reinterpret_cast<byte*>(&iv.front()) ); CryptoPP::StreamTransformationFilter filter (e); jbytearray_holder data_holder(source, env); filter.Put(reinterpret_cast<byte*>(&*data_holder.begin()), data_holder.size()); filter.MessageEnd(); jbyteArray result = env->NewByteArray(filter.MaxRetrievable()); if (!result) throw std::runtime_error("No memory!"); jbytearray_holder result_holder(result, env); filter.Get(reinterpret_cast<byte*>(&*result_holder.begin()), result_holder.size()); return result; } catch (std::exception& e) { throw_jni_exception(env, e); } return NULL; }
Cipher _e = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec skeySpec = new SecretKeySpec(key, "AES"); IvParameterSpec ivspec = new IvParameterSpec(iv); _e.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec); byte[] encrypted = _e.doFinal(data); Cipher _d = Cipher.getInstance("AES/CBC/PKCS5Padding"); _d.init(Cipher.DECRYPT_MODE, skeySpec, ivspec); byte[] decrypted = _d.doFinal(encrypted);
AES.CBC e = new AES.CBC(iv, key); byte[] encrypted = e.Encrypt(data); byte[] decrypted = e.Decrypt(encrypted);
LOCAL_SRC_FILES
- list of source filesLOCAL_MODULE
- module nameLOCAL_STATIC_LIBRARIES
- a list of static libraries to be used when building (optional)LOCAL_CFLAGS
- additional compiler flags (if needed)CLEAR_VARS
macroBUILD_xxx
one of the BUILD_xxx
macros, for example BUILD_STATIC_LIBRARY
or BUILD_SHARED_LIBRARY
APP_STL
- STL Usage FlagAPP_ABI
- list of target architecturesAPP_OPTIM
- build type (debug / release)APP_PLATFORM
- target platform indication LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := nativecryptowrapper LOCAL_CFLAGS := -fexceptions -frtti LOCAL_SRC_FILES := nativecryptowrapper/aes_base.cpp LOCAL_STATIC_LIBRARIES := cryptopp include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := cryptopp LOCAL_CFLAGS := -fexceptions -frtti LOCAL_SRC_FILES := \ cryptopp/3way.cpp \ .... cryptopp/zdeflate.cpp \ cryptopp/zinflate.cpp \ cryptopp/zlib.cpp include $(BUILD_STATIC_LIBRARY)
APP_STL := gnustl_static APP_ABI := armeabi armeabi-v7a x86 APP_OPTIM := release APP_PLATFORM=android-9
-fexceptions
and -frtti
to the -frtti
variable of the LOCAL_CFLAGS
file (since the Crypto ++ library uses exceptions and castings dynamic_cast)System. nanoTime()
method was used System. nanoTime()
System. nanoTime()
from the standard Java class library on Android. Measurements were taken on: Megafon Mint, Pocketbook A10. The results are as follows:Megafon Mint, ms | Pocketbook A10, ms | |
---|---|---|
System Crypt Provider | 998 | 1835 |
Crypto ++ library | 231 | 970 |
Acceleration | 4.3x | 1.9x |
Source: https://habr.com/ru/post/170517/
All Articles