加密算法

基本需求及概念

随着Internet网的广泛应用,信息安全问题日益突出,以数据加密技术为核心的信息安全技术也得到了极大的发展。目前的数据加密技术根据加密密钥类型可分私钥加密(对称加密)系统和公钥加密(非对称加密)系统。

对称加密算法是较传统的加密体制,通信双方在加/解密过程中使用他们共享的单一密钥,鉴于其算法简单和加密速度快的优点,目前仍然是主流的密码体制之一。最常用的对称密码算法是数据加密标准(DES)算法,但是由于DES密钥长度较短,已经不适合当今分布式开放网络对数据加密安全性的要求。最后,一种新的基于Rijndael算法对称高级数据加密标准AES取代了数据加密标准DES。非对称加密由于加/解密钥不同(公钥加密,私钥解密),密钥管理简单,也得到广泛应用。RSA是非对称加密系统最著名的公钥密码算法

AES算法

美国国家标准和技术研究所(NIST)经过三轮候选算法筛选,从众多的分组密码中选中Rijndael算法作为高级加密标准(AES)。Rijndael密码是一个迭代型分组密码,分组长度和密码长度都是可变的,分组长度和密码长度可以独立的指定为128比特,192比特或者256比特。AES的加密算法的数据处理单位是字节,128位的比特信息被分成16个字节,按顺序复制到一个4*4的矩阵中,称为状态(state),AES的所有变换都是基于状态矩阵的变换。

用Nr表示对一个数据分组加密的轮数(加密轮数与密钥长度的关系如表1所示)。在轮函数的每一轮迭代中,包括四步变换,分别是字节代换运算(ByteSub())、行变换(ShiftRows())、列混合(MixColumns())以及轮密钥的添加变换AddRoundKey()[3],其作用就是通过重复简单的非线形变换、混合函数变换,将字节代换运算产生的非线性扩散,达到充分的混合,在每轮迭代中引入不同的密钥,从而实现加密的有效性。

下面是三种不同类型的AES加密密钥分组大小与相应的加密轮数的对照表。加密开始时,输入分组的各字节按表2 的方式装入矩阵state中。如输入ABCDEFGHIJKLMNOP,则输入块影射到如表2的状态矩阵中。 
表1:

AES类型 密钥长度 分组长度 加密轮数 
AES-128 4字 4字 10 
AES-192 6字 4字 12 
AES-256 8字 4字 14

A E I M 
B F J N 
C G K O 
D H L P

1、字节代换运算(ByteSub())

字节代换运算是一个可逆的非线形字节代换操作,对分组中的每个字节进行,对字节的操作遵循一个代换表,即S盒。S盒由有限域 GF(28)上的乘法取逆和GF(2)上的仿射变换两步组成。 
2、行变换ShiftRows()

行变换是一种线性变换,其目的就是使密码信息达到充分的混乱,提高非线形度。行变换对状态的每行以字节为单位进行循环右移,移动字节数根据行数来确定,第0行不发生偏移,第一行循环右移一个字节,第二行移两个,依次类推。 
3、 列混合变换MixColumns()

列变换就是从状态中取出一列,表示成多项式的形式后,用它乘以一个固定的多项式a(x),然后将所得结果进行取模运算,模值为 x4+1。其中a(x)={03}x3+{02}x2+{01}x+{02}, 
这个多项式与x4+1互质,因此是可逆的。列混合变换的算术表达式为:s’(x)= a(x) s(x),其中, s(x)表示状态的列多项式。 
4、轮密钥的添加变换AddRoundKey() 
在这个操作中,轮密钥被简单地异或到状态中,轮密钥根据密钥表获得,其长度等于数据块的长度Nb。
AES算法流程

对于发送方,它首先创建一个AES私钥,并用口令对这个私钥进行加密。然后把用口令加密后的AES密钥通过Internet发送到接收方。发送方解密这个私钥,并用此私钥加密明文得到密文,密文和加密后的AES密钥一起通过Internet发送到接收方。接收方收到后再用口令对加密密钥进行解密得到AES密钥,最后用解密后的密钥把收到的密文解密成明文。图7中是这个过程的实现流程。 
AES算法流程

这里写图片描述

RSA算法

RSA算法基本原理及流程

RSA是在1977年发明RSA密码系统的三个人的名字的首字母的缩写,他们是:Ron Rivest、Adi Shamir和Leonard Adleman。它是第一个公钥加密算法,在很多密码协议中都有应用,如SSL和S/MIME。RSA算法是基于大质数的因数分解的公匙体系。简单的讲,就是两个很大的质数,一个作为公钥,另一个作为私钥,如用其中一个加密,则用另一个解密。密钥长度从40到2048位可变,密钥越长,加密效果越好,但加密解密的开销也大。RSA算法可简单描述如下:

1
2
3
<code class=" hljs handlebars">公开密钥:n=pq,(p,q为两个不同的很大的质数,p和q必须保密)
将(p-1)和(q-1)相乘得到φ(n)
选择一个整数e (1<e<φ(n))与φ(n)互质 秘密密钥:d="e-1modφ(n),即计算一个数字d,使得它满足公式" de="1" modφ(n)="" 加密:c="mc(mod" n)="" 解密:m="cd(mod" n),m为明文,c为密文。<="" code=""></e<φ(n))与φ(n)互质></code>

RSA算法实现流程

首先,接收方创建RSA密匙对,即一个公钥和一个私钥,公钥被发送到发送方,私钥则被保存在接收方。发送方在接收到这个公钥后,用该公钥对明文进行加密得到密文,然后把密文通过网络传输给接收方。接收方在收到它们后,用RSA私钥对收到的密文进行解密,最后得到明文 下面 是整个过程的实现流程。

这里写图片描述

AES与RSA相结合数据加密方案<喎�"/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4KCjxwPlJTQcvjt6jKx7mrv6rD3NS/z7XNs7XEtPqx7aOsxuSwssir0NS9qMGi1Nq+39PQtPPL2Mr90vLX07XEus/K/aOsxuTS8tfTt9a94sCnxNHV4tK7t6jU8tauyc+1xKGjUmlqbmRhZWzL47eo1/fOqtDC0ru0+rXEuN+8trzTw9yx6te8o6zUy9DQyrGyu9Do0qq8xsvju/rT0LfHs6O437XEtKbA7cTcwaa6zbTztcTE2rTmo6yy2df3v8nS1LrcyN3S17XEtdbT+cqxvOS6zb/VvOS1xLmlu/ejrNTasrvNrLXE1MvQ0Lu3vrPPwsq81tXE3LGjs9bBvLrDtcTQ1MTcoaPV4sq5QUVTvauwssiro6y439Cno6zQ1MTco6y3vbHjo6zB6bvu0NS8r9Pa0rvM5aOswO3TprPJzqrN+MLnyv2+3bzTw9y1xMrX0aGho8/gsci9z6Os0vLOqkFFU8Pc1L+1xLOktsjX7rOk1rvT0DI1NrHIzNijrL/J0tTA+9PDyO28/rrN07K8/sq1z9a438vZtKbA7aOstvhSU0HL47eo0OjSqr340NC089X7yv21xLPLw926zcfzxKO1yLbgsbbX1rOktKbA7aOstKbA7cvZtsjD98/Uwv3T2kFFU1s1XaO7y/nS1EFFU8vjt6i8073iw9y0psDt0KfCysP3z9S439PaUlNBy+O3qKGj1NrD3NS/udzA7be9w+ajrNLyzqpBRVPL47eo0qrH89TazajQxcewttTD3NS/vfjQ0MPYw9y31sXko6y94sPctcTLvdS/sdjQ682ouf3N+MLntKvLzdbBvNPD3Mr9vt2908rVt72jrLb4UlNBssnTw7mr1L+808Pco6zLvdS/veLD3KOou/LLvdS/vNPD3KOsuavUv73iw9yjqaOsvNO94sPcuf2zzNbQsrux2M34wue0q8rksaPD3LXEw9zUv6O7y/nS1FJTQcvjt6jD3NS/udzA7dKqw/fP1NPF09pBRVPL47eooaM8L3A+Cgo8cD6008nPw+axyL3PtcPWqqOs08nT2lJTQbzTveLD3MvZtsjC/aOssrvKyrrPtPPBv8r9vt3OxLz+vNPD3KOs0vK0y9TazfjC59bQzerIq9PDuau/qsPcwuvM5dbGtKvK5Lv6w9zQxc+iysfDu9PQsdjSqqOs0rLKx7K7zKvP1sq1tcSho0FFU7zTw9zL2bbIuty/7KOstavKx9TazfjC57SryuS5/bPM1tDI57rOsLLIq7ncwO1BRVPD3NS/ysexo9akQUVTvNPD3LCyyKu1xNbY0qq7t73aoaPV4tH51Nq0q8vNu/rD3NDFz6K1xMurt72jrMjnufvKudPDQUVTttSzxsPcwuvM5dbGttS0q8rkyv2+3bzTw9yjrM2syrHKudPDUlNBsru21LPGw9zC68zl1sbAtLSry81BRVO1xMPc1L+jrL7Nv8nS1Nfbus+3orvTQUVTus1SU0G1xNPFtePNrMqxsdzD4sv8w8fIsbXjwLTKtc/W0rvW1tDCtcTK/b7dvNPD3Le9sLihozwvcD4KCjxwPjxzdHJvbmc+QW5kcm9pZLbLIEFFUytSU0G94brPyrW8+Twvc3Ryb25nPjwvcD4KCjxwPrv5sb7SqsfzPC9wPgoKPHA+saPWpLSryuTK/b7dtcSwssir0NQgPGJyPgqxo9akyv2+3bXEzerV+9DUIDxicj4KxNy5u9Hp1qS/zbuntsu1xMntt90gPGJyPgq7+bG+wfezzDwvcD4KCjxwPkFuZHJvaWS2yzwvcD4KCgq3/s7xxve2yyhzZXJ2ZXIpt9ax8Mn6s8nX1Ly6tcRSU0HD3NS/ttQssqLM4bmpvdO/2rj4QW5kcm9pZL/Nu6e2y7vxyKFSU0G5q9S/KHJzYVB1YmxpY0tleSkKY2xpZW50yfqzyUFFU8Pc1L8oYWVzS2V5KQpjbGllbnTKudPD19S8urXEQUVTw9zUvyhhZXNLZXkpttTXqru7zqpqc29uuPHKvbXEx+vH88P3zsTK/b7dKGRhdGEpvfjQ0LzTw9yjrLXDtb2808PcuvO1xMfrx/PK/b7dZW5jcnlwdERhdGEKY2xpZW50zOG5qXNlcnZlcszhuam1xL3Tv9q78cihUlNBuavUvyhyc2FQdWJsaWNLZXkpCmNsaWVudMq508O78cihUlNBuavUvyhyc2FQdWJsaWNLZXkpttRBRVPD3NS/KGFlc0tleSm9+NDQvNPD3KOstcO1vWVuY3J5cHRBZXNLZXkKPHA+Y2xpZW50vatlbmNyeXB0QWVzS2V51/fOqmh0dHDH68fzzbeyzsr9o6y9q7zTw9y687XEx+vH88r9vt1lbmNyeXB0RGF0Ydf3zqrH68fzzOXSu8bwtKvK5Lj4t/7O8cb3tssgPGJyPgq3/s7xxve2yzwvcD4KCnNlcnZlciDP7NOmY2xpZW50tcRodHRwx+vH86OstsHIoWh0dHDH68fzzbeho7vxtcNjbGllbnS0q7n9wLS1xLzTw9y687XEQUVTw9zUvyhlbmNyeXB0QWVzS2V5KaOstsHIoWh0dHDH68fzzOWjrLvxtcNjbGllbnS0q7n9wLS1xLzTw9y687XEx+vH88r9vt0oZW5jcnlwdERhdGEpoaMKc2VydmVyyrnTw9fUvLq1xFJTQcu91L8ocnNhUHJpdmF0ZUtleSm21LzTw9y687XEQUVTw9zUvyhlbmNyeXB0QWVzS2V5Kb340NBSU0G94sPco6y1w7W9QUVTw9zUvyhhZXNLZXkpCsq508O94sPcuvO1xEFFU8Pc1L8oYWVzS2V5KbbUvNPD3LrztcTH68fzyv2+3ShlbmNyeXB0RGF0YSksvfjQ0EFFU73iw9yy2df3o6y1w7W9veLD3LrztcTH68fzyv2+3ShkYXRhKaOsuMPK/b7dzqpqc29uuPHKvQq21L3iw9y687XEx+vH88r9vt0oZGF0YSm9+NDQanNvbr3izvajrMi7uvPX9s/gudi1xM/s06ay2df3oaMKCgo8cD48aW1nIHNyYz0="/uploadfile/Collfiles/20160419/20160419090501104.png" alt="这里写图片描述" title="\">

分享github上一个demon https://github.com/wustrive2008/aes-rsa-java

下面进入代码实战。

<一>. MD5加密算法: 
消息摘要算法第五版(Message Digest Algorithm),是一种单向加密算法,只能加密、无法解密。然而MD5加密算法已经被中国山东大学王小云教授成功破译哭,但是在安全性要求不高的场景下,MD5加密算法仍然具有应用价值。 
1. 创建md5对象:

MessageDigest md5 = MessageDigest.getInstance(“md5”); 
2. 进行加密操作: 
byte[] cipherData = md5.digest(plainText.getBytes());

将其中的每个字节转成十六进制字符串:byte类型的数据最高位是符号位,通过和0xff进行与操作,转换为int类型的正整数。 
Java代码 
String toHexStr = Integer.toHexString(cipher & 0xff); 如果该正数小于16(长度为1个字符),前面拼接0占位:确保最后生成的是32位字符串。 
Java代码 
builder.append(toHexStr.length() == 1 ? “0” + toHexStr : toHexStr); 加密转换之后的字符串为:c0bb4f54f1d8b14caf6fe1069e5f93ad 完整的MD5算法应用如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<code class=" hljs java">Java代码
/**
 * 功能简述: 测试MD5单向加密.
 * @throws Exception
 */ 
@Test 
public void test01() throws Exception { 
    String plainText = "Hello , world !"
    MessageDigest md5 = MessageDigest.getInstance("md5"); 
    byte[] cipherData = md5.digest(plainText.getBytes()); 
    StringBuilder builder = new StringBuilder(); 
    for(byte cipher : cipherData) { 
        String toHexStr = Integer.toHexString(cipher & 0xff); 
        builder.append(toHexStr.length() == 1 ? "0" + toHexStr : toHexStr); 
    
    System.out.println(builder.toString()); 
    //c0bb4f54f1d8b14caf6fe1069e5f93ad 
}  </code>

<二>. 使用BASE64进行加密/解密: 
使用BASE64算法通常用作对二进制数据进行加密,加密之后的数据不易被肉眼识别。严格来说,经过BASE64加密的数据其实没有安全性可言保密,因为它的加密解密算法都是公开的,典型的防菜鸟不防程序猿的呀。 经过标准的BASE64算法加密后的数据, 通常包含/、+、=等特殊符号,不适合作为url参数传递,幸运的是Apache的Commons Codec模块提供了对BASE64的进一步封装。 (参见最后一部分的说明) 
1. 使用BASE64加密: 
Java代码 
BASE64Encoder encoder = new BASE64Encoder(); 
String cipherText = encoder.encode(plainText.getBytes()); 
2. 使用BASE64解密: 
Java代码 
BASE64Decoder decoder = new BASE64Decoder(); 
plainText = new String(decoder.decodeBuffer(cipherText)); 
3. 完整代码示例: 
Java代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<code class=" hljs java">/**
 * 功能简述: 使用BASE64进行双向加密/解密.
 * @throws Exception
 */ 
@Test 
public void test02() throws Exception { 
    BASE64Encoder encoder = new BASE64Encoder(); 
    BASE64Decoder decoder = new BASE64Decoder(); 
    String plainText = "Hello , world !"
    String cipherText = encoder.encode(plainText.getBytes()); 
    System.out.println("cipherText : " + cipherText); 
    //cipherText : SGVsbG8gLCB3b3JsZCAh 
    System.out.println("plainText : " +  
        new String(decoder.decodeBuffer(cipherText))); 
    //plainText : Hello , world !</code>

<三>. 使用DES对称加密/解密: 
数据加密标准算法(Data Encryption Standard),和BASE64最明显的区别就是有一个工作密钥,该密钥既用于加密、也用于解密,并且要求密钥是一个长度至少大于8位的字符串。使用DES加密、解密的核心是确保工作密钥的安全性。叫 
1. 根据key生成密钥: 
Java代码

1
2
3
<code class=" hljs avrasm">DESKeySpec keySpec = new DESKeySpec(key.getBytes()); 
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("des"); 
SecretKey secretKey = keyFactory.generateSecret(keySpec);  </code>

加密操作: 
Java代码

1
2
3
<code class=" hljs avrasm">Cipher cipher = Cipher.getInstance("des"); 
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new SecureRandom()); 
byte[] cipherData = cipher.doFinal(plainText.getBytes());  </code>

为了便于观察生成的加密数据,使用BASE64再次加密:

1
<code class=" hljs javascript">String cipherText = new BASE64Encoder().encode(cipherData);  </code>
1
2
<code> 生成密文如下:PtRYi3sp7TOR69UrKEIicA==
</code>

4. 解密操作: 
Java代码

1
2
3
<code class=" hljs vbnet">cipher.init(Cipher.DECRYPT_MODE, secretKey, new SecureRandom()); 
byte[] plainData = cipher.doFinal(cipherData); 
String plainText = new String(plainData);  </code>

完整的代码demo: 
Java代码

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
<code class=" hljs java">/**
 * 功能简述: 使用DES对称加密/解密.
 * @throws Exception
 */ 
@Test 
public void test03() throws Exception { 
    String plainText = "Hello , world !"
    String key = "12345678";    //要求key至少长度为8个字符 
 
    SecureRandom random = new SecureRandom(); 
    DESKeySpec keySpec = new DESKeySpec(key.getBytes()); 
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("des"); 
    SecretKey secretKey = keyFactory.generateSecret(keySpec); 
 
    Cipher cipher = Cipher.getInstance("des"); 
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, random); 
    byte[] cipherData = cipher.doFinal(plainText.getBytes()); 
    System.out.println("cipherText : " + new BASE64Encoder().encode(cipherData)); 
    //PtRYi3sp7TOR69UrKEIicA== 
 
    cipher.init(Cipher.DECRYPT_MODE, secretKey, random); 
    byte[] plainData = cipher.doFinal(cipherData); 
    System.out.println("plainText : " + new String(plainData)); 
    //Hello , world ! 
}  </code>

<四>. 使用RSA非对称加密/解密: 
RSA算法是非对称加密算法的典型代表,既能加密、又能解密。和对称加密算法比如DES的明显区别在于用于加密、解密的密钥是不同的。使用RSA算法,只要密钥足够长(一般要求1024bit),加密的信息是不能被破解的。天真用户通过https协议访问服务器时,就是使用非对称加密算法进行数据的加密、解密操作的。 
服务器发送数据给客户端时使用私钥(private key)进行加密,并且使用加密之后的数据和私钥生成数字签名(digital signature)并发送给客户端。客户端接收到服务器发送的数据会使用公钥(public key)对数据来进行解密,并且根据加密数据和公钥验证数字签名的有效性,防止加密数据在传输过程中被第三方进行了修改。 
客户端发送数据给服务器时使用公钥进行加密,服务器接收到加密数据之后使用私钥进行解密。
1. 创建密钥对KeyPair: 
Java代码

1
2
3
<code class=" hljs avrasm">KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("rsa"); 
keyPairGenerator.initialize(1024);  //密钥长度推荐为1024位. 
KeyPair keyPair = keyPairGenerator.generateKeyPair();  </code>

获取公钥/私钥: 
Java代码

1
2
<code class=" hljs avrasm">PublicKey publicKey = keyPair.getPublic(); 
PrivateKey privateKey = keyPair.getPrivate();  </code>

服务器数据使用私钥加密: 
Java代码

1
2
3
<code class=" hljs avrasm">Cipher cipher = Cipher.getInstance("rsa"); 
cipher.init(Cipher.ENCRYPT_MODE, privateKey, new SecureRandom()); 
byte[] cipherData = cipher.doFinal(plainText.getBytes());  </code>

用户使用公钥解密: 
Java代码

1
2
<code class=" hljs avrasm">cipher.init(Cipher.DECRYPT_MODE, publicKey, new SecureRandom()); 
byte[] plainData = cipher.doFinal(cipherData);  </code>

服务器根据私钥和加密数据生成数字签名: 
Java代码

1
2
3
4
<code class=" hljs avrasm">Signature signature  = Signature.getInstance("MD5withRSA"); 
signature.initSign(privateKey); 
signature.update(cipherData); 
byte[] signData = signature.sign();  </code>

用户根据公钥、加密数据验证数据是否被修改过: 
Java代码

1
2
3
<code class=" hljs avrasm">signature.initVerify(publicKey); 
signature.update(cipherData); 
boolean status = signature.verify(signData);  </code>

RSA算法代码demo

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
<code class=" hljs java">Java代码
/**
 * 功能简述: 使用RSA非对称加密/解密.
 * @throws Exception
 */ 
@Test 
public void test04() throws Exception { 
    String plainText = "Hello , world !"
 
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("rsa"); 
    keyPairGenerator.initialize(1024); 
    KeyPair keyPair = keyPairGenerator.generateKeyPair(); 
 
    PublicKey publicKey = keyPair.getPublic(); 
    PrivateKey privateKey = keyPair.getPrivate(); 
 
    Cipher cipher = Cipher.getInstance("rsa"); 
    SecureRandom random = new SecureRandom(); 
 
    cipher.init(Cipher.ENCRYPT_MODE, privateKey, random); 
    byte[] cipherData = cipher.doFinal(plainText.getBytes()); 
    System.out.println("cipherText : " + new BASE64Encoder().encode(cipherData)); 
    //gDsJxZM98U2GzHUtUTyZ/Ir/NXqRWKUJkl6olrLYCZHY3RnlF3olkWPZ35Dwz9BMRqaTL3oPuyVq 
    //sehvHExxj9RyrWpIYnYLBSURB1KVUSLMsd/ONFOD0fnJoGtIk+T/+3yybVL8M+RI+HzbE/jdYa/+ 
    //yQ+vHwHqXhuzZ/N8iNg= 
 
    cipher.init(Cipher.DECRYPT_MODE, publicKey, random); 
    byte[] plainData = cipher.doFinal(cipherData); 
    System.out.println("plainText : " + new String(plainData)); 
    //Hello , world ! 
 
    Signature signature  = Signature.getInstance("MD5withRSA"); 
    signature.initSign(privateKey); 
    signature.update(cipherData); 
    byte[] signData = signature.sign(); 
    System.out.println("signature : " + new BASE64Encoder().encode(signData)); 
    //ADfoeKQn6eEHgLF8ETMXan3TfFO03R5u+cQEWtAQ2lRblLZw1DpzTlJJt1RXjU451I84v3297LhR 
    //co64p6Sq3kVt84wnRsQw5mucZnY+jRZNdXpcbwh2qsh8287NM2hxWqp4OOCf/+vKKXZ3pbJMNT/4 
    ///t9ewo+KYCWKOgvu5QQ= 
 
    signature.initVerify(publicKey); 
    signature.update(cipherData); 
    boolean status = signature.verify(signData); 
    System.out.println("status : " + status); 
    //true 
}  </code>

下面给出工具类

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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
<code class=" hljs java">package com.excelsoft.common.crypto; 
 
import java.io.IOException; 
import java.security.Key; 
import java.security.KeyPair; 
import java.security.KeyPairGenerator; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 
import java.security.PrivateKey; 
import java.security.PublicKey; 
import java.security.SecureRandom; 
import java.security.Signature; 
 
import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.DESKeySpec; 
 
import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
 
import sun.misc.BASE64Decoder; 
import sun.misc.BASE64Encoder; 
 
/**
 * 功能简述: 加密解密工具类,对MD5/BASE64/DES/RSA等算法提供了包装.
 * @author Nick Xu
 * @version 1.0
 */ 
public class EncryptUtil { 
    private static Log logger = LogFactory.getLog(EncryptUtil.class); 
 
    private static final int KEY_SIZE = 1024
    private static final String  MD5_ALGORITHM= "md5"
    private static final String  DES_ALGORITHM= "des"
    private static final String  RSA_ALGORITHM= "rsa"
    private static final String  SIGNATURE_ALGORITHM= "MD5withRSA"
 
    private static MessageDigest md5; 
    private static BASE64Encoder encoder; 
    private static BASE64Decoder decoder; 
    private static SecureRandom random; 
    private static KeyPair keyPair; 
 
    private EncryptUtil() { 
    
 
    static
        try
            md5 = MessageDigest.getInstance(MD5_ALGORITHM); 
 
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM); 
            keyPairGenerator.initialize(KEY_SIZE); 
            keyPair = keyPairGenerator.generateKeyPair(); 
        
        catch (NoSuchAlgorithmException e) { 
            // Exception handler 
            logger.error(e); 
        
        encoder = new BASE64Encoder(); 
        decoder = new BASE64Decoder(); 
        random = new SecureRandom(); 
    
 
    /**
     * 功能简述: 使用md5进行单向加密.
     */ 
    public static String encryptMD5(String plainText) { 
        byte[] cipherData = md5.digest(plainText.getBytes()); 
        StringBuilder builder = new StringBuilder(); 
        for(byte cipher : cipherData) { 
            String toHexStr = Integer.toHexString(cipher & 0xff); 
            builder.append(toHexStr.length() == 1 ? "0" + toHexStr : toHexStr); 
        
        return builder.toString(); 
    
 
    /**
     * 功能简述: 使用BASE64进行加密.
     * @param plainData 明文数据
     * @return 加密之后的文本内容
     */ 
    public static String encryptBASE64(byte[] plainData) { 
        return encoder.encode(plainData); 
    
 
    /**
     * 功能简述: 使用BASE64进行解密.
     * @param cipherText 密文文本
     * @return 解密之后的数据
     */ 
    public static byte[] decryptBASE64(String cipherText) { 
        byte[] plainData = null
        try
            plainData =  decoder.decodeBuffer(cipherText); 
        
        catch (IOException e) { 
            // Exception handler 
            logger.error(e); 
        
        return plainData; 
    
 
    /**
     * 功能简述: 使用DES算法进行加密.
     * @param plainData 明文数据
     * @param key   加密密钥
     * @return  
     */ 
    public static byte[] encryptDES(byte[] plainData, String key) { 
        return processCipher(plainData, createSecretKey(key), Cipher.ENCRYPT_MODE, DES_ALGORITHM); 
    
 
    /**
     * 功能简述: 使用DES算法进行解密.
     * @param cipherData    密文数据
     * @param key   解密密钥
     * @return
     */ 
    public static byte[] decryptDES(byte[] cipherData, String key) { 
        return processCipher(cipherData, createSecretKey(key), Cipher.DECRYPT_MODE, DES_ALGORITHM); 
    
 
    /**
     * 功能简述: 根据key创建密钥SecretKey.
     * @param key 
     * @return
     */ 
    private static SecretKey createSecretKey(String key) { 
        SecretKey secretKey = null
        try
            DESKeySpec keySpec = new DESKeySpec(key.getBytes()); 
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM); 
            secretKey = keyFactory.generateSecret(keySpec); 
        
        catch (Exception e) { 
            // Exception handler 
            logger.error(e); 
        
        return secretKey; 
    
 
    /**
     * 功能简述: 加密/解密处理流程.
     * @param processData   待处理的数据
     * @param key   提供的密钥
     * @param opsMode   工作模式
     * @param algorithm   使用的算法
     * @return  
     */ 
    private static byte[] processCipher(byte[] processData, Key key, int opsMode, String algorithm) { 
        try{  
            Cipher cipher = Cipher.getInstance(algorithm); 
            cipher.init(opsMode, key, random); 
            return cipher.doFinal(processData); 
        
        catch (Exception e) { 
            // Exception handler 
            logger.error(e); 
        
        return null
    
 
    /**
     * 功能简述: 创建私钥,用于RSA非对称加密.
     * @return
     */ 
    public static PrivateKey createPrivateKey() { 
        return keyPair.getPrivate(); 
    
 
    /**
     * 功能简述: 创建公钥,用于RSA非对称加密.
     * @return
     */ 
    public static PublicKey createPublicKey() { 
        return keyPair.getPublic(); 
    
 
    /**
     * 功能简述: 使用RSA算法加密.
     * @param plainData 明文数据
     * @param key   密钥
     * @return
     */ 
    public static byte[] encryptRSA(byte[] plainData, Key key) { 
        return processCipher(plainData, key, Cipher.ENCRYPT_MODE, RSA_ALGORITHM); 
    
 
    /**
     * 功能简述: 使用RSA算法解密.
     * @param cipherData    密文数据
     * @param key   密钥
     * @return
     */ 
    public static byte[] decryptRSA(byte[] cipherData, Key key) { 
        return processCipher(cipherData, key, Cipher.DECRYPT_MODE, RSA_ALGORITHM); 
    
 
    /**
     * 功能简述: 使用私钥对加密数据创建数字签名.
     * @param cipherData     已经加密过的数据
     * @param privateKey    私钥
     * @return
     */ 
    public static byte[] createSignature(byte[] cipherData, PrivateKey privateKey) { 
        try
            Signature signature  = Signature.getInstance(SIGNATURE_ALGORITHM); 
            signature.initSign(privateKey); 
            signature.update(cipherData); 
            return signature.sign(); 
        
        catch (Exception e) { 
            // Exception handler 
            logger.error(e);  
        
        return null
    
 
    /**
     * 功能简述: 使用公钥对数字签名进行验证.
     * @param signData  数字签名
     * @param publicKey 公钥
     * @return
     */ 
    public static boolean verifySignature(byte[] cipherData, byte[] signData, PublicKey publicKey) { 
        try
            Signature signature  = Signature.getInstance(SIGNATURE_ALGORITHM); 
            signature.initVerify(publicKey); 
            signature.update(cipherData); 
            return signature.verify(signData); 
        
        catch (Exception e) { 
            // Exception handler 
            logger.error(e); 
        
        return false
    
}  </code>
posted on 2017-02-06 20:23  巫山老妖  阅读(1039)  评论(0编辑  收藏  举报