最近在搞udp可靠通信(不单单是丢失重传),为了进行密钥传输学习一下密钥长度的一些知识,mark一下
java默认的rsa填充方案为RSA/ECB/PKCS1Padding
一般说的rsa密钥长度单位是bit,本文所有长度单位均为byte,除非另有说明
java的实现中
设:密钥模数长度(与密钥长度相等)lm,公钥e长度lpube,私钥e长度lprie
一、密钥长度=lm
二、lpube=17bit,具体值为 1|00000000|00000001,所以发布公钥时只发布模数即可
三、lprie与指定的密钥长度相关,不是固定值
不进行分段加密
设:明文长度为d,密文长度为e,密钥长度为l
一、d<=l-11,有时大于此值也可以加密但为了不出现随机性必须保证加密的数据符合此关系
二、e=l
进行分段加密时有如下公式(须要自行实现,我的方案仅供大家参考)
设:明文长度ld,密文长度le,密钥模数长度(与密钥长度相等)lm,公钥e长度lpube,私钥e长度lprie
一、密文长度
a=lm-11
num=int(ld/a)
hasMore=ld%a
num+=hasMore?1:0
le=num*lm
二、明文长度。(非函数关系,但有相关性)
blockNum=le/lm
(blockNum-1)*(le-11)
三、给出byte数组(长度为capacity)计算最大可容纳的加密内容大小
blockNum=capacity/lm
ld=(lm-11)*blockNum
进行签名时有如下关系:(使用sha1WithRSA签名算法)
设数据长度ld,签名长度le,密钥模数长度(与密钥长度相等)lm
一、le=lm
二、对ld没有要求
最后附上分段加密的实现
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
/*
注意:
a经实验publickey的exponent始终为[1,0,1]
b不保证线程安全
目的:
a针对每个对端机保存一个密钥对
b实现分段加密
c为各种加/解密和签名操作提供便利
**/
public class RsaTool{
//推荐密钥长度
public static final int advance_key_size=512;
public static final String algorithm="rsa";
public static final String signature_alghorithm="sha1WithRSA";
private RSAPrivateKey priKey;
private RSAPublicKey pubKey;
private Cipher encrypt;
private Cipher decrypt;
public RsaTool() {
}
/*
* 指定密钥长度生成随机密钥
*/
public RsaTool(int keyLength){
KeyPairGenerator kpg=null;
try{
kpg=KeyPairGenerator.getInstance(algorithm);
kpg.initialize(advance_key_size);
encrypt=Cipher.getInstance(algorithm);
decrypt=Cipher.getInstance(algorithm);
}catch(NoSuchAlgorithmException e){
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
kpg.initialize(keyLength);
KeyPair kp=kpg.generateKeyPair();
setPrivateKey((RSAPrivateKey)kp.getPrivate());
setPublicKey((RSAPublicKey)kp.getPublic());
}
/*
* 指定编码后的密钥以还原密钥
*/
public RsaTool(byte[]pubKey,byte[]priKey)throws InvalidKeySpecException{
try{
encrypt=Cipher.getInstance(algorithm);
decrypt=Cipher.getInstance(algorithm);
}catch(Exception e){
e.printStackTrace();
}
setPrivateKey(priKey);
setPublicKey(pubKey);
}
/*
* 指定公钥或私钥的e和m以还原密钥,使密钥构建更加灵活节省存储空间
*/
public RsaTool(byte[]pubKey,byte[]priKey,byte[]modulus)throws InvalidKeySpecException{
try{
encrypt=Cipher.getInstance(algorithm);
decrypt=Cipher.getInstance(algorithm);
}catch(Exception e){
e.printStackTrace();
}
setPrivateKey(priKey,modulus);
setPublicKey(pubKey,modulus);
}
/**
* 由于密钥长度不是常量所以只能通过计算获得
* 对于给出的capacity(c)计算一个值(d),使encrypt(d)<=c
*/
public int getThisBufferCapacity(int capacity){
//计算公钥加密结果的块大小
int resultUnitLen=pubKey.getModulus().bitLength()/8;
//计算指定容量可容纳的块数量
int num=capacity/resultUnitLen;
//数量乘以最大明文块大小
return (resultUnitLen-11)*num;
}
/**
* 计算给出的密文长度解密后的最大文明长度
* 具有一定的函数关系性质
* 设解密后的数据为data 解密前为encrypted
* data.length<=calcDecryptedMaxLength(encrypted.length)
* 即计算出的结果一定大于等于实际解密后的长度
*/
public int calcDecryptedMaxLength(int length){
int resultUnitLen=priKey.getModulus().bitLength()/8;
//大于此长度有时也可以加密但为确保成功使用最小值
int dataBlockNum=length/resultUnitLen;
return (resultUnitLen-11)*dataBlockNum;
}
/**
* 计算给出长度的明文加密后的长度
* 是函数关系
*/
public int calcEncryptedLength(int length){
int resultUnitLen=pubKey.getModulus().bitLength()/8;
//大于此长度有时也可以加密但为确保成功使用最小值
int dataUnitLen=resultUnitLen-11;
int dataBlockNum=length/dataUnitLen;
if(length%dataUnitLen==0){
dataBlockNum+=1;
}
return resultUnitLen*dataBlockNum;
}
//可能同一个类表示的并不是同一个密钥对,所以单独提供获取公钥modulus长度的方法
public int getPublicKeyModulusLength() {
return pubKey.getModulus().bitLength()/8;
}
public RSAPublicKey getPublicKey() {
return pubKey;
}
public PrivateKey getPrivateKey() {
return priKey;
}
public byte[]getEncodedPrivateKey(){
return priKey.getEncoded();
}
public byte[]getEncodedPublicKey(){
return pubKey.getEncoded();
}
public void getEncodedPrivateKey(ByteBuffer buf){
buf.put(getEncodedPrivateKey());
}
public void getEncodedPublicKey(ByteBuffer buf) {
buf.put(getEncodedPublicKey());
}
public void setPrivateKey(byte[]key)throws InvalidKeySpecException{
PKCS8EncodedKeySpec kps=new PKCS8EncodedKeySpec(key);
try{
KeyFactory kf=KeyFactory.getInstance(algorithm);
RSAPrivateKey pri=(RSAPrivateKey)kf.generatePrivate(kps);
setPrivateKey(pri);
}catch(NoSuchAlgorithmException e){
e.printStackTrace();
}
}
public void setPrivateKey(RSAPrivateKey pk){
priKey=pk;
try{
decrypt.init(Cipher.DECRYPT_MODE,pk);
}catch(Exception e){
e.printStackTrace();
}
}
public void setPrivateKey(byte[]bigIntegerE,byte[]bigIntegerM) throws InvalidKeySpecException{
RSAPrivateKeySpec spec=new RSAPrivateKeySpec(new BigInteger(bigIntegerM),new BigInteger(bigIntegerE));
try{
KeyFactory kf=KeyFactory.getInstance(algorithm);
RSAPrivateKey pub=(RSAPrivateKey)kf.generatePrivate(spec);
setPrivateKey(pub);
}catch(NoSuchAlgorithmException e){
e.printStackTrace();
}
}
public void setPublicKey(byte[]key,int offset,int len)throws InvalidKeySpecException{
byte[] kk = Arrays.copyOfRange(key,offset,offset+len);
setPublicKey(kk);
}
public void setPublicKey(byte[]key)throws InvalidKeySpecException{
X509EncodedKeySpec kps=new X509EncodedKeySpec(key);
try{
KeyFactory kf=KeyFactory.getInstance(algorithm);
RSAPublicKey pub=(RSAPublicKey)kf.generatePublic(kps);
setPublicKey(pub);
}catch(NoSuchAlgorithmException e){
e.printStackTrace();
}
}
public void setPublicKey(RSAPublicKey k){
//int l=k.getModulus().bitLength();
//encDataMaxLen=l/8-11;
pubKey=k;
try{
encrypt.init(Cipher.ENCRYPT_MODE,k);
}catch(Exception e){
e.printStackTrace();
}
}
public void setPublicKey(byte[]bigIntegerE,byte[]bigIntegerM) throws InvalidKeySpecException{
RSAPublicKeySpec spec=new RSAPublicKeySpec(new BigInteger(bigIntegerM),new BigInteger(bigIntegerE));
try{
KeyFactory kf=KeyFactory.getInstance(algorithm);
RSAPublicKey pub=(RSAPublicKey)kf.generatePublic(spec);
setPublicKey(pub);
}catch(NoSuchAlgorithmException e){
e.printStackTrace();
}
}
public byte[] encryptByPublicKey(byte[]data){
return encryptByPublicKey(data,0,data.length);
}
public byte[] encryptByPublicKey(byte[]data,int offset,int length){
try{
int resultUnitLen=pubKey.getModulus().bitLength()/8;
//大于此长度有时也可以加密但为确保成功使用最小值
int dataUnitLen=resultUnitLen-11;
int dataBlockNum=length/dataUnitLen;
if(length%dataUnitLen!=0){
dataBlockNum+=1;
}
byte[]result=new byte[dataBlockNum*resultUnitLen];
for(int i=0;idata.length)?data.length-offset:dataUnitLen;
try{
//Counter.update();
encrypt.doFinal(data,offset,dataLen,result,resultUnitLen*i);
//Counter.info();
}catch(ShortBufferException e){
e.printStackTrace();
}
//System.arraycopy(encrypted,0,result,resultUnitLen*i,resultUnitLen);
offset+=dataUnitLen;
}
return result;
}catch(IllegalBlockSizeException e){
e.printStackTrace();
}catch(BadPaddingException e){
e.printStackTrace();
}
return null;
}
public byte[]decryptByPrivateKey(byte[]data){
return decryptByPrivateKey(data,0,data.length);
}
public byte[]decryptByPrivateKey(byte[]data,int offset,int length){
int resultUnitLen=priKey.getModulus().bitLength()/8;
//大于此长度有时也可以加密但为确保成功使用最小值
int dataBlockNum=length/resultUnitLen;
int dataUnitLen=resultUnitLen-11;
try{
byte[]b=new byte[resultUnitLen*dataBlockNum];
int l=0;
for(int i=0;i