安全 加密解密

项目中的经验和用法

在实际开发中,不是太重要的数据用一种加密方式感觉就可以了。但是比较重要的数据建议用多种加密方式结合的方式,比如我用的RSA+AES加密。他主要解决了两个问题:

1.RSA加解密速度慢,不适合大量数据文件加密 
2.AES加密速度很快,但是安全性没有RSA加密方式的安全。

其主要思想就是服务端生成公钥私钥,并提供接口将公钥给android端,android端生成AES秘钥,并用AES秘钥对大量数据进行加密(解决RSA加解密速度慢的问题),然后用调用接口拿到的RSA公钥对自己生成AES秘钥进行加密,客户端将得到的秘钥和通过AES加密的数据发送给服务器。(秘钥可以放在请求头中,数据放在请求体中,这个随意了)。服务拿到你的秘钥和数据后,用私钥加密得到AES秘钥,再通过秘钥得到发送的数据就好了。

[详细请看](https://juejin.im/entry/59b09f4c5188251240635da3)

如果是Jetpack 框架的话就直接用,但是要求minSDK >=23

implementation ‘androidx.security:security-crypto:1.0.0-rc01’

String masterKeyAlias = null;
try {
    masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
} catch (GeneralSecurityException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
        "secret_shared_prefs",
        masterKeyAlias,
        context,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);

// use the shared preferences and editor as you normally would
SharedPreferences.Editor editor = sharedPreferences.edit();


editor.putString("key", "value").apply();// 存

editor.getString("key",null);//取

利用KeyStore来进行密码和token的加密解密

public class EncryUtils {
    static  EncryUtils encryUtilsInstance;
    KeyStore keyStore;
    public static EncryUtils getInstance() {
        synchronized (EncryUtils.class) {
            if (null == encryUtilsInstance) {
                encryUtilsInstance = new EncryUtils();
            }
        }
        return encryUtilsInstance;
    }

    private EncryUtils() {
    }

    private void initKeyStore(String alias){
        try {
            keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            createNewKeys(alias);
        }
    }
    private void  createNewKeys(String alias){
        if(!"".equals(alias)){
            try {
                // Create new key if needed
                if (!keyStore.containsAlias(alias)) {
                    Calendar start = Calendar.getInstance();
                    Calendar end = Calendar.getInstance();
                    end.add(Calendar.YEAR, 1);
                    KeyPairGeneratorSpec spec = null;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        spec = new KeyPairGeneratorSpec.Builder(Application.getApplication())
                                .setAlias(alias)
                                .setSubject(new X500Principal("CN=Sample Name, O=Android Authority"))
                                .setSerialNumber(BigInteger.ONE)
                                .setStartDate(start.getTime())
                                .setEndDate(end.getTime())
                                .build();
                    }
                    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        generator.initialize(spec);
                    }

                    KeyPair keyPair = generator.generateKeyPair();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


    }


    /**
     * 加密方法
     * @param needEncryptWord 需要加密的字符串
     * @param alias 加密秘钥
     * @return
     */
    public String encryptString(String needEncryptWord, String alias) {
        if(!"".equals(alias)&&!"".equals(needEncryptWord)){
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                initKeyStore(alias);
            }
            String encryptStr="";
            byte [] vals=null;
            try {
                KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
//            RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();
                if(needEncryptWord.isEmpty()) {
//                Toast.makeText(this, "Enter text in the 'Initial Text' widget", Toast.LENGTH_LONG).show();
                    return encryptStr;
                }


                Cipher inCipher;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                     inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
                }else {
                    //若加密慢则改用上面的代码
                    inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
                }
//            inCipher.init(Cipher.ENCRYPT_MODE, publicKey);
                inCipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry.getCertificate().getPublicKey());

                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                CipherOutputStream cipherOutputStream = new CipherOutputStream(
                        outputStream, inCipher);
                cipherOutputStream.write(needEncryptWord.getBytes("UTF-8"));
                cipherOutputStream.close();

                vals = outputStream.toByteArray();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return Base64.encodeToString(vals, Base64.DEFAULT);
        }
        return "";
    }


    public String decryptString(String needDecryptWord, String alias) {
        if(!"".equals(alias)&&!"".equals(needDecryptWord)){
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                initKeyStore(alias);
            }
            String decryptStr="";
            try {
                KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
//            RSAPrivateKey privateKey = (RSAPrivateKey) privateKeyEntry.getPrivateKey();

//            Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
                Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding");
//            output.init(Cipher.DECRYPT_MODE, privateKey);
                output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
                CipherInputStream cipherInputStream = new CipherInputStream(
                        new ByteArrayInputStream(Base64.decode(needDecryptWord, Base64.DEFAULT)), 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).byteValue();
                }

                decryptStr = new String(bytes, 0, bytes.length, "UTF-8");
            } catch (Exception e) {
                e.printStackTrace();
            }
            return  decryptStr;
        }
        return "";
    }
}
Loading Disqus comments...
Table of Contents