一个聚合的加解密工具类

2,488 阅读6分钟

小序

字符串,byte[],文件等对象的加密和解密,是开发当中必不可少的操作。这里仅基于不同方式的加解密实现,为方便使用固聚合为一个工具类使用,且代码实现与前辈们的实现并没有什么太大的差别。有需要的亲可直接带走,如若有不正确的地方还望指正。

代码

/**
 * 
    加解密工具 *
  • MD5 *
      {@link #md5(String, String)} 字符串加密
    *
      {@link #md5(File, int)} 文件加密
    *
      {@link #md5(String)} 盐值加密
    *
      {@link #md5(String, int)} 重复加密
  • *
  • Base64 *
      {@link #base64EncodeStr(String)} 字符串加密
    *
      {@link #base64DecodedStr(String)} 字符串解密
    *
      {@link #base64EncodeFile(File)} 文件加密
    *
      {@link #base64DecodedFile(String, String)} 文件解密
  • *
  • AES *
      {@link #aes(String, String, int)} 加解密
  • *
  • DES *
      {@link #des(String, String, int)} 加解密
  • *
  • SHA *
      {@link #sha(String, String)} 字符串加密
  • *
  • RSA *
      {@link #genKeyPair()} 生成密钥对
    *
      {@link #sign(byte[], String)} 生成数字签名
    *
      {@link #verify(byte[], String, String)} 校验数字签名
    *
      {@link #getKey(Map, boolean)} 密钥获取
    *
      {@link #rsa(byte[], String, int)} 密钥加解密
  • *
* * @author gzejia 978862664@qq.com */ public class EncryptUtil { public static final String KEY = "1234567890123456"; private static final String TAG = "EncryptUtil"; private EncryptUtil() { throw new UnsupportedOperationException("cannot be instantiated"); } /** * @param buf 2进制 * @return 转换成16进制 */ private static String parseByte2HexStr(byte buf[]) { StringBuilder sb = new StringBuilder(); for (byte b : buf) { String hex = Integer.toHexString(b & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); } /** * @param hexStr 16进制 * @return 转换为二进制 */ private static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) return null; byte[] result = new byte[hexStr.length() / 2]; for (int i = 0; i < hexStr.length() / 2; i++) { int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); result[i] = (byte) (high * 16 + low); } return result; } /** * @param string 文本内容 * @param slat 盐值key * @return 文本加密结果 */ public static String md5(String string, String slat) { if (TextUtils.isEmpty(string)) return ""; try { MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] bytes = md5.digest((string + slat).getBytes()); String result = ""; for (byte b : bytes) { String temp = Integer.toHexString(b & 0xff); if (temp.length() == 1) { temp = "0" + temp; } result += temp; } return result; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ""; } public static final int MD5_TYPE_IO = 0; public static final int MD5_TYPE_NIO = 1; /** * @param file 文件内容 * @param style {@link #MD5_TYPE_NIO} NIO文件MD5加密; {@link #MD5_TYPE_IO} IO文件MD5加密 * @return 文件加密结果 */ public static String md5(File file, int style) { if (file == null || !file.isFile() || !file.exists()) return ""; FileInputStream in = null; String result = ""; byte buffer[] = new byte[8192]; int len; try { in = new FileInputStream(file); MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] bytes = md5.digest(); if (style == MD5_TYPE_IO) { while ((len = in.read(buffer)) != -1) { md5.update(buffer, 0, len); } } else { MappedByteBuffer byteBuffer = in.getChannel().map( FileChannel.MapMode.READ_ONLY, 0, file.length()); md5.update(byteBuffer); } for (byte b : bytes) { String temp = Integer.toHexString(b & 0xff); if (temp.length() == 1) { temp = "0" + temp; } result += temp; } } catch (Exception e) { e.printStackTrace(); } finally { if (null != in) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } return result; } /** * @param string 文本内容 * @param times 重复加密次数 * @return 多次加密结果 */ public static String md5(String string, int times) { if (TextUtils.isEmpty(string)) return ""; String md5 = md5(string); for (int i = 0; i < times; i++) md5 = md5(md5); return md5; } /** * @return 盐值加密结果 * @see #md5(String, String) */ public static String md5(String string) { return TextUtils.isEmpty(string) ? "" : md5(string, ""); } /** * @param string md5加密字符串 * @return 解密结果 */ public static String md5Decoded(String string) { char[] a = string.toCharArray(); for (int i = 0; i < a.length; i++) { a[i] = (char) (a[i] ^ 't'); } return new String(a); } /** * @param string md5加密字符串 * @param times md5重复加密次数 * @return 解密结果 */ public static String md5Decoded(String string, int times) { if (TextUtils.isEmpty(string)) return ""; String md5Decoded = md5Decoded(string); for (int i = 0; i < times; i++) md5Decoded = md5Decoded(string); return md5Decoded; } /** * @param string 文本内容 * @return base64加密结果 */ public static String base64EncodeStr(String string) { if (TextUtils.isEmpty(string)) return ""; return Base64.encodeToString(string.getBytes(), Base64.DEFAULT); } /** * @param string 文本内容 * @return base64解密结果 */ public static String base64DecodedStr(String string) { if (TextUtils.isEmpty(string)) return ""; return new String(Base64.decode(string, Base64.DEFAULT)); } /** * @param file 文件 * @return base64加密结果 */ public static String base64EncodeFile(File file) { if (null == file) return ""; try { FileInputStream inputFile = new FileInputStream(file); byte[] buffer = new byte[(int) file.length()]; inputFile.read(buffer); inputFile.close(); return Base64.encodeToString(buffer, Base64.DEFAULT); } catch (IOException e) { e.printStackTrace(); } return ""; } /** * @param filePath 文件存储路径 * @param code 文件编码 * @return base64解密结果 */ public static File base64DecodedFile(String filePath, String code) { if (TextUtils.isEmpty(filePath) || TextUtils.isEmpty(code)) { Log.w(TAG, "File path or code not null"); return null; } File desFile = new File(filePath); try { byte[] decodeBytes = Base64.decode(code.getBytes(), Base64.DEFAULT); FileOutputStream fos = new FileOutputStream(desFile); fos.write(decodeBytes); fos.close(); } catch (Exception e) { e.printStackTrace(); } return desFile; } /** * @param content 加密/解密内容 * @param password 加密/解密密钥 * @param type {@link Cipher} ENCRYPT_MODE_指定加密; ENCRYPT_MODE_指定解密 * @return 加密/解密结果 */ public static String aes(String content, String password, int type) { try { KeyGenerator generator = KeyGenerator.getInstance("AES"); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "Crypto"); secureRandom.setSeed(password.getBytes()); generator.init(128, secureRandom); SecretKey secretKey = generator.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); @SuppressLint("GetInstance") Cipher cipher = Cipher.getInstance("AES"); cipher.init(type, key); if (type == Cipher.ENCRYPT_MODE) { byte[] byteContent = content.getBytes("utf-8"); return parseByte2HexStr(cipher.doFinal(byteContent)); } else { byte[] byteContent = parseHexStr2Byte(content); return new String(cipher.doFinal(byteContent)); } } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | UnsupportedEncodingException | InvalidKeyException | NoSuchPaddingException | NoSuchProviderException e) { e.printStackTrace(); } return null; } /** * @param content 加密/解密内容 * @param password 加密/解密密钥 * @param type {@link Cipher} ENCRYPT_MODE_指定加密; ENCRYPT_MODE_指定解密 * @return 加密/解密结果 */ public static String des(String content, String password, int type) { try { SecureRandom random = new SecureRandom(); DESKeySpec desKey = new DESKeySpec(password.getBytes()); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); @SuppressLint("GetInstance") Cipher cipher = Cipher.getInstance("DES"); cipher.init(type, keyFactory.generateSecret(desKey), random); if (type == Cipher.ENCRYPT_MODE) { byte[] byteContent = content.getBytes("utf-8"); return parseByte2HexStr(cipher.doFinal(byteContent)); } else { byte[] byteContent = parseHexStr2Byte(content); return new String(cipher.doFinal(byteContent)); } } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | UnsupportedEncodingException | InvalidKeyException | NoSuchPaddingException | InvalidKeySpecException e) { e.printStackTrace(); } return null; } public final static String SHA224 = "sha-224"; public final static String SHA256 = "sha-256"; public final static String SHA384 = "sha-384"; public final static String SHA512 = "sha-512"; /** * @param string 加密内容 * @param type 加密类型 {@link #SHA224},{@link #SHA256},{@link #SHA384},{@link #SHA512} * @return SHA加密结果 */ public static String sha(String string, String type) { if (TextUtils.isEmpty(string)) return ""; if (TextUtils.isEmpty(type)) type = SHA256; try { MessageDigest md5 = MessageDigest.getInstance(type); byte[] bytes = md5.digest((string).getBytes()); String result = ""; for (byte b : bytes) { String temp = Integer.toHexString(b & 0xff); if (temp.length() == 1) { temp = "0" + temp; } result += temp; } return result; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ""; } /** * @return 随机生成密钥对(公钥和私钥), 客户端公钥加密,服务器私钥解密 * @throws Exception */ public static Map genKeyPair() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA", "BC"); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map keyMap = new HashMap<>(2); keyMap.put("RSAPublicKey", publicKey); keyMap.put("RSAPrivateKey", privateKey); return keyMap; } /** * @param keyMap 密钥对 * @param isPublicKey
  • true:获取公钥
  • false:获取私钥
* @return 获取密钥 */ public static String getKey(Map keyMap, boolean isPublicKey) { Key key = (Key) keyMap.get(isPublicKey ? "RSAPublicKey" : "RSAPrivateKey"); return new String(Base64.encode(key.getEncoded(), Base64.DEFAULT)); } /** * @param data 已加密数据 * @param privateKey 私钥(BASE64编码) * @return 生成数字签名 * @throws Exception */ public static String sign(byte[] data, String privateKey) throws Exception { byte[] keyBytes = Base64.decode(privateKey.getBytes(), Base64.DEFAULT); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC"); PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance("MD5withRSA"); signature.initSign(privateK); signature.update(data); return new String(Base64.encode(signature.sign(), Base64.DEFAULT)); } /** * @param data 已加密数据 * @param publicKey 公钥(BASE64编码) * @param sign 数字签名 * @return 校验数字签名 * @throws Exception */ public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { byte[] keyBytes = Base64.decode(publicKey.getBytes(), Base64.DEFAULT); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC"); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance("MD5withRSA"); signature.initVerify(publicK); signature.update(data); return signature.verify(Base64.decode(sign.getBytes(), Base64.DEFAULT)); } public static final int RSA_PUBLIC_ENCRYPT = 0; public static final int RSA_PUBLIC_DECRYPT = 1; public static final int RSA_PRIVATE_ENCRYPT = 2; public static final int RSA_PRIVATE_DECRYPT = 3; /** * @param data 源数据 * @param string 密钥(BASE64编码) * @param type {@link #RSA_PUBLIC_ENCRYPT} 公钥加密;{@link #RSA_PUBLIC_DECRYPT} 公钥解密;{@link #RSA_PRIVATE_ENCRYPT} 私钥加密;{@link #RSA_PRIVATE_DECRYPT} 私钥解密; * @return 一般情况下,公钥加密私钥解密 * @throws Exception */ public static byte[] rsa(byte[] data, String string, int type) throws Exception { byte[] keyBytes = Base64.decode(string, Base64.DEFAULT); Key key; KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC"); if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PUBLIC_DECRYPT) { X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); key = keyFactory.generatePublic(x509KeySpec); } else { PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); key = keyFactory.generatePrivate(pkcs8KeySpec); } Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PRIVATE_ENCRYPT) { cipher.init(Cipher.ENCRYPT_MODE, key); while (inputLen - offSet > 0) { cache = cipher.doFinal(data, offSet, inputLen - offSet > 117 ? 117 : inputLen - offSet); out.write(cache, 0, cache.length); i++; offSet = i * 117; } } else { cipher.init(Cipher.DECRYPT_MODE, key); while (inputLen - offSet > 0) { if (inputLen - offSet > 128) { cache = cipher.doFinal(data, offSet, 128); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * 128; } } byte[] result = out.toByteArray(); out.close(); return result; } }

加解密测试

  • md5
  • Base64
  • AES
  • DES
  • SHA
  • RSA

public File getBitmap2File(Bitmap bitmap) {
    File file = new File("/mnt/sdcard/01.jpg");
    try {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
        bos.flush();
        bos.close();
        return file;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

md5

// 字符串加密
String str = "123456"
System.out.println("一次加密:" + Encryption.md5(str))
System.out.println("二次加密:" + Encryption.md5(str, 2))
System.out.println("盐值加密:" + Encryption.md5(str, "78"))

System.out: 一次加密:e10adc3949ba59abbe56e057f20f883e
System.out: 二次加密:c56d0e9a7ccec67b4ea131655038d604
System.out: 盐值加密:25d55ad283aa400af464c76d713c07ad

// 文件加密
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)
System.out.println("IO文件加密:" + EncryptUtil.md5(getBitmap2File(bmp), EncryptUtil.MD5_TYPE_IO))
System.out.println("NIO文件加密:" + EncryptUtil.md5(getBitmap2File(bmp), EncryptUtil.MD5_TYPE_NIO))

I/System.out: IO文件加密:d41d8cd98f00b204e9800998ecf8427e
I/System.out: NIO文件加密:d41d8cd98f00b204e9800998ecf8427e

Base64

// 字符串加解密
String baseStr = EncryptUtil.base64EncodeStr("123456")
System.out.println("base64字符串加密:" + baseStr)
System.out.println("base64字符串解密:" + EncryptUtil.base64DecodedStr(baseStr))

I/System.out: base64字符串加密:MTIzNDU2
I/System.out: base64字符串解密:123456

// 文件加解密
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)
String baseFile = EncryptUtil.base64EncodeFile(getBitmap2File(bmp))
System.out.println("base64文件加密:" + baseFile)
System.out.println("base64文件解密:" + EncryptUtil.base64DecodedFile("/mnt/sdcard/01.jpg", baseFile))

I/System.out: base64文件加密:
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB…

I/System.out: base64文件解密:/mnt/sdcard/01.jpg

AES

// 对象加解密
String key = "1234567890123456"
String aesStr = EncryptUtil.aes("gzejia", key, Cipher.ENCRYPT_MODE)
System.out.println("aes对象加密: " + aesStr)
System.out.println("aes对象解密: " + EncryptUtil.aes(aesStr, key, Cipher.DECRYPT_MODE))

I/System.out: aes对象加密: 7E8886393DD34B24CC51B1A9D030DB5A
I/System.out: aes对象解密: gzejia

javax.crypto.BadPaddingException: pad block corrupted,出现该异常的主导原因可能如下:

  1. 密钥key长度不足16位
  2. 缺少 SecureRandom secureRandom = SecureRandom.getInstance(“SHA1PRNG”, “Crypto”);

DES

String key = "1234567890123456"
String desStr = EncryptUtil.des("gzejia", key, Cipher.ENCRYPT_MODE)
System.out.println("des对象加密: " + desStr)
System.out.println("des对象解密: " + EncryptUtil.des(desStr, key, Cipher.DECRYPT_MODE))

I/System.out: des对象加密: 552E6962E5187580
I/System.out: des对象解密: gzejia

SHA

String shaStr = "gzejia"
System.out.println("sha_SHA224对象加密: " + EncryptUtil.sha(shaStr, EncryptUtil.SHA224))
System.out.println("sha_SHA256对象加密: " + EncryptUtil.sha(shaStr, EncryptUtil.SHA256))
System.out.println("sha_SHA384对象加密: " + EncryptUtil.sha(shaStr, EncryptUtil.SHA384))
System.out.println("sha_SHA512对象加密: " + EncryptUtil.sha(shaStr, EncryptUtil.SHA512))

I/System.out: sha_SHA224对象加密:
36e2a37256a87dda91e8dacf9662c49461ecfc68d65488857c146e59

I/System.out: sha_SHA256对象加密:
94a9222df72d5927d1996203b0b186ab857d9055db54b48277bf943272b19fc1

I/System.out: sha_SHA384对象加密:
ea8e751bdfccb96715a37153a831fc935e2986743de72b32941043c1960f2e2ab7d71b965dda42cd128a837191e4667a

I/System.out: sha_SHA512对象加密:
a5e7bea71af1fccdc1f3d353df08013e2bebe8e0a49b435512bdc855f36589cffbf1ac1825e2357a4a4f8b5295173928f76a806ba0c77c2a7ba3ef068cdf3ced

RSA

try {
    byte[] data = "gzejia有中文".getBytes()

    // 密钥与数字签名获取
    Map keyMap = EncryptUtil.genKeyPair()
    String publicKey = EncryptUtil.getKey(keyMap, true)
    System.out.println("rsa获取公钥: " + publicKey)
    String privateKey = EncryptUtil.getKey(keyMap, false)
    System.out.println("rsa获取私钥: " + privateKey)

    // 公钥加密私钥解密
    byte[] rsaPublic =
            EncryptUtil.rsa(data, publicKey, EncryptUtil.RSA_PUBLIC_ENCRYPT)
    System.out.println("rsa公钥加密: " + new String(rsaPublic))
    System.out.println("rsa私钥解密: " + new String(
            EncryptUtil.rsa(rsaPublic, privateKey, EncryptUtil.RSA_PRIVATE_DECRYPT)))

    // 私钥加密公钥解密
    byte[] rsaPrivate =
            EncryptUtil.rsa(data, privateKey, EncryptUtil.RSA_PRIVATE_ENCRYPT)
    System.out.println("rsa私钥加密: " + new String(rsaPrivate))
    System.out.println("rsa公钥解密: " + new String(
            EncryptUtil.rsa(rsaPrivate, publicKey, EncryptUtil.RSA_PUBLIC_DECRYPT)))

    // 私钥签名及公钥签名校验
    String signStr = EncryptUtil.sign(rsaPrivate, privateKey)
    System.out.println("rsa数字签名生成: " + signStr)
    System.out.println("rsa数字签名校验: " +
            EncryptUtil.verify(rsaPrivate, publicKey, signStr))
} catch (Exception e) {
    e.printStackTrace()
}

I/System.out: rsa获取公钥:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3W84EWgATxN4OfjXUResyzy+lf/8TDDmHtRkh…

I/System.out: rsa获取私钥:
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALdbzgRaABPE3g5+NdRF6zLPL6V/…

I/System.out: rsa公钥加密:o�ZW�Ay����&�d��qa�h�]�ɟ�Ӵ�Rg1�0#…

I/System.out: rsa私钥解密: gzejia有中文

I/System.out: rsa私钥加密: � ��IA�{�R�+�y�_����%�=��…

I/System.out: rsa公钥解密: gzejia有中文

I/System.out: rsa数字签名生成:
XYHhwM2d+qUOWfTvi4l0Xh0JHlgf4zOBz81wahV90dxHhoqbi/HG6PlmkPnFnnZAkB5X8VMRKumK…

I/System.out: rsa数字签名校验: true

java.security.spec.InvalidKeySpecException:
java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag,解决途径:

原语句: KeyFactory keyf = KeyFactory.getInstance(“RSA”);
更改为:KeyFactory keyFactory = KeyFactory.getInstance(“RSA”, “BC”);