optimize Security/UIKit

androidx
Ztiany 5 years ago
parent 9a4f84534f
commit f19c35b70d
  1. 1
      lib_base/build.gradle
  2. 2
      lib_base/src/main/java/com/android/base/app/fragment/BaseDialogFragment.kt
  3. 2
      lib_base/src/main/java/com/android/base/app/fragment/BaseFragment.kt
  4. 33
      lib_base/src/main/java/com/android/base/app/ui/UIKit.kt
  5. 32
      lib_base/src/main/java/com/android/base/rx/SchedulerProvider.kt
  6. 40
      lib_base/src/main/java/com/android/base/utils/security/AESCipherStrategy.java
  7. 177
      lib_base/src/main/java/com/android/base/utils/security/AESUtils.java
  8. 43
      lib_base/src/main/java/com/android/base/utils/security/CipherStrategy.java
  9. 45
      lib_base/src/main/java/com/android/base/utils/security/DESCipherStrategy.java
  10. 26
      lib_base/src/main/java/com/android/base/utils/security/DESUtils.java
  11. 49
      lib_base/src/main/java/com/android/base/utils/security/HexUtils.java
  12. 4
      lib_base/src/main/java/com/android/base/utils/security/MD5Utils.java
  13. 68
      lib_base/src/main/java/com/android/base/utils/security/RSACipherStrategy.java
  14. 51
      lib_base/src/main/java/com/android/base/utils/security/RSAUtils.java
  15. 4
      lib_base/src/main/java/com/android/base/utils/security/SHAUtils.java
  16. 4
      lib_base/src/main/java/com/android/base/utils/security/SimpleRsa.java
  17. 4
      lib_base/src/main/java/com/android/base/utils/security/security-utils.kt

@ -89,6 +89,7 @@ dependencies {
api kotlinLibraries.kotlinReflect api kotlinLibraries.kotlinReflect
api kotlinLibraries.kotlinCoroutines api kotlinLibraries.kotlinCoroutines
api kotlinLibraries.kotlinAndroidCoroutines api kotlinLibraries.kotlinAndroidCoroutines
api kotlinLibraries.kotlinxCoroutinesRx2
//RxJava //RxJava
api thirdLibraries.rxJava api thirdLibraries.rxJava

@ -85,7 +85,7 @@ open class BaseDialogFragment : AppCompatDialogFragment(), LoadingView, OnBackPr
*/ */
protected open fun provideLayout(): Any? = null protected open fun provideLayout(): Any? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
Timber.tag(tag()).d("-->onViewCreated savedInstanceState = %s", savedInstanceState) Timber.tag(tag()).d("-->onViewCreated savedInstanceState = %s", savedInstanceState)
if (layoutView !== view) { if (layoutView !== view) {

@ -96,7 +96,7 @@ open class BaseFragment : Fragment(), LoadingView, OnBackPressListener, Fragment
*/ */
protected open fun provideLayout(): Any? = null protected open fun provideLayout(): Any? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
Timber.tag(tag()).d("-->onViewCreated savedInstanceState = %s", savedInstanceState) Timber.tag(tag()).d("-->onViewCreated savedInstanceState = %s", savedInstanceState)
if (layoutView !== view) { if (layoutView !== view) {

@ -23,6 +23,7 @@ interface UIErrorHandler {
fun <H, T> H.handleLiveState( fun <H, T> H.handleLiveState(
liveData: LiveData<State<T>>, liveData: LiveData<State<T>>,
forceLoading: Boolean = true, forceLoading: Boolean = true,
onError: ((Throwable) -> Unit)? = null,
onSuccess: (T?) -> Unit onSuccess: (T?) -> Unit
) where H : UIErrorHandler, H : LoadingView, H : LifecycleOwner { ) where H : UIErrorHandler, H : LoadingView, H : LifecycleOwner {
@ -30,8 +31,13 @@ fun <H, T> H.handleLiveState(
when { when {
state.isError -> { state.isError -> {
Timber.d("handleLiveState -> isError") Timber.d("handleLiveState -> isError")
dismissLoadingDialog() dismissLoadingDialog(Sword.get().minimumShowingDialogMills()) {
handleError(state.error()) if (onError != null) {
onError(state.error())
} else {
handleError(state.error())
}
}
} }
state.isLoading -> { state.isLoading -> {
Timber.d("handleLiveState -> isLoading") Timber.d("handleLiveState -> isLoading")
@ -39,8 +45,7 @@ fun <H, T> H.handleLiveState(
} }
state.isSuccess -> { state.isSuccess -> {
Timber.d("handleLiveState -> isSuccess") Timber.d("handleLiveState -> isSuccess")
val minimumShowingDialogMills = Sword.get().minimumShowingDialogMills() dismissLoadingDialog(Sword.get().minimumShowingDialogMills()) {
dismissLoadingDialog(minimumShowingDialogMills) {
onSuccess(state.get()) onSuccess(state.get())
} }
}//success end }//success end
@ -49,6 +54,18 @@ fun <H, T> H.handleLiveState(
} }
fun <H, T> H.handleLiveState2(
liveData: LiveData<State<T>>,
forceLoading: Boolean = true,
handler: StateHandler<T>.() -> Unit
) where H : UIErrorHandler, H : LoadingView, H : LifecycleOwner {
liveData.observe(this, Observer { state ->
handleState(state, forceLoading, handler)
})
}
fun <T> LoadingView.handleState( fun <T> LoadingView.handleState(
state: State<T>, state: State<T>,
forceLoading: Boolean = true, forceLoading: Boolean = true,
@ -61,8 +78,9 @@ fun <T> LoadingView.handleState(
when { when {
state.isError -> { state.isError -> {
Timber.d("handleState -> isError") Timber.d("handleState -> isError")
dismissLoadingDialog() dismissLoadingDialog(Sword.get().minimumShowingDialogMills()) {
stateHandler.onError?.invoke(state.error()) stateHandler.onError?.invoke(state.error())
}
} }
state.isLoading -> { state.isLoading -> {
Timber.d("handleState -> isLoading") Timber.d("handleState -> isLoading")
@ -70,8 +88,7 @@ fun <T> LoadingView.handleState(
} }
state.isSuccess -> { state.isSuccess -> {
Timber.d("handleState -> isSuccess") Timber.d("handleState -> isSuccess")
val minimumShowingDialogMills = Sword.get().minimumShowingDialogMills() dismissLoadingDialog(Sword.get().minimumShowingDialogMills()) {
dismissLoadingDialog(minimumShowingDialogMills) {
stateHandler.onSuccess?.invoke(state.get()) stateHandler.onSuccess?.invoke(state.get())
if (state.hasData()) { if (state.hasData()) {
stateHandler.onSuccessWithData?.invoke(state.data()) stateHandler.onSuccessWithData?.invoke(state.data())

@ -1,9 +1,13 @@
@file:JvmName("SchedulerProviders") @file:JvmName("SchedulerProviders")
package com.android.base.rx package com.android.base.rx
import io.reactivex.Scheduler import io.reactivex.Scheduler
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.rx2.asCoroutineDispatcher
/** /**
@ -19,6 +23,12 @@ interface SchedulerProvider {
fun database(): Scheduler fun database(): Scheduler
fun ioDispatcher(): CoroutineDispatcher
fun defaultDispatcher(): CoroutineDispatcher
fun uiDispatcher(): CoroutineDispatcher
} }
fun newDefaultSchedulerProvider(): SchedulerProvider { fun newDefaultSchedulerProvider(): SchedulerProvider {
@ -27,6 +37,26 @@ fun newDefaultSchedulerProvider(): SchedulerProvider {
private class DefaultSchedulerProvider : SchedulerProvider { private class DefaultSchedulerProvider : SchedulerProvider {
private val ioDispatcher by lazy {
io().asCoroutineDispatcher()
}
private val defaultDispatcher by lazy {
io().asCoroutineDispatcher()
}
override fun ioDispatcher(): CoroutineDispatcher {
return ioDispatcher
}
override fun defaultDispatcher(): CoroutineDispatcher {
return defaultDispatcher
}
override fun uiDispatcher(): CoroutineDispatcher {
return Dispatchers.Main
}
override fun computation(): Scheduler { override fun computation(): Scheduler {
return Schedulers.computation() return Schedulers.computation()
} }
@ -43,4 +73,4 @@ private class DefaultSchedulerProvider : SchedulerProvider {
return Schedulers.single() return Schedulers.single()
} }
} }

@ -1,40 +0,0 @@
package com.android.base.utils.security;
import java.io.UnsupportedEncodingException;
/**
* Reference: https://github.com/zhengxiaopeng/Rocko-Android-Demos
*/
public class AESCipherStrategy extends CipherStrategy {
private String key;
public AESCipherStrategy(String key) {
this.key = key;
}
@Override
public String encrypt(String content) {
byte[] encryptByte = new byte[0];
try {
encryptByte = AESUtils.encryptData(content.getBytes(CHARSET), key);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return encodeConvert(encryptByte);
}
@Override
public String decrypt(String encryptContent) {
byte[] encryptByte = decodeConvert(encryptContent);
byte[] decryptByte = AESUtils.decryptData(encryptByte, key);
String result = "";
try {
result = new String(decryptByte, CHARSET);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
}

@ -1,71 +1,53 @@
/*
* Copyright 2015 Rocko (http://rocko.xyz) <rocko.zxp@gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.base.utils.security; package com.android.base.utils.security;
import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import androidx.annotation.Nullable;
/** /**
* AES 对称加密 * AES 对称加密
*/ */
@SuppressWarnings("unused")
public class AESUtils { public class AESUtils {
/** //算法/模式/填充
* 算法/模式/填充 * public static String AES = "AES";
*/ public static String AES_CBC_ISO10126PADDING = "AES/CBC/ISO10126Padding";
private static final String CIPHER_MODE = "AES"; public static String AES_CBC_NOPADDING = "AES/CBC/NoPadding";
public static String AES_CBC_PKCS5PADDING = "AES/CBC/PKCS5Padding";
public static String AES_CFB_ISO10126PADDING = "AES/CFB/ISO10126Padding";
public static String AES_CFB_NOPADDING = "AES/CFB/NoPadding";
public static String AES_CFB_PKCS5PADDING = "AES/CFB/PKCS5Padding";
public static String AES_CTR_ISO10126PADDING = "AES/CTR/ISO10126Padding";
public static String AES_CTR_NOPADDING = "AES/CTR/NoPadding";
public static String AES_CTR_PKCS5PADDING = "AES/CTR/PKCS5Padding";
public static String AES_CTS_ISO10126PADDING = "AES/CTS/ISO10126Padding";
public static String AES_CTS_NOPADDING = "AES/CTS/NoPadding";
public static String AES_CTS_PKCS5PADDING = "AES/CTS/PKCS5Padding";
public static String AES_ECB_ISO10126PADDING = "AES/ECB/ISO10126Padding";
public static String AES_ECB_NOPADDING = "AES/ECB/NoPadding";
public static String AES_ECB_PKCS5PADDING = "AES/ECB/PKCS5Padding";
public static String AES_OFB_ISO10126PADDING = "AES/OFB/ISO10126Padding";
public static String AES_OFB_NOPADDING = "AES/OFB/NoPadding";
public static String AES_OFB_PKCS5PADDING = "AES/OFB/PKCS5Padding";
/** private static final int LIMIT_LEN = 16;
* 创建密钥
* private static SecretKeySpec generateAESKey(String algorithm, String password) {
* @param password 例如"0123456701234567" 128位 16*8 <br> byte[] passwordData = password.getBytes();
* 所有密钥长度不能超过16字符中文占两个192 24 256 32 if (passwordData.length != LIMIT_LEN) {
* @return SecretKeySpec 实例 throw new IllegalArgumentException("password 长度必须等于16");
*/
private static SecretKeySpec generateAESKey(String password) {
byte[] data;
StringBuilder sb = new StringBuilder();
sb.append(password);
while (sb.length() < 16)
sb.append("0");
if (sb.length() > 16)
sb.setLength(16);
try {
data = sb.toString().getBytes(StandardCharsets.UTF_8);
return new SecretKeySpec(data, CIPHER_MODE);
} catch (Exception e) {
e.printStackTrace();
return null;
} }
return new SecretKeySpec(passwordData, algorithm);
} }
/** @Nullable
* 加密字节数据 public static byte[] encryptData(byte[] content, String algorithm, String password) {
*
* @param content 需要加密的字节数组
* @param password 密钥 128 <16个字节 192 <24,256 <32个字节
* @return 加密完后的字节数组
*/
public static byte[] encryptData(byte[] content, String password) {
try { try {
SecretKeySpec key = generateAESKey(password); SecretKeySpec key = generateAESKey(algorithm, password);
Cipher cipher = Cipher.getInstance(CIPHER_MODE); Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, key); cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(content); return cipher.doFinal(content);
} catch (Exception e) { } catch (Exception e) {
@ -74,35 +56,11 @@ public class AESUtils {
return null; return null;
} }
/** @Nullable
* 加密(结果为16进制字符串), UTF-8 编码 public static byte[] decryptData(byte[] content, String algorithm, String password) {
*
* @param content 要加密的字符串
* @param password 密钥
* @return 加密后的16进制字符串
*/
public static String encryptData(String content, String password) {
byte[] data = null;
try {
data = content.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
}
data = encryptData(data, password);
return byte2hex(data);
}
/**
* 解密字节数组 UTF-8
*
* @param content
* @param password
* @return
*/
public static byte[] decryptData(byte[] content, String password) {
try { try {
SecretKeySpec key = generateAESKey(password); SecretKeySpec key = generateAESKey(algorithm, password);
Cipher cipher = Cipher.getInstance(CIPHER_MODE); Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key); cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(content); return cipher.doFinal(content);
} catch (Exception e) { } catch (Exception e) {
@ -111,61 +69,4 @@ public class AESUtils {
return null; return null;
} }
/**
* 解密16进制的字符串为字符串 *
*/
public static String decryptData(String content, String password) {
byte[] data = null;
try {
data = hex2byte(content);
} catch (Exception e) {
e.printStackTrace();
}
data = decryptData(data, password);
if (data == null)
return null;
String result = null;
result = new String(data, StandardCharsets.UTF_8);
return result;
}
/**
* 字节数组转成16进制字符串
*
* @return 16进制字符串
*/
public static String byte2hex(byte[] bytes) { // 一个字节的数,
StringBuilder sb = new StringBuilder(bytes.length * 2);
String tmp;
for (byte theByte : bytes) {
// 整数转成十六进制表示
tmp = (Integer.toHexString(theByte & 0XFF));
if (tmp.length() == 1) {
sb.append("0");
}
sb.append(tmp);
}
return sb.toString().toUpperCase(); // 转成大写
}
/**
* 将hex字符串转换成字节数组
*
* @param inputString 16进制的字符串
* @return 字节数组
*/
public static byte[] hex2byte(String inputString) {
if (inputString == null || inputString.length() < 2) {
return new byte[0];
}
inputString = inputString.toLowerCase();
int l = inputString.length() / 2;
byte[] result = new byte[l];
for (int i = 0; i < l; ++i) {
String tmp = inputString.substring(2 * i, 2 * i + 2);
result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
}
return result;
}
} }

@ -1,43 +0,0 @@
package com.android.base.utils.security;
import android.util.Base64;
/**
* Reference: https://github.com/zhengxiaopeng/Rocko-Android-Demos
*/
abstract class CipherStrategy {
final static String CHARSET = "UTF-8";
/**
* 将加密内容的 Base64 编码转换为二进制内容
*/
protected byte[] decodeConvert(String str) {
return Base64.decode(str, Base64.DEFAULT);
}
/**
* 对加密后的二进制结果转换为 Base64 编码
*/
protected String encodeConvert(byte[] bytes) {
return new String(Base64.encode(bytes, Base64.DEFAULT));
}
/**
* 对字符串进行加密
*
* @param content 需要加密的字符串
* @return
*/
public abstract String encrypt(String content);
/**
* 对字符串进行解密
*
* @param encryptContent 加密内容的 Base64 编码
* @return
*/
public abstract String decrypt(String encryptContent);
}

@ -1,45 +0,0 @@
package com.android.base.utils.security;
import java.io.UnsupportedEncodingException;
/**
* Reference: https://github.com/zhengxiaopeng/Rocko-Android-Demos
*/
public class DESCipherStrategy extends CipherStrategy {
private String key;// 解密密码
/**
* @param key 加解密的 key
*/
public DESCipherStrategy(String key) {
this.key = key;
}
@Override
public String encrypt(String content) {
byte[] encryptByte = null;
try {
encryptByte = DESUtils.encrypt(content.getBytes(CHARSET), key);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return encodeConvert(encryptByte);
}
@Override
public String decrypt(String encryptContent) {
byte[] encryptByte = decodeConvert(encryptContent);
byte[] decryptByte = DESUtils.decrypt(encryptByte, key);
String result = "";
try {
result = new String(decryptByte, CHARSET);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
}

@ -1,19 +1,3 @@
/*
* Copyright 2015 Rocko (http://rocko.xyz) <rocko.zxp@gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.base.utils.security; package com.android.base.utils.security;
import java.security.SecureRandom; import java.security.SecureRandom;
@ -23,7 +7,9 @@ import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory; import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.DESKeySpec;
@SuppressWarnings("WeakerAccess") import androidx.annotation.Nullable;
@SuppressWarnings("unused")
public class DESUtils { public class DESUtils {
/** /**
@ -32,14 +18,15 @@ public class DESUtils {
* @param bytesContent 待加密内容 * @param bytesContent 待加密内容
* @param key 加密的密钥 * @param key 加密的密钥
*/ */
@Nullable
public static byte[] encrypt(byte[] bytesContent, String key) { public static byte[] encrypt(byte[] bytesContent, String key) {
try { try {
SecureRandom random = new SecureRandom(); SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(key.getBytes()); DESKeySpec desKey = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey); SecretKey secretKey = keyFactory.generateSecret(desKey);
Cipher cipher = Cipher.getInstance("DES"); Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, securekey, random); cipher.init(Cipher.ENCRYPT_MODE, secretKey, random);
return cipher.doFinal(bytesContent); return cipher.doFinal(bytesContent);
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@ -53,6 +40,7 @@ public class DESUtils {
* @param content 待解密内容 * @param content 待解密内容
* @param key 解密的密钥 * @param key 解密的密钥
*/ */
@Nullable
public static byte[] decrypt(byte[] content, String key) { public static byte[] decrypt(byte[] content, String key) {
try { try {
SecureRandom random = new SecureRandom(); SecureRandom random = new SecureRandom();

@ -0,0 +1,49 @@
package com.android.base.utils.security;
/**
* @author Ztiany
* Email: ztiany3@gmail.com
* Date : 2019-10-23 15:09
*/
public class HexUtils {
/**
* 字节数组转成16进制字符串
*
* @return 16进制字符串
*/
public static String byte2hex(byte[] bytes) { // 一个字节的数,
StringBuilder sb = new StringBuilder(bytes.length * 2);
String tmp;
for (byte theByte : bytes) {
// 整数转成十六进制表示
tmp = (Integer.toHexString(theByte & 0XFF));
if (tmp.length() == 1) {
sb.append("0");
}
sb.append(tmp);
}
return sb.toString().toUpperCase(); // 转成大写
}
/**
* 将hex字符串转换成字节数组
*
* @param inputString 16进制的字符串
* @return 字节数组
*/
public static byte[] hex2byte(String inputString) {
if (inputString == null || inputString.length() < 2) {
return new byte[0];
}
inputString = inputString.toLowerCase();
int l = inputString.length() / 2;
byte[] result = new byte[l];
for (int i = 0; i < l; ++i) {
String tmp = inputString.substring(2 * i, 2 * i + 2);
result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
}
return result;
}
}

@ -6,6 +6,9 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import androidx.annotation.Nullable;
@SuppressWarnings("unused")
public class MD5Utils { public class MD5Utils {
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
@ -22,6 +25,7 @@ public class MD5Utils {
/** /**
* 文件加密 * 文件加密
*/ */
@Nullable
public static String md5file(String filename) { public static String md5file(String filename) {
InputStream fis; InputStream fis;
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];

@ -1,68 +0,0 @@
package com.android.base.utils.security;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* Reference: https://github.com/zhengxiaopeng/Rocko-Android-Demos
*/
public class RSACipherStrategy extends CipherStrategy {
private PublicKey mPublicKey;
private PrivateKey mPrivateKey;
public void initPublicKey(String publicKeyContentStr) {
try {
mPublicKey = RSAUtils.loadPublicKey(publicKeyContentStr);
} catch (Exception e) {
e.printStackTrace();
}
}
public void initPublicKey(InputStream publicKeyIs) {
try {
mPublicKey = RSAUtils.loadPublicKey(publicKeyIs);
} catch (Exception e) {
e.printStackTrace();
}
}
public void initPrivateKey(String privateKeyContentStr) {
try {
mPrivateKey = RSAUtils.loadPrivateKey(privateKeyContentStr);
} catch (Exception e) {
e.printStackTrace();
}
}
public void initPrivateKey(InputStream privateIs) {
try {
mPrivateKey = RSAUtils.loadPrivateKey(privateIs);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public String encrypt(String content) {
if (mPublicKey == null) {
throw new NullPointerException("PublicKey is null, please initialize it first");
}
byte[] encryptByte = RSAUtils.encryptData(content.getBytes(), mPublicKey);
return encodeConvert(encryptByte);
}
@Override
public String decrypt(String encryptContent) {
if (mPrivateKey == null) {
throw new NullPointerException("PrivateKey is null, please initialize it first");
}
byte[] encryptByte = decodeConvert(encryptContent);
byte[] decryptByte = RSAUtils.decryptData(encryptByte, mPrivateKey);
return new String(decryptByte);
}
}

@ -1,19 +1,3 @@
/*
* Copyright 2015 Rocko (http://rocko.xyz) <rocko.zxp@gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.base.utils.security; package com.android.base.utils.security;
import android.util.Base64; import android.util.Base64;
@ -36,10 +20,9 @@ import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import androidx.annotation.Nullable;
/** @SuppressWarnings("WeakerAccess,unused")
* @author Mr.Zheng
*/
public final class RSAUtils { public final class RSAUtils {
private final static String KEY_PAIR = "RSA"; private final static String KEY_PAIR = "RSA";
@ -69,13 +52,13 @@ public final class RSAUtils {
} }
/** /**
* 用公钥加密 <br> * 用公钥加密每次加密的字节数不能超过密钥的长度值减去11
* 每次加密的字节数不能超过密钥的长度值减去11
* *
* @param data 需加密数据的byte数据 * @param data 需加密数据的byte数据
* @param publicKey 公钥 * @param publicKey 公钥
* @return 加密后的byte型数据 * @return 加密后的byte型数据
*/ */
@Nullable
public static byte[] encryptData(byte[] data, PublicKey publicKey) { public static byte[] encryptData(byte[] data, PublicKey publicKey) {
try { try {
Cipher cipher = Cipher.getInstance(CIPHER); Cipher cipher = Cipher.getInstance(CIPHER);
@ -95,6 +78,7 @@ public final class RSAUtils {
* @param encryptedData 经过encryptedData()加密返回的byte数据 * @param encryptedData 经过encryptedData()加密返回的byte数据
* @param privateKey 私钥 * @param privateKey 私钥
*/ */
@Nullable
public static byte[] decryptData(byte[] encryptedData, PrivateKey privateKey) { public static byte[] decryptData(byte[] encryptedData, PrivateKey privateKey) {
try { try {
Cipher cipher = Cipher.getInstance(CIPHER); Cipher cipher = Cipher.getInstance(CIPHER);
@ -108,11 +92,10 @@ public final class RSAUtils {
/** /**
* 通过公钥byte[](publicKey.getEncoded())将公钥还原适用于RSA算法 * 通过公钥byte[](publicKey.getEncoded())将公钥还原适用于RSA算法
* *
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException NoSuchAlgorithm
* @throws InvalidKeySpecException * @throws InvalidKeySpecException InvalidKeySpec
*/ */
public static PublicKey getPublicKey(byte[] keyBytes) throws NoSuchAlgorithmException, public static PublicKey getPublicKey(byte[] keyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
InvalidKeySpecException {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIR); KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIR);
return keyFactory.generatePublic(keySpec); return keyFactory.generatePublic(keySpec);
@ -121,11 +104,10 @@ public final class RSAUtils {
/** /**
* 通过私钥byte[]将公钥还原适用于RSA算法 * 通过私钥byte[]将公钥还原适用于RSA算法
* *
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException NoSuchAlgorithm
* @throws InvalidKeySpecException * @throws InvalidKeySpecException InvalidKeySpec
*/ */
public static PrivateKey getPrivateKey(byte[] keyBytes) throws NoSuchAlgorithmException, public static PrivateKey getPrivateKey(byte[] keyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
InvalidKeySpecException {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIR); KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIR);
return keyFactory.generatePrivate(keySpec); return keyFactory.generatePrivate(keySpec);
@ -134,11 +116,10 @@ public final class RSAUtils {
/** /**
* 使用Ne值还原公钥 * 使用Ne值还原公钥
* *
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException NoSuchAlgorithm
* @throws InvalidKeySpecException * @throws InvalidKeySpecException InvalidKeySpec
*/ */
public static PublicKey getPublicKey(String modulus, String publicExponent) public static PublicKey getPublicKey(String modulus, String publicExponent) throws NoSuchAlgorithmException, InvalidKeySpecException {
throws NoSuchAlgorithmException, InvalidKeySpecException {
BigInteger bigIntModulus = new BigInteger(modulus); BigInteger bigIntModulus = new BigInteger(modulus);
BigInteger bigIntPrivateExponent = new BigInteger(publicExponent); BigInteger bigIntPrivateExponent = new BigInteger(publicExponent);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus, bigIntPrivateExponent); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus, bigIntPrivateExponent);
@ -149,8 +130,8 @@ public final class RSAUtils {
/** /**
* 使用Nd值还原私钥 * 使用Nd值还原私钥
* *
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException NoSuchAlgorithm
* @throws InvalidKeySpecException * @throws InvalidKeySpecException InvalidKeySpec
*/ */
public static PrivateKey getPrivateKey(String modulus, String privateExponent) throws NoSuchAlgorithmException, InvalidKeySpecException { public static PrivateKey getPrivateKey(String modulus, String privateExponent) throws NoSuchAlgorithmException, InvalidKeySpecException {
BigInteger bigIntModulus = new BigInteger(modulus); BigInteger bigIntModulus = new BigInteger(modulus);

@ -4,6 +4,8 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import androidx.annotation.Nullable;
/** /**
* @author Ztiany * @author Ztiany
* Email: ztiany3@gmail.com * Email: ztiany3@gmail.com
@ -14,10 +16,12 @@ public class SHAUtils {
private static final String SHA256 = "SHA256"; private static final String SHA256 = "SHA256";
@Nullable
public static byte[] toSHA256(String content) { public static byte[] toSHA256(String content) {
return toSHA256(content.getBytes(StandardCharsets.UTF_8)); return toSHA256(content.getBytes(StandardCharsets.UTF_8));
} }
@Nullable
public static byte[] toSHA256(byte[] bytes) { public static byte[] toSHA256(byte[] bytes) {
try { try {
MessageDigest md = MessageDigest.getInstance(SHA256); MessageDigest md = MessageDigest.getInstance(SHA256);

@ -16,6 +16,8 @@ import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import androidx.annotation.Nullable;
public class SimpleRsa { public class SimpleRsa {
@ -49,6 +51,7 @@ public class SimpleRsa {
* @param content 加密字符串 * @param content 加密字符串
* @return 加密后的字符串 * @return 加密后的字符串
*/ */
@Nullable
public static String encryptByPublic(String content, String RSA_PUBLIC_KEY) { public static String encryptByPublic(String content, String RSA_PUBLIC_KEY) {
try { try {
PublicKey pubKey = getPublicKeyFromX509(ALGORITHM, RSA_PUBLIC_KEY); PublicKey pubKey = getPublicKeyFromX509(ALGORITHM, RSA_PUBLIC_KEY);
@ -68,6 +71,7 @@ public class SimpleRsa {
* @param content 密文 * @param content 密文
* @return 解密后的字符串 * @return 解密后的字符串
*/ */
@Nullable
public static String decryptByPublic(String content, String RSA_PUBLIC_KEY) { public static String decryptByPublic(String content, String RSA_PUBLIC_KEY) {
try { try {
PublicKey pubkey = getPublicKeyFromX509(ALGORITHM, RSA_PUBLIC_KEY); PublicKey pubkey = getPublicKeyFromX509(ALGORITHM, RSA_PUBLIC_KEY);

@ -3,10 +3,10 @@ package com.android.base.utils.security
import android.annotation.SuppressLint import android.annotation.SuppressLint
fun md5(content: String): String { fun md5(content: String): String {
return MD5Utils.md5(content) return MD5Utils.md5(content) ?: ""
} }
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
fun md5UpperCase(content: String): String { fun md5UpperCase(content: String): String {
return MD5Utils.md5(content).toUpperCase() return MD5Utils.md5(content)?.toUpperCase() ?: ""
} }

Loading…
Cancel
Save