【问题标题】:Encryption of text containing tables and structures加密包含表格和结构的文本
【发布时间】:2016-10-19 11:35:04
【问题描述】:

我正在通过 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;
    }

【问题讨论】:

  • 您的代码中某处存在错误。没看到也能这么说。
  • @Henry 简单的文本内容没有问题,但如果是图表和表格,则无法正常工作。
  • 所以在加密图表和表格时,您的代码中存在错误。可能会得到什么样的答案?
  • 那么如何编码解码包含这些内容的文本文件?
  • @R.chow 以正确的方式进行操作。

标签: java x509certificate public-key-encryption


【解决方案1】:

你几乎犯了本书中的所有错误。

        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;
}

【讨论】:

  • 函数encryptBytes()返回加密数据的字符串值。
  • “幻数”110 来自错误的方法,试图解决并非所有 RSA 块都具有相同长度的事实。
【解决方案2】:

文件是否包含表或其他结构与现代加密完全无关,因为它适用于已经从“文档”序列化的二进制数据。

您正在尝试对原始文件的某些块应用 RSA。这是非常棘手的,因为您必须确保输入小于考虑填充的 RSA 模数。然后您必须确保每个密文块具有完全相同的长度,以便您在解密期间知道哪些字节属于哪个块。在 RSA 中,不能保证输出总是具有相同的字节数。与填充输入相比,它可以更小。因此,您需要始终如一地填充密文块。

一个更好的主意是使用hybrid encryption。您可以使用 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 加密,你必须考虑操作模式、填充模式、如何处理初始化向量以及是否要添加经过身份验证的加密。

【讨论】:

  • 可能是 110 格,我添加的填充空间正在做anamoly..谢谢 Artjom,我会研究混合加密。
  • 但是对称密钥有阻碍向所有人共享密钥,但在我的情况下,这还不够合适。你能帮我更有效地填充吗?(在这种情况下)
  • 不,你误会了。 AES 密钥只能由持有 RSA 私钥的人恢复。
猜你喜欢
  • 2019-06-24
  • 2015-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多