關於RSA的介紹Google一下不少,這裏不作說明。項目開發中通常會把公鑰放在本地進行加密,服務端經過私鑰進行解密。Android項目開發中要用到這個加密算法,總結後實現以下:java
import android.content.Context; import android.util.Base64; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.security.Key; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; public class RSAUtil { /** * KEY_ALGORITHM */ public static final String KEY_ALGORITHM = "RSA"; /** * 加密Key的長度等於1024 */ public static int KEYSIZE = 1024; /** * 解密時必須按照此分組解密 */ public static int decodeLen = KEYSIZE / 8; /** * 加密時小於117便可 */ public static int encodeLen = 110;//(DEFAULT_KEY_SIZE / 8) - 11; /** * 加密填充方式,android系統的RSA實現是"RSA/None/NoPadding",而標準JDK實現是"RSA/None/PKCS1Padding" ,這形成了在android機上加密後沒法在服務器上解密的緣由 */ public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding"; public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; /** * 經過公鑰加密 */ public static byte[] encryptPublicKey(byte[] encryptedData, String key) throws Exception { if (encryptedData == null) { throw new IllegalArgumentException("Input encryption data is null"); } byte[] encode = new byte[]{}; for (int i = 0; i < encryptedData.length; i += encodeLen) { byte[] subarray = subarray(encryptedData, i, i + encodeLen); byte[] doFinal = encryptByPublicKey(subarray, key); encode = addAll(encode, doFinal); } return encode; } /** * 經過私鑰解密 */ public static byte[] decryptPrivateKey(byte[] encode, String key) throws Exception { if (encode == null) { throw new IllegalArgumentException("Input data is null"); } byte[] buffers = new byte[]{}; for (int i = 0; i < encode.length; i += decodeLen) { byte[] subarray = subarray(encode, i, i + decodeLen); byte[] doFinal = decryptByPrivateKey(subarray, key); buffers = addAll(buffers, doFinal); } return buffers; } /** * 從字符串中加載公鑰 * * @param publicKeyStr 公鑰數據字符串 */ private static PublicKey loadPublicKey(String publicKeyStr) throws Exception { try { byte[] buffer = decode(publicKeyStr); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); //表示根據 ASN.1 類型 SubjectPublicKeyInfo 進行編碼的公用密鑰的 ASN.1 編碼。 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer); return keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException e) { throw new Exception("無此算法"); } catch (InvalidKeySpecException e) { throw new Exception("公鑰非法"); } catch (NullPointerException e) { throw new Exception("公鑰數據爲空"); } } /** * 從字符串中加載私鑰<br> * 加載時使用的是PKCS8EncodedKeySpec(PKCS#8編碼的Key指令)。 */ private static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception { try { byte[] buffer = decode(privateKeyStr); //表示按照 ASN.1 類型 PrivateKeyInfo 進行編碼的專用密鑰的 ASN.1 編碼。 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); return keyFactory.generatePrivate(keySpec); } catch (NoSuchAlgorithmException e) { throw new Exception("無此算法"); } catch (InvalidKeySpecException e) { throw new Exception("私鑰非法"); } catch (NullPointerException e) { throw new Exception("私鑰數據爲空"); } } /** * 用私鑰解密 */ private static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception { if (data == null) { throw new IllegalArgumentException("Input data is null"); } //取得私鑰 Key privateKey = loadPrivateKey(key); // 對數據解密 Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 用公鑰加密 */ private static byte[] encryptByPublicKey(byte[] data, String key) throws Exception { if (data == null) { throw new IllegalArgumentException("Input data is null"); } // 取得公鑰 Key publicKey = loadPublicKey(key); // 對數據加密 Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data); } /** * <p> * BASE64字符串解碼爲二進制數據 * </p> */ public static byte[] decode(String base64) { return Base64.decode(base64, Base64.DEFAULT); } /** * <p> * 二進制數據編碼爲BASE64字符串 * </p> */ public static String encode(byte[] bytes) { return Base64.encodeToString(bytes, Base64.DEFAULT); } /** * <p>Produces a new {@code byte} array containing the elements * between the start and end indices. * * <p>The start index is inclusive, the end index exclusive. * Null array input produces null output. * * @param array the array * @param startIndexInclusive the starting index. Undervalue (<0) * is promoted to 0, overvalue (>array.length) results * in an empty array. * @param endIndexExclusive elements up to endIndex-1 are present in the * returned subarray. Undervalue (< startIndex) produces * empty array, overvalue (>array.length) is demoted to * array length. * @return a new array containing the elements between * the start and end indices. * @since 2.1 */ private static byte[] subarray(final byte[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null) { return null; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive > array.length) { endIndexExclusive = array.length; } final int newSize = endIndexExclusive - startIndexInclusive; if (newSize <= 0) { return EMPTY_BYTE_ARRAY; } final byte[] subarray = new byte[newSize]; System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); return subarray; } /** * <p>Adds all the elements of the given arrays into a new array. * <p>The new array contains all of the element of {@code array1} followed * by all of the elements {@code array2}. When an array is returned, it is always * a new array. * * @param array1 the first array whose elements are added to the new array. * @param array2 the second array whose elements are added to the new array. * @return The new byte[] array. * @since 2.1 */ private static byte[] addAll(final byte[] array1, final byte... array2) { if (array1 == null) { return clone(array2); } else if (array2 == null) { return clone(array1); } final byte[] joinedArray = new byte[array1.length + array2.length]; System.arraycopy(array1, 0, joinedArray, 0, array1.length); System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } /** * <p>Clones an array returning a typecast result and handling * {@code null}. * * <p>This method returns {@code null} for a {@code null} input array. * * @param array the array to clone, may be {@code null} * @return the cloned array, {@code null} if {@code null} input */ private static byte[] clone(final byte[] array) { if (array == null) { return null; } return array.clone(); } /** * 讀取密鑰信息 */ public static String readString(InputStream in) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(in)); String readLine = null; StringBuilder sb = new StringBuilder(); while ((readLine = br.readLine()) != null) { if (readLine.charAt(0) == '-') { continue; } else { sb.append(readLine); sb.append('\r'); } } return sb.toString(); } }
使用以下:android
/** * 獲取加密數據 * * @param encryptStr 待加密字符串 * rsa_public_key.pem 爲本地公鑰 */ public String getEncryptData(Context context, String encryptStr) { try { InputStream inPublic = context.getResources().getAssets().open("rsa_public_key.pem"); String publicKey = readString(inPublic); byte[] encodedData = encryptPublicKey(encryptStr.getBytes(), publicKey); return encode(encodedData); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return ""; }