我正在通过java本地repo的证书加密解密文件。但对于包含表格、图表的文字处理文件,文件与实际文件并不相同。我使用正常的文件输入/输出流。任何帮助都是有用的,谢谢。
public int encryptFileWithpubkey(String filepath,PublicKey pubkey){
int retval=0;
FileInputStream fis = null;
File file=null;
final String location = filepath;
PublicKey pubKey= pubkey;
try{
try {
fis = AccessController.doPrivileged(
new PrivilegedExceptionAction<FileInputStream>() {
public FileInputStream run() throws FileNotFoundException {
return new FileInputStream(location);
}
});
} catch (PrivilegedActionException e) {
throw (FileNotFoundException) e.getException();
}
InputStream is = fis;
//long length = file.length();
byte[] bytes = new byte[fis.available()];
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
is.close();
file=null;
String encString="";
int iFixedLen=110;
if(bytes.length>=iFixedLen){
int noOfBlocks=(int)Math.ceil((bytes.length/110.0));
// System.out.println("Noof blocks :"+noOfBlocks);
for(int i=0;i<noOfBlocks;i++){
byte[] tempStr=null;
if(i==noOfBlocks-1){
//System.out.println("Last block");
tempStr=new byte[(bytes.length-(i*iFixedLen))];
System.arraycopy(bytes, (i*iFixedLen), tempStr, 0,(bytes.length-(i*iFixedLen)));
}
else
{
//System.out.println("i : "+i);
tempStr=new byte[iFixedLen];
//tempStr=new byte[iFixedLen];
System.arraycopy(bytes, (i*iFixedLen), tempStr, 0,iFixedLen);
//tempStr=plainText.substring(0,110) ;
//plainText=plainText.substring(110);
}
encString+= encryptBytes(tempStr,pubKey)+" ";
}
encString=encString.substring(0,encString.length()-1);
retval=noOfBlocks;
}else{
encString=encryptBytes(bytes,pubKey);
retval=1;
}
FileOutputStream fos = null;
try {
fos = AccessController.doPrivileged(
new PrivilegedExceptionAction<FileOutputStream>() {
public FileOutputStream run() throws FileNotFoundException {
return new FileOutputStream(location);
}
});
} catch (PrivilegedActionException e) {
throw (FileNotFoundException) e.getException();
}
fos.write(encString.getBytes());
fos.close();
}catch(Exception e){
e.printStackTrace();
return 0;
}
return retval;
}
encryptBytes函数如下:
public String encryptBytes(byte[] rawData,PublicKey pubkey){
String retval=null;
try{
byte[] rawByteData=rawData;
Cipher cp=Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cp.init( Cipher.ENCRYPT_MODE,pubkey);
byte[] getDat=cp.doFinal(rawByteData);
retval=java.util.Base64.getEncoder().encodeToString(getDat);
}catch(Exception e)
{
e.printStackTrace();
}
return retval;
}
你几乎犯了书中所有的错误。
InputStream is = fis;
//long length = file.length();
byte[] bytes = new byte[fis.available()];
InputStream.available()
不是输入流长度的指示符。请参阅Javadoc,其中包含针对此处操作的特定警告。在进行任何类型的I/O操作时,实际上总是可以使用固定大小的缓冲区,并且很少需要将整个文件读取到内存中。编译器不会这样做:你为什么要这样做呢?
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
is.close();
file=null;
file = null;
语句在这里是没有意义的,可以省略整个循环,如下所示。
String encString="";
String
不是二进制数据的容器。
int iFixedLen=110;
魔数110
从何而来?
if(bytes.length>=iFixedLen){
int noOfBlocks=(int)Math.ceil((bytes.length/110.0));
// System.out.println("Noof blocks :"+noOfBlocks);
for(int i=0;i<noOfBlocks;i++){
byte[] tempStr=null;
if(i==noOfBlocks-1){
//System.out.println("Last block");
tempStr=new byte[(bytes.length-(i*iFixedLen))];
System.arraycopy(bytes, (i*iFixedLen), tempStr, 0,(bytes.length-(i*iFixedLen)));
}
else
{
//System.out.println("i : "+i);
tempStr=new byte[iFixedLen];
//tempStr=new byte[iFixedLen];
System.arraycopy(bytes, (i*iFixedLen), tempStr, 0,iFixedLen);
//tempStr=plainText.substring(0,110) ;
//plainText=plainText.substring(110);
}
encString+= encryptBytes(tempStr,pubKey)+" ";
}
encString=encString.substring(0,encString.length()-1);
retval=noOfBlocks;
}else{
encString=encryptBytes(bytes,pubKey);
retval=1;
}
我不知道这一切应该做什么,但你不应该使用110字节的块,或字符,或无论它们是什么,或以字节数组的形式转换加密数据到字符串,你不应该追加四个空格到它。
FileOutputStream fos = null;
try {
fos = AccessController.doPrivileged(
new PrivilegedExceptionAction<FileOutputStream>() {
public FileOutputStream run() throws FileNotFoundException {
return new FileOutputStream(location);
}
});
} catch (PrivilegedActionException e) {
throw (FileNotFoundException) e.getException();
}
fos.write(encString.getBytes());
在这里,您可以只编写由实际加密产生的原始字节数组,从而避免整个问题。
你还没有发布encryptBytes()
方法,所以不可能进一步评论。
fos.close();
}catch(Exception e){
e.printStackTrace();
return 0;
}
return retval;
}
文件是否包含表或其他结构与现代加密完全无关,因为它工作于已经从"文档"序列化的二进制数据。
您正在尝试对原始文件的一些块应用RSA。这是非常棘手的正确的,因为你必须确保输入小于RSA模数考虑到填充。然后,您必须确保每个密文块具有完全相同的长度,以便在解密过程中知道哪些字节属于哪个块。在RSA中,不能保证输出总是具有相同的字节数。与填充输入相比,它可以更小。因此,您需要始终如一地填充密文块。
一个更好的主意是使用混合加密。您可以使用AES加密实际数据,并使用RSA加密随机生成的AES密钥。简单的格式应该易于操作:
4 bytes - Length of the RSA-encrypted AES key (= x)
x bytes - RSA-encrypted AES key
remaining bytes - AES-encrypted file
当然,如果你在做AES加密,你必须考虑操作模式,填充模式,如何处理初始化向量以及是否要添加经过身份验证的加密。