Android: AndroidKeyStore 对数据进行签名和验证
来源:互联网 发布:函数式编程 好书 编辑:程序博客网 时间:2024/06/10 21:22
采用的是RSA加密方式进行签名和验证,同时把密钥放在AndroidKeyStore中,增加安全系数。
效果如下:
- 生成RSA秘钥工具类:KeyStoneUtils
package tsou.com.encryption.androidkeystoresign;import android.content.Context;import android.os.Build;import android.security.KeyPairGeneratorSpec;import android.security.keystore.KeyGenParameterSpec;import android.security.keystore.KeyProperties;import android.support.annotation.RequiresApi;import android.util.Base64;import android.util.Log;import java.io.IOException;import java.math.BigInteger;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.KeyStore;import java.security.KeyStoreException;import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException;import java.security.Signature;import java.security.SignatureException;import java.security.UnrecoverableEntryException;import java.security.cert.CertificateException;import java.security.spec.AlgorithmParameterSpec;import java.util.Calendar;import java.util.GregorianCalendar;import javax.security.auth.x500.X500Principal;/** * Created by Administrator on 2017/10/10 0010. */public class KeyStoneUtils { /** * 自己给你的别名,方便在keystore中查找秘钥 */ public static final String SAMPLE_ALIAS = "xiaoGuoKey"; /** * 自己给你的别名 就是SAMPLE_ALIAS */ private static String mAlias = null; public static void setAlias(String alias) { mAlias = alias; } /** * 创建一个公共和私人密钥,并将其存储使用Android密钥存储库中,因此,只有 * 这个应用程序将能够访问键。 * * @param context * @throws InvalidAlgorithmParameterException * @throws NoSuchProviderException * @throws NoSuchAlgorithmException */ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) public static void createKeys(Context context) throws InvalidAlgorithmParameterException, NoSuchProviderException, NoSuchAlgorithmException { setAlias(SAMPLE_ALIAS); //创建一个开始和结束时间,有效范围内的密钥对才会生成。 Calendar start = new GregorianCalendar(); Calendar end = new GregorianCalendar(); end.add(Calendar.YEAR, 1);//往后加一年 AlgorithmParameterSpec spec; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { //使用别名来检索的key 。这是一个key 的key ! spec = new KeyPairGeneratorSpec.Builder(context) //使用别名来检索的关键。这是一个关键的关键! .setAlias(mAlias) // 用于生成自签名证书的主题 X500Principal 接受 RFC 1779/2253的专有名词 .setSubject(new X500Principal("CN=" + mAlias)) //用于自签名证书的序列号生成的一对。 .setSerialNumber(BigInteger.valueOf(1337)) // 签名在有效日期范围内 .setStartDate(start.getTime()) .setEndDate(end.getTime()) .build(); } else { //Android 6.0(或者以上)使用KeyGenparameterSpec.Builder 方式来创建, // 允许你自定义允许的的关键属性和限制// String AES_MODE_CBC = KeyProperties.KEY_ALGORITHM_AES + "/" +// KeyProperties.BLOCK_MODE_CBC + "/" +// KeyProperties.ENCRYPTION_PADDING_PKCS7; spec = new KeyGenParameterSpec.Builder(mAlias, KeyProperties.PURPOSE_SIGN) .setCertificateSubject(new X500Principal("CN=" + mAlias)) .setDigests(KeyProperties.DIGEST_SHA256) .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) .setBlockModes(KeyProperties.BLOCK_MODE_GCM, KeyProperties.BLOCK_MODE_CTR, KeyProperties.BLOCK_MODE_CBC, KeyProperties.BLOCK_MODE_ECB)// .setBlockModes(KeyProperties.BLOCK_MODE_GCM/CTR/CBC/ECB) .setCertificateSerialNumber(BigInteger.valueOf(1337)) .setCertificateNotBefore(start.getTime()) .setCertificateNotAfter(end.getTime()) .build(); } KeyPairGenerator kpGenerator = KeyPairGenerator .getInstance(SecurityConstants.TYPE_RSA, SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE); kpGenerator.initialize(spec); KeyPair kp = kpGenerator.generateKeyPair(); Log.d("huangxiaoguo", "公共密钥: " + kp.getPublic().toString()); Log.d("huangxiaoguo", "私钥: " + kp.getPrivate().toString()); } /** * 签名 * * @param inputStr * @return * @throws KeyStoreException * @throws CertificateException * @throws NoSuchAlgorithmException * @throws IOException * @throws UnrecoverableEntryException * @throws InvalidKeyException * @throws SignatureException */ public static String signData(String inputStr) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableEntryException, InvalidKeyException, SignatureException { byte[] data = inputStr.getBytes(); //AndroidKeyStore KeyStore ks = KeyStore.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE); // 如果你没有InputStream加载,你仍然需要 //称之为“负载”,或者它会崩溃 ks.load(null); if (mAlias == null) { setAlias(SAMPLE_ALIAS); } //从Android加载密钥对密钥存储库中 KeyStore.Entry entry = ks.getEntry(mAlias, null); /* * *进行判断处理钥匙是不是存储的当前别名下 不存在要遍历别名列表Keystore.aliases() */ if (entry == null) { Log.w("huangxiaoguo", "No key found under alias: " + mAlias); Log.w("huangxiaoguo", "Exiting signData()..."); return null; } if (!(entry instanceof KeyStore.PrivateKeyEntry)) { Log.w("huangxiaoguo", "Not an instance of a PrivateKeyEntry"); Log.w("huangxiaoguo", "Exiting signData()..."); return null; } // 开始签名 Signature s = Signature.getInstance(SecurityConstants.SIGNATURE_SHA256withRSA); //初始化使用指定的私钥签名 s.initSign(((KeyStore.PrivateKeyEntry) entry).getPrivateKey()); // 签名并存储结果作为Base64编码的字符串。 s.update(data); byte[] signature = s.sign(); String result = Base64.encodeToString(signature, Base64.DEFAULT); return result; } /** * 校验签名的字符串 * * @param input * @param signatureStr * @return * @throws KeyStoreException * @throws CertificateException * @throws NoSuchAlgorithmException * @throws IOException * @throws UnrecoverableEntryException * @throws InvalidKeyException * @throws SignatureException */ public static boolean verifyData(String input, String signatureStr) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableEntryException, InvalidKeyException, SignatureException { //要验证的数据 byte[] data = input.getBytes(); //签名 byte[] signature; //判断签名是否存在 if (signatureStr == null) { Log.w("huangxiaoguo", "Invalid signature."); Log.w("huangxiaoguo", "Exiting verifyData()..."); return false; } try { //Base64解码字符串 signature = Base64.decode(signatureStr, Base64.DEFAULT); } catch (IllegalArgumentException e) { return false; } KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); // Load the key pair from the Android Key Store if (mAlias == null) { setAlias(SAMPLE_ALIAS); } //从Android加载密钥对密钥存储库中 KeyStore.Entry entry = ks.getEntry(mAlias, null); if (entry == null) { Log.w("huangxiaoguo", "No key found under alias: " + mAlias); Log.w("huangxiaoguo", "Exiting verifyData()..."); return false; } if (!(entry instanceof KeyStore.PrivateKeyEntry)) { Log.w("huangxiaoguo", "Not an instance of a PrivateKeyEntry"); return false; } Signature s = Signature.getInstance(SecurityConstants.SIGNATURE_SHA256withRSA); // 开始校验签名 s.initVerify(((KeyStore.PrivateKeyEntry) entry).getCertificate()); s.update(data); boolean valid = s.verify(signature); return valid;//true 签名一致 } /** * 判断是否创建过秘钥 * * @return * @throws KeyStoreException * @throws CertificateException * @throws NoSuchAlgorithmException * @throws IOException * @throws UnrecoverableEntryException */ public static boolean isHaveKeyStore() { try { KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); if (mAlias == null) { setAlias(SAMPLE_ALIAS); } // Load the key pair from the Android Key Store //从Android加载密钥对密钥存储库中 KeyStore.Entry entry = ks.getEntry(mAlias, null); if (entry == null) { return false; } } catch (KeyStoreException e) { e.printStackTrace(); return false; } catch (CertificateException e) { e.printStackTrace(); return false; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return false; } catch (IOException e) { e.printStackTrace(); return false; } catch (UnrecoverableEntryException e) { e.printStackTrace(); return false; } return true; }}
package tsou.com.encryption.androidkeystoresign;public class SecurityConstants { public static final String KEYSTORE_PROVIDER_ANDROID_KEYSTORE = "AndroidKeyStore"; public static final String TYPE_RSA = "RSA"; public static final String TYPE_DSA = "DSA"; public static final String TYPE_BKS = "BKS"; public static final String SIGNATURE_SHA256withRSA = "SHA256withRSA"; public static final String SIGNATURE_SHA512withRSA = "SHA512withRSA";}
- 执行操作
package tsou.com.encryption.activity.AndroidKeyStore;import android.app.Activity;import android.content.Context;import android.os.Build;import android.os.Bundle;import android.support.annotation.RequiresApi;import android.support.v7.app.AppCompatActivity;import android.text.TextUtils;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import java.io.IOException;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.KeyStoreException;import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException;import java.security.SignatureException;import java.security.UnrecoverableEntryException;import java.security.cert.CertificateException;import tsou.com.encryption.R;import tsou.com.encryption.aescbc.Base64Encoder;import tsou.com.encryption.androidkeystoresign.KeyStoneUtils;/** * Android AndroidKeyStore 对数据进行签名和验证 */public class AndroidKeyStoreActivity extends AppCompatActivity implements View.OnClickListener { private EditText encryptionContext; private Button encryption; private TextView tvEncryption; private Button decode; private TextView tvDecode; private Activity mActivity; private Context mContext; private Button encryptionNotFixed; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_or); mActivity = this; mContext = this; encryptionContext = (EditText) findViewById(R.id.et_encryption_context); encryption = (Button) findViewById(R.id.btn_encryption); encryptionNotFixed = (Button) findViewById(R.id.btn_encryption_not_fixed); tvEncryption = (TextView) findViewById(R.id.tv_encryption); decode = (Button) findViewById(R.id.btn_decode); tvDecode = (TextView) findViewById(R.id.tv_decode); encryption.setText("创建Key"); encryptionNotFixed.setText("签名"); decode.setText("验证"); initListener(); } private void initListener() { encryption.setOnClickListener(this); encryptionNotFixed.setOnClickListener(this); decode.setOnClickListener(this); } private String mSignatureStr = null; @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @Override public void onClick(View view) { switch (view.getId()) { /** * 在应用安装后第一次运行时,生成一个随机密钥,并存入 KeyStore 当你想存储一个数据,便从 KeyStore 中取出之前生成的随机密钥,对你的数据进行加密, 加密完成后,已完成加密的数据可以随意存储在任意地方,比如 SharePreferences, 此时即使它被他人读取到,也无法解密出你的原数据,因为他人取不到你的密钥 当你需要拿到你的原数据,只需要从 SharePreferences 中读取你加密后的数据, 并从 KeyStore 取出加密密钥,使用加密密钥对 “加密后的数据” 进行解密即可 */ case R.id.btn_encryption://创建Key,在项目中放在application或启动页中 if (KeyStoneUtils.isHaveKeyStore()) {//是否有秘钥 Toast.makeText(mContext, "已经创建过秘钥", Toast.LENGTH_SHORT).show(); return; } try { KeyStoneUtils.createKeys(mContext); Toast.makeText(mContext, "秘钥创建成功", Toast.LENGTH_SHORT).show(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); Toast.makeText(mContext, "不支持RSA", Toast.LENGTH_SHORT).show(); } catch (NoSuchProviderException e) { e.printStackTrace(); Toast.makeText(mContext, "没有提供:AndroidKeyStore", Toast.LENGTH_SHORT).show(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); Toast.makeText(mContext, "无效的算法参数异常", Toast.LENGTH_SHORT).show(); } break; case R.id.btn_encryption_not_fixed://签名 String encryptionString = encryptionContext.getText().toString().trim(); if (TextUtils.isEmpty(encryptionString)) { Toast.makeText(mContext, "请输入签名内容", Toast.LENGTH_SHORT).show(); return; } if (!KeyStoneUtils.isHaveKeyStore()) {//是否有秘钥 Toast.makeText(mContext, "没有生成秘钥对,请先创建key", Toast.LENGTH_SHORT).show(); return; } try { mSignatureStr = KeyStoneUtils.signData(encryptionString); tvEncryption.setText(Base64Encoder.encode(mSignatureStr)); } catch (KeyStoreException e) { e.printStackTrace(); Toast.makeText(mContext, "密钥存储库没有初始化,可能没有生成秘钥对", Toast.LENGTH_SHORT).show(); } catch (CertificateException e) { e.printStackTrace(); Toast.makeText(mContext, "加载证书时发生错误", Toast.LENGTH_SHORT).show(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); Toast.makeText(mContext, "不支持RSA", Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(mContext, "IO Exception", Toast.LENGTH_SHORT).show(); } catch (UnrecoverableEntryException e) { e.printStackTrace(); Toast.makeText(mContext, "密钥对没有恢复", Toast.LENGTH_SHORT).show(); } catch (InvalidKeyException e) { e.printStackTrace(); Toast.makeText(mContext, "无效的key", Toast.LENGTH_SHORT).show(); } catch (SignatureException e) { e.printStackTrace(); Toast.makeText(mContext, "无效的签名", Toast.LENGTH_SHORT).show(); } break; case R.id.btn_decode://验证 String encryptionverifyString = encryptionContext.getText().toString().trim(); if (TextUtils.isEmpty(encryptionverifyString)) { Toast.makeText(mContext, "请输入验证内容", Toast.LENGTH_SHORT).show(); return; } if (TextUtils.isEmpty(mSignatureStr)) { Toast.makeText(mContext, "请先签名", Toast.LENGTH_SHORT).show(); return; } try { boolean b = KeyStoneUtils.verifyData(encryptionverifyString, mSignatureStr); if (b) { tvDecode.setText("签名一致"); } else { tvDecode.setText("签名不一致"); } } catch (KeyStoreException e) { e.printStackTrace(); Toast.makeText(mContext, "密钥存储库没有初始化,可能没有生成秘钥对", Toast.LENGTH_SHORT).show(); } catch (CertificateException e) { e.printStackTrace(); Toast.makeText(mContext, "加载证书时发生错误", Toast.LENGTH_SHORT).show(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); Toast.makeText(mContext, "不支持RSA", Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(mContext, "IO Exception", Toast.LENGTH_SHORT).show(); } catch (UnrecoverableEntryException e) { e.printStackTrace(); Toast.makeText(mContext, "密钥对没有恢复", Toast.LENGTH_SHORT).show(); } catch (InvalidKeyException e) { e.printStackTrace(); Toast.makeText(mContext, "无效的key", Toast.LENGTH_SHORT).show(); } catch (SignatureException e) { e.printStackTrace(); Toast.makeText(mContext, "无效的签名", Toast.LENGTH_SHORT).show(); } break; } }}
更多加密方式DEMO请查看:https://gitee.com/huangxiaoguo/androidGeZhongJiaMiZongJie
更多加密方式博文请查看:http://blog.csdn.net/huangxiaoguo1/article/details/78043354
阅读全文
0 0
- Android: AndroidKeyStore 对数据进行签名和验证
- Android本地数据AES加密,使用AndroidKeyStore
- 使用 Apache WSS4J 和 WebSphere DataPower SOA Appliances 对 XML 文档进行签名和验证
- Android 对APK进行系统签名
- Android实践 -- 对apk进行系统签名
- 如何对Android应用进行签名
- 对 Android 应用程序包进行签名
- Android 用signkey.jks签名文件对 Apk 进行签名
- .NET中使用数字证书用RSA算法对数据进行加密和签名
- Java中使用RSA对请求和接收数据进行签名校验
- 如何对应用进行Android系统签名和常用adb命令总结
- 写接口时,对数据进行验证
- 写接口时,对数据进行验证
- 对apk进行签名
- 对空包进行签名
- 如何使用USB Key中的证书对数据进行签名
- 自学Android历程->对Android应用APK包进行签名
- 无法对jar进行签名,Android jarsigner问题
- HTML和CSS的相同效果之处
- 初涉CSDN
- iOS百度推送上传pem证书提示‘证书无效’
- 应堆栈、内存和寄存器变化,
- javascript查看浏览器
- Android: AndroidKeyStore 对数据进行签名和验证
- 航线规划(离线+路径压缩)
- View 用 Paint 实现的小Demo(2)
- Java 并发 --- 阻塞队列之ArrayBlockingQueue源码分析
- dijkstra算法
- SDR用途简介
- Qt 文本文件的打开、新建、保存以及另存为
- Android 8.0 Oreo 推送通知的变化
- Android 支持库 v26 有哪些变化?