Skip to content

liufx/RSA

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

在网上找了许多篇关于RSA加密解密的文章与博客,是很有帮助,但比较零散与不简洁。 因此我进行了整理实现 IOS、java、android 从客户端用公钥加密,服务端用公钥解密; 制作步骤: 首先,打开Terminal, 生成必要的公钥、私钥、证书: openssl genrsa -out private_key.pem 1024

openssl req -new -key private_key.pem -out rsaCertReq.csr

openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt

openssl x509 -outform der -in rsaCert.crt -out public_key.der               // Create public_key.der For IOS

openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt  // Create private_key.p12 For IOS. 这一步,请记住你输入的密码,IOS代码里会用到

openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout             // Create rsa_public_key.pem For Java   openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt  上面七个步骤,总共生成7个文件。其中 public_key.der 和 private_key.p12 这对公钥私钥是给IOS用的, rsa_public_key.pem 和 pkcs8_private_key.pem 是给JAVA服务和android端用的。 它们的源都来自一个私钥:private_key.pem , 所以IOS端加密的数据,是可以被JAVA端解密的,反过来也一样。

android 使用的是自定义Base64转换算法

java服务使用的是

import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;

java 主要代码

import android.util.Base64;

import java.io.BufferedReader; import java.io.FileReader; 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.util.ArrayList; import java.util.List;

import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException;

import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;

public class RSAEncryptor {

public static void main(String[] args) throws Exception {

    String privateKeyPath = "/Users/liufx/rsa_public_key.pem";        // replace your public key path here
    String publicKeyPath = "/Users/liufx/pkcs8_private_key.pem";     // replace your private path here
    RSAEncryptor rsaEncryptor = new RSAEncryptor(privateKeyPath, publicKeyPath);

    try {

        String test = "这是一段将要使用'.der'文件加密的字符串!";
        String testRSAEnWith64 = rsaEncryptor.encryptWithBase64(test);
        String testRSADeWith64 = rsaEncryptor.decryptWithBase64(testRSAEnWith64);
        System.out.println(System.currentTimeMillis());
        System.out.println("\nEncrypt: \n" + testRSAEnWith64);
        System.out.println("\nDecrypt: \n" + testRSADeWith64);


        // NSLog the encrypt string from Xcode , and paste it here.
        // 请粘贴来自IOS端加密后的字符串
        String rsaBase46StringFromIOS =
                "GIYYULvWeKyXC9mPXn3+96qzz4vh5kE+hTMmVYbIlhrWYsAHt55xL6yEmK1MlONtCFPEGuWgDjwfcr5nyYQOPs1CQjITAOBUpQJgs5RrjoQGgvQFXzR4lDo1Fga67PApaifkjVq7AX82V9wFNgQ7Mw/Y4kJtNhEai5mvcEqj6OE=";

        String decryptStringFromIOS = rsaEncryptor.decryptWithBase64(rsaBase46StringFromIOS);
        System.out.println("Decrypt result from ios client: \n" + decryptStringFromIOS);
        System.out.println(System.currentTimeMillis());
    } catch (Exception e) {
        e.printStackTrace();
    }

}


/**
 * @param publicKeyFilePath
 * @param privateKeyFilePath
 */
public RSAEncryptor(String publicKeyFilePath, String privateKeyFilePath) throws Exception {
    String public_key = getKeyFromFile(publicKeyFilePath);
    String private_key = getKeyFromFile(privateKeyFilePath);
    loadPublicKey(public_key);
    loadPrivateKey(private_key);
}

public RSAEncryptor() {
    // load the PublicKey and PrivateKey manually
}


public String getKeyFromFile(String filePath) throws Exception {
    BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));

    String line = null;
    List<String> list = new ArrayList<String>();
    while ((line = bufferedReader.readLine()) != null) {
        list.add(line);
    }

    // remove the firt line and last line
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 1; i < list.size() - 1; i++) {
        stringBuilder.append(list.get(i)).append("\r");
    }

    String key = stringBuilder.toString();
    return key;
}

public String decryptWithBase64(String base64String) throws Exception {
    //  https://commons.apache.org/proper/commons-codec/ : org.apache.commons.codec.binary.Base64
    // sun.misc.BASE64Decoder
    byte[] binaryData = decrypt(getPrivateKey(), new BASE64Decoder().decodeBuffer(base64String) /*org.apache.commons.codec.binary.Base64.decodeBase64(base46String.getBytes())*/);
    String string = new String(binaryData);
    return string;
}

public String encryptWithBase64(String string) throws Exception {
    //  https://commons.apache.org/proper/commons-codec/ : org.apache.commons.codec.binary.Base64
    // sun.misc.BASE64Encoder
    byte[] binaryData = encrypt(getPublicKey(), string.getBytes());
    String base64String = new BASE64Encoder().encodeBuffer(binaryData) /* org.apache.commons.codec.binary.Base64.encodeBase64(binaryData) */;
    return base64String;
}


// convenient properties
public static RSAEncryptor sharedInstance = null;

public static void setSharedInstance(RSAEncryptor rsaEncryptor) {
    sharedInstance = rsaEncryptor;
}


// From: https://blog.csdn.net/chaijunkun/article/details/7275632

/**
 * 私钥
 */
private RSAPrivateKey privateKey;

/**
 * 公钥
 */
private RSAPublicKey publicKey;

/**
 * 获取私钥
 *
 * @return 当前的私钥对象
 */
public RSAPrivateKey getPrivateKey() {
    return privateKey;
}

/**
 * 获取公钥
 *
 * @return 当前的公钥对象
 */
public RSAPublicKey getPublicKey() {
    return publicKey;
}

/**
 * 随机生成密钥对
 */
public void genKeyPair() {
    KeyPairGenerator keyPairGen = null;
    try {
        keyPairGen = KeyPairGenerator.getInstance("RSA");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    keyPairGen.initialize(1024, 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('\r');
            }
        }
        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 {
    try {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        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("公钥数据为空");
    }
}

/**
 * 从文件中加载私钥
 *
 * @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('\r');
            }
        }
        loadPrivateKey(sb.toString());
    } catch (IOException e) {
        throw new Exception("私钥数据读取错误");
    } catch (NullPointerException e) {
        throw new Exception("私钥输入流为空");
    }
}

public void loadPrivateKey(String privateKeyStr) throws Exception {
    try {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] buffer = base64Decoder.decodeBuffer(privateKeyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        this.privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    } catch (NoSuchAlgorithmException e) {
        throw new Exception("无此算法");
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
        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("RSA");//, 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("RSA");//, new BouncyCastleProvider());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        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("密文数据已损坏");
    }
}


/**
 * 字节数据转字符串专用集合
 */
private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

/**
 * 字节数据转十六进制字符串
 *
 * @param data 输入数据
 * @return 十六进制内容
 */
public static String byteArrayToString(byte[] data) {
    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();
}

}

android 主要代码

import java.io.UnsupportedEncodingException;

/**

  • 自定义Base64转换算法
  • @author liufx

*/ public class Base64Helper { private static char[] base64EncodeChars = new char[]{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; private static byte[] base64DecodeChars = new byte[]{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1};

public static String encode(byte[] data) {
    StringBuffer sb = new StringBuffer();
    int len = data.length;
    int i = 0;
    int b1, b2, b3;
    while (i < len) {
        b1 = data[i++] & 0xff;
        if (i == len) {
            sb.append(base64EncodeChars[b1 >>> 2]);
            sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
            sb.append("==");
            break;
        }
        b2 = data[i++] & 0xff;
        if (i == len) {
            sb.append(base64EncodeChars[b1 >>> 2]);
            sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
            sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
            sb.append("=");
            break;
        }
        b3 = data[i++] & 0xff;
        sb.append(base64EncodeChars[b1 >>> 2]);
        sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
        sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
        sb.append(base64EncodeChars[b3 & 0x3f]);
    }
    return sb.toString();
}

public static byte[] decode(String str){
	try {
		return decodePrivate(str);
	} catch (UnsupportedEncodingException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	return new byte[]{};
}

private static byte[] decodePrivate(String str) throws UnsupportedEncodingException{
    StringBuffer sb = new StringBuffer();
    byte[] data = null;
	data = str.getBytes("US-ASCII");
    int len = data.length;
    int i = 0;
    int b1, b2, b3, b4;
    while (i < len) {
       
        do {
            b1 = base64DecodeChars[data[i++]];
        } while (i < len && b1 == -1);
        if (b1 == -1) break;
       
        do {
            b2 = base64DecodeChars
                    [data[i++]];
        } while (i < len && b2 == -1);
        if (b2 == -1) break;
        sb.append((char) ((b1 << 2) | ((b2 & 0x30) >>> 4)));
       
        do {
            b3 = data[i++];
            if (b3 == 61) return sb.toString().getBytes("iso8859-1");
            b3 = base64DecodeChars[b3];
        } while (i < len && b3 == -1);
        if (b3 == -1) break;
        sb.append((char) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));
       
        do {
            b4 = data[i++];
            if (b4 == 61) return sb.toString().getBytes("iso8859-1");
            b4 = base64DecodeChars[b4];
        } while (i < len && b4 == -1);
        if (b4 == -1) break;
        sb.append((char) (((b3 & 0x03) << 6) | b4));
    }
    return sb.toString().getBytes("iso8859-1");
}
public static void main(String[] args) throws UnsupportedEncodingException {
    String s = "我来测试一下";
    System.out.println("加密前:" + s);
    String x = encode(s.getBytes());
    System.out.println("加密后:" + x);
    String x1 = new String(decode(x));
    System.out.println("解密后:" + x1);
}

}

IOS 先请你把 public_key.der 和 private_key.p12 拖进你的Xcode项目里去 , 也请引入 Security.framework 以及 NSData+Base64.h/m (Download) 到项目里。

其他详情见代码中

感谢 https://www.apkbus.com/forum.php?mod=viewthread&tid=140480

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published