RSA加密算法
我們來(lái)回顧一下RSA的加密算法。我們從公鑰加密算法和簽名算法的定義出發(fā),用比較規(guī)范的語(yǔ)言來(lái)描述這一算法。
RSA公鑰加密體制包含如下3個(gè)算法:KeyGen(密鑰生成算法),Encrypt(加密算法)以及Decrypt(解密算法)。
密鑰生成算法以安全常數(shù)作為輸入,輸出一個(gè)公鑰PK,和一個(gè)私鑰SK。安全常數(shù)用于確定這個(gè)加密算法的安全性有多高,一般以加密算法使用的質(zhì)數(shù)p的大小有關(guān)。越大,質(zhì)數(shù)p一般越大,保證體制有更高的安全性。在RSA中,密鑰生成算法如下:算法首先隨機(jī)產(chǎn)生兩個(gè)不同大質(zhì)數(shù)p和q,計(jì)算N=pq。隨后,算法計(jì)算歐拉函數(shù)。接下來(lái),算法隨機(jī)選擇一個(gè)小于的整數(shù)e,并計(jì)算e關(guān)于的模反元素d。最后,公鑰為PK=(N, e),私鑰為SK=(N, d)。
加密算法以公鑰PK和待加密的消息M作為輸入,輸出密文CT。在RSA中,加密算法如下:算法直接輸出密文為
解密算法以私鑰SK和密文CT作為輸入,輸出消息M。在RSA中,解密算法如下:算法直接輸出明文為。由于e和d在下互逆,因此我們有:
所以,從算法描述中我們也可以看出:公鑰用于對(duì)數(shù)據(jù)進(jìn)行加密,私鑰用于對(duì)數(shù)據(jù)進(jìn)行解密。當(dāng)然了,這個(gè)也可以很直觀的理解:公鑰就是公開(kāi)的密鑰,其公開(kāi)了大家才能用它來(lái)加密數(shù)據(jù)。私鑰是私有的密鑰,誰(shuí)有這個(gè)密鑰才能夠解密密文。否則大家都能看到私鑰,就都能解密,那不就亂套了。
下面就來(lái)看一下Java中的簡(jiǎn)單實(shí)現(xiàn):
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
|
package com.stone.security; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.util.Arrays; import javax.crypto.Cipher; /** * RSA算法 公鑰加密 非對(duì)稱(chēng)加密 */ public class RSA { public static final String KEY_ALGORITHM = "RSA" ; public static final String CIPHER_ALGORITHM_ECB1 = "RSA/ECB/PKCS1Padding" ; public static final String CIPHER_ALGORITHM_ECB2 = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding" ; //不能用 public static final String CIPHER_ALGORITHM_ECB3 = "OAEPWithSHA-256AndMGF1Padding" ; //不能用 static PublicKey publicKey; static PrivateKey privateKey; static Cipher cipher; static KeyPair keyPair; public static void main(String[] args) throws Exception { method1( "斯柯達(dá)U*(Sfsad7f()*^%%$" ); method2( "斯柯達(dá)U*(Sfsad7f()*^%%$" ); method3( "斯柯達(dá)U*(Sfsad7f()*^%%$" ); } /** * 公鑰加密,私鑰解密 使用默認(rèn)CIPHER_ALGORITHM_ECB1 * @param str * @throws Exception */ static void method1(String str) throws Exception { KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM); KeyPair keyPair = keyGenerator.generateKeyPair(); publicKey = keyPair.getPublic(); privateKey = keyPair.getPrivate(); cipher = Cipher.getInstance(KEY_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, publicKey); //公鑰加密 byte [] encrypt = cipher.doFinal(str.getBytes()); System.out.println( "公鑰加密后1:" + Arrays.toString(encrypt)); cipher.init(Cipher.DECRYPT_MODE, privateKey); //私鑰解密 byte [] decrypt = cipher.doFinal(encrypt); System.out.println( "私鑰解密后1:" + new String(decrypt)); } /** * 私鑰加密,公鑰解密 使用默認(rèn)CIPHER_ALGORITHM_ECB1 * @param str * @throws Exception */ static void method2(String str) throws Exception { KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM); KeyPair keyPair = keyGenerator.generateKeyPair(); publicKey = keyPair.getPublic(); privateKey = keyPair.getPrivate(); cipher = Cipher.getInstance(KEY_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, privateKey); //私鑰加密 byte [] encrypt = cipher.doFinal(str.getBytes()); System.out.println( "私鑰加密后2:" + Arrays.toString(encrypt)); cipher.init(Cipher.DECRYPT_MODE, publicKey); //公鑰解密 byte [] decrypt = cipher.doFinal(encrypt); System.out.println( "公鑰解密后2:" + new String(decrypt)); } /** * 私鑰加密,公鑰解密 使用CIPHER_ALGORITHM_ECB1 = RSA/ECB/PKCS1Padding * @param str * @throws Exception */ static void method3(String str) throws Exception { KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM); KeyPair keyPair = keyGenerator.generateKeyPair(); publicKey = keyPair.getPublic(); privateKey = keyPair.getPrivate(); cipher = Cipher.getInstance(CIPHER_ALGORITHM_ECB1); cipher.init(Cipher.ENCRYPT_MODE, privateKey); //私鑰加密 byte [] encrypt = cipher.doFinal(str.getBytes()); System.out.println( "私鑰加密后3:" + Arrays.toString(encrypt)); cipher.init(Cipher.DECRYPT_MODE, publicKey); //公鑰解密 byte [] decrypt = cipher.doFinal(encrypt); System.out.println( "公鑰解密后3:" + new String(decrypt)); } } |
DSA算法和數(shù)字簽名
DSA 一般用于數(shù)字簽名和認(rèn)證。
DSA是Schnorr和ElGamal簽名算法的變種,被美國(guó)NIST作為DSS(DigitalSignature Standard)。
DSA是基于整數(shù)有限域離散對(duì)數(shù)難題的,其安全性與RSA相比差不多。
在DSA數(shù)字簽名和認(rèn)證中,發(fā)送者使用自己的私鑰對(duì)文件或消息進(jìn)行簽名,接受者收到消息后使用發(fā)送者的公鑰
來(lái)驗(yàn)證簽名的真實(shí)性。DSA只是一種算法,和RSA不同之處在于它不能用作加密和解密,也不能進(jìn)行密鑰交換,
只用于簽名,它比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
175
176
177
178
179
180
181
182
183
184
185
186
|
package com.stone.security; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Signature; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /** * DSA-Digital Signature Algorithm 是Schnorr和ElGamal簽名算法的變種,被美國(guó)NIST作為DSS(DigitalSignature Standard)。 * 簡(jiǎn)單的說(shuō),這是一種更高級(jí)的驗(yàn)證方式,用作數(shù)字簽名。不單單只有公鑰、私鑰,還有數(shù)字簽名。私鑰加密生成數(shù)字簽名,公鑰驗(yàn)證數(shù)據(jù)及簽名。 * 如果數(shù)據(jù)和簽名不匹配則認(rèn)為驗(yàn)證失敗!即 傳輸中的數(shù)據(jù) 可以不再加密,接收方獲得數(shù)據(jù)后,拿到公鑰與簽名 驗(yàn)證數(shù)據(jù)是否有效 */ public class DSA { /** *不僅可以使用DSA算法,同樣也可以使用RSA算法做數(shù)字簽名 */ public static final String KEY_ALGORITHM = "RSA" ; public static final String SIGNATURE_ALGORITHM = "MD5withRSA" ;*/ public static final String KEY_ALGORITHM = "DSA" ; public static final String SIGNATURE_ALGORITHM = "DSA" ; public static final String DEFAULT_SEED = "$%^*%^()(HJG8awfjas7" ; //默認(rèn)種子 public static final String PUBLIC_KEY = "DSAPublicKey" ; public static final String PRIVATE_KEY = "DSAPrivateKey" ; public static void main(String[] args) throws Exception { String str = "!@#$!#^$#&ZXVDF呆軍工路愛(ài)著你*()_+" ; byte [] data = str.getBytes(); Map<String, Object> keyMap = initKey(); // 構(gòu)建密鑰 PublicKey publicKey = (PublicKey) keyMap.get(PUBLIC_KEY); PrivateKey privateKey = (PrivateKey) keyMap.get(PRIVATE_KEY); System.out.println( "私鑰format:" + privateKey.getFormat()); System.out.println( "公鑰format:" + publicKey.getFormat()); // 產(chǎn)生簽名 String sign = sign(data, getPrivateKey(keyMap)); // 驗(yàn)證簽名 boolean verify1 = verify( "aaa" .getBytes(), getPublicKey(keyMap), sign); System.err.println( "經(jīng)驗(yàn)證 數(shù)據(jù)和簽名匹配:" + verify1); boolean verify = verify(data, getPublicKey(keyMap), sign); System.err.println( "經(jīng)驗(yàn)證 數(shù)據(jù)和簽名匹配:" + verify); } /** * 生成密鑰 * * @param seed 種子 * @return 密鑰對(duì)象 * @throws Exception */ public static Map<String, Object> initKey(String seed) throws Exception { System.out.println( "生成密鑰" ); KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM); SecureRandom secureRandom = new SecureRandom(); secureRandom.setSeed(seed.getBytes()); //Modulus size must range from 512 to 1024 and be a multiple of 64 keygen.initialize( 640 , secureRandom); KeyPair keys = keygen.genKeyPair(); PrivateKey privateKey = keys.getPrivate(); PublicKey publicKey = keys.getPublic(); Map<String, Object> map = new HashMap<String, Object>( 2 ); map.put(PUBLIC_KEY, publicKey); map.put(PRIVATE_KEY, privateKey); return map; } /** * 生成默認(rèn)密鑰 * * @return 密鑰對(duì)象 * @throws Exception */ public static Map<String, Object> initKey() throws Exception { return initKey(DEFAULT_SEED); } /** * 取得私鑰 * * @param keyMap * @return * @throws Exception */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded()); //base64加密私鑰 } /** * 取得公鑰 * * @param keyMap * @return * @throws Exception */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded()); //base64加密公鑰 } /** * 用私鑰對(duì)信息進(jìn)行數(shù)字簽名 * @param data 加密數(shù)據(jù) * @param privateKey 私鑰-base64加密的 * @return * @throws Exception */ public static String sign( byte [] data, String privateKey) throws Exception { System.out.println( "用私鑰對(duì)信息進(jìn)行數(shù)字簽名" ); byte [] keyBytes = decryptBASE64(privateKey); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey priKey = factory.generatePrivate(keySpec); //生成 私鑰 //用私鑰對(duì)信息進(jìn)行數(shù)字簽名 Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(priKey); signature.update(data); return encryptBASE64(signature.sign()); } /** * BASE64Encoder 加密 * @param data 要加密的數(shù)據(jù) * @return 加密后的字符串 */ private static String encryptBASE64( byte [] data) { BASE64Encoder encoder = new BASE64Encoder(); String encode = encoder.encode(data); return encode; } /** * BASE64Decoder 解密 * @param data 要解密的字符串 * @return 解密后的byte[] * @throws Exception */ private static byte [] decryptBASE64(String data) throws Exception { BASE64Decoder decoder = new BASE64Decoder(); byte [] buffer = decoder.decodeBuffer(data); return buffer; } /** * 校驗(yàn)數(shù)字簽名 * @param data 加密數(shù)據(jù) * @param publicKey * @param sign 數(shù)字簽名 * @return * @throws Exception */ 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)); //驗(yàn)證簽名 } } |