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

原创粉丝点击