SM2SM4实现字符串和文件的数字信封(小文件不支持超过堆内存的大文件)
先解释一下什么是数字信封: 将对称密钥通过非对称加密(即:有公钥和私钥两个)的结果分发对称密钥的方法。大白话讲: 用对称秘钥对文件或字节加密,然后用非对称秘钥对对称秘钥的钥匙进行加密.
这里再解释一下对称秘钥和非对称秘钥:
- 非对称秘钥: 非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法
- 对称秘钥算法:加密是双方使用相同的密钥,必须以绝对安全的形式传送密钥才能保证安全。若果密钥泄露,加密数据将受到威胁,这点不如非对称密钥。只有一个秘钥
数字信封是实现信息保密性验证的技术。
- 文件加密流程:
- 文件解密流程:
- 我的实现思路: 对称算法选择国密的sm4算法, 采用SM4/ECB/PKCS5Padding, 非对称算法采用国密sm2 ,
具体实现代码:
- 数字信封加密
package com.ymwk;
import java.io.BufferedOutputStream;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.security.InvalidKeyException;import java.security.KeyFactory;import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException;import java.security.PublicKey;import java.security.Security;import java.security.cert.CertificateException;import java.security.cert.CertificateFactory;import java.security.cert.X509Certificate;import java.security.spec.InvalidKeySpecException;import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.crypto.InvalidCipherTextException;import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.ymwk.base64.Base64Utils;import com.ymwk.file.FileUtils;import com.ymwk.result.Result;import com.ymwk.sm2.GMBaseUtil;import com.ymwk.sm2.SM2CertUtil;import com.ymwk.sm2.SM2Util;import com.ymwk.sm4.Sm4Utils;
/** * 对文件的数字信封 * @author Saxon * @Date 2021年7月8日 */public class FileEncrypt extends GMBaseUtil{
/** * @param publicKey 公钥对象 * @param fileBytes 文件字节数组 * @return Result if(code== 200)success else fail * encryptFileStr 加密后的文件字符串 * encryptKeyStr 加密后的秘钥字符串 * @throws IOException * @throws NoSuchProviderException * @throws NoSuchAlgorithmException */ public static Result fileEncrypt(PublicKey publicKey,byte[] fileBytes) { try { //创建对称秘钥对 byte[] key = Sm4Utils.generateKey(); //对文件加密 byte[] fileEncryptBytes = Sm4Utils.encryptEcbPadding(key, fileBytes); //对秘钥对加密 byte[] encryptKey = SM2Util.encrypt((BCECPublicKey)publicKey, key); //将返回值base64加密 String encryptKeyStr = Base64Utils.encode(encryptKey); return new Result(Result.CODE_SUCCESS,"文件加密成功",encryptKeyStr,fileEncryptBytes); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return new Result(Result.CODE_EXCEPTION, "NoSuchAlgorithmException,没有找到该摘要算法"); } catch (NoSuchProviderException e) { e.printStackTrace(); return new Result(Result.CODE_EXCEPTION, "NoSuchProviderException,没有找到该加密机"); }catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException | InvalidCipherTextException e ) { e.printStackTrace(); return new Result(Result.CODE_EXCEPTION, "文件加密失败:"+e.getMessage()); } }
/** * * @param publicKey 公钥对象 * @param fileInput 文件输入流 * @return Result if(code== 200)success else fail * encryptFileStr 加密后的文件字符串 * encryptKeyStr 加密后的秘钥字符串 * @throws IOException */ public static Result fileEncrypt(PublicKey publicKey,InputStream fileInput) { ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buffer = new byte[1024*4]; int n = 0; try { while (-1 != (n = fileInput.read(buffer))) { output.write(buffer, 0, n); } } catch (IOException e) { e.printStackTrace(); } return fileEncrypt(publicKey,output.toByteArray()); }
/** * @param cert 证书对象 * @param file 文件 * @return Result if(code== 200)success else fail * encryptFileStr 加密后的文件字符串 * encryptKeyStr 加密后的秘钥字符串 */ public static Result fileEncrypt(X509Certificate cert,File file) { try { return fileEncrypt(cert,new FileInputStream(file)); } catch (FileNotFoundException e) { e.printStackTrace(); return new Result(Result.CODE_ERROR_PARAM, "文件不存在:"+e.getMessage()); } }
/** * * @param cert 证书对象 * @param fileInput 文件输入流 * @return Result if(code== 200)success else fail * encryptFileStr 加密后的文件字符串 * encryptKeyStr 加密后的秘钥字符串 * @throws IOException */ public static Result fileEncrypt(X509Certificate cert,InputStream fileInput) { return fileEncrypt(SM2CertUtil.getBCECPublicKey(cert),fileInput); }
/** * @param certStr 证书base64 * @param fileInput 文件输入流 * @return Result if(code== 200)success else fail * encryptFileStr 加密后的文件字符串 * encryptKeyStr 加密后的秘钥字符串 * @throws IOException */ public static Result fileEncrypt(String certStr,InputStream fileInput) { try { ByteArrayInputStream bais = new ByteArrayInputStream(Base64Utils.decode(certStr)); CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); return fileEncrypt(cert,fileInput); }catch (Exception e) { e.printStackTrace(); return new Result(Result.CODE_EXCEPTION, "证书base64转换证书对象失败:"+e.getMessage()); } } /** * @param certStr 证书base64 * @param filePath 文件路径 * @return Result if(code== 200)success else fail * encryptFileStr 加密后的文件字符串 * encryptKeyStr 加密后的秘钥字符串 */ public static Result fileEncrypt(String certStr,String filePath){ return fileEncrypt(certStr,new File(filePath)); }
/** * @param certStr 证书base64 * @param file 文件 * @return Result if(code== 200)success else fail * encryptFileStr 加密后的文件字符串 * encryptKeyStr 加密后的秘钥字符串 * @throws FileNotFoundException * @throws IOException */ public static Result fileEncrypt(String certStr,File file) { try { return fileEncrypt(certStr,new FileInputStream(file)); } catch (FileNotFoundException e) { e.printStackTrace(); return new Result(Result.CODE_ERROR_PARAM, "文件不存在:"+e.getMessage()); } }
public static void main(String[] args) throws CertificateException, NoSuchProviderException, IOException, NoSuchAlgorithmException, InvalidKeySpecException { Security.addProvider(new BouncyCastleProvider()); // FileInputStream bais = new FileInputStream("D:\\test.cer"); //CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); // X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); // String cert = "MIICzzCCAnSgAwIBAgIJAdInmr8fIJiNMAoGCCqBHM9VAYN1MIGPMQswCQYDVQQGEwJDTjEzMDEGA1UECgwq5rmW5Y2X5b6h56CB572R5o6n5L+h5oGv5oqA5pyv5pyJ6ZmQ5YWs5Y+4MQ4wDAYDVQQLDAVIVU5ZTTETMBEGA1UEAwwKSFVOQU5ZTVNNMjESMBAGA1UEBwwJ6ZW/5rKZ5biCMRIwEAYDVQQIDAnmuZbljZfnnIEwHhcNMjEwNzEyMDczMjMxWhcNNDEwNzA3MDczMjMxWjCBqDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCea5luWNl+ecgTESMBAGA1UEBwwJ5bi45b635biCMTYwNAYDVQQKDC3muZbljZfnnIHmlbDlrZforqTor4HmnI3liqHkuK3lv4PmnInpmZDlhazlj7gxITAfBgNVBAsMGOW4uOW+t+W4gua1i+ivleS4k+eUqOeroDEWMBQGA1UEAwwNNDMwMzAxMDAwMzAwNDBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABOK7wKAe409JYZkd8tx6Ey6cb0OxeHZc1AG1TKrTiuM7ErQPFwPTRjkCrmnk19+xu4vZKuPR+KmYSOshoAIlm5+jgZ0wgZowHQYDVR0OBBYEFJbAkoS2vkJuuXZT+Gj0XMtEjBHwMB8GA1UdIwQYMBaAFJS9gxFrCotSpHOaUiZRiKVK6SPiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAYBgNVHREEETAPgg00MzAzMDEwMDAzMDA0MAoGCCqBHM9VAYN1A0kAMEYCIQCNBSkNdrrO0ZqZC6zwpDo7ZpWwr8PqkJdge8IEBgVjbQIhAIZHM5FZY+0Bb3Kui9ZaJr5eAZb83jGXpOGSpMCQUIr6"; String publicKeyStr = "MIIBMzCB7AYHKoZIzj0CATCB4AIBATAsBgcqhkjOPQEBAiEA/v8AAAAA//8wRAQg/v8AAAAA//wEICjp+p6dn140TVqeS89lCafzl4n1FauPkt28vUFNlA6TBEEEMsSuLB8ZgRlfmQRGajnJlI/jC7/yZgvhcVpFiTNMdMe8Nzai9PZ3nFm9zuNraSFT0KmHfMYqR0AC3zLlITnwoAIhAP7///9yA99rIcYFK1O79Ak51UEjAgEBA0IABMWwe7cKGGDCHWVCCmI195Ump1xqhZcXn7oYa23gNPUYs8vAxmC/nf7t+8Kq7Iq2KR5zlafOR5+Igs/BX4AkUkQ="; X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64Utils.decode(publicKeyStr)); KeyFactory keyFactory = KeyFactory.getInstance("EC"); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); Result fileEncrypt = fileEncrypt(publicKey,new FileInputStream("C:\\Users\\Saxon\\Desktop\\Test.java")); BufferedOutputStream bos = null; FileOutputStream fos = null; File file = null; file = new File("d://test.java"); if (!file.getParentFile().exists()){ //文件夹不存在 生成 file.getParentFile().mkdirs(); } fos = new FileOutputStream(file); bos = new BufferedOutputStream(fos); bos.write(fileEncrypt.getEncryptFileByte()); bos.close(); fos.close(); System.out.println(fileEncrypt); }}
- 数字信封解密
/** * * @param privateKey 私钥 * @param file 加密后的文件 * @param keyString 加密后的秘钥 */ public static void decrypt(PrivateKey privateKey,File file,String keyString) throws IOException, InvalidCipherTextException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException { byte[] keyByte = Base64Utils.decode(keyString); FileInputStream fileInputStream = new FileInputStream(file); ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int n = 0; while (-1 != (n = fileInputStream.read(buffer))) { output.write(buffer, 0, n); } byte[] byteArray = output.toByteArray(); //用私钥解密秘钥 byte[] key = SM2Util.decrypt((BCECPrivateKey)privateKey, keyByte); byte[] decryptEcbPadding = Sm4Utils.decryptEcbPadding(key, byteArray); //将解密后的文件输出到本地 OutputStream out = new FileOutputStream("D:\\bbb.txt"); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decryptEcbPadding); byte[] buff = new byte[1024]; int len = 0; while((len=byteArrayInputStream.read(buff))!=-1){ out.write(buff, 0, len); } byteArrayInputStream.close(); out.close(); }
以上就是数字信封的加解密操作的全部内容, 想要代码中其他工具类的朋友可以加我微信或者访问我的gitee,所有的代码都在里面.
gitee地址: https://gitee.com/saxonkiku/encrypt_and_decrypt_file.git
SM2SM4实现字符串和文件的数字信封(小文件不支持超过堆内存的大文件)相关推荐
- SM2SM4实现字符串和文件的数字信封(不限制文件大小)
相比于以前的实现方式,处理了文件超过堆内存限制的文件做数字信封.现在的支持任何大小的数字信封.速度的话基本上1G的文件加密在50s秒左右! 上期的数字信封SM4工具类如果文件太大会报 OutOfMem ...
- 附加的文件超过了服务器,将大文件附加到 Outlook 邮件或事件
将大文件附加到 Outlook 邮件或事件 2021/8/12 本文内容 使用 Microsoft Graph API,可将最大 150 MB 的文件附加到 Outlook 邮件或 事件项目. 根据文 ...
- html大文件占用内存,[Flutter] 大文件上传之随传随处理(避免占用大量内存)
今天碰到一个上传较大的视频文件到S3引发闪退的问题.经查此问题产生的原因是内存溢出,连个闪退日志都没有. 这个上传使用的是第三方的插件,我是用 uploadFileStream 来上传文件的,查看其实 ...
- Linux fs清理文件,linux找出已经删除但磁盘空间未释放的大文件并清空
linux找出已经删除但磁盘空间未释放的大文件并清空 1.找出已经删除但磁盘空间未释放的文件 如果文件已经删除,但实际的磁盘空间未释放,这个时候文件句柄fd相关信息还在内存中,可以通过lsof命令找出 ...
- vue 文件及描述信息一起上传_用Vue实现一个大文件上传和断点续传
前言 这段时间面试官都挺忙的,频频出现在博客文章标题,虽然我不是特别想蹭热度,但是实在想不到好的标题了-.-,蹭蹭就蹭蹭 :) 事实上我在面试的时候确实被问到了这个问题,而且是一道在线 coding ...
- Qt反射内存读取大文件
近期写程序,需要对大文件进行读写操作,使用传统的QFile发现效率及其地下,于是想到了内存映射. QFile写文件: QFile f("c:\\test.txt"); if(!f. ...
- 哪里有免费大文件传输平台?通过这4个网站免费来进行大文件传输
使用电子邮件发送大文件时,可能会遇到大小文件传输的限制.这四个免费大文件传输网站让大文件传输变得轻而易举.有许多大文件传输网站,但是通常您必须经过一些步骤才能使用它们,例如创建帐户,验证电子邮件地址或 ...
- PHP有限内存处理大文件(从两个文件提取相同行)
面试题: 有两个文件文件,大小都超过了1G,一行一条数据,每行数据不超过500字节,两文件中有一部分内容是完全相同的,请写代码找到相同的行,并写到新文件中.PHP最大允许内内为256M. 解题步骤 遇 ...
- java里怎么实现播放文件_java程序,一步实现音乐文件的播放(小应用:听你想听)-nrg文件怎么播放...
java学习分享 ~java完整代码如下~ package one; //包名随意 import java.awt.*; import java.applet.*; import java.awt.e ...
最新文章
- RANSAC算法原理与实现
- 【转】C#对象的深拷贝与浅拷贝
- 石川es6课程---5、函数-参数
- 【设计模式】中介者模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
- JavaScript对象的创建之动态原型方式
- linux命令解释程序实验,实验二 命令解释程序的使用
- 飘逸的python - 命令行漂亮的显示json数据
- 对datatable类型列名排序_表格数据的排序功能(支持多列)
- 13分钟,教你python可视化分析20W数据,找到妹子最爱的内衣
- 【笔记】VUE学习笔记
- windows c语言 sata 序列号,【Delphi】获取IDE/SATA硬盘序列号
- 学完python可以当黑客吗_想当黑客吗?我教你啊!精心整理最简单的黑客入门——PYTHON教程,免费系统又经典...
- dp动态规划解题套路 剑指offer 42连续子数组的最大和
- 组成计算机cpu的两大部件是,组成计算机的cpu的两大部分是什么
- Screeps入门: harvest,upgrader,builder初级自动化
- vb.net 生成随机数
- 140套高清、超优秀的PPT模板----毕业设计、毕业答辩主题
- win10 删除无用的bios引导
- 最浅显易懂kerberos认证和黄金白银票据
- windows中无法删除文件,报无法删除****,找不到指定文件,请确定指定的路径及文件名是否正确的解决