1、加密概述:
加密就是是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使以获得了加密的信息,但因不知解密方式,仍无法了解信息的内容。大体上又分为双向加密和单向加密。
2、单项加密
2.1、概述:
单向加密又称为不可逆加密算法,在加密过程中不使用密钥,明文由系统加密成密文,密文无法破解,一般都是采用验证的方式,具体是:在验证过程中,重新输入明文,并经过同样的加密算法后,得到相同的密文。单向加密广泛用于口令加密。
2.2、特点:
(1)对同一消息反复执行加密得到相同的密文;
(2)加密算法生成密文不可预见;
(3)不可逆,一般不能通过密文获取明文
2.3、类别
2.3.1、MD5加密
2.3.1.1、概述:
MD5的全称是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由MIT Laboratory for Computer Science和RSA Data Security Inc的Ronald L. Rivest开发出来,经MD2、MD3和MD4发展而来。
MD5用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。
MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。
2.3.1.2、算法原理:
对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448。因此,信息的位长(Bits Length)将被扩展至N*512+448,N为一个非负整数,N可以是零。填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。然后,在这个结果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,信息的位长=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。
2.3.1.3、java代码中使用MD5加密
1 /** 2 * md5计算. 3 * 4 * @param datas 5 * 待计算的数据 6 * @return 计算结果 7 */ 8 public static byte[] md5(byte[] datas) { 9 MessageDigest md = null; 10 try { 11 md = MessageDigest.getInstance("MD5"); 12 md.reset(); 13 md.update(datas); 14 return md.digest(); 15 } catch (Exception e) { 16 log.error("MD5计算失败", e); 17 return null; 18 } 19 }
2.3.2、SHA加密
2.3.2.1、概述
其思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)的密文。可以简单的理解为取一串输入码(称为预映射或信息),并把他们转化为长度较短、位数固定的输出序列的过程。
安全散列算法SHA(Secure Hash Algorithm,SHA)是美国国家标准技术研究所发布的国家标准FIPS PUB 180,最新的标准已经于2008年更新到FIPS PUB 180-3。其中规定了SHA-1,SHA-224,SHA-256,SHA-384,和SHA-512这几种单向散列算法。SHA-1,SHA-224和SHA-256适用于长度不超过2^64二进制位的消息。SHA-384和SHA-512适用于长度不超过2^128二进制位的消息。
2.3.2.2、原理
SHA-1是一种数据加密算法,该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。
单向散列函数的安全性在于其产生散列值的操作过程具有较强的单向性。如果在输入序列中嵌入密码,那么任何人在不知道密码的情况下都不能产生正确的散列值,从而保证了其安全性。SHA将输入流按照每块512位(64个字节)进行分块,并产生20个字节的被称为信息认证代码或信息摘要的输出。
该算法输入报文的长度不限,产生的输出是一个160位的报文摘要。输入是按512 位的分组进行处理的。SHA-1是不可逆的、防冲突,并具有良好的雪崩效应。
通过散列算法可实现数字签名实现,数字签名的原理是将要传送的明文通过一种函数运算(Hash)转换成报文摘要(不同的明文对应不同的报文摘要),报文摘要加密后与明文一起传送给接受方,接受方将接受的明文产生新的报文摘要与发送方的发来报文摘要解密比较,比较结果一致表示明文未被改动,如果不一致表示明文已被篡改。
MAC (信息认证代码)就是一个散列结果,其中部分输入信息是密码,只有知道这个密码的参与者才能再次计算和验证MAC码的合法性。
2.3.2.3、java中的SHA实现
/** * SHA1签名 * @param paramStr 要加签的字符串 * @return */ public static String SHA1(String paramStr) { MessageDigest alg; String result = ""; String tmp = ""; try { alg = MessageDigest.getInstance("SHA-1"); alg.update(paramStr.getBytes()); byte[] bts = alg.digest(); for (int i = 0; i < bts.length; i++) { tmp = (Integer.toHexString(bts[i] & 0xFF)); if (tmp.length() == 1) result += "0"; result += tmp; } } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; }
2.4、SHA与MD5的区别:
(1)对强行攻击的安全性:最显著和最重要的区别是:SHA-1的摘要比MD5的摘要长32位。使用强行技术,产生任何一个报文使其摘要等于给定摘要的难度对MD5是是2^128数量级的操作,而对SHA-1则是2^160数量级的操作。这样,SHA-1对强行攻击有更大的强度。
(2)对密码分析的安全性:由于MD5的设计,易受密码分析的攻击,SHA-1不易受这样的攻击。
3、双向加密
3.1概述
大体意思是明文加密后形成密文,可以通过算法还原成明文。
3.2分类
3.2.1对称加密
3.2.1.1概述
对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。
3.2.1.2特点
优点:
(1)算法公开,计算量小、加密速度快、加密效率高
缺点:
(1)交易双方都使用同样的密钥,安全性得不到保证
(2)每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一密钥,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的负担。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。
3.2.1.3常用对称加密算法
基于“对称密钥”的加密算法比较常用的主要有:DES 、 3DES 、AES
(1)DES
概述:
DES算法全称为Data Encryption Standard,即数据加密算法,它是IBM公司于1975年研究成功并公开发表的。DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。
算法原理:
DES算法的入口参数有三个:Key、Data、Mode。
(1)Key为8个字节共64位,是DES算法的工作密钥;
(2)Data也为8个字节64位,是要被加密或被解密的数据;
(3)Mode为DES的工作方式,有两种:加密或解密。
DES算法是这样工作的:如Mode为加密,则用Key 去把数据Data进行加密, 生成Data的密码形式(64位)作为DES的输出结果;如Mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式(64位)作为DES的输出结果。在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、MAC等)在公共通信网中传输的安全性和可靠性。来源:
链接:https://www.zhihu.com/question/36767829/answer/68911532
算法应用:
目前在国内,随着三金工程尤其是金卡工程的启动,DES算法在POS、ATM、磁卡及智能卡(IC卡)、加油站、高速公路收费站等领域被广泛应用,以此来实现关键数据的保密,如信用卡持卡人的PIN的加密传输,IC卡与POS间的双向认证、金融交易数据包的MAC校验等,均用到DES算法。
java代码实现:
1 /** 2 * 3DES加密 3 * 4 * @param key 5 * 密钥信息 6 * @param content 7 * 待加密信息 8 * @return 9 * @throws Exception 10 */ 11 public static byte[] encode3DES(byte[] key, byte[] content) throws Exception { 12 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 13 // 不是8的倍数的,补足 14 if (key.length % 8 != 0) { 15 int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0); 16 byte[] temp = new byte[groups * 8]; 17 Arrays.fill(temp, (byte) 0); 18 System.arraycopy(key, 0, temp, 0, key.length); 19 key = temp; 20 } 21 // 长度为16位,转换成24位的密钥 22 if (key.length == 16) { 23 byte[] temp = new byte[24]; 24 System.arraycopy(key, 0, temp, 0, key.length); 25 System.arraycopy(key, 0, temp, key.length, temp.length - key.length); 26 key = temp; 27 } 28 29 // 不是8的倍数的,补足 30 byte[] srcBytes = content; 31 if (srcBytes.length % 8 != 0) { 32 int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0); 33 srcBytes = new byte[groups * 8]; 34 Arrays.fill(srcBytes, (byte) 0); 35 System.arraycopy(content, 0, srcBytes, 0, content.length); 36 } 37 38 SecretKey deskey = new SecretKeySpec(key, "DESede"); 39 Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding"); 40 cipher.init(Cipher.ENCRYPT_MODE, deskey); 41 byte[] temp = cipher.doFinal(srcBytes); 42 byte[] tgtBytes = new byte[content.length]; 43 System.arraycopy(temp, 0, tgtBytes, 0, tgtBytes.length); 44 return tgtBytes; 45 } 46 47 /** 48 * 3DES解密 49 * 50 * @param key 51 * 密钥 52 * @param content 53 * 待解密信息 54 * @return 55 * @throws Exception 56 */ 57 public static byte[] decode3DES(byte[] key, byte[] content) throws Exception { 58 // 不是8的倍数的,补足 59 if (key.length % 8 != 0) { 60 int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0); 61 byte[] temp = new byte[groups * 8]; 62 Arrays.fill(temp, (byte) 0); 63 System.arraycopy(key, 0, temp, 0, key.length); 64 key = temp; 65 } 66 // 长度为16位,转换成24位的密钥 67 if (key.length == 16) { 68 byte[] temp = new byte[24]; 69 System.arraycopy(key, 0, temp, 0, key.length); 70 System.arraycopy(key, 0, temp, key.length, temp.length - key.length); 71 key = temp; 72 } 73 74 // 不是8的倍数的,补足 75 byte[] srcBytes = content; 76 if (srcBytes.length % 8 != 0) { 77 int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0); 78 srcBytes = new byte[groups * 8]; 79 Arrays.fill(srcBytes, (byte) 0); 80 System.arraycopy(content, 0, srcBytes, 0, content.length); 81 } 82 83 SecretKey deskey = new SecretKeySpec(key, "DESede"); 84 Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding"); 85 cipher.init(Cipher.DECRYPT_MODE, deskey); 86 byte[] tgtBytes = cipher.doFinal(srcBytes); 87 return tgtBytes; 88 } 89 90 /** 91 * DES加密 92 * 93 * @param key 94 * 密钥信息 95 * @param content 96 * 待加密信息 97 * @return 98 * @throws Exception 99 */ 100 public static byte[] encodeDES(byte[] key, byte[] content) throws Exception { 101 // 不是8的倍数的,补足 102 if (key.length % 8 != 0) { 103 int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0); 104 byte[] temp = new byte[groups * 8]; 105 Arrays.fill(temp, (byte) 0); 106 System.arraycopy(key, 0, temp, 0, key.length); 107 key = temp; 108 } 109 110 // 不是8的倍数的,补足 111 byte[] srcBytes = content; 112 if (srcBytes.length % 8 != 0) { 113 int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0); 114 srcBytes = new byte[groups * 8]; 115 Arrays.fill(srcBytes, (byte) 0); 116 System.arraycopy(content, 0, srcBytes, 0, content.length); 117 } 118 119 IvParameterSpec iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); 120 SecureRandom sr = new SecureRandom(); 121 DESKeySpec dks = new DESKeySpec(key); 122 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 123 SecretKey secretKey = keyFactory.generateSecret(dks); 124 Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding"); 125 cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv, sr); 126 byte[] tgtBytes = cipher.doFinal(srcBytes); 127 return tgtBytes; 128 } 129 130 /** 131 * DES解密 132 * 133 * @param key 134 * 密钥信息 135 * @param content 136 * 待加密信息 137 * @return 138 * @throws Exception 139 */ 140 public static byte[] decodeDES(byte[] key, byte[] content) throws Exception { 141 // 不是8的倍数的,补足 142 if (key.length % 8 != 0) { 143 int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0); 144 byte[] temp = new byte[groups * 8]; 145 Arrays.fill(temp, (byte) 0); 146 System.arraycopy(key, 0, temp, 0, key.length); 147 key = temp; 148 } 149 // 不是8的倍数的,补足 150 byte[] srcBytes = content; 151 if (srcBytes.length % 8 != 0) { 152 int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0); 153 srcBytes = new byte[groups * 8]; 154 Arrays.fill(srcBytes, (byte) 0); 155 System.arraycopy(content, 0, srcBytes, 0, content.length); 156 } 157 158 IvParameterSpec iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); 159 SecureRandom sr = new SecureRandom(); 160 DESKeySpec dks = new DESKeySpec(key); 161 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 162 SecretKey secretKey = keyFactory.generateSecret(dks); 163 Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding"); 164 cipher.init(Cipher.DECRYPT_MODE, secretKey, iv, sr); 165 byte[] tgtBytes = cipher.doFinal(content); 166 return tgtBytes; 167 }
(2)3DES
概述:
3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。
算法原理:
3DES(即Triple DES)是DES向AES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),加密算法,其具体实现如下:设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,M代表明文,C代表密文,这样:
(1)3DES加密过程为:C=Ek3(Dk2(Ek1(M)))
(2)3DES解密过程为:M=Dk1(EK2(Dk3(C)))
java代码实现:
1 package cn.mars.app.txn.bjyl; 2 3 import java.security.Key; 4 import java.security.Security; 5 6 import javax.crypto.Cipher; 7 import javax.crypto.SecretKeyFactory; 8 import javax.crypto.spec.DESedeKeySpec; 9 10 /** 11 * 3DES加密 12 * 13 * @version 1.0 14 * @author 15 * 16 */ 17 public class DesUtil { 18 19 /** 20 * 密钥算法 21 */ 22 public static final String KEY_ALGORITHM = "DESede"; 23 public static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding"; 24 private static String strDefaultKey = "national"; 25 private Cipher encryptCipher = null; 26 private Cipher decryptCipher = null; 27 28 public DesUtil() throws Exception { 29 this(strDefaultKey); 30 } 31 32 public static String byteArr2HexStr(byte[] arrB) throws Exception { 33 int iLen = arrB.length; 34 StringBuffer sb = new StringBuffer(iLen * 2); 35 for (int i = 0; i < iLen; i++) { 36 int intTmp = arrB[i]; 37 while (intTmp < 0) { 38 intTmp = intTmp + 256; 39 } 40 if (intTmp < 16) { 41 sb.append("0"); 42 } 43 sb.append(Integer.toString(intTmp, 16)); 44 } 45 return sb.toString(); 46 } 47 48 public static byte[] hexStr2ByteArr(String strIn) throws Exception { 49 byte[] arrB = strIn.getBytes(); 50 int iLen = arrB.length; 51 byte[] arrOut = new byte[iLen / 2]; 52 for (int i = 0; i < iLen; i = i + 2) { 53 String strTmp = new String(arrB, i, 2); 54 arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16); 55 } 56 return arrOut; 57 } 58 /** 59 * @param strKey 60 * @throws Exception 61 */ 62 public DesUtil(String strKey) throws Exception { 63 Security.addProvider(new com.sun.crypto.provider.SunJCE()); 64 Key key = getKey(StringUtil.hexStringToByteArray(strKey)); 65 encryptCipher = Cipher.getInstance("DES/ECB/NoPadding"); 66 encryptCipher.init(Cipher.ENCRYPT_MODE, key); 67 decryptCipher = Cipher.getInstance("DES/ECB/NoPadding"); 68 decryptCipher.init(Cipher.DECRYPT_MODE, key); 69 } 70 71 public byte[] encrypt(byte[] arrB) throws Exception { 72 return encryptCipher.doFinal(arrB); 73 } 74 75 public String encrypt(String strIn) throws Exception { 76 return byteArr2HexStr(encrypt(strIn.getBytes())); 77 } 78 79 public byte[] decrypt(byte[] arrB) throws Exception { 80 return decryptCipher.doFinal(arrB); 81 } 82 83 public String decrypt(String strIn) throws Exception { 84 return new String(decrypt(hexStr2ByteArr(strIn))); 85 } 86 87 private Key getKey(byte[] arrBTmp) throws Exception { 88 byte[] arrB = new byte[8]; 89 for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) { 90 arrB[i] = arrBTmp[i]; 91 } 92 Key key = new javax.crypto.spec.SecretKeySpec(arrB, "DES"); 93 return key; 94 } 95 96 public static String printbytes(String tip, byte[] b) { 97 String ret = ""; 98 String str; 99 System.out.println(tip); 100 for (int i = 0; i < b.length; i++) { 101 str = Integer.toHexString((int) (b[i] & 0xff)); 102 if (str.length() == 1) 103 str = "0" + str; 104 System.out.print(str + " "); 105 ret = ret + str + " "; 106 } 107 return ret; 108 } 109 /** 110 * 加密 111 * @param data 112 * @param key 113 * @return 114 * @throws Exception 115 * @author yangxing 116 * 2014-7-22 117 */ 118 public static byte[] encrypt(byte[] data, byte[] key) throws Exception { 119 Key k = toKey(key);// 还原密钥 120 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 121 cipher.init(Cipher.ENCRYPT_MODE, k); 122 return cipher.doFinal(data); 123 } 124 /** 125 * 解密 126 * 127 * @param data 待解密数据 128 * @param key 密钥 129 * @return byte[] 解密数据 130 */ 131 public static byte[] decrypt(byte[] data, byte[] key) throws Exception { 132 // 还原密钥 133 Key k = toKey(key); 134 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 135 // 初始化,设置为解密模式 136 cipher.init(Cipher.DECRYPT_MODE, k); 137 // 执行操作 138 return cipher.doFinal(data); 139 } 140 /** 141 * 转换密钥 142 * @param key 二进制密钥 143 * @return key 密钥 144 */ 145 public static Key toKey(byte[] key) throws Exception { 146 DESedeKeySpec dks = new DESedeKeySpec(key); 147 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM); 148 return keyFactory.generateSecret(dks); 149 } 150 151 public static void main(String[] args) { 152 try { 153 byte[] data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 }; 154 DesUtil des1 = new DesUtil("498F456AC9D9CBA0"); 155 printbytes("data", des1.encrypt(data)); 156 } catch (Exception e) { 157 e.printStackTrace(); 158 } 159 } 160 }
(3)AES
概述:
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。
原理:
AES加密过程涉及到4种操作:字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(AddRoundKey)。解密过程分别为对应的逆操作。由于每一步操作都是可逆的,按照相反的顺序进行解密即可恢复明文。加解密中每轮的密钥分别由初始密钥扩展得到。算法中16字节的明文、密文和轮密钥都以一个4x4的矩阵表示。
java代码实现:
1 package cn.mars.app.txn.wanglian; 2 3 import java.security.MessageDigest; 4 import java.security.NoSuchAlgorithmException; 5 import java.security.SecureRandom; 6 import java.security.Security; 7 8 import javax.crypto.Cipher; 9 import javax.crypto.KeyGenerator; 10 import javax.crypto.SecretKey; 11 import javax.crypto.spec.SecretKeySpec; 12 13 import org.bouncycastle.jce.provider.BouncyCastleProvider; 14 15 import cfca.util.Base64; 16 17 /** 18 * java实现AES256加密解密 19 * @author xiaoqiang 20 * 21 */ 22 23 public class AES256Util { 24 25 public static byte[] encrypt(String content, String password) { 26 try { 27 // "AES":请求的密钥算法的标准名称 28 KeyGenerator kgen = KeyGenerator.getInstance("AES"); 29 // 256:密钥生成参数;securerandom:密钥生成器的随机源 30 SecureRandom securerandom = new SecureRandom(tohash256Deal(password)); 31 kgen.init(256, securerandom); 32 // 生成秘密(对称)密钥 33 SecretKey secretKey = kgen.generateKey(); 34 // 返回基本编码格式的密钥 35 byte[] enCodeFormat = secretKey.getEncoded(); 36 // 根据给定的字节数组构造一个密钥。enCodeFormat:密钥内容;"AES":与给定的密钥内容相关联的密钥算法的名称 37 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 38 // 将提供程序添加到下一个可用位置 39 Security.addProvider(new BouncyCastleProvider()); 40 // 创建一个实现指定转换的 Cipher对象,该转换由指定的提供程序提供。 41 // "AES/ECB/PKCS7Padding":转换的名称;"BC":提供程序的名称 42 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC"); 43 44 cipher.init(Cipher.ENCRYPT_MODE, key); 45 byte[] byteContent = content.getBytes("utf-8"); 46 byte[] cryptograph = cipher.doFinal(byteContent); 47 byte[] encode = Base64.encode(cryptograph); 48 49 return encode; 50 } catch (Exception e) { 51 e.printStackTrace(); 52 } 53 return null; 54 } 55 56 public static String decrypt(byte[] cryptograph, String password) { 57 try { 58 KeyGenerator kgen = KeyGenerator.getInstance("AES"); 59 SecureRandom securerandom = new SecureRandom(tohash256Deal(password)); 60 kgen.init(256, securerandom); 61 SecretKey secretKey = kgen.generateKey(); 62 byte[] enCodeFormat = secretKey.getEncoded(); 63 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 64 Security.addProvider(new BouncyCastleProvider()); 65 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 66 67 cipher.init(Cipher.DECRYPT_MODE, key); 68 byte[] content = cipher.doFinal(Base64.decode(cryptograph)); 69 return new String(content); 70 } catch (Exception e) { 71 e.printStackTrace(); 72 } 73 return null; 74 } 75 76 public static String parseByte2HexStr(byte buf[]) { 77 StringBuffer sb = new StringBuffer(); 78 for (int i = 0; i < buf.length; i++) { 79 String hex = Integer.toHexString(buf[i] & 0xFF); 80 if (hex.length() == 1) { 81 hex = ‘0‘ + hex; 82 } 83 sb.append(hex.toUpperCase()); 84 } 85 return sb.toString(); 86 } 87 88 /* 89 * private static byte[] parseHexStr2Byte(String hexStr) { if 90 * (hexStr.length() < 1) return null; byte[] result = new 91 * byte[hexStr.length()/2]; for (int i = 0;i< hexStr.length()/2; i++) { int 92 * high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); int low = 93 * Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); result[i] = (byte) 94 * (high * 16 + low); } return result; } 95 */ 96 97 private static byte[] tohash256Deal(String datastr) { 98 try { 99 MessageDigest digester = MessageDigest.getInstance("SHA-256"); 100 digester.update(datastr.getBytes()); 101 byte[] hex = digester.digest(); 102 return hex; 103 } catch (NoSuchAlgorithmException e) { 104 throw new RuntimeException(e.getMessage()); 105 } 106 } 107 108 /** 109 * 生成随机密钥 110 * 111 * @param size 112 * 位数 113 * @return 114 */ 115 public static String generateRandomKey(int size) { 116 StringBuilder key = new StringBuilder(); 117 String chars = "0123456789ABCDEF"; 118 for (int i = 0; i < size; i++) { 119 int index = (int) (Math.random() * (chars.length() - 1)); 120 key.append(chars.charAt(index)); 121 } 122 return key.toString(); 123 } 124 125 public static void main(String[] args) { 126 127 String content = "123456"; 128 String password = generateRandomKey(32); 129 System.out.println("明文:" + content); 130 System.out.println("key:" + password); 131 132 byte[] encryptResult = AES256Util.encrypt(content, password); 133 System.out.println(encryptResult); 134 System.out.println("密文:" + AES256Util.parseByte2HexStr(encryptResult)); 135 136 String decryptResult = AES256Util.decrypt(encryptResult, password); 137 System.out.println("解密:" + decryptResult); 138 } 139 }
3.2.2非对称加密
3.2.2.1概述
1976年,美国学者Dime和Henman为解决信息公开传送和密钥管理问题,提出一种新的密钥交换协议,允许在不安全的媒体上的通讯双方交换信息,安全地达成一致的密钥,这就是“公开密钥系统”。
与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
3.2.2.2工作流程
如下图所示,甲乙之间使用非对称加密的方式完成了重要信息的安全传输。
非对称加密工作过程简要示意图
1、乙方生成一对密钥(公钥和私钥)并将公钥向其它方公开。
2、得到该公钥的甲方使用该密钥对机密信息进行加密后再发送给乙方。
3、乙方再用自己保存的另一把专用密钥(私钥)对加密后的信息进行解密。乙方只能用其专用密钥(私钥)解密由对应的公钥加密后的信息。
在传输过程中,即使攻击者截获了传输的密文,并得到了乙的公钥,也无法破解密文,因为只有乙的私钥才能解密密文。
同样,如果乙要回复加密信息给甲,那么需要甲先公布甲的公钥给乙用于加密,甲自己保存甲的私钥用于解密。
3.2.2.3优缺点:
(1)优点:非对称加密与对称加密相比,其安全性更好:对称加密的通信双方使用相同的秘钥,如果一方的秘钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存的,不需要像对称加密那样在通信之前要先同步秘钥。
(2)缺点:非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
3.2.2.4常用非对称加密算法:
在非对称加密中使用的主要算法有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等,其中RSA是最常用的。
(1)RSA加密算法
概述:
RSA是目前最有影响力和最常用的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。
RSA公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。
在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK。
正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA对话密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要。
RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现今的三十多年里,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。
加密过程:
(1)用户A和用户B通信,为了保证信息安全,使用RSA加密;
(2)用户A生成一对公司钥,保留私钥,提供公钥给B用户;A发送信息给B,使用生成的私钥进行加密;
(3)用户B接收用户A加密后的信息,使用A提供的公钥进行解密
java代码实现:
1 package cn.mars.app.txn.zjyl; 2 3 import java.io.ByteArrayOutputStream; 4 import java.security.Key; 5 import java.security.KeyFactory; 6 import java.security.KeyPair; 7 import java.security.KeyPairGenerator; 8 import java.security.NoSuchAlgorithmException; 9 import java.security.interfaces.RSAPrivateKey; 10 import java.security.interfaces.RSAPublicKey; 11 import java.security.spec.PKCS8EncodedKeySpec; 12 import java.security.spec.X509EncodedKeySpec; 13 import java.util.HashMap; 14 import java.util.Map; 15 16 import javax.crypto.Cipher; 17 18 /** 19 * Rsa工具类 20 * 21 * @author ThinkPad 22 * 23 */ 24 public abstract class RsaUtils { 25 /** 26 * 生成公钥私钥对,使用默认模长1024。 27 * 28 * @return Object[] : 0:公钥( RSAPublicKey ),1:私钥( RSAPrivateKey ) 29 */ 30 31 private static final int DEFAULT_KEY_LEN = 2048; 32 33 public static Map<String, String> genKeyPair() { 34 return genKeyPair(DEFAULT_KEY_LEN); 35 36 } 37 38 /** 39 * 指定模长生成公私钥对 40 * 41 * @param modulus 42 * @return 43 */ 44 public static Map<String, String> genKeyPair(int modulus) { 45 KeyPairGenerator keyPairGen; 46 try { 47 keyPairGen = KeyPairGenerator.getInstance("RSA"); 48 keyPairGen.initialize(modulus); 49 KeyPair keyPair = keyPairGen.generateKeyPair(); 50 51 Map<String, String> keyMaps = new HashMap<String, String>(); 52 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 53 keyMaps.put("publicKey", new String(Base64.encode(publicKey.getEncoded()))); 54 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 55 keyMaps.put("privateKey", new String(Base64.encode(privateKey.getEncoded()))); 56 57 return keyMaps; 58 } catch (NoSuchAlgorithmException e) { 59 throw new RuntimeException(e); 60 } 61 } 62 63 /** 64 * 公钥加密 65 * 66 * @param publicKeyBytes 67 * @param data 68 * @param modulus 69 * 公钥模长,范围512-2048。 70 * @return 71 */ 72 public static byte[] encryptByPublicKey(byte[] publicKeyBytes, byte[] data, int modulus) { 73 try { 74 // RSA最大加密明文大小 75 int maxEncryptBlock = modulus / 8 - 11; 76 77 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes); 78 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 79 Key publicK = keyFactory.generatePublic(x509KeySpec); 80 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 81 cipher.init(Cipher.ENCRYPT_MODE, publicK); 82 int inputLen = data.length; 83 ByteArrayOutputStream out = new ByteArrayOutputStream(); 84 int offSet = 0; 85 byte[] cache; 86 int i = 0; 87 while (inputLen - offSet > 0) { 88 if (inputLen - offSet > maxEncryptBlock) { 89 cache = cipher.doFinal(data, offSet, maxEncryptBlock); 90 } else { 91 cache = cipher.doFinal(data, offSet, inputLen - offSet); 92 } 93 out.write(cache, 0, cache.length); 94 i++; 95 offSet = i * maxEncryptBlock; 96 } 97 byte[] encryptedData = out.toByteArray(); 98 out.close(); 99 return encryptedData; 100 } catch (Exception e) { 101 throw new RuntimeException(e); 102 } 103 104 } 105 106 /** 107 * 公钥加密,密钥模长使用默认长度1024。 108 * 109 * @param publicKeyBytes 110 * 公钥RSAPublicKey getEncoded() 111 * @param data 112 * 要加密的字节数组 113 */ 114 public static byte[] encryptByPublicKey(byte[] publicKeyBytes, byte[] data) { 115 return encryptByPublicKey(publicKeyBytes, data, DEFAULT_KEY_LEN); 116 } 117 118 /** 119 * 公钥解密 120 * 121 * @param publicKeyBytes 122 * 公钥RSAPublicKey getEncoded() 123 * @param encryptedData 124 * 被(私钥)加密过的字节数组 125 * @param modulus 126 * 模长,范围512-2048 127 * @return 128 */ 129 public static byte[] decryptByPublicKey(byte[] publicKeyBytes, byte[] encryptedData, int modulus) { 130 // RSA最大解密密文大小 131 int maxDecryptBlock = modulus / 8; 132 try { 133 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes); 134 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 135 Key publicK = keyFactory.generatePublic(x509KeySpec); 136 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 137 cipher.init(Cipher.DECRYPT_MODE, publicK); 138 int inputLen = encryptedData.length; 139 ByteArrayOutputStream out = new ByteArrayOutputStream(); 140 int offSet = 0; 141 byte[] cache; 142 int i = 0; 143 // 对数据分段解密 144 while (inputLen - offSet > 0) { 145 if (inputLen - offSet > maxDecryptBlock) { 146 cache = cipher.doFinal(encryptedData, offSet, maxDecryptBlock); 147 } else { 148 cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); 149 } 150 out.write(cache, 0, cache.length); 151 i++; 152 offSet = i * maxDecryptBlock; 153 } 154 byte[] decryptedData = out.toByteArray(); 155 out.close(); 156 return decryptedData; 157 } catch (Exception e) { 158 throw new RuntimeException(e); 159 } 160 } 161 162 /** 163 * 公钥解密,默认模长1024 164 * 165 * @param publicKeyBytes 166 * 公钥RSAPublicKey getEncoded() 167 * @param encryptedData 168 * 被(私钥)加密过的字节数组 169 */ 170 public static byte[] decryptByPublicKey(byte[] publicKeyBytes, byte[] encryptedData) { 171 return decryptByPublicKey(publicKeyBytes, encryptedData, DEFAULT_KEY_LEN); 172 } 173 174 /** 175 * 私钥加密 176 * 177 * @param privateKeyBytes 178 * 私钥RSAPrivateKey getEncoded() 179 * @param data 180 * 要加密的字节数组 181 * @param modulus 182 * 模长,范围512-2048。 183 */ 184 public static byte[] encryptByPrivateKey(byte[] privateKeyBytes, byte[] data, int modulus) { 185 try { 186 // RSA最大加密明文大小 187 int maxEncryptBlock = modulus / 8 - 11; 188 189 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); 190 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 191 Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); 192 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 193 cipher.init(Cipher.ENCRYPT_MODE, privateK); 194 int inputLen = data.length; 195 ByteArrayOutputStream out = new ByteArrayOutputStream(); 196 int offSet = 0; 197 byte[] cache; 198 int i = 0; 199 while (inputLen - offSet > 0) { 200 if (inputLen - offSet > maxEncryptBlock) { 201 cache = cipher.doFinal(data, offSet, maxEncryptBlock); 202 } else { 203 cache = cipher.doFinal(data, offSet, inputLen - offSet); 204 } 205 out.write(cache, 0, cache.length); 206 i++; 207 offSet = i * maxEncryptBlock; 208 } 209 byte[] encryptedData = out.toByteArray(); 210 out.close(); 211 return encryptedData; 212 } catch (Exception e) { 213 throw new RuntimeException(e); 214 } 215 } 216 217 /** 218 * 私钥加密,默认模长1024。 219 * 220 * @param privateKeyBytes 221 * 私钥RSAPrivateKey getEncoded() 222 * @param data 223 * 要加密的字节数组 224 */ 225 public static byte[] encryptByPrivateKey(byte[] privateKeyBytes, byte[] data) { 226 return encryptByPrivateKey(privateKeyBytes, data, DEFAULT_KEY_LEN); 227 } 228 229 /** 230 * 私钥解密 231 * 232 * @param privateKeyBytes 233 * 私钥RSAPrivateKey getEncoded() 234 * @param encryptedData 235 * 被(公钥)加密过的字节数组 236 * @param modulus 237 * 模长,范围512-2048 238 */ 239 public static byte[] decryptByPrivateKey(byte[] privateKeyBytes, byte[] encryptedData, int modulus) { 240 try { 241 // RSA最大解密密文大小 242 int maxDecryptBlock = modulus / 8; 243 244 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); 245 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 246 Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); 247 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 248 cipher.init(Cipher.DECRYPT_MODE, privateK); 249 int inputLen = encryptedData.length; 250 ByteArrayOutputStream out = new ByteArrayOutputStream(); 251 int offSet = 0; 252 byte[] cache; 253 int i = 0; 254 while (inputLen - offSet > 0) { 255 if (inputLen - offSet > maxDecryptBlock) { 256 cache = cipher.doFinal(encryptedData, offSet, maxDecryptBlock); 257 } else { 258 cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); 259 } 260 out.write(cache, 0, cache.length); 261 i++; 262 offSet = i * maxDecryptBlock; 263 } 264 byte[] decryptedData = out.toByteArray(); 265 out.close(); 266 return decryptedData; 267 } catch (Exception e) { 268 throw new RuntimeException(e); 269 } 270 } 271 272 /** 273 * 私钥解密,默认模长1024。 274 * 275 * @param privateKeyBytes 276 * 私钥RSAPrivateKey getEncoded() 277 * @param encryptedData 278 * 被(公钥)加密过的字节数组 279 */ 280 public static byte[] decryptByPrivateKey(byte[] privateKeyBytes, byte[] encryptedData) { 281 return decryptByPrivateKey(privateKeyBytes, encryptedData, DEFAULT_KEY_LEN); 282 } 283 284 public static void main(String[] args) { 285 genKeyPair(); 286 } 287 }
此文只是简单介绍了java常用的加减密算法,之后文章会对每种算法做具体说明。