最近在做图片上传的应用,出于对文件上传的完整性和安全性的校验,我们使用了较为简单的MD5校验。今天我们就来简单的说一下在Android平台下如何使用官方提供的API获取文件以及文本的MD5密纹用于校验。本篇主要会介绍两种方式,一种是MD5,一种是SHA-1;至于原因可以参见下面我从API文档截取的图片:
关于MD5和SHA的理论介绍,网上也有很多介绍,这里不再累述,具体可以参见类似SHA 加密是什么( sha1 和 MD5 的区别 )的博客。
从上面的截图我们不难看出,ANdroid.security包下面提供了一个抽象类MessageDigest(信息摘要),其有两个直接子类分别对应MD5和SHA-1获取文件或者文本密纹。两者的区别可以参见我上面给出的那篇博客介绍。它们的使用方式是一样的,下面就先来看一下示例的效果图:
这里面给出了文本以及文件的MD5密纹和SHA-1密纹获取实现。下面就来看看具体的代码实现:
activity_main.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.hfut.myapplication.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MD5密纹:" />
<TextView
android:id="@+id/md5_encode_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SHA-1密纹:" />
<TextView
android:id="@+id/sha-1_encode_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<EditText
android:id="@+id/raw_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="encodeText"
android:text="获取文本密文" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="文件路径:" />
<TextView
android:id="@+id/file_path"
android:layout_width="400dp"
android:layout_height="wrap_content" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="chooseFile"
android:text="选择文件" />
</LinearLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="encodeFile"
android:text="获取文件密文" />
</LinearLayout>
MainActivity.java代码:
package com.hfut.myapplication;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @author why
* @date 2019-1-30 12:06:38
*/
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
TextView MD5EncodeResult;
TextView SHA1EncodeResult;
EditText rawContent;
TextView filePtah;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
filePtah.setText((String) msg.obj);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MD5EncodeResult = findViewById(R.id.md5_encode_result);
SHA1EncodeResult=findViewById(R.id.sha_1_encode_result);
rawContent = findViewById(R.id.raw_content);
filePtah = findViewById(R.id.file_path);
}
public static String md5Encode(String content) {
byte[] hash;
try {
hash = MessageDigest.getInstance("MD5").digest(content.getBytes("UTF-8"));
} catch (Exception e) {
throw new RuntimeException("Exception", e);
}
//TODO transform byte array to hex string
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
if ((b & 0xFF) < 0x10) {
hex.append("0");
}
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString();
}
public static String sha1Encode(String content) {
byte[] hash;
try {
hash = MessageDigest.getInstance("SHA-1").digest(content.getBytes("UTF-8"));
} catch (Exception e) {
throw new RuntimeException("NoSuchAlgorithmException", e);
}
//TODO transform byte array to hex string
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
if ((b & 0xFF) < 0x10) {
hex.append("0");
}
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString();
}
public static String md5ForFile(File file) {
int bufferSize = 1024;
FileInputStream fis = null;
DigestInputStream dis = null;
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
fis = new FileInputStream(file);
dis = new DigestInputStream(fis, messageDigest);
byte[] buffer = new byte[bufferSize];
while (dis.read(buffer) > 0) ;
messageDigest = dis.getMessageDigest();
byte[] array = messageDigest.digest();
//TODO transform byte array to hex string
StringBuilder hex = new StringBuilder(array.length * 2);
for (byte b : array) {
if ((b & 0xFF) < 0x10) {
hex.append("0");
}
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String sha1ForFile(File file) {
int bufferSize = 1024;
FileInputStream fis = null;
DigestInputStream dis = null;
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
fis = new FileInputStream(file);
dis = new DigestInputStream(fis, messageDigest);
byte[] buffer = new byte[bufferSize];
while (dis.read(buffer) > 0) ;
messageDigest = dis.getMessageDigest();
byte[] array = messageDigest.digest();
//TODO transform byte array to hex string
StringBuilder hex = new StringBuilder(array.length * 2);
for (byte b : array) {
if ((b & 0xFF) < 0x10) {
hex.append("0");
}
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static final int FILE_SELECT_CODE = 0;
private void chooseFileImp() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");// any type file is supported
intent.addCategory(Intent.CATEGORY_OPENABLE);
try {
startActivityForResult(Intent.createChooser(intent, "Please choose file"), FILE_SELECT_CODE);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(this, "No file manager", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
if (resultCode != Activity.RESULT_OK) {
Log.e(TAG, "onActivityResult() error, resultCode: " + resultCode);
super.onActivityResult(requestCode, resultCode, data);
return;
}
if (requestCode == FILE_SELECT_CODE) {
Uri uri = data.getData();
Message message = new Message();
message.obj = uri.getPath();
Log.e(TAG, "onActivityResult: "+uri.getPath());
handler.sendMessage(message);
}
super.onActivityResult(requestCode, resultCode, data);
}
/**
* To get text's MD5 code
*
* @param view
*/
public void encodeText(View view) {
String content = rawContent.getText().toString();
if (!content.isEmpty()) {
MD5EncodeResult.setText(md5Encode(content));
SHA1EncodeResult.setText(sha1Encode(content));
}
else {
Toast.makeText(this,"Data can not be empty",Toast.LENGTH_SHORT).show();
}
}
/**
* To get file's MD5 code
*
* @param view
*/
public void encodeFile(View view) {
String filePath = filePtah.getText().toString();
if (!filePath.isEmpty()) {
File file = new File(filePath);
MD5EncodeResult.setText(md5ForFile(file));
SHA1EncodeResult.setText(sha1ForFile(file));
}
else {
Toast.makeText(this,"Please choose a file",Toast.LENGTH_SHORT).show();
}
}
/**
* Choose file
* @param view
*/
public void chooseFile(View view) {
chooseFileImp();
}
}
因为需要读取文件,所以需要添加读写组权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
使用的流程很简单,通过MessageDigest的digest方法获取文本或者文件的固定位数(MD5 128位,SHA-1 160位)的hash值(byte数组,MD5 size为16 ,SHA-1 size为20)转换为16进制(MD5 length为32,SHA-1 length为40)输出即可。
注:欢迎扫码关注