一、密码学基本概念
密码在我们的生活中有着重要的作用,那么密码究竟来自何方,为何会产生呢?
密码学是网络安全、信息安全、区块链等产品的基础,常见的非对称加密、对称加密、散列函数等,都属于密码学范畴。
密码学有数千年的历史,从最开始的替换法到如今的非对称加密算法,经历了古典密码学,近代密码学和现代密码学三个阶段。密码学不仅仅是数学家们的智慧,更是如今网络空间安全的重要基础。
二、密码学分类
三、加解密代码实现
1、凯撒加密
1 package com.test.kaiser; 2 3 /** 4 * 凯撒加密 5 */ 6 public class KaiserDemo { 7 public static void main(String[] args) { 8 // 定义原文 9 String input = "Hello World"; 10 // 把原文右移动3位 11 int key = 3; 12 String encryption = encryption(input, key); 13 System.out.println("encryption = " + encryption); 14 String decryption = decryption(encryption, key); 15 System.out.println("decryption = " + decryption); 16 } 17 18 19 /** 20 * 解密 21 * @param input 22 * @return 23 */ 24 private static String decryption(String input, int key) { 25 26 char[] chars = input.toCharArray(); 27 StringBuilder sb = new StringBuilder(); 28 for (char aChar : chars) { 29 sb.append((char)(aChar - key)); 30 } 31 return sb.toString(); 32 } 33 34 /** 35 * 加密 36 * @param input 37 * @return 38 */ 39 private static String encryption(String input, int key) { 40 41 char[] chars = input.toCharArray(); 42 StringBuilder sb = new StringBuilder(); 43 for (char aChar : chars) { 44 sb.append((char)(aChar + key)); 45 } 46 return sb.toString(); 47 } 48 }
2、对称加密
DES
1 package com.test.desaes; 2 3 import com.sun.org.apache.xml.internal.security.utils.Base64; 4 5 import javax.crypto.BadPaddingException; 6 import javax.crypto.Cipher; 7 import javax.crypto.IllegalBlockSizeException; 8 import javax.crypto.NoSuchPaddingException; 9 import javax.crypto.spec.SecretKeySpec; 10 import java.security.InvalidKeyException; 11 import java.security.NoSuchAlgorithmException; 12 13 /** 14 * 对称加密 15 */ 16 public class DesAesDemo { 17 public static void main(String[] args) throws Exception { 18 // 原文 19 String input = "Hello World"; 20 // 定义key 21 // 如果使用DES加密,密钥必须是8位 22 String key = "12345678"; 23 // 算法 24 String transformation = "DES"; 25 // 加密类型 26 String algorithm = "DES"; 27 // 加密 28 String encryptDES = encryptDES(input, key, transformation, algorithm); 29 System.out.println("encryptDES = " + encryptDES); 30 // 解密 31 String decryptDES = decryptDES(encryptDES, key, transformation, algorithm); 32 System.out.println("decryptDES = " + decryptDES); 33 } 34 35 // 解密 36 private static String decryptDES(String input, String key, String transformation, String algorithm) throws Exception { 37 // 创建加密对象 38 Cipher cipher = Cipher.getInstance(transformation); 39 // 创建加密规则 40 // 第一个参数:表示key的字节 41 // 第二个参数:表示加密的类型 42 SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm); 43 // 进行加密初始化 44 // 第一个参数表示模式:解密 45 // 第二个参数表示加密规则 46 cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); 47 // 调用加密方法 48 // 参数:表示原文的字节数组 49 byte[] decode = Base64.decode(input); 50 byte[] bytes = cipher.doFinal(decode); 51 // String encode = Base64.encode(bytes); 52 // System.out.println("encode = " + encode); 53 return new String(bytes); 54 } 55 56 // 加密 57 private static String encryptDES(String input, String key, String transformation, String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { 58 // 创建加密对象 59 Cipher cipher = Cipher.getInstance(transformation); 60 // 创建加密规则 61 // 第一个参数:表示key的字节 62 // 第二个参数:表示加密的类型 63 SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm); 64 // 进行加密初始化 65 // 第一个参数表示模式:加密 66 // 第二个参数表示加密规则 67 cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 68 // 调用加密方法 69 // 参数:表示原文的字节数组 70 byte[] bytes = cipher.doFinal(input.getBytes()); 71 String encode = Base64.encode(bytes); 72 // System.out.println("encode = " + encode); 73 return encode; 74 75 // for (byte aByte : bytes) { 76 // System.out.println("aByte = " + aByte); 77 // } 78 // // 打印秘文 79 // System.out.println("bytes = " + new String(bytes)); 80 } 81 }
AES
1 package com.test.desaes; 2 3 import com.sun.org.apache.xml.internal.security.utils.Base64; 4 5 import javax.crypto.BadPaddingException; 6 import javax.crypto.Cipher; 7 import javax.crypto.IllegalBlockSizeException; 8 import javax.crypto.NoSuchPaddingException; 9 import javax.crypto.spec.SecretKeySpec; 10 import java.security.InvalidKeyException; 11 import java.security.NoSuchAlgorithmException; 12 13 /** 14 * 对称加密 15 */ 16 public class AesDemo { 17 public static void main(String[] args) throws Exception { 18 // 原文 19 String input = "Hello World"; 20 // 定义key 21 // 如果使用AES加密,密钥必须是16位 22 String key = "1234567812345678"; 23 // 算法 24 String transformation = "AES"; 25 // 加密类型 26 String algorithm = "AES"; 27 // 加密 28 String encryptAES = encryptAES(input, key, transformation, algorithm); 29 System.out.println("encryptAES = " + encryptAES); 30 // 解密 31 String decryptAES = decryptAES(encryptAES, key, transformation, algorithm); 32 System.out.println("decryptAES = " + decryptAES); 33 } 34 35 // 解密 36 private static String decryptAES(String input, String key, String transformation, String algorithm) throws Exception { 37 // 创建加密对象 38 Cipher cipher = Cipher.getInstance(transformation); 39 // 创建加密规则 40 // 第一个参数:表示key的字节 41 // 第二个参数:表示加密的类型 42 SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm); 43 // 进行加密初始化 44 // 第一个参数表示模式:解密 45 // 第二个参数表示加密规则 46 cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); 47 // 调用加密方法 48 // 参数:表示原文的字节数组 49 byte[] decode = Base64.decode(input); 50 byte[] bytes = cipher.doFinal(decode); 51 // String encode = Base64.encode(bytes); 52 // System.out.println("encode = " + encode); 53 return new String(bytes); 54 } 55 56 // 加密 57 private static String encryptAES(String input, String key, String transformation, String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { 58 // 创建加密对象 59 Cipher cipher = Cipher.getInstance(transformation); 60 // 创建加密规则 61 // 第一个参数:表示key的字节 62 // 第二个参数:表示加密的类型 63 SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm); 64 // 进行加密初始化 65 // 第一个参数表示模式:加密 66 // 第二个参数表示加密规则 67 cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 68 // 调用加密方法 69 // 参数:表示原文的字节数组 70 byte[] bytes = cipher.doFinal(input.getBytes()); 71 String encode = Base64.encode(bytes); 72 // System.out.println("encode = " + encode); 73 return encode; 74 75 // for (byte aByte : bytes) { 76 // System.out.println("aByte = " + aByte); 77 // } 78 // // 打印秘文 79 // System.out.println("bytes = " + new String(bytes)); 80 } 81 }
3、非对称加密
RSA
1 package com.test.rsa; 2 3 import com.sun.org.apache.xml.internal.security.utils.Base64; 4 import com.test.utils.FileUtils; 5 6 import javax.crypto.Cipher; 7 import java.io.File; 8 import java.security.*; 9 import java.security.spec.PKCS8EncodedKeySpec; 10 import java.security.spec.X509EncodedKeySpec; 11 12 /** 13 * 非对称加密 14 */ 15 public class RSADemo { 16 public static void main(String[] args) throws Exception { 17 18 String input = "Hello World"; 19 20 // 加密算法 21 String algorithm = "RSA"; 22 23 //生成密钥对并保存在本地文件中 24 // generateKeyToFile(algorithm, "test-encryption/a.pub", "test-encryption/a.pri"); 25 // 从本地文件中获取密钥 26 PrivateKey privateKey = getPrivateKey(algorithm, "test-encryption/a.pri"); 27 PublicKey publicKey = getPublicKey(algorithm, "test-encryption/a.pub"); 28 29 // 私钥加密 - 公钥解密 30 String encode = encryptRSA(input, algorithm, privateKey); 31 System.out.println("encode = " + encode); 32 String decode = decryptRSA(encode, algorithm, publicKey); 33 System.out.println("decode = " + decode); 34 35 // 公钥加密 - 私钥解密 36 // String encode = encryptRSA(input, algorithm, publicKey); 37 // System.out.println("encode = " + encode); 38 // String decode = decryptRSA(encode, algorithm, privateKey); 39 // System.out.println("decode = " + decode); 40 41 42 43 // // 私钥进行解密(无法解密) 44 // cipher.init(Cipher.DECRYPT_MODE, privateKey); 45 // byte[] bytes1 = cipher.doFinal(bytes); 46 // System.out.println("new String(bytes1) = " + new String(bytes1)); 47 48 // // 公钥进行解密 49 // cipher.init(Cipher.DECRYPT_MODE, publicKey); 50 // byte[] bytes1 = cipher.doFinal(bytes); 51 // System.out.println("new String(bytes1) = " + new String(bytes1)); 52 53 } 54 55 public static PublicKey getPublicKey(String algorithm, String pubPath) throws Exception { 56 // 将文件内容转为字符串 57 String publicKeyString = FileUtils.readFileToString(new File(pubPath)); 58 // 获取密钥工厂 59 KeyFactory keyFactory = KeyFactory.getInstance(algorithm); 60 // 构建密钥规范 进行Base64解码 61 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKeyString)); 62 // 生成公钥 63 PublicKey publicKey = keyFactory.generatePublic(keySpec); 64 return publicKey; 65 } 66 67 public static PrivateKey getPrivateKey(String algorithm, String priPath) throws Exception { 68 // 将文件内容转为字符串 69 String publicKeyString = FileUtils.readFileToString(new File(priPath)); 70 // 获取密钥工厂 71 KeyFactory keyFactory = KeyFactory.getInstance(algorithm); 72 // 构建密钥规范 进行Base64解码 73 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(publicKeyString)); 74 // 生成公钥 75 PrivateKey privateKey = keyFactory.generatePrivate(keySpec); 76 return privateKey; 77 } 78 79 private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception { 80 // 创建密钥生成器对象 81 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm); 82 // 生成密钥对象 83 KeyPair keyPair = keyPairGenerator.generateKeyPair(); 84 // 生成密钥 85 // 私钥 86 PrivateKey privateKey = keyPair.getPrivate(); 87 // 公钥 88 PublicKey publicKey = keyPair.getPublic(); 89 // 获取私钥字节数组 90 byte[] privateKeyEncoded = privateKey.getEncoded(); 91 // 获取公钥字节数组 92 byte[] publicKeyEncoded = publicKey.getEncoded(); 93 // 对密钥字节数组进行base64编码 94 String privateKeyString = Base64.encode(privateKeyEncoded); 95 String publicKeyString = Base64.encode(publicKeyEncoded); 96 97 FileUtils.writeStringToFile(new File(priPath), privateKeyString); 98 FileUtils.writeStringToFile(new File(pubPath), publicKeyString); 99 // // 打印私钥 100 // System.out.println("privateKeyString = " + privateKeyString); 101 // // 打印公钥 102 // System.out.println("publicKeyString = " + publicKeyString); 103 104 } 105 106 private static String encryptRSA(String input, String algorithm, Key key) throws Exception { 107 // 创建加密对象 108 // 参数表示加密算法 109 Cipher cipher = Cipher.getInstance(algorithm); 110 // 初始化加密 111 // 第一个参数:加密的模式 112 // 第二个参数:使用私钥进行加密 113 cipher.init(Cipher.ENCRYPT_MODE, key); 114 // 私钥加密 115 byte[] bytes = cipher.doFinal(input.getBytes()); 116 String encode = Base64.encode(bytes); 117 return encode; 118 } 119 120 private static String decryptRSA(String input, String algorithm, Key key) throws Exception { 121 // 创建加密对象 122 // 参数表示加密算法 123 Cipher cipher = Cipher.getInstance(algorithm); 124 // 初始化加密 125 // 第一个参数:加密的模式 126 // 第二个参数:使用私钥进行加密 127 cipher.init(Cipher.DECRYPT_MODE, key); 128 // 密钥解密 129 byte[] decode = Base64.decode(input); 130 byte[] bytes = cipher.doFinal(decode); 131 return new String(bytes); 132 } 133 }
工具类
1 package com.test.utils; 2 3 import java.io.*; 4 5 public class FileUtils { 6 7 public static String writeStringToFile(File destFile, String content) throws Exception { 8 // 1、创建File类的对象,指明读入和写出的文件 9 // File srcFile = new File("hello.txt"); 10 // File destFile = new File("hello2.txt"); 11 12 // 2、创建输入流和输出流的对象 13 // FileReader fileReader = null; 14 StringBuilder stringBuilder = new StringBuilder(); 15 FileWriter fileWriter = null; 16 try { 17 // fileReader = new FileReader(destFile); 18 fileWriter = new FileWriter(destFile); 19 20 // 3、数据的读入和写出操作 21 // char[] cbuf = new char[1024]; 22 // int len; 23 // while ((len = fileReader.read(cbuf)) != -1) { 24 // stringBuilder.append(new String(cbuf, 0, len)); 25 // fileWriter.write(cbuf, 0, len); 26 // } 27 fileWriter.write(content); 28 29 } catch (FileNotFoundException e) { 30 e.printStackTrace(); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } finally { 34 // 35 // 4、关闭流资源 36 if(fileWriter != null ){ 37 try { 38 fileWriter.close(); 39 } catch (IOException e) { 40 e.printStackTrace(); 41 } 42 } 43 // if (fileReader != null) { 44 // try { 45 // fileReader.close(); 46 // } catch (IOException e) { 47 // e.printStackTrace(); 48 // } 49 // } 50 } 51 return stringBuilder.toString(); 52 } 53 54 public static String readFileToString(File srcFile) throws Exception { 55 // 1、创建File类的对象,指明读入和写出的文件 56 // File srcFile = new File("hello.txt"); 57 // File destFile = new File("hello2.txt"); 58 59 // 2、创建输入流和输出流的对象 60 FileReader fileReader = null; 61 StringBuilder stringBuilder = new StringBuilder(); 62 // FileWriter fileWriter = null; 63 try { 64 fileReader = new FileReader(srcFile); 65 // fileWriter = new FileWriter(destFile); 66 67 // 3、数据的读入和写出操作 68 char[] cbuf = new char[1024]; 69 int len; 70 while ((len = fileReader.read(cbuf)) != -1) { 71 stringBuilder.append(new String(cbuf, 0, len)); 72 // fileWriter.write(cbuf, 0, len); 73 } 74 75 } catch (FileNotFoundException e) { 76 e.printStackTrace(); 77 } catch (IOException e) { 78 e.printStackTrace(); 79 } finally { 80 // 81 // // 4、关闭流资源 82 // if(fileWriter != null ){ 83 // try { 84 // fileWriter.close(); 85 // } catch (IOException e) { 86 // e.printStackTrace(); 87 // } 88 // } 89 if (fileReader != null) { 90 try { 91 fileReader.close(); 92 } catch (IOException e) { 93 e.printStackTrace(); 94 } 95 } 96 } 97 return stringBuilder.toString(); 98 } 99 }
4、消息摘要算法
1 package com.test.digest; 2 3 import java.security.MessageDigest; 4 import java.security.NoSuchAlgorithmException; 5 6 /** 7 * 消息摘要算法,为了防止篡改 8 */ 9 public class DigestDemo { 10 public static void main(String[] args) throws NoSuchAlgorithmException { 11 // 原文 12 String input = "Hello World"; 13 // 算法 14 String algorithm = "MD5"; 15 String MD5 = getDigest(input, algorithm); 16 // 使用base64进行转码 17 // String encode = Base64.encode(digest1); 18 // System.out.println("encode = " + encode); 19 System.out.println("MD5 = " + MD5); 20 System.out.println("MD5.length() = " + MD5.length()); 21 22 String sha1 = getDigest(input, "SHA-1"); 23 System.out.println("sha1 = " + sha1); 24 System.out.println("sha1.length() = " + sha1.length()); 25 26 String sha256 = getDigest(input, "SHA-256"); 27 System.out.println("sha256 = " + sha256); 28 System.out.println("sha256.length() = " + sha256.length()); 29 30 String sha512 = getDigest(input, "SHA-512"); 31 System.out.println("sha512 = " + sha512); 32 System.out.println("sha512.length() = " + sha512.length()); 33 } 34 35 private static String getDigest(String input, String algorithm) throws NoSuchAlgorithmException { 36 // 创建消息摘要对象 37 MessageDigest digest = MessageDigest.getInstance(algorithm); 38 // 执行消息摘要算法 39 byte[] digest1 = digest.digest(input.getBytes()); 40 System.out.println("密文的字节长度:" + digest1.length); 41 // 转16进制 42 return toHex(digest1); 43 } 44 45 private static String toHex(byte[] input) { 46 StringBuilder sb = new StringBuilder(); 47 for (byte b : input) { 48 // 转成 16进制 49 String s = Integer.toHexString(b & 0xff); 50 //System.out.println(s); 51 if (s.length() == 1){ 52 // 如果生成的字符只有一个,前面补0 53 s = "0"+s; 54 } 55 sb.append(s); 56 } 57 System.out.println(sb.toString()); 58 return sb.toString(); 59 } 60 }
5、数字签名
1 package com.test.digest; 2 3 import com.sun.org.apache.xml.internal.security.utils.Base64; 4 import com.test.rsa.RSADemo; 5 6 import java.security.NoSuchAlgorithmException; 7 import java.security.PrivateKey; 8 import java.security.PublicKey; 9 import java.security.Signature; 10 11 /** 12 * 数字签名 13 */ 14 public class SignatureDemo { 15 public static void main(String[] args) throws Exception { 16 String input = "Hello World"; 17 // 加密算法 18 String algorithm = "RSA"; 19 // 获取密钥 20 PrivateKey privateKey = RSADemo.getPrivateKey(algorithm, "test-encryption/a.pri"); 21 PublicKey publicKey = RSADemo.getPublicKey(algorithm, "test-encryption/a.pub"); 22 // 获取签名 23 String signature = getSignature(input, "sha256withrsa", privateKey); 24 System.out.println("signature = " + signature); 25 // 校验签名 26 boolean verify = verifySignature(input, "sha256withrsa", publicKey, signature); 27 System.out.println("verify = " + verify); 28 } 29 30 private static boolean verifySignature(String input, String algorithm, PublicKey publicKey, String signatureData) throws Exception { 31 // 获取签名对象 32 Signature signature = Signature.getInstance(algorithm); 33 // 初始化校验 34 signature.initVerify(publicKey); 35 // 传入原文 36 signature.update(input.getBytes()); 37 // 校验 38 byte[] decode = Base64.decode(signatureData.getBytes()); 39 boolean verify = signature.verify(decode); 40 return verify; 41 } 42 43 private static String getSignature(String input, String algorithm, PrivateKey privateKey) throws Exception { 44 // 获取签名对象 45 Signature signature = Signature.getInstance(algorithm); 46 // 初始化签名 47 signature.initSign(privateKey); 48 // 传入原文 49 signature.update(input.getBytes()); 50 // 签名 51 byte[] sign = signature.sign(); 52 // Base64编码 53 String encode = Base64.encode(sign); 54 return encode; 55 } 56 }
6、Base64说明
1 package com.test.base64; 2 3 import com.sun.org.apache.xml.internal.security.utils.Base64; 4 5 public class TestBase64 { 6 public static void main(String[] args) { 7 // 当字节不够3个字节,需要使用 = 进行补齐 8 // 1 表示一个字节,不够3个字节 9 System.out.println(Base64.encode("1".getBytes())); 10 System.out.println(Base64.encode("12".getBytes())); 11 System.out.println(Base64.encode("123".getBytes())); 12 } 13 }
参考:https://blog.csdn.net/xiaotai1234/category_10362621.html