RSA 1024 表示加密后的长度为 1024 位,即 128 个字节,但明文的最大长度不能超过 117 个字节,超过 117 个字节需要使用 RSA 2048,超过 245 个字节,需要使用更高位数的 RSA。
RSA 的位数越高,其密钥对产生及加密、解密的速度越慢,这是基于大素数非对称加密算法的缺陷。这样的非对称加密算法在效率上远比基于离散对数的非对称加密算法(比如:椭圆曲线加密算法)差。
Cipher rsa = Cipher.getInstance( "RSA/ECB/PKCS1Padding ");
表示,使用RSA算法,并且加PAD的方式按照PKCS1的标准。即输入数据长度小于等于密钥的位数/8-11,例如:1024位密钥,1024/8-11 =117。 不足的部分,程序会自动补气。加密后的数据还是等于密钥的位数/8。
以下是我实现的一个类:支持使用1024时加密超过117个字节的文本,并支持加密字符串为中英文。
生成公钥与私钥的类:
//*此类作用为生成密钥与公钥,密钥生成到文件中。公钥生成为字符串,可提供给他人。
public class Skey_RSA {
public static void main(String args[]) throws Exception{
KeyPairGenerator kpg=KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp=kpg.genKeyPair();
PublicKey pbkey=kp.getPublic();
PrivateKey prkey=kp.getPrivate();
FileOutputStream f2=new FileOutputStream("C://Skey_RSA_priv.dat");
ObjectOutputStream b2=new ObjectOutputStream(f2);
b2.writeObject(prkey);
try {
//此处使用了sun.misc.BASE64Encoder。网上说不建议使用,可找到相关类替换。我太懒了。。。^_^
System.err.println("公:"+(new BASE64Encoder()).encode(pbkey.getEncoded()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
加密解密类:
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import sun.misc.BASE64Decoder;
/**
* @author yhcui
* @version 创建时间:May 18, 2011 2:44:51 PM 类说明
* RSA加密解实实现。
* 支持加密字节长度超过117。
* 支持加密中文与英文混合。
*/
public class RSAUtils {
/**
* 算法名称
*/
private final static String RSA = "RSA";
/**
* 加密后的字节分隔长度
*/
private final static int encryptSepLength = 256;
/**
* 明文字节分隔长度
*/
private final static int plainSepLneght = 100;
private static byte[] encrypt(byte[] text, PublicKey pubRSA)
throws Exception {
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.ENCRYPT_MODE, pubRSA);
return cipher.doFinal(text);
}
public final static String encrypt(String text, PublicKey uk) {
StringBuffer sbf = new StringBuffer(200);
try {
text = URLEncoder.encode(text, "UTF-8");//用这个的原因是为了支持汉字、汉字和英文混排,解密方法中同理
byte[] plainByte = text.getBytes();
ByteArrayInputStream bays = new ByteArrayInputStream(plainByte);
byte[] readByte = new byte[plainSepLneght];
int n = 0;
//这个位置很恶心人的写了一堆,是为了支持超过117字节,我每次加密100字节。
while ((n = bays.read(readByte)) > 0) {
if (n >= plainSepLneght) {
sbf.append(byte2hex(encrypt(readByte, uk)));
} else {
byte[] tt = new byte[n];
for (int i = 0; i < n; i++) {
tt[i] = readByte[i];
}
sbf.append(byte2hex(encrypt(tt, uk)));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return sbf.toString();
}
public final static String decrypt(String data, PrivateKey rk) {
String rrr = "";
StringBuffer sb = new StringBuffer(100);
try {
ByteArrayInputStream bais = new ByteArrayInputStream(
data.getBytes());
//此处之所以是 256,而不是128的原因是因为有一个16进行的转换,所以由128变为了256
byte[] readByte = new byte[256];
int n = 0;
while ((n = bais.read(readByte)) > 0) {
if (n >= encryptSepLength) {
sb.append(new String(decrypt(hex2byte(readByte), rk)));
} else {
}
}
rrr = URLDecoder.decode(sb.toString(), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return rrr;
}
private static byte[] decrypt(byte[] src, PrivateKey rk) throws Exception {
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.DECRYPT_MODE, rk);
return cipher.doFinal(src);
}
public static String byte2hex(byte[] b) {
String hs = "";
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = Integer.toHexString(b[n] & 0xFF);
if (stmp.length() == 1)
hs += ("0" + stmp);
else
hs += stmp;
}
return hs.toUpperCase();
}
public static byte[] hex2byte(byte[] b) {
if ((b.length % 2) != 0)
throw new IllegalArgumentException("长度不是偶数");
byte[] b2 = new byte[b.length / 2];
for (int n = 0; n < b.length; n += 2) {
String item = new String(b, n, 2);
b2[n / 2] = (byte) Integer.parseInt(item, 16);
}
return b2;
}
public static PrivateKey getPrivateKey() {
try {
FileInputStream f = new FileInputStream("c://Skey_RSA_priv.dat");
ObjectInputStream b = new ObjectInputStream(f);
RSAPrivateKey prk = (RSAPrivateKey) b.readObject();
return prk;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static PublicKey getPublicKey() {
try {
String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaWmSqfTHg0xyRTtih/0Q+Lk9ve+i6+ApxD27F"
+ "u+SvKupeQ/+5Bu6SBXmpvHxcC4dqfYS/NGoJ5ZTuoh8pez6bffINVY47r8UwYMuQMxYs0n1egwYw"
+ "rB+lwYbFhcOQ2BdoXcGF5fmWf2HfauQ6qNwyc2aGDXpgBIgmT5u+rZoOmwIDAQAB";
byte[] keyBytes;
keyBytes = new BASE64Decoder().decodeBuffer(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String args[]) {
try {
String plaintext = "a";
System.out.println("plaintextt.getByte().length:"
+ plaintext.getBytes().length);
String cipherText = encrypt(plaintext, getPublicKey());
System.out.println("cipherText:" + cipherText);
System.err.println("cipherText lenght:" + cipherText.length());
System.err.println("cipherText byte[]:"
+ cipherText.getBytes().length);
String plainText = decrypt(cipherText, getPrivateKey());
System.out.println("orginttext:" + plaintext);
System.out.println("plainTex t:" + plainText);
} catch (Exception e) {
e.printStackTrace();
}
}
}