optimize security utils

androidx
Ztiany 5 years ago
parent 460d2856ea
commit 8261c7af25
  1. 20
      lib_base/src/main/java/com/android/base/utils/security/AESUtils.java
  2. 107
      lib_base/src/main/java/com/android/base/utils/security/RSAUtils.java
  3. 100
      lib_base/src/main/java/com/android/base/utils/security/SimpleRsa.java

@ -1,5 +1,7 @@
package com.android.base.utils.security; package com.android.base.utils.security;
import android.util.Base64;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
@ -12,7 +14,7 @@ import androidx.annotation.Nullable;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class AESUtils { public class AESUtils {
//算法/模式/填充 //算法/加密模式/填充模式
public static String AES = "AES"; public static String AES = "AES";
public static String AES_CBC_ISO10126PADDING = "AES/CBC/ISO10126Padding"; public static String AES_CBC_ISO10126PADDING = "AES/CBC/ISO10126Padding";
public static String AES_CBC_NOPADDING = "AES/CBC/NoPadding"; public static String AES_CBC_NOPADDING = "AES/CBC/NoPadding";
@ -69,4 +71,20 @@ public class AESUtils {
return null; 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;
}
} }

@ -7,6 +7,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
@ -22,46 +23,47 @@ import javax.crypto.Cipher;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
/**
* @see <a href='https://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html'>cryptography-changes-in-android-p.html<a/>
* @see <a href='https://www.jianshu.com/p/7841eae98d16'>Android使用RSA加密和解密cryptography-changes-in-android-p.html<a/>
* @see <a href='https://stackoverflow.com/questions/12471999/rsa-encryption-decryption-in-android/12474193'>rsa-encryption-decryption-in-android/12474193<a/>
* @see <a href='https://proandroiddev.com/secure-data-in-android-encrypting-large-data-dda256a55b36'>secure-data-in-android-encrypting-large-data-dda256a55b36<a/>
*/
@SuppressWarnings("WeakerAccess,unused") @SuppressWarnings("WeakerAccess,unused")
public final class RSAUtils { public final class RSAUtils {
private final static String KEY_PAIR = "RSA"; private final static String KEY_PAIR = "RSA";
private final static String CIPHER = "RSA/ECB/PKCS1Padding";
/** /**
* 随机生成RSA密钥对(默认密钥长度为1024) * 默认
*/ */
public static KeyPair generateRSAKeyPair() { public static final String TRANSFORMATION_DEFAULT = KEY_PAIR;
return generateRSAKeyPair(1024);
}
/** /**
* 随机生成RSA密钥对 * JDK标准
*
* @param keyLength 密钥长度范围5122048一般1024
*/ */
public static KeyPair generateRSAKeyPair(int keyLength) { public static final String TRANSFORMATION_ECB_PKCS1PADDING = "RSA/ECB/PKCS1Padding";
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_PAIR); /**
kpg.initialize(keyLength); * Android标准
return kpg.genKeyPair(); */
} catch (NoSuchAlgorithmException e) { public static final String TRANSFORMATION_ECB_NOPADDING = "RSA/ECB/NoPadding";
e.printStackTrace();
return null; ///////////////////////////////////////////////////////////////////////////
} // 加解密
} ///////////////////////////////////////////////////////////////////////////
/** /**
* 用公钥加密每次加密的字节数不能超过密钥的长度值减去11 * 用公钥加密每次加密的字节数不能超过密钥的长度值减去 11
* *
* @param data 需加密数据的byte数据 * @param data 需加密数据的byte数据
* @param publicKey 公钥 * @param publicKey 公钥
* @return 加密后的byte型数据 * @return 加密后的byte型数据
*/ */
@Nullable @Nullable
public static byte[] encryptData(byte[] data, PublicKey publicKey) { public static byte[] encryptData(String transformation, byte[] data, PublicKey publicKey) {
try { try {
Cipher cipher = Cipher.getInstance(CIPHER); Cipher cipher = Cipher.getInstance(transformation);
// 编码前设定编码方式及密钥 // 编码前设定编码方式及密钥
cipher.init(Cipher.ENCRYPT_MODE, publicKey); cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 传入编码数据并返回编码结果 // 传入编码数据并返回编码结果
@ -79,9 +81,9 @@ public final class RSAUtils {
* @param privateKey 私钥 * @param privateKey 私钥
*/ */
@Nullable @Nullable
public static byte[] decryptData(byte[] encryptedData, PrivateKey privateKey) { public static byte[] decryptData(String transformation, byte[] encryptedData, PrivateKey privateKey) {
try { try {
Cipher cipher = Cipher.getInstance(CIPHER); Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.DECRYPT_MODE, privateKey); cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(encryptedData); return cipher.doFinal(encryptedData);
} catch (Exception e) { } 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 密钥长度范围5122048一般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 NoSuchAlgorithmException NoSuchAlgorithm
* @throws InvalidKeySpecException InvalidKeySpec * @throws InvalidKeySpecException InvalidKeySpec
@ -102,7 +153,7 @@ public final class RSAUtils {
} }
/** /**
* 通过私钥byte[]将公钥还原适用于RSA算法 * 通过私钥 byte[] 将私钥还原适用于 RSA 算法
* *
* @throws NoSuchAlgorithmException NoSuchAlgorithm * @throws NoSuchAlgorithmException NoSuchAlgorithm
* @throws InvalidKeySpecException InvalidKeySpec * @throws InvalidKeySpecException InvalidKeySpec
@ -144,13 +195,13 @@ public final class RSAUtils {
/** /**
* 从字符串中加载公钥 * 从字符串中加载公钥
* *
* @param publicKeyStr 公钥数据字符串 * @param publicKeyStr Base64 编码的公钥数据字符串
* @throws Exception 加载公钥时产生的异常 * @throws Exception 加载公钥时产生的异常
*/ */
public static PublicKey loadPublicKey(String publicKeyStr) throws Exception { public static PublicKey loadPublicKey(String publicKeyStr) throws Exception {
try { try {
byte[] buffer = Base64.decode(publicKeyStr, Base64.DEFAULT); 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); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return keyFactory.generatePublic(keySpec); return keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
@ -165,6 +216,8 @@ public final class RSAUtils {
/** /**
* 从字符串中加载私钥加载时使用的是 PKCS8EncodedKeySpecPKCS#8编码的Key指令 * 从字符串中加载私钥加载时使用的是 PKCS8EncodedKeySpecPKCS#8编码的Key指令
*
* @param privateKeyStr Base64 编码的私钥数据字符串
*/ */
public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception { public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
try { try {

@ -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;
}
}
}
Loading…
Cancel
Save