js java 密码的rsa加密解密配合

时间:2022-06-09 03:59:56
阿影
JS客户端RSA加密,Java服务端解密
阿影 发布于 2011年06月17日 16时, 15评/7967阅
分享到 新浪微博腾讯微博收藏+41踩顶0
在客户端浏览器,Javascript使用RSA算法,以公钥对密码进行加密,服务端使用相应的私钥进行解密。一般用于注册时或登录时填写的密码。 
Java引用到的包: 
commons-lang 
bouncycastle 
slf4j 
commons-codec 
commons-io 


标签: Bouncy Castle RSA JavaScript Java Bouncy Castle
代码片段(3)[全屏查看所有代码]
1. [文件] security.js ~ 19KB     下载(1449)     
2. [文件] RSAUtils.java ~ 15KB     下载(943)     
001
package my.tools.security;
002


003
import java.io.File;
004
import java.io.FileInputStream;
005
import java.io.FileOutputStream;
006
import java.io.ObjectInputStream;
007
import java.io.ObjectOutputStream;
008
import java.math.BigInteger;
009
import java.security.KeyPair;
010
import java.security.KeyFactory;
011
import java.security.KeyPairGenerator;
012
import java.security.Provider;
013
import java.security.PublicKey;
014
import java.security.PrivateKey;
015
import java.security.SecureRandom;
016
import java.security.NoSuchAlgorithmException;
017
import java.security.InvalidParameterException;
018
import java.security.interfaces.RSAPublicKey;
019
import java.security.interfaces.RSAPrivateKey;
020
import java.security.spec.RSAPublicKeySpec;
021
import java.security.spec.RSAPrivateKeySpec;
022
import java.security.spec.InvalidKeySpecException;
023


024
import javax.crypto.Cipher;
025


026
import org.apache.commons.io.IOUtils;
027
import org.apache.commons.io.FileUtils;
028
import org.apache.commons.codec.DecoderException;
029
import org.apache.commons.codec.binary.Hex;
030
import org.bouncycastle.jce.provider.BouncyCastleProvider;
031
import org.slf4j.Logger;
032
import org.slf4j.LoggerFactory;
033


034
import org.apache.commons.lang.StringUtils;
035
import org.apache.commons.lang.time.DateFormatUtils;
036


037
/**
038
 * RSA算法加密/解密工具类。
039
 *
040
 * @author fuchun
041
 * @version 1.0.0, 2010-05-05
042
 */
043
public abstract class RSAUtils {
044


045
    private static final Logger LOGGER = LoggerFactory.getLogger(RSAUtils.class);
046


047
    /** 算法名称 */
048
    private static final String ALGORITHOM = "RSA";
049
    /**保存生成的密钥对的文件名称。 */
050
    private static final String RSA_PAIR_FILENAME = "/__RSA_PAIR.txt";
051
    /** 密钥大小 */
052
    private static final int KEY_SIZE = 1024;
053
    /** 默认的安全服务提供者 */
054
    private static final Provider DEFAULT_PROVIDER = new BouncyCastleProvider();
055


056
    private static KeyPairGenerator keyPairGen = null;
057
    private static KeyFactory keyFactory = null;
058
    /** 缓存的密钥对。 */
059
    private static KeyPair oneKeyPair = null;
060


061
    private static File rsaPairFile = null;
062


063
    static {
064
        try {
065
            keyPairGen = KeyPairGenerator.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
066
            keyFactory = KeyFactory.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
067
        } catch (NoSuchAlgorithmException ex) {
068
            LOGGER.error(ex.getMessage());
069
        }
070
        rsaPairFile = new File(getRSAPairFilePath());
071
    }
072


073
    private RSAUtils() {
074
    }
075


076
    /**
077
     * 生成并返回RSA密钥对。
078
     */
079
    private static synchronized KeyPair generateKeyPair() {
080
        try {
081
            keyPairGen.initialize(KEY_SIZE, newSecureRandom(DateFormatUtils.format("yyyyMMdd").getBytes()));
082
            oneKeyPair = keyPairGen.generateKeyPair();
083
            saveKeyPair(oneKeyPair);
084
            return oneKeyPair;
085
        } catch (InvalidParameterException ex) {
086
            LOGGER.error("KeyPairGenerator does not support a key length of " + KEY_SIZE + ".", ex);
087
        } catch (NullPointerException ex) {
088
            LOGGER.error("RSAUtils#KEY_PAIR_GEN is null, can not generate KeyPairGenerator instance.",
089
                    ex);
090
        }
091
        return null;
092
    }
093


094
    /**
095
     * 返回生成/读取的密钥对文件的路径。
096
     */
097
    private static String getRSAPairFilePath() {
098
        String urlPath = RSAUtils.class.getResource("/").getPath();
099
        return (new File(urlPath).getParent() + RSA_PAIR_FILENAME);
100
    }
101


102
    /**
103
     * 若需要创建新的密钥对文件,则返回 {@code true},否则 {@code false}。
104
     */
105
    private static boolean isCreateKeyPairFile() {
106
        // 是否创建新的密钥对文件
107
        boolean createNewKeyPair = false;
108
        if (!rsaPairFile.exists() || rsaPairFile.isDirectory()) {
109
            createNewKeyPair = true;
110
        }
111
        return createNewKeyPair;
112
    }
113


114
    /**
115
     * 将指定的RSA密钥对以文件形式保存。
116
     *
117
     * @param keyPair 要保存的密钥对。
118
     */
119
    private static void saveKeyPair(KeyPair keyPair) {
120
        FileOutputStream fos = null;
121
        ObjectOutputStream oos = null;
122
        try {
123
            fos = FileUtils.openOutputStream(rsaPairFile);
124
            oos = new ObjectOutputStream(fos);
125
            oos.writeObject(keyPair);
126
        } catch (Exception ex) {
127
            ex.printStackTrace();
128
        } finally {
129
            IOUtils.closeQuietly(oos);
130
            IOUtils.closeQuietly(fos);
131
        }
132
    }
133


134
    /**
135
     * 返回RSA密钥对。
136
     */
137
    public static KeyPair getKeyPair() {
138
        // 首先判断是否需要重新生成新的密钥对文件
139
        if (isCreateKeyPairFile()) {
140
            // 直接强制生成密钥对文件,并存入缓存。
141
            return generateKeyPair();
142
        }
143
        if (oneKeyPair != null) {
144
            return oneKeyPair;
145
        }
146
        return readKeyPair();
147
    }
148
     
149
    // 同步读出保存的密钥对
150
    private static KeyPair readKeyPair() {
151
        FileInputStream fis = null;
152
        ObjectInputStream ois = null;
153
        try {
154
            fis = FileUtils.openInputStream(rsaPairFile);
155
            ois = new ObjectInputStream(fis);
156
            oneKeyPair = (KeyPair) ois.readObject();
157
            return oneKeyPair;
158
        } catch (Exception ex) {
159
            ex.printStackTrace();
160
        } finally {
161
            IOUtils.closeQuietly(ois);
162
            IOUtils.closeQuietly(fis);
163
        }
164
        return null;
165
    }
166


167
    /**
168
     * 根据给定的系数和专用指数构造一个RSA专用的公钥对象。
169
     *
170
     * @param modulus 系数。
171
     * @param publicExponent 专用指数。
172
     * @return RSA专用公钥对象。
173
     */
174
    public static RSAPublicKey generateRSAPublicKey(byte[] modulus, byte[] publicExponent) {
175
        RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger(modulus),
176
                new BigInteger(publicExponent));
177
        try {
178
            return (RSAPublicKey) keyFactory.generatePublic(publicKeySpec);
179
        } catch (InvalidKeySpecException ex) {
180
            LOGGER.error("RSAPublicKeySpec is unavailable.", ex);
181
        } catch (NullPointerException ex) {
182
            LOGGER.error("RSAUtils#KEY_FACTORY is null, can not generate KeyFactory instance.", ex);
183
        }
184
        return null;
185
    }
186


187
    /**
188
     * 根据给定的系数和专用指数构造一个RSA专用的私钥对象。
189
     *
190
     * @param modulus 系数。
191
     * @param privateExponent 专用指数。
192
     * @return RSA专用私钥对象。
193
     */
194
    public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus, byte[] privateExponent) {
195
        RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(newBigInteger(modulus),
196
                new BigInteger(privateExponent));
197
        try {
198
            return (RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec);
199
        } catch (InvalidKeySpecException ex) {
200
            LOGGER.error("RSAPrivateKeySpec is unavailable.", ex);
201
        } catch (NullPointerException ex) {
202
            LOGGER.error("RSAUtils#KEY_FACTORY is null, can not generate KeyFactory instance.", ex);
203
        }
204
        return null;
205
    }
206
     
207
    /**
208
     * 根据给定的16进制系数和专用指数字符串构造一个RSA专用的私钥对象。
209
     *
210
     * @param modulus 系数。
211
     * @param privateExponent 专用指数。
212
     * @return RSA专用私钥对象。
213
     */
214
    public static RSAPrivateKey getRSAPrivateKey(String hexModulus, String hexPrivateExponent) {
215
        if(StringUtils.isBlank(hexModulus) || StringUtils.isBlank(hexPrivateExponent)) {
216
            if(LOGGER.isDebugEnabled()) {
217
                LOGGER.debug("hexModulus and hexPrivateExponent cannot be empty. RSAPrivateKey value is null to return.");
218
            }
219
            return null;
220
        }
221
        byte[] modulus = null;
222
        byte[] privateExponent = null;
223
        try {
224
            modulus = Hex.decodeHex(hexModulus.toCharArray());
225
            privateExponent = Hex.decodeHex(hexPrivateExponent.toCharArray());
226
        } catch(DecoderException ex) {
227
            LOGGER.error("hexModulus or hexPrivateExponent value is invalid. return null(RSAPrivateKey).");
228
        }
229
        if(modulus != null && privateExponent != null) {
230
            return generateRSAPrivateKey(modulus, privateExponent);
231
        }
232
        return null;
233
    }
234
     
235
    /**
236
     * 根据给定的16进制系数和专用指数字符串构造一个RSA专用的公钥对象。
237
     *
238
     * @param modulus 系数。
239
     * @param publicExponent 专用指数。
240
     * @return RSA专用公钥对象。
241
     */
242
    public static RSAPublicKey getRSAPublidKey(String hexModulus, String hexPublicExponent) {
243
        if(StringUtils.isBlank(hexModulus) || StringUtils.isBlank(hexPublicExponent)) {
244
            if(LOGGER.isDebugEnabled()) {
245
                LOGGER.debug("hexModulus and hexPublicExponent cannot be empty. return null(RSAPublicKey).");
246
            }
247
            return null;
248
        }
249
        byte[] modulus = null;
250
        byte[] publicExponent = null;
251
        try {
252
            modulus = Hex.decodeHex(hexModulus.toCharArray());
253
            publicExponent = Hex.decodeHex(hexPublicExponent.toCharArray());
254
        } catch(DecoderException ex) {
255
            LOGGER.error("hexModulus or hexPublicExponent value is invalid. return null(RSAPublicKey).");
256
        }
257
        if(modulus != null && publicExponent != null) {
258
            return generateRSAPublicKey(modulus, publicExponent);
259
        }
260
        return null;
261
    }
262


263
    /**
264
     * 使用指定的公钥加密数据。
265
     *
266
     * @param publicKey 给定的公钥。
267
     * @param data 要加密的数据。
268
     * @return 加密后的数据。
269
     */
270
    public static byte[] encrypt(PublicKey publicKey, byte[] data) throws Exception {
271
        Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
272
        ci.init(Cipher.ENCRYPT_MODE, publicKey);
273
        return ci.doFinal(data);
274
    }
275


276
    /**
277
     * 使用指定的私钥解密数据。
278
     *
279
     * @param privateKey 给定的私钥。
280
     * @param data 要解密的数据。
281
     * @return 原数据。
282
     */
283
    public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws Exception {
284
        Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
285
        ci.init(Cipher.DECRYPT_MODE, privateKey);
286
        return ci.doFinal(data);
287
    }
288


289
    /**
290
     * 使用给定的公钥加密给定的字符串。
291
     * <p />
292
     * 若 {@code publicKey} 为 {@code null},或者 {@code plaintext} 为 {@code null} 则返回 {@code
293
     * null}。
294
     *
295
     * @param publicKey 给定的公钥。
296
     * @param plaintext 字符串。
297
     * @return 给定字符串的密文。
298
     */
299
    public static String encryptString(PublicKey publicKey, String plaintext) {
300
        if (publicKey == null || plaintext == null) {
301
            return null;
302
        }
303
        byte[] data = plaintext.getBytes();
304
        try {
305
            byte[] en_data = encrypt(publicKey, data);
306
            return new String(Hex.encodeHex(en_data));
307
        } catch (Exception ex) {
308
            LOGGER.error(ex.getCause().getMessage());
309
        }
310
        return null;
311
    }
312
     
313
    /**
314
     * 使用默认的公钥加密给定的字符串。
315
     * <p />
316
     * 若{@code plaintext} 为 {@code null} 则返回 {@code null}。
317
     *
318
     * @param plaintext 字符串。
319
     * @return 给定字符串的密文。
320
     */
321
    public static String encryptString(String plaintext) {
322
        if(plaintext == null) {
323
            return null;
324
        }
325
        byte[] data = plaintext.getBytes();
326
        KeyPair keyPair = getKeyPair();
327
        try {
328
            byte[] en_data = encrypt((RSAPublicKey)keyPair.getPublic(), data);
329
            return new String(Hex.encodeHex(en_data));
330
        } catch(NullPointerException ex) {
331
            LOGGER.error("keyPair cannot be null.");
332
        } catch(Exception ex) {
333
            LOGGER.error(ex.getCause().getMessage());
334
        }
335
        return null;
336
    }
337


338
    /**
339
     * 使用给定的私钥解密给定的字符串。
340
     * <p />
341
     * 若私钥为 {@code null},或者 {@code encrypttext} 为 {@code null}或空字符串则返回 {@code null}。
342
     * 私钥不匹配时,返回 {@code null}。
343
     *
344
     * @param privateKey 给定的私钥。
345
     * @param encrypttext 密文。
346
     * @return 原文字符串。
347
     */
348
    public static String decryptString(PrivateKey privateKey, String encrypttext) {
349
        if (privateKey == null || StringUtils.isBlank(encrypttext)) {
350
            return null;
351
        }
352
        try {
353
            byte[] en_data = Hex.decodeHex(encrypttext.toCharArray());
354
            byte[] data = decrypt(privateKey, en_data);
355
            return new String(data);
356
        } catch (Exception ex) {
357
            LOGGER.error(String.format("\"%s\" Decryption failed. Cause: %s", encrypttext, ex.getCause().getMessage()));
358
        }
359
        return null;
360
    }
361
     
362
    /**
363
     * 使用默认的私钥解密给定的字符串。
364
     * <p />
365
     * 若{@code encrypttext} 为 {@code null}或空字符串则返回 {@code null}。
366
     * 私钥不匹配时,返回 {@code null}。
367
     *
368
     * @param encrypttext 密文。
369
     * @return 原文字符串。
370
     */
371
    public static String decryptString(String encrypttext) {
372
        if(StringUtils.isBlank(encrypttext)) {
373
            return null;
374
        }
375
        KeyPair keyPair = getKeyPair();
376
        try {
377
            byte[] en_data = Hex.decodeHex(encrypttext.toCharArray());
378
            byte[] data = decrypt((RSAPrivateKey)keyPair.getPrivate(), en_data);
379
            return new String(data);
380
        } catch(NullPointerException ex) {
381
            LOGGER.error("keyPair cannot be null.");
382
        } catch (Exception ex) {
383
            LOGGER.error(String.format("\"%s\" Decryption failed. Cause: %s", encrypttext, ex.getMessage()));
384
        }
385
        return null;
386
    }
387
     
388
    /**
389
     * 使用默认的私钥解密由JS加密(使用此类提供的公钥加密)的字符串。
390
     *
391
     * @param encrypttext 密文。
392
     * @return {@code encrypttext} 的原文字符串。
393
     */
394
    public static String decryptStringByJs(String encrypttext) {
395
        String text = decryptString(encrypttext);
396
        if(text == null) {
397
            return null;
398
        }
399
        return StringUtils.reverse(text);
400
    }
401
     
402
    /** 返回已初始化的默认的公钥。*/
403
    public static RSAPublicKey getDefaultPublicKey() {
404
        KeyPair keyPair = getKeyPair();
405
        if(keyPair != null) {
406
            return (RSAPublicKey)keyPair.getPublic();
407
        }
408
        return null;
409
    }
410
     
411
    /** 返回已初始化的默认的私钥。*/
412
    public static RSAPrivateKey getDefaultPrivateKey() {
413
        KeyPair keyPair = getKeyPair();
414
        if(keyPair != null) {
415
            return (RSAPrivateKey)keyPair.getPrivate();
416
        }
417
        return null;
418
    }
419
}
3. [代码][Java]代码     
01
// Struts2 Action方法中:
02
// 将公钥的 modulus 和 exponent 传给页面。
03
// Hex -> apache commons-codec
04
RSAPublicKey publicKey = RSAUtils.getDefaultPublicKey();
05
            ActionContext.getContext().put("modulus", newString(Hex.encodeHex(publicKey.getModulus().toByteArray())));
06
            ActionContext.getContext().put("exponent", newString(Hex.encodeHex(publicKey.getPublicExponent().toByteArray())));
07


08
// 页面里,Javascript对明文进行加密:
09
var modulus = $('#hid_modulus').val(), exponent = $('#hid_exponent').val();
10
var key = RSAUtils.getKeyPair(exponent, '', modulus);
11
pwd1 = RSAUtils.encryptedString(key, pwd1);
12
pwd2 = RSAUtils.encryptedString(key, pwd2);
13


14
// 服务器端,使用RSAUtils工具类对密文进行解密
15
RSAUtils.decryptStringByJs(password1);