上传文件的加密和下载文件解密

2022-06-21 00:00:00 加密 解密 上传文件

文件上传加密

在很多应用场景中,出于安全考虑,我们不得不实行上传文件时对文件进行加密,
存入服务器的文件就会变成二进制文件,当别人直接冲服务器拿到文件时,也无法查看,这就保证了安全性。
但是我们需要在页面上查看自己上传的文件,这时候就需要再次请求服务器文件的解密接口,
通过解密代码,获得原来的图片,这样对于一些银行等相关业务可有效的保证安全性。

首先导入文件加密解密工具类

public class AES { 
    /**
     * 块大小固定为8字节
     */
    private final static String AES_CBC_PKCS5PADDING = "AES/ECB/PKCS5Padding";

    /**
     * KeyGenerator Init params
     */
    private final static int KGEN_256 = 256;
    private final static String SHA_256 = "SHA-256";
    private final static String S_KEY = "9538172738539384";
    private final static String SHA1PRNG = "SHA1PRNG";

//    private static AlgorithmParameters params = null;

    /**
     * 字符串加密
     * @param content
     * @return
     */
    public static String encrypt(String content) { 
        if (StringUtils.isNotBlank(content)) { 
            try { 
                byte[] byteContent = content.getBytes(Constant.ConfigConsts.ENCODE_UTF_8);
                byte[] cryptograph = getCipher(Cipher.ENCRYPT_MODE, S_KEY).doFinal(byteContent);
                return new Base64().encodeToString(cryptograph);
            } catch (Exception e) { 
                e.printStackTrace();
            }
        }
        return "";
    }

    /**
     * 字符串解密
     * @param content
     * @return
     */
    public static String decrypt(String content) { 
        if (StringUtils.isNotBlank(content)) { 
            try { 
                byte[] byteContent = new Base64().decode(content);
                byte[] result = getCipher(Cipher.DECRYPT_MODE, S_KEY).doFinal(byteContent);
                return new String(result);
            } catch (Exception e) { 
                e.printStackTrace();
            }
        }
        return "";
    }

    /**
     * 通过Skey得到秘钥算法对象
     * @param sKey
     * @return
     */
    private static SecretKeySpec getSecretKeySpec (String sKey) { 
        SecretKeySpec key = null;
        try { 
            //"AES":请求的密钥算法的标准名称
            KeyGenerator kgen = KeyGenerator.getInstance(Constant.ConfigConsts.SECRET_AES);
            //256:密钥生成参数;securerandom:密钥生成器的随机源
            SecureRandom securerandom = SecureRandom.getInstance(SHA1PRNG);
            securerandom.setSeed(sKey.getBytes());
            kgen.init(KGEN_256, securerandom);
            //生成秘密(对称)密钥
            SecretKey secretKey = kgen.generateKey();
            //返回基本编码格式的密钥
            byte[] enCodeFormat = secretKey.getEncoded();
            //根据给定的字节数组构造一个密钥。enCodeFormat:密钥内容;"AES":与给定的密钥内容相关联的密钥算法的名称
            key = new SecretKeySpec(enCodeFormat, Constant.ConfigConsts.SECRET_AES);
            //将提供程序添加到下一个可用位置
            Security.addProvider(new BouncyCastleProvider());
        } catch (Exception e) { 
            e.printStackTrace();
        }
        return key;
    }

    /**
     * get Cipher
     * @param mode
     * @param sKey
     * @return
     */
    private static Cipher getCipher(int mode, String sKey) { 
        byte[] IV = new byte[16];
        SecureRandom random = new SecureRandom();
        random.nextBytes(IV);
        Cipher cipher = null;
        try { 
//            params = AlgorithmParameters.getInstance("IV", "LunaProvider");
//            params.init(new IvParameterSpec(IV));
            cipher = Cipher.getInstance(AES_CBC_PKCS5PADDING);
            cipher.init(mode, getSecretKeySpec(sKey));
        } catch(Exception e) { 
            e.printStackTrace();
        }
        return cipher;
    }

    /**
     * 上传文件加密(传入文件流,输出流对象后直接处理即加密文件流后存储文件)
     * @param inputStream
     * @param outputStream
     * @return
     */
    public static boolean encryptFile(InputStream inputStream, OutputStream outputStream) { 
        try { 
            CipherInputStream cipherInputStream = new CipherInputStream(
                    inputStream, getCipher(Cipher.ENCRYPT_MODE, S_KEY));
            byte[] cache = new byte[1024];
            int nRead = 0;
            while ((nRead = cipherInputStream.read(cache)) != -1) { 
                outputStream.write(cache, 0, nRead);
                outputStream.flush();
            }

            cipherInputStream.close();
        } catch (Exception e) { 
            e.printStackTrace();
        }
        return true;
    }

    /**
     * **上传文件加密(传入字节,加密后返回字节)**
     * @param plainFile
     * @return
     * @throws Exception
     */
    public static byte[] encryptFile(byte[] plainFile) throws Exception { 
        byte[] cipherText = getCipher(Cipher.ENCRYPT_MODE, S_KEY).doFinal(plainFile);
        return cipherText;
    }

    /**
     * 下载文件解密(传入文件流,输出流对象后直接处理即解密文件流后输出文件)
     * @param inputStream
     * @param outputStream
     * @return
     */
    public static boolean decryptFile(InputStream inputStream, OutputStream outputStream) { 
        try { 
            CipherOutputStream cipherOutputStream = new CipherOutputStream(
                    outputStream, getCipher(Cipher.DECRYPT_MODE, S_KEY));
            byte[] buffer = new byte[1024];
            int r;
            while ((r = inputStream.read(buffer)) >= 0) { 
                cipherOutputStream.write(buffer, 0, r);
            }
            cipherOutputStream.close();
        } catch (Exception e) { 
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 下载文件解密(传入字节,解密后返回字节)
     * @param cipherFile
     * @return
     * @throws Exception
     */
    public static byte[] decryptFile(byte[] cipherFile) throws Exception  { 
        byte[] cipherText = getCipher(Cipher.DECRYPT_MODE, S_KEY).doFinal(cipherFile);
        return cipherText;
    }

  
    /**
     * 获得指定文件的byte数组
     */
    private static byte[] getBytes(String filePath){ 
        byte[] buffer = null;
        try { 
            File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) { 
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        } catch (FileNotFoundException e) { 
            e.printStackTrace();
        } catch (IOException e) { 
            e.printStackTrace();
        }
        return buffer;
    }

    /**
     * 根据byte数组,生成文件
     */
    public static void getFile(byte[] bfile, String filePath,String fileName) { 
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try { 
            File dir = new File(filePath);
            if(!dir.exists()&&dir.isDirectory()){ //判断文件目录是否存在
                dir.mkdirs();
            }
            file = new File(filePath+"\\"+fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bfile);
        } catch (Exception e) { 
            e.printStackTrace();
        } finally { 
            if (bos != null) { 
                try { 
                    bos.close();
                } catch (IOException e1) { 
                    e1.printStackTrace();
                }
            }
            if (fos != null) { 
                try { 
                    fos.close();
                } catch (IOException e1) { 
                    e1.printStackTrace();
                }
            }
        }
    }
}

在这个工具方法中,我们使用 encryptFile(InputStream inputStream, OutputStream outputStream)对文件加密,在这个方法中需要把文件转成流的形式,并以byte【】的形式输出到指定位置。其中用到了类CipherInputStream,CipherInputStream由InputStream和Cipher组成,它允许我们自定义一个key,同时把key的信息揉进文件流中。解密的时候再次输入key,才能完成解密。

文件上传加密代码

 @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public RtnResult springUpload(HttpServletRequest request) throws IllegalStateException, IOException { 
        RtnResult result = new RtnResult(RtnResultCode.SUCCESS);
        Map<String, String> map = new HashMap<>();

        // 将request变成多部分request
        MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
        // 获取multiRequest 中所有的文件名

        Iterator iter = multiRequest.getFileNames();
        while (iter.hasNext()) { 
            //一次遍历所有文件
            MultipartFile file = multiRequest.getFile(iter.next().toString());
            if (file != null) { 
                // 取得当前上传文件的文件名称
                String originalFileName = file.getOriginalFilename().replace(",", ";");

                // 文件名前缀
                int lastIndexOf = originalFileName.lastIndexOf(".");
                String name = originalFileName;
                String extension = "";
                if (lastIndexOf != -1) { 
                    name = originalFileName.substring(0, originalFileName.lastIndexOf("."));
                    extension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
                }
                if (!extension.equalsIgnoreCase("png") && !extension.equalsIgnoreCase("jpg")
                        && !extension.equalsIgnoreCase("jpeg") && !extension.equalsIgnoreCase("gif")
                        && !extension.equalsIgnoreCase("pdf") && !extension.equalsIgnoreCase("xlsx")
                        && !extension.equalsIgnoreCase("lsx") && !extension.equalsIgnoreCase("docx")
                        && !extension.equalsIgnoreCase("doc")) { 
                    return RtnResult.Fail(RtnResultCode.FILE_TYPE_ERROR);
                }
                // 时间戳
                long timeStr = (new Date()).getTime();
                // 4位随机数
                int random = new Random().nextInt(10000);
                // 文件后缀名
                String fileName =timeStr + random + "." + extension;

                //上传
                String dateStr = DateUtils.getDateTime("yyyyMMdd");
                //上传 ,替代掉常量类中的数据
                String path = PathConstants.DIRECTORY_UPLOAD_TEMP_SUB
                        .replace("{yyyyMMdd}", dateStr)
                        .replace("{fileName}", fileName);
                File temp = new File(configProperties.getFileLocation() + PathConstants.DIRECTORY_UPLOAD_TEMP + path);
                if (!temp.getParentFile().exists()) { 
                    temp.getParentFile().mkdirs();
                }

                //上传文件加密
                OutputStream enOutputStream = new FileOutputStream(temp);
                boolean b = AES.encryptFile(file.getInputStream(), enOutputStream);
                if (!b){ 
                    return RtnResult.Fail("文件上传失败!");
                }
                logger.info("文件上传成功!------------------");


               // file.transferTo(temp);
                map.put("fileName", file.getOriginalFilename());
                map.put("filePath", path);
                String dowUrl = PathConstants.URL_FILE_TEMP_ORIGIN.replace("{date}", dateStr).replace("{fileName}", fileName);
                map.put("downUrl", dowUrl);
            }
        }

        result.setData(map);
        return result;
    }

下载文件解密

传入文件名,根据配置文件拼装出文件地址,通过new file(path) ,得到真实文件。通过HttpServletResponse.getOutputStream以及相关设置可以向页面输出文件内容,再调用机密方法即可

@RequestMapping(value = "/download/temp", method = RequestMethod.GET)
    @ResponseBody
    public void downloadTemp(@RequestParam("date") String date,@RequestParam("fileName") String fileName,HttpServletResponse response) throws IOException { 
        logger.info("FileController.downloadTemp=========>start");
        if (StringUtils.isNotBlank(fileName) && StringUtils.isNotBlank(date)) { 
            String path =
                    configProperties.getFileLocation()+PathConstants.DIRECTORY_UPLOAD_TEMP +
                            PathConstants.DIRECTORY_UPLOAD_TEMP_SUB.replace("{yyyyMMdd}", date)
                                    .replace("{fileName}", fileName);
            
            //通过路径得到文件
            File file = new File(path);
            logger.info("FileController.downloadTemp=========File:{},exits:{}",path,file.exists());
            if (file.exists()) { 
				
				//浏览器接受图片设置
                String contentType = Files.probeContentType(Paths.get(path));
                contentType = StringUtils.isBlank(contentType) ? MediaType.ALL_VALUE : contentType;
                response.setContentType(contentType);
                response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName()));
                response.setCharacterEncoding("UTF-8");
                OutputStream outputStream = response.getOutputStream();
                FileInputStream fis = FileUtils.openInputStream(file);
                
                //文件解密
                boolean b = AES.decryptFile(fis, outputStream);
                if (b){ 
                    logger.info("文件解密成功-----------------------");
                }else { 
                    logger.info("文件解密失败!----------------------");
                }

               //IOUtils.copy(fis, outputStream);

                outputStream.flush();
                outputStream.close();
                IOUtils.closeQuietly(fis);
            }
        }
    }
    原文作者:知识分子_
    原文地址: https://blog.csdn.net/qq_45076180/article/details/102843078
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。

相关文章