Android SharedPreference MD5 哈希校验
对于某些比较重要的,只是用来判断是否匹配是否一致的数据,我们可以使用 MD5
做一次哈希,这样,至少不会是明文保存和传输,一看到字符串知道是啥数据的悲剧
我们假设 SharedPreference
需要存储一个表示当前 APP 标识的字符串 token
1522381039.imyufei
段 | 说明 |
---|---|
1522381039 | 生成 token 数据时的时间戳 |
imyufei | 客户端唯一标识 |
我们在不使用 MD5 之前,那么文本操作就类似于
editor.putString("token","1522381039.imyufei"); editor.commit();
当这样明文保存肯定不好啊,大家都知道 token
是啥意思,大家都知道我是 imyufei
我们想要的就是保存这样的字符串 1522381039.a675bcb1d0d9461ce75eedf616255806
editor.putString("token","1522381039.a675bcb1d0d9461ce75eedf616255806"); editor.commit();
神,谁一眼就能看出这是啥啊,对吧
a675bcb1d0d9461ce75eedf616255806
这个字符串,就是用 MD5
生成的
MD5
首先要说明的是
MD5 不是加密算法,不是加密算法,不是加密算法
它只是一个哈希校验算法,通俗的解释就是一致性匹配算法
MD5 ( Message Digest Algorithm MD5) ,中文消息摘要算法第五版,是计算机安全领域广泛 使用的一种散列函数,用以提供消息的完整性保护
简单的说,就是它可以把一段非常长的文本,压缩哈希成一个只有 128
字节的数据,可用于防止中间传递人修改数据
举个例子,A 想要通过 B 肉身那一些文件给 C,但又怕 B 中间给调包了,于是他想出了先用 MD5
算法把文件内容摘要一下,然后通过电报把这个摘要的信息发给 C,同时通过 B 把文件带给 C 。 C 收到文件后,也用 MD5
把文件摘要一下,如果和 A 发过来的摘要文本一样,就说明 B 是好人,没有调包
MD5值唯一吗 ?
不唯一,一个原始数据只对应一个 MD5 值,但是一个 MD5 值可能对应多个原始数据
MD5 能破解吗?
MD5 不可逆,就是说没有对应的算法,无法从生成的 MD5 值逆向得到原始数据
但现在很多人都有庞大的彩虹库,保存了几亿甚至几十亿的 MD5 值,可以用于反向查询得到可能的原始数据
Java 中的 MD5
Java 如何使用 MD5
的文章网上一大堆,我们这里就不解释了,直接贴出常用的 MD5 帮助类
package cn.twle.android.common; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Helper { public static String get(String content) { try { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(content.getBytes()); return hexHash(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } private static String hexHash(MessageDigest digest) { StringBuilder builder = new StringBuilder(); for (byte b : digest.digest()) { builder.append(Integer.toHexString((b >> 4) & 0xf)); builder.append(Integer.toHexString(b & 0xf)); } return builder.toString(); } }
使用 MD5 对 SharedPreference 中的数据做签名
我们写一个 demo 来演示如何使用 MD5 对 SharedPreference 中的数据做签名
-
创建一个 空的 Android 项目
cn.twle.android.SDMD5
-
修改
activity_main.xml
添加两个TextView
和一个Button
<?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="请输入你的用户名" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/ms_username" android:text="imyufei" /> <Button android:id="@+id/btn_sign" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="生成 Token"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/ms_rs_md5" android:text="" /> </LinearLayout>
-
新建一个包
cn.twle.android.common
并创建 MD5 帮助类MD5Helper.java
package cn.twle.android.common; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Helper { public static String get(String content) { try { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(content.getBytes()); return hexHash(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } private static String hexHash(MessageDigest digest) { StringBuilder builder = new StringBuilder(); for (byte b : digest.digest()) { builder.append(Integer.toHexString((b >> 4) & 0xf)); builder.append(Integer.toHexString(b & 0xf)); } return builder.toString(); } }
-
然后在
MainActivity.java
目录下创建一个SharedPreferences
的帮助类SharedHelper.java
package cn.twle.android.sdmd5; import android.content.Context; import android.content.SharedPreferences; import java.util.HashMap; import java.util.Map; public class SharedHelper { private Context mContext; public SharedHelper() { } public SharedHelper(Context mContext) { this.mContext = mContext; } //定义一个保存数据的方法 public void save(String key, String value) { SharedPreferences sp = mContext.getSharedPreferences("ms_sp", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.putString(key,value); editor.commit(); } //定义一个读取 SP 文件的方法 public String read(String key ) { Map<String, String> data = new HashMap<String, String>(); SharedPreferences sp = mContext.getSharedPreferences("ms_sp", Context.MODE_PRIVATE); return sp.getString(key,""); } }
-
修改
MainActivity.java
给按钮添加点击事件package cn.twle.android.sdmd5; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import cn.twle.android.common.MD5Helper; public class MainActivity extends AppCompatActivity { TextView ms_rs_md5; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn_sign = (Button) findViewById(R.id.btn_sign); final TextView ms_username = findViewById(R.id.ms_username); ms_rs_md5 = findViewById(R.id.ms_rs_md5); btn_sign.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String username = ms_username.getText().toString(); String tm_now = String.valueOf(System.currentTimeMillis()); String token = MD5Helper.get(tm_now + "." + username); SharedHelper sh = new SharedHelper(MainActivity.this); sh.save("token",tm_now + "." + token); ms_rs_md5.setText(sh.read("token")); Toast.makeText(MainActivity.this, "信息已写入 SharedPreference 中", Toast.LENGTH_SHORT).show(); } }); } }
注意,这个时间戳时毫秒的,可以自己转成秒