在Java中,加密英文文本通常涉及到使用加密算法,比如对称加密(如AES)或非对称加密(如RSA)。本文整理了几种java常用的几种加密方法。
参考文章:
Java常用加密方式
加密算法分类
- 对称加密:指加密和解密的密钥相同,优点就是加解密的效率高且易于实现。
 
- 非对称加密:指加密和解密的密钥不相同,也称为公私钥加密。
 
- 不可逆加密:特征就是加密过程不需要密钥,并且加密后的数据不能被解密,只能输入同样的数据并且经过同样的不可逆加密算法才能获取同样的加密数据。
 
加密算法的应用
- 数字签名:进行身份认证和数据完整性验证,主要用到了非对称密钥加密技术与数字摘要技术。
 
- 数字证书:主要用来确保数字签名是安全有效的,数字证书由独立的证书发行机构发布。数字证书各不相同,每种证书可提供不同级别的可信度,该证书内包含用户的个人信息和他的公钥信息,同时还附有认证中心的签名信息。
 
- MD5:对用户密码进行加密并进行保存。
 
- 网络数据加密:保障传输的数据安全,即使被截获报文,在没有密匙的情况下也无法得知报文真实内容。
 
- SSL协议:在握手阶段使用的是非对称加密,在传输阶段使用的是对称加密,即在SSL上传送的数据是使用对称密钥加密的。同时HTTPS也是由
SSL+HTTP协议构建的可进行加密传输、身份认证(确认客户端连接的目标主机是否是真实正确的主机)的网络协议。 
对称加密算法
- 优点:算法对消息双方公开、计算量小、加解密速度快、效率高。
 
- 缺点:在数据传送前,发送方和接收方必须商定好秘钥,然后双方保存好秘钥。如果一方的秘钥被泄露,那么加密信息就会被破解。
 
DES介绍
DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,24小时内即可被破解。DES加密和解密过程中,**密钥长度都必须是8的倍数**。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
   | public class DESHelper {     public String encrypt(String dataSource, String password) throws Exception {                  SecureRandom random = new SecureRandom();         DESKeySpec desKey = new DESKeySpec(password.getBytes(StandardCharsets.UTF_8));                  SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");         SecretKey secretKey = keyFactory.generateSecret(desKey);                  Cipher cipher = Cipher.getInstance("DES");                  cipher.init(Cipher.ENCRYPT_MODE,secretKey,random);                  return new String(cipher.doFinal(dataSource.getBytes(StandardCharsets.UTF_8)));     }
      public String decrypt(String src, String password) throws Exception {         SecureRandom random = new SecureRandom();         DESKeySpec desKey = new DESKeySpec(password.getBytes(StandardCharsets.UTF_8));         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");         SecretKey secretKey = keyFactory.generateSecret(desKey);                  Cipher cipher = Cipher.getInstance("DES");         cipher.init(Cipher.DECRYPT_MODE,secretKey,random);         return new String(cipher.doFinal(src.getBytes(StandardCharsets.UTF_8)));     } }
  | 
 
加解密测试:
1 2 3 4 5 6 7 8 9 10
   | @Test public void DESTest() throws Exception {     DESHelper desHelper = new DESHelper();     String source = "满天星辰不及你!";     System.out.println("原始数据:"+source);     byte[] encryptData = desHelper.encrypt(source, "1qaz2wsx");     System.out.println("加密后数据:"+encryptData);     byte[] decryptData = desHelper.decrypt(encryptData, "1qaz2wsx");     System.out.println("解密后数据:"+new String(decryptData)); }
   | 
 
IDEA介绍
- 这种算法是在DES算法的基础上发展出来的,类似于三重DES。
 
- 发展IDEA也是因为感到DES具有密钥太短等缺点。
 
- DEA的密钥为128位,这么长的密钥在今后若干年内应该是安全的。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
   | public class IDEAHelper {     public static final String KEY_ALGORITHM = "IDEA";           public static final String CIPHER_ALGORITHM = "IDEA/ECB/ISO10126Padding";
      
 
 
      public static byte[] initKey() throws Exception {         Security.addProvider(new BouncyCastleProvider());          KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);           kg.init(128);          SecretKey secretKey=kg.generateKey();          return secretKey.getEncoded();      }     
 
 
 
      public static Key toKey(byte[] key) throws Exception {         SecretKey secretKey = new SecretKeySpec(key,KEY_ALGORITHM);          return secretKey;      }
      
 
 
 
 
      public static byte[] encrypt(byte[] data,byte[] key) throws Exception {         Security.addProvider(new BouncyCastleProvider());          Key k = toKey(key);          Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);          cipher.init(Cipher.ENCRYPT_MODE, k);           return cipher.doFinal(data);      }     
 
 
 
 
      public static byte[] decrypt(byte[] data,byte[] key) throws Exception {         Security.addProvider(new BouncyCastleProvider());          Key k = toKey(key);          Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);         cipher.init(Cipher.DECRYPT_MODE, k);          return cipher.doFinal(data);      } }
  | 
 
加解密测试:
1 2 3 4 5 6 7 8 9 10 11
   | @Test public void IDEATest() throws Exception {     String str = "满天星辰不及你!";     System.out.println("原始数据:"+str);     byte[] key = IDEAHelper.initKey();      System.out.println("密钥:"+ Base64.encodeBase64String(key));     byte[] data = IDEAHelper.encrypt(str.getBytes(), key);      System.out.println("加密后数据:"+Base64.encodeBase64String(data));     data=IDEAHelper.decrypt(data, key);     System.out.println("解密后数据:"+new String(data)); }
   | 
 
非对称加密算法
- 优点:非对称加密与对称加密相比其安全性更好,只要私钥不泄露,很难被破解。
 
- 缺点:加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
 
RSA介绍
RSA是目前最有影响力和最常用的公钥加密算法。它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。RSA公开密钥密码体制的原理是:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
   | public class RSAHelper {     public static final String KEY_ALGORITHM = "RSA";     public static final String SIGNATURE_ALGORITHM = "MD5withRSA";     private static final String PUBLIC_KEY = "RSAPublicKey";     private static final String PRIVATE_KEY = "RSAPrivateKey";
      public static byte[] decryptBASE64(String key) {         return Base64.decodeBase64(key);     }
      public static String encryptBASE64(byte[] bytes) {         return Base64.encodeBase64String(bytes);     }
      
 
 
 
 
      public static String sign(byte[] data, String privateKey) throws Exception {                  byte[] keyBytes = decryptBASE64(privateKey);                  PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);                  KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);                  PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);                  Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);         signature.initSign(priKey);         signature.update(data);         return encryptBASE64(signature.sign());
      }
      
 
 
 
 
 
 
      public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {                  byte[] keyBytes = decryptBASE64(publicKey);                  X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);                  KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);                  PublicKey pubKey = keyFactory.generatePublic(keySpec);         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);         signature.initVerify(pubKey);         signature.update(data);                  return signature.verify(decryptBASE64(sign));     }
      public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception {                  byte[] keyBytes = decryptBASE64(key);                  PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);         Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);                  Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());         cipher.init(Cipher.DECRYPT_MODE, privateKey);         return cipher.doFinal(data);     }
      
 
 
 
 
      public static byte[] decryptByPrivateKey(String data, String key) throws Exception {         return decryptByPrivateKey(decryptBASE64(data), key);     }
      
 
 
 
 
      public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception {                  byte[] keyBytes = decryptBASE64(key);                  X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);         Key publicKey = keyFactory.generatePublic(x509KeySpec);                  Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());         cipher.init(Cipher.DECRYPT_MODE, publicKey);         return cipher.doFinal(data);     }
      
 
 
 
 
      public static byte[] encryptByPublicKey(String data, String key) throws Exception {                  byte[] keyBytes = decryptBASE64(key);                  X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);         Key publicKey = keyFactory.generatePublic(x509KeySpec);                  Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());         cipher.init(Cipher.ENCRYPT_MODE, publicKey);         return cipher.doFinal(data.getBytes());     }
      
 
 
 
 
      public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception {                  byte[] keyBytes = decryptBASE64(key);                  PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);         Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);                  Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());         cipher.init(Cipher.ENCRYPT_MODE, privateKey);         return cipher.doFinal(data);     }
      
 
 
 
      public static String getPrivateKey(Map<String, Key> keyMap) throws Exception {         Key key = (Key) keyMap.get(PRIVATE_KEY);         return encryptBASE64(key.getEncoded());     }
      
 
 
 
      public static String getPublicKey(Map<String, Key> keyMap) throws Exception {         Key key = keyMap.get(PUBLIC_KEY);         return encryptBASE64(key.getEncoded());     }     
 
 
      public static Map<String, Key> initKey() throws Exception {         KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);         keyPairGen.initialize(1024);         KeyPair keyPair = keyPairGen.generateKeyPair();         Map<String, Key> keyMap = new HashMap(2);         keyMap.put(PUBLIC_KEY, keyPair.getPublic());         keyMap.put(PRIVATE_KEY, keyPair.getPrivate());         return keyMap;     } }
  | 
 
加解密测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | @Test public void RSATest() throws Exception {     Map<String, Key> keyMap = initKey();     String publicKey = getPublicKey(keyMap);     String privateKey = getPrivateKey(keyMap);     System.out.println("公钥:" + publicKey);     System.out.println("私钥:" + privateKey);     String src = "满天星辰不及你!";     System.out.println("原始数据:" + src);     byte[] encryptByPrivateKey = encryptByPrivateKey(src.getBytes(), privateKey);     byte[] encryptByPublicKey = encryptByPublicKey(src, publicKey);     System.out.println("私钥加密后数据" + encryptByPrivateKey);     System.out.println("公钥加密后数据" + encryptByPublicKey);     String sign = sign(encryptByPrivateKey, privateKey);     System.out.println("数字签名:" + sign);     boolean verify = verify(encryptByPrivateKey, publicKey, sign);     System.out.println("签名验证结果:" + verify);     byte[] decryptByPublicKey = decryptByPublicKey(encryptByPrivateKey, publicKey);     byte[] decryptByPrivateKey = decryptByPrivateKey(encryptByPublicKey, privateKey);     System.out.println("公钥解密私钥加密后的数据:"+ new String(decryptByPublicKey));     System.out.println("私钥解密公钥加密后的数据:"+ new String(decryptByPrivateKey)); }
   | 
 
不可逆算法
MD5介绍
MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被”压缩”成一种保密的格式(也就是把一个任意长度的字节串变换成一定长的十六进制数字串)。主要有以下特点:
- 压缩性: 任意长度的数据,算出的MD5值长度都是固定的。
 
- 容易计算: 从原数据计算出MD5值很容易。
 
- 抗修改性: 对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
 
- 强抗碰撞: 已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | public class MD5Helper {     public String encode(String s) throws NoSuchAlgorithmException {         MessageDigest md5 = MessageDigest.getInstance("MD5");         byte[] md5Bytes = md5.digest(s.getBytes(StandardCharsets.UTF_8));         return md5ToString(md5Bytes);     }
           public String md5ToString(byte[] md5Bytes) {         StringBuilder hexValue = new StringBuilder();         for (int i = 0; i < md5Bytes.length; i++) {             int val = md5Bytes[i] & 0Xff;             if (val < 16){                 hexValue.append("0");             }             hexValue.append(Integer.toHexString(val));         }         return hexValue.toString();     } }
  | 
 
加密测试:
1 2 3 4 5 6 7 8
   | @Test public void MD5Test() throws NoSuchAlgorithmException {     MD5Helper md5Helper = new MD5Helper();     String src1 = "满天星辰不及你!";     String src2 = "满天星辰不及你!";     System.out.println("src1 加密后数据:" + md5Helper.encode(src1));     System.out.println("src2 加密后数据:" + md5Helper.encode(src2)); }
   | 
 
SHA1介绍
对于长度小于2^64位的消息,SHA1会产生一个160位(40个字符)的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。SHA1有如下特性:
- 不可以从消息摘要中复原信息;
 
- 两个不同的消息不会产生同样的消息摘要,(但会有1x10 ^ 48分之一的机率出现相同的消息摘要,一般使用时忽略)。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | public class SHA1Helper {     public String encode(String str) throws NoSuchAlgorithmException {         if (null == str || str.length() == 0){             return null;         }       char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };         MessageDigest mdTemp = MessageDigest.getInstance("SHA1");          mdTemp.update(str.getBytes(StandardCharsets.UTF_8));          byte[] md = mdTemp.digest();                   int j = md.length;         char[] buf = new char[j*2];         int k = 0;         for (int i = 0; i < j; i++) {             byte byte0 = md[i];             buf[k++] = hexDigits[byte0 >>> 4 & 0xf];             buf[k++] = hexDigits[byte0 & 0xf];         }         return new String(buf);     } }
  | 
 
加密测试:
1 2 3 4 5 6 7 8
   | @Test public void SHA1Test() throws NoSuchAlgorithmException {     SHA1Helper sha1Helper = new SHA1Helper();     String src1 = "满天星辰不及你!";     String src2 = "满天星辰不及你!";     System.out.println("src1 加密后数据:" + sha1Helper.encode(src1));     System.out.println("src2 加密后数据:" + sha1Helper.encode(src2)); }
   | 
 
HMAC 介绍
HMAC 是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),HMAC 运算利用 哈希算法 (MD5、SHA1 等),以 一个密钥 和 一个消息 为输入,生成一个 消息摘要 作为 输出。HMAC 发送方 和 接收方 都有的 key 进行计算,而没有该 key 的第三方,则 无法计算 出正确的 散列值,这样就可以 防止数据被篡改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | public class HMACHelper {     private Mac mac;          private static final String KEY_MAC = "HmacMD5";     public HMACHelper(String key) throws Exception {         SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), KEY_MAC);         mac = Mac.getInstance(secretKey.getAlgorithm());         mac.init(secretKey);     }
      public String sign(String content){         return new String(mac.doFinal(content.getBytes(StandardCharsets.UTF_8)));     }
      public boolean verify(String signature, String content){         byte[] result = mac.doFinal(content.getBytes(StandardCharsets.UTF_8));         return Arrays.equals(result, signature.getBytes(StandardCharsets.UTF_8));     } }
  | 
 
加密测试:
1 2 3 4 5 6 7 8 9
   | @Test public void HMACTest() throws Exception {     HMACHelper hmacHelper = new HMACHelper("123456");     String src = "满天星辰不及你!";     byte[] signature = hmacHelper.sign(src);     boolean b = hmacHelper.verify(signature, src);     System.out.println("src 生成数字签名:" + signature);     System.out.println("签名验证结果:" + b); }
   |