我有两个用于计算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();
}
我希望有另一种可能使其运行,因为我需要性能。
我使用了JNI加载的高性能c ++实现。
有关更多详细信息,请发表评论。
编辑:
JNI的要求是Android
NDK。对于Windows,还需要cygwin或类似的东西。
如果您决定使用cygwin,我会给您一些指导,说明如何使其与NDK一起使用:
cd /cygdrive/d
导航到字母 D 的驱动器。./ndk-build
。应该出现类似的错误Android NDK: Could not find application project directory !
。在我们从项目开始之前,搜索哈希算法的C / C
++实现。我从此站点CSHA1中获取了代码。
您应该根据需要编辑源代码。
现在我们可以从JNI开始。
您在Android项目中创建一个名为 jni 的文件夹。它还包含所有本机源文件和 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 #include <android/log.h>
。
现在您可以使用登录__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "Version [%s]", "19");
。
第一个参数是消息的类型,第二个参数是原因库。
您可以看到我的代码中有一个版本号。这很有用,因为有时apk生成器不使用新的本机库。如果在线版本错误,则可以极大地缩短故障排除时间。
本机代码中的命名约定有点麻烦:Java_[package name]_[class name]_[method name]
。
始终提供first到arguments,但是应根据应用程序进行区分:
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
在我的情况下,我必须额外提供 bootclasspath ,因为我使用的是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
类 de / dhbw / file /
sha1 / SHA1HashFileAsyncTask 的完整限定路径。
要查找方法,您需要 JNIEnv 和该类的实例:
jmethodID midSet = callEnv->GetMethodID(callClass, "setFileSize", "(J)V");
第一个参数是该类的实例,第二个参数是该方法的名称,第三个是该方法的签名。
您可以从JDK给定的二进制 javap.exe中 获得签名。只需使用fe类的完全限定路径进行调用即可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);
第一个参数是“ main”方法给定的 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();
}
技术指标
建立/清洁
生成
创建完所有文件并将其填充内容之后,就可以对其进行生成。
打开cygwin,导航到项目根目录,然后从NDK根目录中执行 ndk-build 。
这开始编译,如果成功,您将得到如下输出:
$ /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
在构建本机库之后,您可以构建您的项目。我发现干净了,使用eclipse功能 清理项目 是有利的。
调试
Java代码的调试与以前没有什么不同。
C ++代码的调试将在下一次进行。
问题内容: 我有一个简单的问题,当我想将SHA1哈希的结果存储在MySQL数据库中时发生: 我将散列结果存储在 VARCHAR 字段中多长时间? 问题答案: 我将使用可变长度的数据,但不使用固定长度的数据。由于SHA-1值 始终为 160位长,因此将仅在固定长度字段的长度上浪费一个额外的字节。 而且我也不会存储返回的值。因为每个字符只使用4位,因此需要160/4 = 40个字符。但是,如果每个字符
我正在写一个Django应用程序,需要与现有的Java播放框架应用程序一起工作。Play应用程序使用PasswordHash.java来存储密码。它以冒号分隔的格式存储密码。每个哈希都存储为::。 例如,下面是密码“测试”的条目: 在这里,我们可以通过拆分字符串并找到: 迭代次数: 盐: PBKDF2哈希:。 我修改了Django的check_密码机制以与此格式兼容,但发现它认为密码不正确。我用了
问题内容: 在Objective-C中,它看起来像这样: 我需要Swift这样的东西,可以吗? 请显示工作示例。 问题答案: 您的Objective-C代码(使用类别)可以直接转换为Swift(使用扩展名)。 首先,您必须创建一个“桥接头”并添加 然后: 这可以写得更短和更快速 Swift 2更新: 要返回以Base-64编码的字符串而不是十六进制编码的字符串,只需替换 与 Swift 3更新:
问题内容: 我已经到处寻找答案,但是似乎只能找到可以满足您需求的软件。有人知道如何在python中执行此操作吗? 问题答案: 我写了一段python代码,根据 .torrent文件 中的内容验证 下载文件 的哈希值。假设您要检查下载是否损坏,则可能会发现此功能有用。 __ 您需要bencode包才能使用它。Bencode是.torrent文件中使用的序列化格式。它可以封送列表,字典,字符串和数字,
我试图解决这个问题,我需要实现线性探测。 给定一个整数数组和一个哈希表大小。使用线性探测将数组元素填充到哈希表中以处理冲突。 例1: 例2: 您的任务: 您不需要读取输入或打印任何内容。 您的任务是完成函数linearProbing(),该函数将空哈希表(hash)、哈希表大小(hashSize)、整数数组arr[]及其大小N作为输入,并将数组arr[]的所有元素插入给定的哈希表中。 哈希表的空单
好吧,这里都是我的问题。我正在尝试用MD5哈希加密字符串。下面是我试图哈希的字符串: 以下是预期输出: 下面是我在Android应用程序中得到的信息: 下面是我正在使用的代码: 在Android上运行这段代码时,我得到了上述意想不到的结果,但当我运行这段代码时,就像一个Java程序传递相同的字符串一样,我得到了预期的输出... 究竟是怎么回事?几天来,我一直被这件事难住,在网上搜寻线索。我已经尝试