RSA加密解密,JS、PHP、JAVA三平台互通

参考文章:

使用代码:
我自己修改了bug的js代码:https://github.com/oren-git/jsencrypt
关键点:RSA有个特点,对要加密的明文的长度有限制,跟密钥长度有关,超过长度无法加密,所以需要分片加密,然后合并,解密的时候也要分片解密,然后合并。但是这些都需要自己来实现,看的一些开源库里面,只有www.ohdave.com的加密实现了分片加密,但是解密却不成功,最后手动修改jsencrypt实现了分片加密解密
 
 
JS:

var publicKey = document.getElementById("publicKey").value;
var privateKey = document.getElementById("privateKey").value;
var encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);//设置公钥
encrypt.setPrivateKey(privateKey);//设置私钥

//待加密的明文
var plaintext = "A1EC954671AB698C740B0F71D6408A47B72CC155550F1E8BD9D07E33BD0D6204EE2A5D3335DDF4D93372E98E63C60F4F89F9A6DE1636ECE9286ECE2B5BB7840BE1F038F7AD8CD0B24EFC6004F474F297873E48786AB5A195AB43C00BE69CC4C21782358FCC09115D29AA61DCBEA31ADE826EF37F87817AE9E1BD79F5FDF2FB8CF46B1807B1B2E5FF1576A9AA7432C833127428D2385D90CAB57A128473C43FBDFFFF478F3E5B483D2081D9C98B04806C3128A6DF1CF10D8EA455CC2EA033F6ADEB59C35A699CA015288614BDFD93A2A4814907D68618575";
//var plaintext = "zzz";

var cipherText = encrypt.encrypt(plaintext);//加密
console.info(cipherText);//输出加密后的密文,已经base64编码了

var uncrypted = encrypt.decrypt(cipherText);//解密,输入加密后的base64密文
console.info(uncrypted);//输出解密后的明文


PHP:

public function encode($plaintext ){

$publicKey = openssl_pkey_get_public(file_get_contents(APP_PATH.'/public.key'));
$details = openssl_pkey_get_details($publicKey);
$length = $details['bits'] / 8 - 11;
$chunks = chunk_split($plaintext, $length, '<br>');
$chunks = explode('<br>', $chunks);
$result = '';
foreach($chunks as $chunk){
$chunk = trim($chunk);
if($chunk){
if(openssl_public_encrypt($chunk, $ciphertext, $publicKey, OPENSSL_PKCS1_PADDING)){
$result .= $ciphertext;
}else{
var_dump(openssl_error_string());
}
}
}
$ciphertext = base64_encode($result);
return $ciphertext;
}

public function decode($data ){

$privateKey = openssl_pkey_get_private(file_get_contents(APP_PATH.'/private.key'));
$details = openssl_pkey_get_details($privateKey);
$length = $details['bits'] / 8;
$bin_ciphertext = base64_decode($data);
$chunks = chunk_split($bin_ciphertext, $length, '<br>');
$chunks = explode('<br>', $chunks);
$result = '';
foreach($chunks as $chunk){
$chunk = trim($chunk);
if($chunk){
if(openssl_private_decrypt($chunk, $plaintext, $privateKey, OPENSSL_PKCS1_PADDING)){
$result .= $plaintext;
}else{
var_dump(openssl_error_string().var_export($chunk, true));exit();
}
}
}
return $result;
}

JAVA:

import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import javax.crypto.Cipher;

public class RSA {

private RSAPublicKey publicKey;
private RSAPrivateKey privateKey;
public static String charset = "utf-8";

public RSA(String publicKey, String privateKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] keyBytes = base64Decode(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
this.publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);

keyBytes = base64Decode(privateKey);
PKCS8EncodedKeySpec pkeySpec = new PKCS8EncodedKeySpec(keyBytes);
this.privateKey = (RSAPrivateKey) keyFactory.generatePrivate(pkeySpec);
}

public String encode(String data) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
int key_len = publicKey.getModulus().bitLength() / 8;
int MAX_ENCRYPT_BLOCK = key_len - 11;

cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] dataBytes = data.getBytes();
int inputLen = dataBytes.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(dataBytes, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();

return base64Encode(encryptedData);
}

public String decode(String data) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
int MAX_DECRYPT_BLOCK = privateKey.getModulus().bitLength() / 8;
cipher.init(Cipher.DECRYPT_MODE, privateKey);

byte[] dataBytes = base64Decode(data);
int inputLen = dataBytes.length;

ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(dataBytes, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return new String(decryptedData);
}

public static String base64Encode(byte[] data){
try {
return new String(Base64.getEncoder().encode(data), charset);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

public static String base64Encode(String str){
try {
return base64Encode(str.getBytes(charset));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

public static byte[] base64Decode(String str){
try {
return Base64.getDecoder().decode(str.getBytes(charset));
} catch (Exception e1) {
e1.printStackTrace();
}
return null;
}
}