Вопрос по stream, hash, sha1, java, android –  здесь совершенно неправильно. Base64 не является шестнадцатеричным. Шестнадцатеричное основание 16.

5

я есть два небольших фрагмента для расчета SHA1.

Один очень быстрый, но кажется, что он не правильный, а другой очень медленный, но правильный.
я думаюFileInputStream преобразование вByteArrayInputStream это проблема.

Быстрая версия:

MessageDigest md = MessageDigest.getInstance("SHA1");
FileInputStream fis = new FileInputStream("path/to/file.exe");
ByteArrayInputStream byteArrayInputStream =
    new ByteArrayInputStream(fis.toString().getBytes());
DigestInputStream dis = new DigestInputStream(byteArrayInputStream, md);
BufferedInputStream bis = new BufferedInputStream(fis);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

int ch;
while ((ch = dis.read()) != -1) {
    byteArrayOutputStream.write(ch);
}

byte[] newInput = byteArrayOutputStream.toByteArray();
System.out.println("in digest : " +
    byteArray2Hex(dis.getMessageDigest().digest()));

byteArrayOutputStream = new ByteArrayOutputStream();
DigestOutputStream digestOutputStream =
    new DigestOutputStream(byteArrayOutputStream, md);
digestOutputStream.write(newInput);

System.out.println("out digest: " +
    byteArray2Hex(digestOutputStream.getMessageDigest().digest()));
System.out.println("length: " + 
    new String(
        byteArray2Hex(digestOutputStream.getMessageDigest().digest())).length());

digestOutputStream.close();
byteArrayOutputStream.close();
dis.close();

Медленная версия:

MessageDigest algorithm = MessageDigest.getInstance("SHA1");
FileInputStream fis = new FileInputStream("path/to/file.exe");
BufferedInputStream bis = new BufferedInputStream(fis);
DigestInputStream   dis = new DigestInputStream(bis, algorithm);

// read the file and update the hash calculation
while (dis.read() != -1);

 // get the hash value as byte array
byte[] hash = algorithm.digest();

Метод конвертации:

private static String byteArray2Hex(byte[] hash) {
    Formatter formatter = new Formatter();
    for (byte b : hash) {
        formatter.format("%02x", b);
    }
    return formatter.toString();
}

Я надеюсь, что есть еще одна возможность запустить его, потому что мне нужна производительность.

Ваш Ответ

1   ответ
17

которую загружаю с помощью JNI.
Для более подробной информации напишите комментарий, пожалуйста.

РЕДАКТИРОВАТЬ:
Требования к JNIAndroid NDK, Для Windows требуется дополнительноCygwin или что-то подобное.
Если вы выбрали Cygwin, я дам вам несколько небольших инструкций, как заставить его работать с NDK:

Скачатьsetup.exe от Cygwin и выполнить его.Нажмите наследующий и выборУстановить из интернета подтвердить сследующий.Следующие два шага измените настройки по желанию и, как всегда, нажмитеследующий.Выберите подключение к Интернету и выполните ту же процедуру, что и на последних этапах.Страница загрузки попадется на глаза, выберите ее или возьмите только страницу загрузки, которая находится в вашей стране. Больше нечего сказать.Нам нужны пакетысделать а такжеGCC-г ++, Вы можете найти их с помощью поиска в левом верхнем углу, нажмите наПропускать Пока отображается версия и выбрано первое поле. Делайте то, что мы всегда делали после выбора.Вы получите информацию, что есть зависимости, которые необходимо устранить. Обычно нет необходимости делать это самостоятельно и подтверждать это.Началась загрузка и установка.Если вам нужно, вы можете создать ярлыки, в противном случае нажмите на исключительныйКонец.Загрузите zip-файл и распакуйте NDK в путь без пробелов.Вы можете начать сейчас Cygwin.Перейдите к NDK. Тропинка/ cydrive дает вам все доступные диски, напримерcd /cygdrive/d переходит на диск с буквойD.В корневой папке NDK вы можете выполнить файлNDK-сборки с участием./ndk-build, Там должно быть ошибка возникает какAndroid NDK: Could not find application project directory !.
Вы должны перейти в проект Android, чтобы выполнить команду. Итак, начнем с проекта.

Прежде чем мы сможем начать с поиска проекта реализации алгоритма хэширования на C / C ++. Я взял код с этого сайтаCSHA1.
Вы должны отредактировать исходный код для ваших требований.

Теперь мы можем начать с JNI.
Вы создаете папку с именемJNI в вашем проекте Android. Он содержит все исходные файлы иAndroid.mk (подробнее об этом файле позже) тоже.
Скопируйте загруженные (и отредактированные) исходные файлы в эту папку.

Мой пакет Java называетсяde.dhbw.file.sha1, поэтому я назвал мои исходные файлы похожими, чтобы легко их найти.

Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_LDLIBS := -llog

# How the lib is called?
LOCAL_MODULE    := SHA1Calc
# Which is your main SOURCE(!) file?
LOCAL_SRC_FILES := de_dhbw_file_sha1_SHA1Calc.cpp

include $(BUILD_SHARED_LIBRARY)

Java-код:
Я использовалAsyncTask сProgressDialog дать пользователю некоторую обратную связь о действии.

package de.dhbw.file.sha1;

// TODO: Add imports

public class SHA1HashFileAsyncTask extends AsyncTask<String, Integer, String> {
    // [...]

    static {
        // loads a native library
        System.loadLibrary("SHA1Calc");
    }

    // [...]

    // native is the indicator for native written methods
    protected native void calcFileSha1(String filePath);

    protected native int getProgress();

    protected native void unlockMutex();

    protected native String getHash();

    // [...]
}

Нативный код (C ++):

Помните, что для доступа к переменным внутри нативного кода или другого способа использования потоков требуется синхронизация, иначе вы скоро получите ошибку сегментации!

Для использования JNI вы должны добавить#include <jni.h>.

Для регистрации вставьте следующее:#include <android/log.h>.
Теперь вы можете войти с__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "Version [%s]", "19");.
Первый аргумент - это тип сообщения, а второй - вызывающая библиотека.
Вы можете видеть, что у меня был номер версии в моем коде. Это очень полезно, потому что иногда сборщик apk не использует новые нативные библиотеки. Устранение неполадок может быть значительно сокращено, если в сети установлена ​​неправильная версия.

Соглашения об именах в нативном коде немного ошибочны:Java_[package name]_[class name]_[method name].

Первые аргументы всегда даются, но в зависимости от приложения вы должны различать:

func(JNIEnv * env, jobject jobj) -> вызов JNI является методом экземпляраfunc(JNIEnv * env, jclass jclazz) -> вызов JNI является статическим методом

Заголовок для методаcalcFileSha1(...):
JNIEXPORT void JNICALL Java_de_dhbw_file_sha1_SHA1HashFileAsyncTask_calcFileSha1(JNIEnv * env, jobject jobj, jstring file)

JDK поставляет двоичный файлjavah.exe, который генерирует заголовочный файл для собственного кода. Использование очень просто, просто назовите его с полным квалифицированным классом:
javah de.dhbw.file.sha1.SHA1HashFileAsyncTask

В моем случае я должен датьзагрузочный путь к классам Кроме того, потому что я использую классы Android:javah -bootclasspath <path_to_the_used_android_api> de.dhbw.file.sha1.SHA1HashFileAsyncTask

Это будет сгенерированный файл:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class de_dhbw_file_sha1_SHA1HashFileAsyncTask */

#ifndef _Included_de_dhbw_file_sha1_SHA1HashFileAsyncTask
#define _Included_de_dhbw_file_sha1_SHA1HashFileAsyncTask
#ifdef __cplusplus
extern "C" {
#endif
#undef de_dhbw_file_sha1_SHA1HashFileAsyncTask_ERROR_CODE
#define de_dhbw_file_sha1_SHA1HashFileAsyncTask_ERROR_CODE -1L
#undef de_dhbw_file_sha1_SHA1HashFileAsyncTask_PROGRESS_CODE
#define de_dhbw_file_sha1_SHA1HashFileAsyncTask_PROGRESS_CODE 1L
/*
 * Class:     de_dhbw_file_sha1_SHA1HashFileAsyncTask
 * Method:    calcFileSha1
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_de_dhbw_file_sha1_SHA1HashFileAsyncTask_calcFileSha1
  (JNIEnv *, jobject, jstring);

/*
 * Class:     de_dhbw_file_sha1_SHA1HashFileAsyncTask
 * Method:    getProgress
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_de_dhbw_file_sha1_SHA1HashFileAsyncTask_getProgress
  (JNIEnv *, jobject);

/*
 * Class:     de_dhbw_file_sha1_SHA1HashFileAsyncTask
 * Method:    unlockMutex
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_de_dhbw_file_sha1_SHA1HashFileAsyncTask_unlockMutex
  (JNIEnv *, jobject);

/*
 * Class:     de_dhbw_file_sha1_SHA1HashFileAsyncTask
 * Method:    getHash
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_de_dhbw_file_sha1_SHA1HashFileAsyncTask_getHash
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

Вы можете изменить файл без предварительного уведомления. Но не используйтеjavah очередной раз!

Класс и методы
Чтобы получить экземпляр класса, вы можете использоватьjclass clz = callEnv->FindClass(CALL_CLASS);, В этом случаеCALL_CLASS полный квалифицированный путь к классуде / dhbw / файл / sha1 / SHA1HashFileAsyncTask.

Чтобы найти метод, вам нуженJNIEnv и экземпляр класса:
jmethodID midSet = callEnv->GetMethodID(callClass, "setFileSize", "(J)V"); Первый аргумент - это экземпляр класса, второй - имя метода, а третий - сигнатура метода.
Подпись, которую вы можете получить с помощью двоичного файла от JDKjavap.exe, Просто назовите его с полным квалифицированным путем класса f.e.javap -s de.dhbw.file.sha1.SHA1HashFileAsyncTask.
Вы получите результат как:

Compiled from "SHA1HashFileAsyncTask.java"
public class de.dhbw.file.sha1.SHA1HashFileAsyncTask extends android.os.AsyncTas
k<java.lang.String, java.lang.Integer, java.lang.String> {
  [...]
  static {};
    Signature: ()V

  public de.dhbw.file.sha1.SHA1HashFileAsyncTask(android.content.Context, de.dhb
w.file.sha1.SHA1HashFileAsyncTask$SHA1AsyncTaskListener);
    Signature: (Landroid/content/Context;Lde/dhbw/file/sha1/SHA1HashFileAsyncTas
k$SHA1AsyncTaskListener;)V

  protected native void calcFileSha1(java.lang.String);
    Signature: (Ljava/lang/String;)V

  protected native int getProgress();
    Signature: ()I

  protected native void unlockMutex();
    Signature: ()V

  protected native java.lang.String getHash();
    Signature: ()Ljava/lang/String;

  [...]

  public void setFileSize(long);
    Signature: (J)V

  [...]
}

Если метод найден, переменная не равна 0.
Вызов метода очень прост:

callEnv->CallVoidMethod(callObj, midSet, size);

Первый аргумент данjobject из "основного" метода я думаю и другие понятны.

Помните, что вы можете вызывать из нативного кода хотя и частные методы класса, потому что нативный код является его частью!

Струны
Данная строка будет преобразована с помощью следующего кода:

jboolean jbol;
const char *fileName = env->GetStringUTFChars(file, &jbol);

И другой способ:

TCHAR* szReport = new TCHAR;
jstring result = callEnv->NewStringUTF(szReport);

Это может быть каждыйchar* переменная.

Исключения
Может быть брошено сJNIEnv:

callEnv->ThrowNew(callEnv->FindClass("java/lang/Exception"), 
    "Hash generation failed");

Вы также можете проверить, произошло ли исключение также сJNIEnv:

if (callEnv->ExceptionOccurred()) {
    callEnv->ExceptionDescribe();
    callEnv->ExceptionClear();
}

Характеристики

Спецификации нативного интерфейса Java

Сборка / Clean

строить
После того, как мы создали все файлы и наполнили их содержимым, мы можем создать его.
Откройте cygwin, перейдите к корню проекта и выполните оттудаNDK-сборки, который находится в корне NDK.
Это запустит компиляцию, в случае успеха вы получите такой вывод:

$ /cygdrive/d/android-ndk-r5c/ndk-build
Compile++ thumb  : SHA1Calc <= SHA1Calc.cpp
SharedLibrary  : libSHA1Calc.so
Install        : libSHA1Calc.so => libs/armeabi/libSHA1Calc.so

Если есть какая-либо ошибка, вы получите типичный вывод от компилятора.

чистый
Откройте cygwin, включите ваш проект Android и выполните команду/cygdrive/d/android-ndk-r5c/ndk-build clean.

Построить apk
После того, как вы соберете собственные библиотеки, вы можете создать свой проект. Я нашел чистым, выгодно использовать функцию затмениячистый проект.

отладка
Отладка Java-кода не отличается от предыдущей.
Отладка кода на С ++ последует в следующий раз.

Можете ли вы предоставить подробную информацию о том, как это сделать? Matt Wolfe
Посмотрите на мою правку. :) CSchulz

Похожие вопросы