KeyStore存储密钥

1.KeyStore简介:

Keytool:
一个Java数据证书的管理工具,Keytool将密钥(key)和证书(certificates)存在一个称为keystore的文件中

keystore
可以理解为一个容器,它里面存储了:
1.可以存储对称密钥实体,或者密钥对的公钥和私钥
2.可信任的证书,只包含公钥

使用keytool命令或者AndroidStudio自带工具都可以生成我们自己的KeyStore,这里略

2.生成签名APK时需要一个KeyStore文件:

在通过AndroidStudio–>Build–>Generate Signed APK生成一个带签名的APK时,会要求输入一个key store path:在这里插入图片描述
选择创建新的KeyStore,并填入新建KeyStore的名字,密码,以及开发者认证信息(国家,组织等)就可以创建一个自己的KeyStore,打包带签名的APK时,这个KeyStore中的信息会被一起封到APK中,所以每个带有签名的App中,都会有一个开发者为之创建的KeyStore,其他的App无法访问这个KeyStore,所以利用这个KeyStore可以存储一些密钥在里面。

3.Keystore做AES加密例:

通过ailas和password可以唯一地关联一个KeyStore文件,这个alias通常不区分大小写

public class EncryptTool {
    private static final String alias = "AndroidKeyStore";
	KeyStore keyStore;

 	public void initKeyStore() throws Exception {
        keyStore = KeyStore.getInstance("AndroidKeyStore");
        keyStore.load(null);
    }
    
    public static byte[] encrypt(String password) throws Exception {
		//初始化一个使用AES加密的密钥生成器
        final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
        //配置参数
        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
        
        } else {
        	//这里生成密钥的参数中设置了alias,生成密钥的时候会自动将这个密钥保存在KeyStore中
        	final KeyGenParameterSpec keyGenParameterSpec =
                new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                        .build();
        	//用参数初始化密钥生成器
        	keyGenerator.init(keyGenParameterSpec);
        }
        //用密钥生成器产生密钥
        final SecretKey secretKey = keyGenerator.generateKey();
        //构造密码
        final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        //获取默认的initialization vector (IV),解密需要这个iv
        //这个iv也可以手动生成一个随机数,并设置给
        iv = cipher.getIV();
        byte[] encryption = cipher.doFinal(password.getBytes("UTF-8"));
        //加密完成,产生一个字节数组
        return encryption;
    }

    public static String decrypt(byte[] data) throws Exception {
        initKeyStore();
        //从keystore中获取密钥Entry
        final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore.getEntry(alias, null);
        //从entry中获取AES密钥
        final SecretKey secretKey = secretKeyEntry.getSecretKey();
        final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        final GCMParameterSpec spec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
        final byte[] decodedData = cipher.doFinal(data);
        return new String(decodedData, "UTF-8");
    }
}
4.Keystore做RSA加密例:
public class KeyStoreTool {
    private static volatile KeyStoreTool sInstance = new KeyStoreTool();

    private static final String PROVIDER_NAME = "AndroidKeyStore";
    private static final String ALGORITHM = "RSA";
    private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding";

    private KeyStore keyStore;

	//获取AndroidKeyStore类型的KeyStore
    public KeyStoreTool() {
        try {
            keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
	//用alias创建一个新的密钥对
    private void createNewRSAKeyPair(Context context, @NonNull String keyAlias) throw Exception {
          if (!keyStore.containsAlias(keyAlias)) {
            	Calendar start = Calendar.getInstance();
            	Calendar end = Calendar.getInstance();
            	end.add(Calendar.YEAR, 30);

            	AlgorithmParameterSpec spec;

            	if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                	spec = new KeyPairGeneratorSpec.Builder(context.getApplicationContext())
                		//生成密钥的参数中设置了alias,生成密钥的时候会自动将这个密钥保存在KeyStore中
                        .setAlias(keyAlias)		
                        .setSerialNumber(BigInteger.ONE)
                        .setStartDate(start.getTime())
                        .setEndDate(end.getTime())
                        .build();
            	} else {
                	spec = new KeyGenParameterSpec.Builder(keyAlias,KeyProperties.PURPOSE_ENCRYPT| KeyProperties.PURPOSE_DECRYPT)
                        .setDigests(KeyProperties.DIGEST_SHA256)
                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                        .setCertificateSerialNumber(BigInteger.ONE)
                        .setCertificateNotBefore(start.getTime())
                        .setCertificateNotAfter(end.getTime())
                        .build();
            	}
            	KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM, PROVIDER_NAME);
            	generator.initialize(spec);
            	generator.generateKeyPair();
        }
    }
    
	//获取alias对应的密钥对中的私钥
    private KeyStore.PrivateKeyEntry getPrivateKey(@NonNull String keyAlias) throws Exception {
        keyStore.load(null);
        KeyStore.Entry entry = keyStore.getEntry(keyAlias, null);
        return (KeyStore.PrivateKeyEntry) entry;
    }
	
	//用alias对应的密钥加密字节数组
    public byte[] encrypt(@NonNull byte[] data, @NonNull String keyAlias) throws Exception {

        KeyStore.PrivateKeyEntry privateKeyEntry = getPrivateKey(keyAlias);
        final Cipher inCipher = Cipher.getInstance(TRANSFORMATION);
        inCipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry.getCertificate().getPublicKey());

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, inCipher);
        cipherOutputStream.write(data);
        cipherOutputStream.close();
        return outputStream.toByteArray();

    }
	//用alias对应的密钥加密一个String
    public String encryptString(@NonNull String plainText, @NonNull String keyAlias) throws Exception {
        if (!TextUtils.isEmpty(plainText) && !TextUtils.isEmpty(keyAlias)) {
            byte[] encrypted = encrypt(plainText.getBytes(), keyAlias);

            if (encrypted != null) {
                return Base64.encodeToString(encrypted, Base64.DEFAULT);
            }
        }
        return "";
    }

    public byte[] decrypt(@NonNull byte[] data, @NonNull String keyAlias) throws Exception {
        KeyStore.PrivateKeyEntry privateKeyEntry = getPrivateKey(keyAlias);
        Cipher output = Cipher.getInstance(TRANSFORMATION);
        output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
        CipherInputStream cipherInputStream =new CipherInputStream(new ByteArrayInputStream(data), output);
        ArrayList<Byte> values = new ArrayList<>();
        int nextByte;
        while ((nextByte = cipherInputStream.read()) != -1) {
            values.add((byte) nextByte);
        }
        byte[] bytes = new byte[values.size()];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = values.get(i);
        }
        return bytes;
    }
    
	//用alias对应的密钥解密字符串
    public String decryptString(@NonNull String secureText, @NonNull String keyAlias) throws Exception{
        if (!TextUtils.isEmpty(secureText) && !TextUtils.isEmpty(keyAlias)) {
            byte[] encrypted = Base64.decode(secureText, Base64.DEFAULT);
            byte[] raw = decrypt(encrypted, keyAlias);
            if (raw != null) {
                return new String(raw, 0, raw.length);
            }
        }
        return "";
    }
}

可以看到使用KeyStore管理密钥和用普通方式处理加密使用的基本类型都差不多,只是用keystore管理需要一个alias,添加了alias的密钥创建时会自动保存在KeyStore中,已创建AES密钥为例:

生成AES密钥的过程:

	final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
	KeyGenParameterSpec keyGenParameterSpec = ...
	keyGenerator.init(keyGenParameterSpec);
	final SecretKey secretKey = keyGenerator.generateKey();

密钥参数可以配置keystoreAlias

public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs {
	private final String mKeystoreAlias;
}

KeyGenerator通过KeyGeneratorSpi生成密钥:

public class KeyGenerator {
	private volatile KeyGeneratorSpi spi;
	
	public final SecretKey generateKey() {
		...
		return spi.engineGenerateKey();
	}
}

对于AES加密,它的KeyGeneratorSpi是一个AndroidKeyStoreKeyGeneratorSpi对象:

public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
	private final KeyStore mKeyStore = KeyStore.getInstance();
	private KeyGenParameterSpec mSpec;
	protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) {
		mSpec = spec;
	}
	//KeyStore保存了keyAliasInKeystore
	protected SecretKey engineGenerateKey() {
		String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + spec.getKeystoreAlias();
		int errorCode = mKeyStore.generateKey(keyAliasInKeystore,...);
		...
		return new AndroidKeyStoreSecretKey(keyAliasInKeystore, spec.getUid(), keyAlgorithmJCA);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值