From 8261c7af250ba0a2b09075ee12dee1412bf3b634 Mon Sep 17 00:00:00 2001 From: Ztiany Date: Tue, 3 Dec 2019 20:10:27 +0800 Subject: [PATCH] optimize security utils --- .../android/base/utils/security/AESUtils.java | 20 ++- .../android/base/utils/security/RSAUtils.java | 115 +++++++++++++----- .../base/utils/security/SimpleRsa.java | 100 --------------- 3 files changed, 103 insertions(+), 132 deletions(-) delete mode 100644 lib_base/src/main/java/com/android/base/utils/security/SimpleRsa.java diff --git a/lib_base/src/main/java/com/android/base/utils/security/AESUtils.java b/lib_base/src/main/java/com/android/base/utils/security/AESUtils.java index 1d7ac61..a3c0dbb 100644 --- a/lib_base/src/main/java/com/android/base/utils/security/AESUtils.java +++ b/lib_base/src/main/java/com/android/base/utils/security/AESUtils.java @@ -1,5 +1,7 @@ package com.android.base.utils.security; +import android.util.Base64; + import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; @@ -12,7 +14,7 @@ import androidx.annotation.Nullable; @SuppressWarnings("unused") public class AESUtils { - //算法/模式/填充 + //算法/加密模式/填充模式 public static String AES = "AES"; public static String AES_CBC_ISO10126PADDING = "AES/CBC/ISO10126Padding"; public static String AES_CBC_NOPADDING = "AES/CBC/NoPadding"; @@ -69,4 +71,20 @@ public class AESUtils { return null; } + /** + * @param content base64 编码的密文 + */ + @Nullable + public static byte[] decryptData(String content, String algorithm, String password) { + try { + SecretKeySpec key = generateAESKey(algorithm, password); + Cipher cipher = Cipher.getInstance(algorithm); + cipher.init(Cipher.DECRYPT_MODE, key); + return cipher.doFinal(Base64.decode(content, Base64.DEFAULT)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + } \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/security/RSAUtils.java b/lib_base/src/main/java/com/android/base/utils/security/RSAUtils.java index e1776e9..5a0367a 100644 --- a/lib_base/src/main/java/com/android/base/utils/security/RSAUtils.java +++ b/lib_base/src/main/java/com/android/base/utils/security/RSAUtils.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -22,46 +23,47 @@ import javax.crypto.Cipher; import androidx.annotation.Nullable; +/** + * @see cryptography-changes-in-android-p.html + * @see Android使用RSA加密和解密cryptography-changes-in-android-p.html + * @see rsa-encryption-decryption-in-android/12474193 + * @see secure-data-in-android-encrypting-large-data-dda256a55b36 + */ @SuppressWarnings("WeakerAccess,unused") public final class RSAUtils { private final static String KEY_PAIR = "RSA"; - private final static String CIPHER = "RSA/ECB/PKCS1Padding"; /** - * 随机生成RSA密钥对(默认密钥长度为1024) + * 默认 */ - public static KeyPair generateRSAKeyPair() { - return generateRSAKeyPair(1024); - } + public static final String TRANSFORMATION_DEFAULT = KEY_PAIR; /** - * 随机生成RSA密钥对 - * - * @param keyLength 密钥长度,范围:512~2048,一般1024 + * JDK标准 */ - public static KeyPair generateRSAKeyPair(int keyLength) { - try { - KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_PAIR); - kpg.initialize(keyLength); - return kpg.genKeyPair(); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - return null; - } - } + public static final String TRANSFORMATION_ECB_PKCS1PADDING = "RSA/ECB/PKCS1Padding"; /** - * 用公钥加密,每次加密的字节数,不能超过密钥的长度值减去11 + * Android标准 + */ + public static final String TRANSFORMATION_ECB_NOPADDING = "RSA/ECB/NoPadding"; + + /////////////////////////////////////////////////////////////////////////// + // 加解密 + /////////////////////////////////////////////////////////////////////////// + + /** + * 用公钥加密,每次加密的字节数,不能超过密钥的长度值减去 11。 * * @param data 需加密数据的byte数据 * @param publicKey 公钥 * @return 加密后的byte型数据 */ @Nullable - public static byte[] encryptData(byte[] data, PublicKey publicKey) { + public static byte[] encryptData(String transformation, byte[] data, PublicKey publicKey) { try { - Cipher cipher = Cipher.getInstance(CIPHER); + Cipher cipher = Cipher.getInstance(transformation); // 编码前设定编码方式及密钥 cipher.init(Cipher.ENCRYPT_MODE, publicKey); // 传入编码数据并返回编码结果 @@ -75,13 +77,13 @@ public final class RSAUtils { /** * 用私钥解密 * - * @param encryptedData 经过encryptedData()加密返回的byte数据 + * @param encryptedData 经过 encryptedData() 加密返回的 byte 数据 * @param privateKey 私钥 */ @Nullable - public static byte[] decryptData(byte[] encryptedData, PrivateKey privateKey) { + public static byte[] decryptData(String transformation, byte[] encryptedData, PrivateKey privateKey) { try { - Cipher cipher = Cipher.getInstance(CIPHER); + Cipher cipher = Cipher.getInstance(transformation); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(encryptedData); } catch (Exception e) { @@ -90,7 +92,56 @@ public final class RSAUtils { } /** - * 通过公钥byte[](publicKey.getEncoded())将公钥还原,适用于RSA算法 + * 用公钥解密 + * + * @param encryptedData 经过 encryptedData() 加密返回的 byte 数据 + * @param publicKey 公钥 + */ + @Nullable + public static String decryptData(String transformation, byte[] encryptedData, PublicKey publicKey) { + try { + Cipher cipher = Cipher.getInstance(transformation); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + return new String(cipher.doFinal(encryptedData), StandardCharsets.UTF_8); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /////////////////////////////////////////////////////////////////////////// + // 生成新的私钥/密钥 + /////////////////////////////////////////////////////////////////////////// + + /** + * 随机生成 RSA 密钥对(默认密钥长度为 1024) + */ + public static KeyPair generateRSAKeyPair() { + return generateRSAKeyPair(1024); + } + + /** + * 随机生成 RSA 密钥对 + * + * @param keyLength 密钥长度,范围:512~2048,一般1024 + */ + public static KeyPair generateRSAKeyPair(int keyLength) { + try { + KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_PAIR); + kpg.initialize(keyLength); + return kpg.genKeyPair(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return null; + } + } + + /////////////////////////////////////////////////////////////////////////// + // 根据key创建 PublicKey 或 PrivateKey + /////////////////////////////////////////////////////////////////////////// + + /** + * 通过公钥 byte[](publicKey.getEncoded()) 将公钥还原,适用于 RSA 算法。 * * @throws NoSuchAlgorithmException NoSuchAlgorithm * @throws InvalidKeySpecException InvalidKeySpec @@ -102,7 +153,7 @@ public final class RSAUtils { } /** - * 通过私钥byte[]将公钥还原,适用于RSA算法 + * 通过私钥 byte[] 将私钥还原,适用于 RSA 算法。 * * @throws NoSuchAlgorithmException NoSuchAlgorithm * @throws InvalidKeySpecException InvalidKeySpec @@ -114,7 +165,7 @@ public final class RSAUtils { } /** - * 使用N、e值还原公钥 + * 使用 N、e 值还原公钥 * * @throws NoSuchAlgorithmException NoSuchAlgorithm * @throws InvalidKeySpecException InvalidKeySpec @@ -128,7 +179,7 @@ public final class RSAUtils { } /** - * 使用N、d值还原私钥 + * 使用 N、d 值还原私钥 * * @throws NoSuchAlgorithmException NoSuchAlgorithm * @throws InvalidKeySpecException InvalidKeySpec @@ -144,13 +195,13 @@ public final class RSAUtils { /** * 从字符串中加载公钥 * - * @param publicKeyStr 公钥数据字符串 + * @param publicKeyStr Base64 编码的公钥数据字符串 * @throws Exception 加载公钥时产生的异常 */ public static PublicKey loadPublicKey(String publicKeyStr) throws Exception { try { byte[] buffer = Base64.decode(publicKeyStr, Base64.DEFAULT); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIR, "BC"); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIR); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer); return keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException e) { @@ -164,7 +215,9 @@ public final class RSAUtils { } /** - * 从字符串中加载私钥,加载时使用的是PKCS8EncodedKeySpec(PKCS#8编码的Key指令)。 + * 从字符串中加载私钥,加载时使用的是 PKCS8EncodedKeySpec(PKCS#8编码的Key指令)。 + * + * @param privateKeyStr Base64 编码的私钥数据字符串 */ public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception { try { diff --git a/lib_base/src/main/java/com/android/base/utils/security/SimpleRsa.java b/lib_base/src/main/java/com/android/base/utils/security/SimpleRsa.java deleted file mode 100644 index e1a0dfd..0000000 --- a/lib_base/src/main/java/com/android/base/utils/security/SimpleRsa.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.android.base.utils.security; - -import android.os.Build; -import android.util.Base64; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; - -import javax.crypto.Cipher; - -import androidx.annotation.Nullable; - - -public class SimpleRsa { - - private static final String ALGORITHM = "RSA"; - private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding"; - - /** - * 得到公钥 - * - * @param algorithm 算法 - * @param bysKey key - * @return 公钥 - */ - private static PublicKey getPublicKeyFromX509(String algorithm, String bysKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException { - byte[] decodedKey = Base64.decode(bysKey, Base64.DEFAULT); - X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodedKey); - KeyFactory keyFactory; - //适配Android P及以后版本,否则报错NoSuchAlgorithmException - //https://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - keyFactory = KeyFactory.getInstance(algorithm); - } else { - keyFactory = KeyFactory.getInstance(algorithm, "BC"); - } - return keyFactory.generatePublic(x509); - } - - /** - * 使用公钥加密 - * - * @param content 加密字符串 - * @return 加密后的字符串 - */ - @Nullable - public static String encryptByPublic(String content, String RSA_PUBLIC_KEY) { - try { - PublicKey pubKey = getPublicKeyFromX509(ALGORITHM, RSA_PUBLIC_KEY); - Cipher cipher = Cipher.getInstance(TRANSFORMATION); - cipher.init(Cipher.ENCRYPT_MODE, pubKey); - byte[] plaintext = content.getBytes(StandardCharsets.UTF_8); - byte[] output = cipher.doFinal(plaintext); - return new String(Base64.encode(output, Base64.DEFAULT)); - } catch (Exception e) { - return null; - } - } - - /** - * 使用公钥解密 - * - * @param content 密文 - * @return 解密后的字符串 - */ - @Nullable - public static String decryptByPublic(String content, String RSA_PUBLIC_KEY) { - try { - PublicKey pubkey = getPublicKeyFromX509(ALGORITHM, RSA_PUBLIC_KEY); - Cipher cipher = Cipher.getInstance(TRANSFORMATION); - cipher.init(Cipher.DECRYPT_MODE, pubkey); - InputStream ins = new ByteArrayInputStream(Base64.decode(content, Base64.DEFAULT)); - ByteArrayOutputStream writer = new ByteArrayOutputStream(); - byte[] buf = new byte[128]; - int offset; - while ((offset = ins.read(buf)) != -1) { - byte[] block; - if (buf.length == offset) { - block = buf; - } else { - block = new byte[offset]; - System.arraycopy(buf, 0, block, 0, offset); - } - writer.write(cipher.doFinal(block)); - } - return new String(writer.toByteArray(), StandardCharsets.UTF_8); - } catch (Exception e) { - return null; - } - } - -} \ No newline at end of file