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

mac2024-07-13  53

文件上传加密

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

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

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); } } }
最新回复(0)