国密SM3是一种由中国国家密码局发布的加密哈希函数,是国家标准 GB/T 32918.1-2016《信息安全技术 公钥基础设施 公钥密码算法 第1部分:SM3密码杂凑算法》规定的加密算法。SM3基于SHA-256算法改进而成,是一种哈希函数,常用于文件摘要、签名验证、消息认证码等方面的安全性要求较高的场合。
相较于其他哈希函数,SM3具有一些优势,包括以下几点:
-
速度快:SM3算法速度较快,在当前主流平台上计算速度快于SHA-256;
-
安全性强:目前尚未发现明显的漏洞,具备良好的安全性;
-
支持国产芯片加速:很多国产芯片支持SM3加速功能,可以进一步提高计算速度。
基于BC库,在Android上实现SM3
实现效果
工具类
/**
* @description: SM3工具类
* @Time 2023/8/14 9:11
* @Author gz
*/
public class SM3Util {
private static String TAG = SM3Util.class.getSimpleName();
static {
double version = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME).getVersion();
Log.i(TAG, "generateKey1: " + version);
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Log.i(TAG, "运行环境没有BouncyCastleProvider");
Security.addProvider(new BouncyCastleProvider());
}
version = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME).getVersion();
Log.i(TAG, "generateKey2: " + version);
}
/**
* sm3算法加密
*
* @param paramStr 待加密字符串
* @return 返回加密后,固定长度=32的16进制字符串
* @explain
*/
public static byte[] encrypt(String paramStr) {
byte[] resultHash = new byte[0];
try {
// 将字符串转换成byte数组
byte[] srcData = paramStr.getBytes(ENCODING);
// 调用hash()
resultHash = hash(srcData);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return resultHash;
}
/**
* 返回长度=32的byte数组
*
* @param srcData
* @return
* @explain 生成对应的hash值
*/
public static byte[] hash(byte[] srcData) {
SM3Digest digest = new SM3Digest();
digest.update(srcData, 0, srcData.length);
byte[] hash = new byte[digest.getDigestSize()];
digest.doFinal(hash, 0);
return hash;
}
/**
* sm3算法加密
*
* @param paramStr 待加密字符串
* @param key 密钥
* @return 返回加密后,固定长度=32的16进制字符串
* @explain
*/
public static byte[] encryptByKey(String paramStr, String key) {
// 将返回的hash值转换成16进制字符串
byte[] resultHash = new byte[0];
try {
// 将字符串转换成byte数组
byte[] srcData = paramStr.getBytes(ENCODING);
// 调用hash()
resultHash = hashMac(srcData, key.getBytes(ENCODING));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return resultHash;
}
/**
* 通过密钥进行加密
*
* @param key 密钥
* @param srcData 被加密的byte数组
* @return
* @explain 指定密钥进行加密
*/
public static byte[] hashMac(byte[] key, byte[] srcData) {
KeyParameter keyParameter = new KeyParameter(key);
SM3Digest digest = new SM3Digest();
HMac mac = new HMac(digest);
mac.init(keyParameter);
mac.update(srcData, 0, srcData.length);
byte[] result = new byte[mac.getMacSize()];
mac.doFinal(result, 0);
return result;
}
/**
* 判断源数据与加密数据是否一致
*
* @param srcStr 原字符串
* @param sm3HexString 16进制字符串
* @return 校验结果
* @explain 通过验证原数组和生成的hash数组是否为同一数组,验证2者是否为同一数据
*/
public static boolean verify(String srcStr, String sm3HexString) {
boolean flag = false;
try {
byte[] srcData = srcStr.getBytes(ENCODING);
// byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString);
byte[] sm3Hash = Hex.decode(sm3HexString);
byte[] newHash = hash(srcData);
if (Arrays.equals(newHash, sm3Hash))
flag = true;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return flag;
}
/**
* 有密钥的加密,判断源数据与加密数据是否一致
*
* @param srcStr 原字符串
* @param sm3HexString 16进制字符串
* @param key 用户自定义密钥
* @return 校验结果
* @explain 通过验证原数组和生成的hash数组是否为同一数组,验证2者是否为同一数据
*/
public static boolean verifyByKey(String srcStr, String sm3HexString, String key) {
boolean flag = false;
try {
byte[] srcData = srcStr.getBytes(ENCODING);
// byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString);
byte[] sm3Hash = Hex.decode(sm3HexString);
byte[] newHash = hashMac(srcData, key.getBytes(ENCODING));
if (Arrays.equals(newHash, sm3Hash))
flag = true;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return flag;
}
}
工具类调用
public void onClick(View v) {
switch (v.getId()) {
case R.id.cal_sm3:
content = mBinding.inputText.getText().toString();
if (TextUtils.isEmpty(content)) {
Toast.makeText(this, "请输入要计算的内容", Toast.LENGTH_SHORT).show();
break;
}
byte[] bytes = SM3Util.encrypt(content);
// hexResult = ByteUtils.toHexString(bytes);
hexResult = Hex.toHexString(bytes);
result = CommonUtils.changeFormat(bytes);
Log.e(TAG, "onClick2: " + result);
viewModel.createResult.set(hexResult);
break;
case R.id.verify_result:
String str = mBinding.calSm3Result.getText().toString();
if (TextUtils.isEmpty(str)) {
Toast.makeText(this, "请先计算", Toast.LENGTH_SHORT).show();
break;
}
boolean result = SM3Util.verify(content, str);
viewModel.verifyResult.set("验证结果:\n" + result);
Log.e(TAG, "result: " + result);
break;
case R.id.cal_sm3_key:
key = mBinding.inputKey.getText().toString();
if (TextUtils.isEmpty(key)) {
Toast.makeText(this, "请先输入密钥", Toast.LENGTH_SHORT).show();
break;
}
byte[] bytes2 = SM3Util.encryptByKey(content, key);
// hexResultKey = ByteUtils.toHexString(bytes2);
hexResultKey = Hex.toHexString(bytes2);
resultKey = CommonUtils.changeFormat(bytes2);
Log.e(TAG, "onClick: " + resultKey);
viewModel.createKeyResult.set(hexResultKey);
break;
case R.id.verify_key_result:
String str2 = mBinding.calSm3KeyResult.getText().toString();
if (TextUtils.isEmpty(str2)) {
Toast.makeText(this, "请先计算", Toast.LENGTH_SHORT).show();
break;
}
boolean resultKey = SM3Util.verifyByKey(content, str2, key);
viewModel.verifyKeyResult.set("验证结果:\n" + resultKey);
Log.e(TAG, "result: " + resultKey);
break;
}
}
```
```