IOS, Android, Java Web Rest : RSA 加密和解密问题
一对公钥私钥可以使用 OpenSSL创建, 通常 1024位长度够了.
注意:
1. 公钥私钥是BASE64编码的,私钥需要转换成PKCS8格式;
2. 密文是字节数组,可以转化为BASE64编码字符串或16进制字符串。
3.JAVA,Android RSA 加密默认是"RSA/None/NoPadding", IOS需要调用方法进行设置。
(1)IOS RSA 加密算法,
https://github.com/ideawu/Objective-C-RSA
加密模式是"RSA/None/NoPadding", IOS需要调用方法进行设置。
(2)Android, Java , RSA加密:
下面是Java代码 (公钥私钥需要替换成你自己的,否则不工作!)
加密默认是"RSA/None/NoPadding"
package com.jcfax.app.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.security.Security; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import org.bouncycastle.jce.provider.BouncyCastleProvider; import sun.misc.BASE64Decoder;//将base64转换为byte[] import sun.misc.BASE64Encoder;//转byet[]换为base64 import java.net.URLEncoder; import java.net.URLDecoder; import java.io.UnsupportedEncodingException; //================================================================================ public class RSAEncrypt { /** 指定加密算法为RSA */ private static String ALGORITHM = "RSA"; /** 指定key的大小 */ private static int KEYSIZE = 1024; //String source_text= "Hello,World!"; //RSA Public key private static final String DEFAULT_PUBLIC_KEY= "MIGfMA0GCSqGSIb3DwQEBAQUAA4GNADCBiQKBgQDSS5owhX3tsB5tCuVuJMZrmMrq" + " " + "KmctKjAUOdBAFO2i5VvJzVTwwCxY3XJ2L9pAZZDKorpxCrkQ7b6sA+93lxJ6TABtq" + " " + "kRaGaEJEE2GclgkkdCesozecGkDXitPQ/Y1i+HKVxnNxv9E/a/ChvfGn50DKIW1S" + " " + "Pzna8iFwgEq1QcUrrfwIDAQAB" + " "; //RSA Private Key (PKCS8 格式) private static final String DEFAULT_PRIVATE_KEY= "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANJLmjCFfe2wHm0K" + " " + "5W4kxmuYyuoqZy0qMBQ50EAU7aLlW8nNVPALFjdcnYv2kBlkMqiunEKuRDtvqwD7" + " " + "3eXEnpMAG2qRFoZoQkQTYZyWCSR0J6yjN5waQNeK09D9jWL4cpXGc3G/0T9r8KG9" + " " + "8afnQMohbVI/OdryIWASrVBxSut/AgMBAAECgYEAj7qMT81tHB7bLLvdw0HvO2ra" + " " + "hOEmU4AaDDjXVHT5VfRcn7hu7QEm1f++zgJeynvpA9ETi59/kv/naGy8ZGXV2nRG" + " " + "cWK0U5+6DgT7oOeG6KlZie3Hw/KHPlKnwW3FoXRIh4bSGcxx6pxyrxCwQYKzM4Yc" + " " + "VetYXBS6gnZbuj8D8YECQQD8+dl0rG2Xm/Khn0M69g3rStL4QAaLXGOcB0uiDl+J" + " " + "trpw3D1fDN/yFrrE0VzxzvXxalGzVn4NOP/PZckvjUZ3AkEA1M8kg3xlPWQURfKZ" + " " + "KpBphPa13v1V2ot43Ce2wHTwpxXU9Uj5cwlz/+Jv5VZSwiYNCXwPkv79Kh8d14nMZ" + " " + "L+tdOQJBANrZav48jTKzftvDY+4GH1SGjqyk9wRpEONSjGPN+2iv4+rvHUi1YqeU" + " " + "ck8CsF2gpbQMPlHfaX0W6ncJn1q75VECQCB84xEjq3z8y0+GYrWpyEIhO9CoEjRD" + " " + "+JZ7hZ3J+2pGpK7qkFSnx/gXL7BN+8lyfW5t9L0FIgaqf6erdJvpLZkCQEmc2Ml2" + " " + "bgTq5sWFr+KsI+yWxUgP76M4JP7u8/XeH7a16nJSj/D6xSpkYz9bYkOI2Ulh3wbE" + " " + "sLxepdwmlvm3kSIY=" + " "; /** * 私钥 */ private RSAPrivateKey privateKey; /** * 公钥 */ private RSAPublicKey publicKey; /** * 字节数据转字符串专用集合 */ private static final char[] HEX_CHAR= {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; /** * 获取私钥 * @return 当前的私钥对象 */ public RSAPrivateKey getPrivateKey() { return privateKey; } /** * 获取公钥 * @return 当前的公钥对象 */ public RSAPublicKey getPublicKey() { return publicKey; } /** * 随机生成密钥对:1024位密钥 */ public void genKeyPair(){ KeyPairGenerator keyPairGen= null; try { keyPairGen= KeyPairGenerator.getInstance(ALGORITHM); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } keyPairGen.initialize(KEYSIZE, new SecureRandom()); KeyPair keyPair= keyPairGen.generateKeyPair(); this.privateKey= (RSAPrivateKey) keyPair.getPrivate(); this.publicKey= (RSAPublicKey) keyPair.getPublic(); } /** * 从文件中输入流中加载公钥 * @param in 公钥输入流 * @throws Exception 加载公钥时产生的异常 */ public void loadPublicKey(InputStream in) throws Exception{ try { 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(' '); } } loadPublicKey(sb.toString()); } catch (IOException e) { throw new Exception("公钥数据流读取错误"); } catch (NullPointerException e) { throw new Exception("公钥输入流为空"); } } /** * 从字符串中加载公钥 * @param publicKeyStr 公钥数据字符串 * @throws Exception 加载公钥时产生的异常 */ public void loadPublicKey(String publicKeyStr) throws Exception{ //System.out.println("==print publicKeyStr=="); //System.out.println(publicKeyStr); try { BASE64Decoder base64Decoder= new BASE64Decoder(); byte[] buffer= base64Decoder.decodeBuffer(publicKeyStr); //System.out.println(new String(buffer)); KeyFactory keyFactory= KeyFactory.getInstance(ALGORITHM); X509EncodedKeySpec keySpec= new X509EncodedKeySpec(buffer); this.publicKey= (RSAPublicKey) keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException e) { throw new Exception("无此算法"); } catch (InvalidKeySpecException e) { throw new Exception("公钥非法"); } catch (IOException e) { throw new Exception("公钥数据内容读取错误"); } catch (NullPointerException e) { throw new Exception("公钥数据为空"); } } /** * 从文件中加载私钥 * @param keyFileName 私钥文件名 * @return 是否成功 * @throws Exception */ public void loadPrivateKey(InputStream in) throws Exception{ try { 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(' '); } } loadPrivateKey(sb.toString()); } catch (IOException e) { throw new Exception("私钥数据读取错误"); } catch (NullPointerException e) { throw new Exception("私钥输入流为空"); } } public void loadPrivateKey(String privateKeyStr) throws Exception{ //System.out.println("==print privateKeyStr=="); //System.out.println(privateKeyStr); try { BASE64Decoder base64Decoder= new BASE64Decoder(); byte[] buffer= base64Decoder.decodeBuffer(privateKeyStr); //System.out.println(new String(buffer)); PKCS8EncodedKeySpec keySpec= new PKCS8EncodedKeySpec(buffer); KeyFactory keyFactory= KeyFactory.getInstance(ALGORITHM); this.privateKey= (RSAPrivateKey) keyFactory.generatePrivate(keySpec); } catch (NoSuchAlgorithmException e) { throw new Exception("无此算法"); } catch (InvalidKeySpecException e) { throw new Exception("私钥非法"); } catch (IOException e) { throw new Exception("私钥数据内容读取错误"); } catch (NullPointerException e) { throw new Exception("私钥数据为空"); } } /** * 加密过程 * @param publicKey 公钥 * @param plainTextData 明文数据 * @return * @throws Exception 加密过程中的异常信息 */ public byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception{ if(publicKey== null){ throw new Exception("加密公钥为空, 请设置"); } Cipher cipher= null; try { cipher= Cipher.getInstance(ALGORITHM, new BouncyCastleProvider()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] output= cipher.doFinal(plainTextData); return output; } catch (NoSuchAlgorithmException e) { throw new Exception("无此加密算法"); } catch (NoSuchPaddingException e) { e.printStackTrace(); return null; }catch (InvalidKeyException e) { throw new Exception("加密公钥非法,请检查"); } catch (IllegalBlockSizeException e) { throw new Exception("明文长度非法"); } catch (BadPaddingException e) { throw new Exception("明文数据已损坏"); } } /** * 解密过程 * @param privateKey 私钥 * @param cipherData 密文数据 * @return 明文 * @throws Exception 解密过程中的异常信息 */ public byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception{ if (privateKey== null){ throw new Exception("解密私钥为空, 请设置"); } Cipher cipher= null; try { cipher= Cipher.getInstance(ALGORITHM, new BouncyCastleProvider()); cipher.init(Cipher.DECRYPT_MODE, privateKey); //Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); //final Cipher cipher = Cipher.getInstance(PADDING, PROVIDER); byte[] output= cipher.doFinal(cipherData); return output; } catch (NoSuchAlgorithmException e) { throw new Exception("无此解密算法"); } catch (NoSuchPaddingException e) { e.printStackTrace(); return null; }catch (InvalidKeyException e) { throw new Exception("解密私钥非法,请检查"); } catch (IllegalBlockSizeException e) { throw new Exception("密文长度非法"); } catch (BadPaddingException e) { throw new Exception("密文数据已损坏"); } } /** * 字节数据转十六进制字符串 * @param data 输入数据 * @return 十六进制内容 */ public static String byteArrayToString(byte[] data){ //char[] HEX_CHAR= {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; StringBuilder stringBuilder= new StringBuilder(); for (int i=0; i<data.length; i++){ //取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移 stringBuilder.append(HEX_CHAR[(data[i] & 0xf0)>>> 4]); //取出字节的低四位 作为索引得到相应的十六进制标识符 stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]); // if (i<data.length-1){ // stringBuilder.append(' '); // } } return stringBuilder.toString(); } private static byte toByte(char c) { byte b = (byte) "0123456789abcdef".indexOf(c); return b; } /** * 把16进制字符串转换成字节数组 * @param hex * @return */ public static byte[] hexStringToByte(String hex) { int len = (hex.length() / 2); byte[] result = new byte[len]; char[] achar = hex.toCharArray(); for (int i = 0; i < len; i++) { int pos = i * 2; result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1])); } return result; } //=================================================================== //测试用例 public static void main(String[] args) { RSAEncrypt rsaEncrypt= new RSAEncrypt(); //rsaEncrypt.genKeyPair(); //加载公钥 try { rsaEncrypt.loadPublicKey(RSAEncrypt.DEFAULT_PUBLIC_KEY); System.out.println("Loading RSA Public Key,成功!"); } catch (Exception e) { System.err.println(e.getMessage()); System.err.println("Loading RSA Public Key,失败!"); } //加载私钥 try { rsaEncrypt.loadPrivateKey(RSAEncrypt.DEFAULT_PRIVATE_KEY); System.out.println("Loading RSA Private Key,成功!"); } catch (Exception e) { System.err.println(e.getMessage()); System.err.println("Loading RSA Private Key,失败!"); } long currentTime =System.currentTimeMillis(); System.err.println(currentTime/1000); //测试字符串 //System.out.println("--print source_text --"); String source_text= "Hello,World!"; // System.out.println(source_text); // System.out.println("明文长度:"+ source_text.length()); try { //使用公钥加密 System.out.println("==使用公钥加密=="); byte[] cipher_byte = rsaEncrypt.encrypt(rsaEncrypt.getPublicKey(), source_text.getBytes()); System.out.println(new String(cipher_byte)); System.out.println("密文长度:"+ cipher_byte.length); //for(int i=0;i<cipher_text.length;i++) // System.out.println(cipher_text[i]); //System.out.println(RSAEncrypt.byteArrayToString(cipher_byte)); //String cipher_hex="7e4f2c4794d19a1800060f0d716411d8c1eebefb080415154eb39ef3f703377dec058b0c319f729b4fe40fba5656ee71f75efe1b7b80683207243e7ec1ee81b854ea39768a0bb190923a2437a1f51bff11fc4c0847cf6c4c46c4010f54af4334cd7a88ca9d846c3ea2e12e7d5744c949d174483bf78c08d68a89b4d5cdb9fc65"; //cipher_byte=RSAEncrypt.hexStringToByte(cipher_hex); //System.out.println(new String(cipher_byte)); //使用私钥解密,从这里开始! System.out.println("==使用私钥解密,得到明文!=="); //byte[] cipher_byte 密文二进制数组,最大长度小于128 Bytes. byte[] plain_text = rsaEncrypt.decrypt(rsaEncrypt.getPrivateKey(), cipher_byte); System.out.println(new String(plain_text)); //System.out.println("明文长度:"+ plain_text.length); //System.out.println(RSAEncrypt.byteArrayToString(plain_text)); } catch (Exception e) { System.err.println(e.getMessage()); } } }
--