JAVA各种加密与解密方式( 三 )

7.SHA(Secure Hash Algorithm,安全散列算法)
SHA全名叫做安全散列算法,是FIPS所认证的安全散列算法 。能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法 。且若输入的消息不同,它们对应到不同字符串的机率很高 。
数字签名等密码学应用中重要的工具,被广泛地应用于电子商务等信息安全领域,示例:
import java.security.MessageDigest; public class SHAUtil {public static final String KEY_SHA = "SHA";public static final String ALGORITHM = "SHA-256";/**** SHA加密(比MD5更安全)* @param data* @return* @throws Exception*/ public static byte[] encryptSHA(byte[] data) throws Exception{MessageDigest sha = MessageDigest.getInstance(KEY_SHA);sha.update(data);return sha.digest(); }public static String SHAEncrypt(final String content) {try {MessageDigest sha = MessageDigest.getInstance(KEY_SHA);byte[] sha_byte = sha.digest(content.getBytes());StringBuffer hexValue = https://www.isolves.com/it/cxkf/yy/JAVA/2021-11-08/new StringBuffer();for (byte b : sha_byte) {//将其中的每个字节转成十六进制字符串:byte类型的数据最高位是符号位,通过和0xff进行与操作,转换为int类型的正整数 。String toHexString = Integer.toHexString(b & 0xff);hexValue.append(toHexString.length() == 1 ? "0" + toHexString : toHexString);}return hexValue.toString();} catch (Exception e) {e.printStackTrace();}return "";}//SHA-256加密public static String SHA256Encrypt(String sourceStr) {MessageDigest md = null;try {md = MessageDigest.getInstance(ALGORITHM);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}if (null != md) {md.update(sourceStr.getBytes());String digestStr = getDigestStr(md.digest());return digestStr;}return null;}private static String getDigestStr(byte[] origBytes) {String tempStr = null;StringBuilder stb = new StringBuilder();for (int i = 0; i < origBytes.length; i++) {tempStr = Integer.toHexString(origBytes[i] & 0xff);if (tempStr.length() == 1) {stb.append("0");}stb.append(tempStr);}return stb.toString();}}8.RSA 加密/解密
RSA算法是一种非对称加密算法,所谓非对称就是该算法需要一对密钥,若使用其中一个加密,则需要用另一个才能解密 。目前它是最有影响力和最常用的公钥加密算法,能够抵抗已知的绝大多数密码攻击 。从提出到现今的三十多年里,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一 。
该算法基于一个的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥 。由于进行的都是大数计算,RSA 最快的情况也比 DES 慢上好几倍,比对应同样安全级别的对称密码算法要慢 1000 倍左右 。所以 RSA 一般只用于少量数据加密,比如说交换对称加密的密钥 。
使用 RSA 加密主要有这么几步:生成密钥对、公开公钥、公钥加密私钥解密、私钥加密公钥解密 。
示例代码:
import com.sun.org.Apache.xml.internal.security.utils.Base64;import javax.crypto.Cipher; import org.apache.commons.io.FileUtils; import java.io.ByteArrayOutputStream;import java.io.File;import java.nio.charset.Charset;import java.security.*;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec; public class RsaUtil {/*** 生成密钥对并保存在本地文件中** @param algorithm : 算法* @param pubPath: 公钥保存路径* @param priPath: 私钥保存路径* @throws Exception*/private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {// 获取密钥对生成器KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);// 获取密钥对KeyPair keyPair = keyPairGenerator.generateKeyPair();// 获取公钥PublicKey publicKey = keyPair.getPublic();// 获取私钥PrivateKey privateKey = keyPair.getPrivate();// 获取byte数组byte[] publicKeyEncoded = publicKey.getEncoded();byte[] privateKeyEncoded = privateKey.getEncoded();// 进行Base64编码String publicKeyString = Base64.encode(publicKeyEncoded);String privateKeyString = Base64.encode(privateKeyEncoded);// 保存文件FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));}/*** 从文件中加载公钥** @param algorithm : 算法* @param filePath: 文件路径* @return : 公钥* @throws Exception*/private static PublicKey loadPublicKeyFromFile(String algorithm, String filePath) throws Exception {// 将文件内容转为字符串String keyString = FileUtils.readFileToString(new File(filePath), Charset.forName("UTF-8"));return loadPublicKeyFromString(algorithm, keyString);}/*** 从字符串中加载公钥** @param algorithm : 算法* @param keyString : 公钥字符串* @return : 公钥* @throws Exception*/private static PublicKey loadPublicKeyFromString(String algorithm, String keyString) throws Exception {// 进行Base64解码byte[] decode = Base64.decode(keyString);// 获取密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(algorithm);// 构建密钥规范X509EncodedKeySpec keyspec = new X509EncodedKeySpec(decode);// 获取公钥return keyFactory.generatePublic(keyspec);}/*** 从文件中加载私钥** @param algorithm : 算法* @param filePath: 文件路径* @return : 私钥* @throws Exception*/private static PrivateKey loadPrivateKeyFromFile(String algorithm, String filePath) throws Exception {// 将文件内容转为字符串String keyString = FileUtils.readFileToString(new File(filePath), Charset.forName("UTF-8"));return loadPrivateKeyFromString(algorithm, keyString);}/*** 从字符串中加载私钥** @param algorithm : 算法* @param keyString : 私钥字符串* @return : 私钥* @throws Exception*/private static PrivateKey loadPrivateKeyFromString(String algorithm, String keyString) throws Exception {// 进行Base64解码byte[] decode = Base64.decode(keyString);// 获取密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(algorithm);// 构建密钥规范PKCS8EncodedKeySpec keyspec = new PKCS8EncodedKeySpec(decode);// 生成私钥return keyFactory.generatePrivate(keyspec);}/*** 使用密钥加密数据** @param algorithm: 算法* @param input: 原文* @param key: 密钥* @param maxEncryptSize : 最大加密长度(需要根据实际情况进行调整)* @return : 密文* @throws Exception*/private static String encrypt(String algorithm, String input, Key key, int maxEncryptSize) throws Exception {// 获取Cipher对象Cipher cipher = Cipher.getInstance(algorithm);// 初始化模式(加密)和密钥cipher.init(Cipher.ENCRYPT_MODE, key);// 将原文转为byte数组byte[] data = input.getBytes();// 总数据长度int total = data.length;// 输出流ByteArrayOutputStream baos = new ByteArrayOutputStream();decodeByte(maxEncryptSize, cipher, data, total, baos);// 对密文进行Base64编码return Base64.encode(baos.toByteArray());}/*** 解密数据** @param algorithm: 算法* @param encrypted: 密文* @param key: 密钥* @param maxDecryptSize : 最大解密长度(需要根据实际情况进行调整)* @return : 原文* @throws Exception*/private static String decrypt(String algorithm, String encrypted, Key key, int maxDecryptSize) throws Exception {// 获取Cipher对象Cipher cipher = Cipher.getInstance(algorithm);// 初始化模式(解密)和密钥cipher.init(Cipher.DECRYPT_MODE, key);// 由于密文进行了Base64编码, 在这里需要进行解码byte[] data = Base64.decode(encrypted);// 总数据长度int total = data.length;// 输出流ByteArrayOutputStream baos = new ByteArrayOutputStream();decodeByte(maxDecryptSize, cipher, data, total, baos);// 输出原文return baos.toString();}/*** 分段处理数据** @param maxSize : 最大处理能力* @param cipher: Cipher对象* @param data: 要处理的byte数组* @param total: 总数据长度* @param baos: 输出流* @throws Exception*/private static void decodeByte(int maxSize, Cipher cipher, byte[] data, int total, ByteArrayOutputStream baos) throws Exception {// 偏移量int offset = 0;// 缓冲区byte[] buffer;// 如果数据没有处理完, 就一直继续while (total - offset > 0) {// 如果剩余的数据 >= 最大处理能力, 就按照最大处理能力来加密数据if (total - offset >= maxSize) {// 加密数据buffer = cipher.doFinal(data, offset, maxSize);// 偏移量向右侧偏移最大数据能力个offset += maxSize;} else {// 如果剩余的数据 < 最大处理能力, 就按照剩余的个数来加密数据buffer = cipher.doFinal(data, offset, total - offset);// 偏移量设置为总数据长度, 这样可以跳出循环offset = total;}// 向输出流写入数据baos.write(buffer);}}}


推荐阅读