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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336 1-------RSAUtils.java---------------- package my.tools.security;
2
3import java.io.File;
4import java.io.FileInputStream;
5import java.io.FileOutputStream;
6import java.io.ObjectInputStream;
7import java.io.ObjectOutputStream;
8import java.math.BigInteger;
9import java.security.KeyPair;
10import java.security.KeyFactory;
11import java.security.KeyPairGenerator;
12import java.security.Provider;
13import java.security.PublicKey;
14import java.security.PrivateKey;
15import java.security.SecureRandom;
16import java.security.NoSuchAlgorithmException;
17import java.security.InvalidParameterException;
18import java.security.interfaces.RSAPublicKey;
19import java.security.interfaces.RSAPrivateKey;
20import java.security.spec.RSAPublicKeySpec;
21import java.security.spec.RSAPrivateKeySpec;
22import java.security.spec.InvalidKeySpecException;
23
24import javax.crypto.Cipher;
25
26import org.apache.commons.io.IOUtils;
27import org.apache.commons.io.FileUtils;
28import org.apache.commons.codec.DecoderException;
29import org.apache.commons.codec.binary.Hex;
30import org.bouncycastle.jce.provider.BouncyCastleProvider;
31import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
33
34import org.apache.commons.lang.StringUtils;
35import org.apache.commons.lang.time.DateFormatUtils;
36
37/**
38 * RSA算法加密/解密工具类。
39 *
40 * @author fuchun
41 * @version 1.0.0, 2010-05-05
42 */
43public abstract class RSAUtils {
44
45 private static final Logger LOGGER = LoggerFactory.getLogger(RSAUtils.class);
46
47 /** 算法名称 */
48 private static final String ALGORITHOM = "RSA";
49 /**保存生成的密钥对的文件名称。 */
50 private static final String RSA_PAIR_FILENAME = "/__RSA_PAIR.txt";
51 /** 密钥大小 */
52 private static final int KEY_SIZE = 1024;
53 /** 默认的安全服务提供者 */
54 private static final Provider DEFAULT_PROVIDER = new BouncyCastleProvider();
55
56 private static KeyPairGenerator keyPairGen = null;
57 private static KeyFactory keyFactory = null;
58 /** 缓存的密钥对。 */
59 private static KeyPair oneKeyPair = null;
60
61 private static File rsaPairFile = null;
62
63 static {
64 try {
65 keyPairGen = KeyPairGenerator.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
66 keyFactory = KeyFactory.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
67 } catch (NoSuchAlgorithmException ex) {
68 LOGGER.error(ex.getMessage());
69 }
70 rsaPairFile = new File(getRSAPairFilePath());
71 }
72
73 private RSAUtils() {
74 }
75
76 /**
77 * 生成并返回RSA密钥对。
78 */
79 private static synchronized KeyPair generateKeyPair() {
80 try {
81 keyPairGen.initialize(KEY_SIZE, new SecureRandom(DateFormatUtils.format("yyyyMMdd").getBytes()));
82 oneKeyPair = keyPairGen.generateKeyPair();
83 saveKeyPair(oneKeyPair);
84 return oneKeyPair;
85 } catch (InvalidParameterException ex) {
86 LOGGER.error("KeyPairGenerator does not support a key length of " + KEY_SIZE + ".", ex);
87 } catch (NullPointerException ex) {
88 LOGGER.error("RSAUtils#KEY_PAIR_GEN is null, can not generate KeyPairGenerator instance.",
89 ex);
90 }
91 return null;
92 }
93
94 /**
95 * 返回生成/读取的密钥对文件的路径。
96 */
97 private static String getRSAPairFilePath() {
98 String urlPath = RSAUtils.class.getResource("/").getPath();
99 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(new BigInteger(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
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 1}
2
3 /**
4 * 使用给定的私钥解密给定的字符串。
5 * <p />
6 * 若私钥为 {@code null},或者 {@code encrypttext} 为 {@code null}或空字符串则返回 {@code null}。
7 * 私钥不匹配时,返回 {@code null}。
8 *
9 * @param privateKey 给定的私钥。
10 * @param encrypttext 密文。
11 * @return 原文字符串。
12 */
13 public static String decryptString(PrivateKey privateKey, String encrypttext) {
14 if (privateKey == null || StringUtils.isBlank(encrypttext)) {
15 return null;
16 }
17 try {
18 byte[] en_data = Hex.decodeHex(encrypttext.toCharArray());
19 byte[] data = decrypt(privateKey, en_data);
20 return new String(data);
21 } catch (Exception ex) {
22 LOGGER.error(String.format("\"%s\" Decryption failed. Cause: %s", encrypttext, ex.getCause().getMessage()));
23 }
24 return null;
25 }
26
27 /**
28 * 使用默认的私钥解密给定的字符串。
29 * <p />
30 * 若{@code encrypttext} 为 {@code null}或空字符串则返回 {@code null}。
31 * 私钥不匹配时,返回 {@code null}。
32 *
33 * @param encrypttext 密文。
34 * @return 原文字符串。
35 */
36 public static String decryptString(String encrypttext) {
37 if(StringUtils.isBlank(encrypttext)) {
38 return null;
39 }
40 KeyPair keyPair = getKeyPair();
41 try {
42 byte[] en_data = Hex.decodeHex(encrypttext.toCharArray());
43 byte[] data = decrypt((RSAPrivateKey)keyPair.getPrivate(), en_data);
44 return new String(data);
45 } catch(NullPointerException ex) {
46 LOGGER.error("keyPair cannot be null.");
47 } catch (Exception ex) {
48 LOGGER.error(String.format("\"%s\" Decryption failed. Cause: %s", encrypttext, ex.getMessage()));
49 }
50 return null;
51 }
52
53 /**
54 * 使用默认的私钥解密由JS加密(使用此类提供的公钥加密)的字符串。
55 *
56 * @param encrypttext 密文。
57 * @return {@code encrypttext} 的原文字符串。
58 */
59 public static String decryptStringByJs(String encrypttext) {
60 String text = decryptString(encrypttext);
61 if(text == null) {
62 return null;
63 }
64 return StringUtils.reverse(text);
65 }
66
67 /** 返回已初始化的默认的公钥。*/
68 public static RSAPublicKey getDefaultPublicKey() {
69 KeyPair keyPair = getKeyPair();
70 if(keyPair != null) {
71 return (RSAPublicKey)keyPair.getPublic();
72 }
73 return null;
74 }
75
76 /** 返回已初始化的默认的私钥。*/
77 public static RSAPrivateKey getDefaultPrivateKey() {
78 KeyPair keyPair = getKeyPair();
79 if(keyPair != null) {
80 return (RSAPrivateKey)keyPair.getPrivate();
81 }
82 return null;
83 }
84} 文档:
85
// Struts2 Action方法中:
// 将公钥的 modulus 和 exponent 传给页面。
// Hex -> apache commons-codec
RSAPublicKey publicKey = RSAUtils.getDefaultPublicKey();
ActionContext.getContext().put("modulus", new String(Hex.encodeHex(publicKey.getModulus().toByteArray())));
ActionContext.getContext().put("exponent", new String(Hex.encodeHex(publicKey.getPublicExponent().toByteArray())));
// 页面里,Javascript对明文进行加密:
var modulus = $('#hid_modulus').val(), exponent = $('#hid_exponent').val();
var key = RSAUtils.getKeyPair(exponent, '', modulus);
pwd1 = RSAUtils.encryptedString(key, pwd1);
pwd2 = RSAUtils.encryptedString(key, pwd2);
13
14 // 服务器端,使用RSAUtils工具类对密文进行解密
15 RSAUtils.decryptStringByJs(password1);
1
2 1所需的jar包 及 js文件 :
2
1
2 1 ![](http://img.5iqiqu.com/images2/b4/b42abb5654e836d77425785cfc25ce6d.jpg)
2
————-security.js——————-
/*
* RSA, a suite of routines for performing RSA public-key computations in JavaScript.
* Copyright 1998-2005 David Shapiro.
* Dave Shapiro
* dave@ohdave.com
* changed by Fuchun, 2010-05-06
* fcrpg2005@gmail.com
*/
(function($w) {
if(typeof $w.RSAUtils === 'undefined')
var RSAUtils = $w.RSAUtils = {};
var biRadixBase = 2;
var biRadixBits = 16;
var bitsPerDigit = biRadixBits;
var biRadix = 1 << 16; // = 2^16 = 65536
var biHalfRadix = biRadix >>> 1;
var biRadixSquared = biRadix * biRadix;
var maxDigitVal = biRadix – 1;
var maxInteger = 9999999999999998;
//maxDigits:
//Change this to accommodate your largest number size. Use setMaxDigits()
//to change it!
//
//In general, if you're working with numbers of size N bits, you'll need 2*N
//bits of storage. Each digit holds 16 bits. So, a 1024-bit key will need
//
//1024 * 2 / 16 = 128 digits of storage.
//
var maxDigits;
var ZERO_ARRAY;
var bigZero, bigOne;
var BigInt = $w.BigInt = function(flag) {
if (typeof flag == "boolean" && flag == true) {
this.digits = null;
} else {
this.digits = ZERO_ARRAY.slice(0);
}
this.isNeg = false;
};
RSAUtils.setMaxDigits = function(value) {
maxDigits = value;
ZERO_ARRAY = new Array(maxDigits);
for (var iza = 0; iza < ZERO_ARRAY.length; iza++) ZERO_ARRAY[iza] = 0;
bigZero = new BigInt();
bigOne = new BigInt();
bigOne.digits[0] = 1;
};
RSAUtils.setMaxDigits(20);
//The maximum number of digits in base 10 you can convert to an
//integer without JavaScript throwing up on you.
var dpl10 = 15;
RSAUtils.biFromNumber = function(i) {
var result = new BigInt();
result.isNeg = i < 0;
i = Math.abs(i);
var j = 0;
while (i > 0) {
result.digits[j++] = i & maxDigitVal;
i = Math.floor(i / biRadix);
}
return result;
};
//lr10 = 10 ^ dpl10
var lr10 = RSAUtils.biFromNumber(1000000000000000);
RSAUtils.biFromDecimal = function(s) {
var isNeg = s.charAt(0) == '-';
var i = isNeg ? 1 : 0;
var result;
// Skip leading zeros.
while (i < s.length && s.charAt(i) == '0') ++i;
if (i == s.length) {
result = new BigInt();
}
else {
var digitCount = s.length – i;
var fgl = digitCount % dpl10;
if (fgl == 0) fgl = dpl10;
result = RSAUtils.biFromNumber(Number(s.substr(i, fgl)));
i += fgl;
while (i < s.length) {
result = RSAUtils.biAdd(RSAUtils.biMultiply(result, lr10),
RSAUtils.biFromNumber(Number(s.substr(i, dpl10))));
i += dpl10;
}
result.isNeg = isNeg;
}
return result;
};
RSAUtils.biCopy = function(bi) {
var result = new BigInt(true);
result.digits = bi.digits.slice(0);
result.isNeg = bi.isNeg;
return result;
};
RSAUtils.reverseStr = function(s) {
var result = "";
for (var i = s.length – 1; i > -1; –i) {
result += s.charAt(i);
}
return result;
};
var hexatrigesimalToChar = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z'
];
RSAUtils.biToString = function(x, radix) { // 2 <= radix <= 36
var b = new BigInt();
b.digits[0] = radix;
var qr = RSAUtils.biDivideModulo(x, b);
var result = hexatrigesimalToChar[qr[1].digits[0]];
while (RSAUtils.biCompare(qr[0], bigZero) == 1) {
qr = RSAUtils.biDivideModulo(qr[0], b);
digit = qr[1].digits[0];
result += hexatrigesimalToChar[qr[1].digits[0]];
}
return (x.isNeg ? "-" : "") + RSAUtils.reverseStr(result);
};
RSAUtils.biToDecimal = function(x) {
var b = new BigInt();
b.digits[0] = 10;
var qr = RSAUtils.biDivideModulo(x, b);
var result = String(qr[1].digits[0]);
while (RSAUtils.biCompare(qr[0], bigZero) == 1) {
qr = RSAUtils.biDivideModulo(qr[0], b);
result += String(qr[1].digits[0]);
}
return (x.isNeg ? "-" : "") + RSAUtils.reverseStr(result);
};
var hexToChar = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f'];
RSAUtils.digitToHex = function(n) {
var mask = 0xf;
var result = "";
for (i = 0; i < 4; ++i) {
result += hexToChar[n & mask];
n >>>= 4;
}
return RSAUtils.reverseStr(result);
};
RSAUtils.biToHex = function(x) {
var result = "";
var n = RSAUtils.biHighIndex(x);
for (var i = RSAUtils.biHighIndex(x); i > -1; –i) {
result += RSAUtils.digitToHex(x.digits[i]);
}
return result;
};
RSAUtils.charToHex = function(c) {
var ZERO = 48;
var NINE = ZERO + 9;
var littleA = 97;
var littleZ = littleA + 25;
var bigA = 65;
var bigZ = 65 + 25;
var result;
if (c >= ZERO && c <= NINE) {
result = c – ZERO;
} else if (c >= bigA && c <= bigZ) {
result = 10 + c – bigA;
} else if (c >= littleA && c <= littleZ) {
result = 10 + c – littleA;
} else {
result = 0;
}
return result;
};
RSAUtils.hexToDigit = function(s) {
var result = 0;
var sl = Math.min(s.length, 4);
for (var i = 0; i < sl; ++i) {
result <<= 4;
result |= RSAUtils.charToHex(s.charCodeAt(i));
}
return result;
};
RSAUtils.biFromHex = function(s) {
var result = new BigInt();
var sl = s.length;
for (var i = sl, j = 0; i > 0; i -= 4, ++j) {
result.digits[j] = RSAUtils.hexToDigit(s.substr(Math.max(i – 4, 0), Math.min(i, 4)));
}
return result;
};
RSAUtils.biFromString = function(s, radix) {
var isNeg = s.charAt(0) == '-';
var istop = isNeg ? 1 : 0;
var result = new BigInt();
var place = new BigInt();
place.digits[0] = 1; // radix^0
for (var i = s.length – 1; i >= istop; i–) {
var c = s.charCodeAt(i);
var digit = RSAUtils.charToHex(c);
var biDigit = RSAUtils.biMultiplyDigit(place, digit);
result = RSAUtils.biAdd(result, biDigit);
place = RSAUtils.biMultiplyDigit(place, radix);
}
result.isNeg = isNeg;
return result;
};
RSAUtils.biDump = function(b) {
return (b.isNeg ? "-" : "") + b.digits.join(" ");
};
RSAUtils.biAdd = function(x, y) {
var result;
if (x.isNeg != y.isNeg) {
y.isNeg = !y.isNeg;
result = RSAUtils.biSubtract(x, y);
y.isNeg = !y.isNeg;
}
else {
result = new BigInt();
var c = 0;
var n;
for (var i = 0; i < x.digits.length; ++i) {
n = x.digits[i] + y.digits[i] + c;
result.digits[i] = n % biRadix;
c = Number(n >= biRadix);
}
result.isNeg = x.isNeg;
}
return result;
};
RSAUtils.biSubtract = function(x, y) {
var result;
if (x.isNeg != y.isNeg) {
y.isNeg = !y.isNeg;
result = RSAUtils.biAdd(x, y);
y.isNeg = !y.isNeg;
} else {
result = new BigInt();
var n, c;
c = 0;
for (var i = 0; i < x.digits.length; ++i) {
n = x.digits[i] – y.digits[i] + c;
result.digits[i] = n % biRadix;
// Stupid non-conforming modulus operation.
if (result.digits[i] < 0) result.digits[i] += biRadix;
c = 0 – Number(n < 0);
}
// Fix up the negative sign, if any.
if (c == -1) {
c = 0;
for (var i = 0; i < x.digits.length; ++i) {
n = 0 – result.digits[i] + c;
result.digits[i] = n % biRadix;
// Stupid non-conforming modulus operation.
if (result.digits[i] < 0) result.digits[i] += biRadix;
c = 0 – Number(n < 0);
}
// Result is opposite sign of arguments.
result.isNeg = !x.isNeg;
} else {
// Result is same sign.
result.isNeg = x.isNeg;
}
}
return result;
};
RSAUtils.biHighIndex = function(x) {
var result = x.digits.length – 1;
while (result > 0 && x.digits[result] == 0) –result;
return result;
};
RSAUtils.biNumBits = function(x) {
var n = RSAUtils.biHighIndex(x);
var d = x.digits[n];
var m = (n + 1) * bitsPerDigit;
var result;
for (result = m; result > m – bitsPerDigit; –result) {
if ((d & 0x8000) != 0) break;
d <<= 1;
}
return result;
};
RSAUtils.biMultiply = function(x, y) {
var result = new BigInt();
var c;
var n = RSAUtils.biHighIndex(x);
var t = RSAUtils.biHighIndex(y);
var u, uv, k;
for (var i = 0; i <= t; ++i) {
c = 0;
k = i;
for (j = 0; j <= n; ++j, ++k) {
uv = result.digits[k] + x.digits[j] * y.digits[i] + c;
result.digits[k] = uv & maxDigitVal;
c = uv >>> biRadixBits;
//c = Math.floor(uv / biRadix);
}
result.digits[i + n + 1] = c;
}
// Someone give me a logical xor, please.
result.isNeg = x.isNeg != y.isNeg;
return result;
};
RSAUtils.biMultiplyDigit = function(x, y) {
var n, c, uv;
result = new BigInt();
n = RSAUtils.biHighIndex(x);
c = 0;
for (var j = 0; j <= n; ++j) {
uv = result.digits[j] + x.digits[j] * y + c;
result.digits[j] = uv & maxDigitVal;
c = uv >>> biRadixBits;
//c = Math.floor(uv / biRadix);
}
result.digits[1 + n] = c;
return result;
};
RSAUtils.arrayCopy = function(src, srcStart, dest, destStart, n) {
var m = Math.min(srcStart + n, src.length);
for (var i = srcStart, j = destStart; i < m; ++i, ++j) {
dest[j] = src[i];
}
};
var highBitMasks = [0x0000, 0x8000, 0xC000, 0xE000, 0xF000, 0xF800,
0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0,
0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF];
RSAUtils.biShiftLeft = function(x, n) {
var digitCount = Math.floor(n / bitsPerDigit);
var result = new BigInt();
RSAUtils.arrayCopy(x.digits, 0, result.digits, digitCount,
result.digits.length – digitCount);
var bits = n % bitsPerDigit;
var rightBits = bitsPerDigit – bits;
for (var i = result.digits.length – 1, i1 = i – 1; i > 0; –i, –i1) {
result.digits[i] = ((result.digits[i] << bits) & maxDigitVal) |
((result.digits[i1] & highBitMasks[bits]) >>>
(rightBits));
}
result.digits[0] = ((result.digits[i] << bits) & maxDigitVal);
result.isNeg = x.isNeg;
return result;
};
var lowBitMasks = [0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F,
0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF,
0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF];
RSAUtils.biShiftRight = function(x, n) {
var digitCount = Math.floor(n / bitsPerDigit);
var result = new BigInt();
RSAUtils.arrayCopy(x.digits, digitCount, result.digits, 0,
x.digits.length – digitCount);
var bits = n % bitsPerDigit;
var leftBits = bitsPerDigit – bits;
for (var i = 0, i1 = i + 1; i < result.digits.length – 1; ++i, ++i1) {
result.digits[i] = (result.digits[i] >>> bits) |
((result.digits[i1] & lowBitMasks[bits]) << leftBits);
}
result.digits[result.digits.length – 1] >>>= bits;
result.isNeg = x.isNeg;
return result;
};
RSAUtils.biMultiplyByRadixPower = function(x, n) {
var result = new BigInt();
RSAUtils.arrayCopy(x.digits, 0, result.digits, n, result.digits.length – n);
return result;
};
RSAUtils.biDivideByRadixPower = function(x, n) {
var result = new BigInt();
RSAUtils.arrayCopy(x.digits, n, result.digits, 0, result.digits.length – n);
return result;
};
RSAUtils.biModuloByRadixPower = function(x, n) {
var result = new BigInt();
RSAUtils.arrayCopy(x.digits, 0, result.digits, 0, n);
return result;
};
RSAUtils.biCompare = function(x, y) {
if (x.isNeg != y.isNeg) {
return 1 – 2 * Number(x.isNeg);
}
for (var i = x.digits.length – 1; i >= 0; –i) {
if (x.digits[i] != y.digits[i]) {
if (x.isNeg) {
return 1 – 2 * Number(x.digits[i] > y.digits[i]);
} else {
return 1 – 2 * Number(x.digits[i] < y.digits[i]);
}
}
}
return 0;
};
RSAUtils.biDivideModulo = function(x, y) {
var nb = RSAUtils.biNumBits(x);
var tb = RSAUtils.biNumBits(y);
var origYIsNeg = y.isNeg;
var q, r;
if (nb < tb) {
// |x| < |y|
if (x.isNeg) {
q = RSAUtils.biCopy(bigOne);
q.isNeg = !y.isNeg;
x.isNeg = false;
y.isNeg = false;
r = biSubtract(y, x);
// Restore signs, 'cause they're references.
x.isNeg = true;
y.isNeg = origYIsNeg;
} else {
q = new BigInt();
r = RSAUtils.biCopy(x);
}
return [q, r];
}
q = new BigInt();
r = x;
// Normalize Y.
var t = Math.ceil(tb / bitsPerDigit) – 1;
var lambda = 0;
while (y.digits[t] < biHalfRadix) {
y = RSAUtils.biShiftLeft(y, 1);
++lambda;
++tb;
t = Math.ceil(tb / bitsPerDigit) – 1;
}
// Shift r over to keep the quotient constant. We'll shift the
// remainder back at the end.
r = RSAUtils.biShiftLeft(r, lambda);
nb += lambda; // Update the bit count for x.
var n = Math.ceil(nb / bitsPerDigit) – 1;
var b = RSAUtils.biMultiplyByRadixPower(y, n – t);
while (RSAUtils.biCompare(r, b) != -1) {
++q.digits[n – t];
r = RSAUtils.biSubtract(r, b);
}
for (var i = n; i > t; –i) {
var ri = (i >= r.digits.length) ? 0 : r.digits[i];
var ri1 = (i – 1 >= r.digits.length) ? 0 : r.digits[i – 1];
var ri2 = (i – 2 >= r.digits.length) ? 0 : r.digits[i – 2];
var yt = (t >= y.digits.length) ? 0 : y.digits[t];
var yt1 = (t – 1 >= y.digits.length) ? 0 : y.digits[t – 1];
if (ri == yt) {
q.digits[i – t – 1] = maxDigitVal;
} else {
q.digits[i – t – 1] = Math.floor((ri * biRadix + ri1) / yt);
}
var c1 = q.digits[i – t – 1] * ((yt * biRadix) + yt1);
var c2 = (ri * biRadixSquared) + ((ri1 * biRadix) + ri2);
while (c1 > c2) {
–q.digits[i – t – 1];
c1 = q.digits[i – t – 1] * ((yt * biRadix) | yt1);
c2 = (ri * biRadix * biRadix) + ((ri1 * biRadix) + ri2);
}
b = RSAUtils.biMultiplyByRadixPower(y, i – t – 1);
r = RSAUtils.biSubtract(r, RSAUtils.biMultiplyDigit(b, q.digits[i – t – 1]));
if (r.isNeg) {
r = RSAUtils.biAdd(r, b);
–q.digits[i – t – 1];
}
}
r = RSAUtils.biShiftRight(r, lambda);
// Fiddle with the signs and stuff to make sure that 0 <= r < y.
q.isNeg = x.isNeg != origYIsNeg;
if (x.isNeg) {
if (origYIsNeg) {
q = RSAUtils.biAdd(q, bigOne);
} else {
q = RSAUtils.biSubtract(q, bigOne);
}
y = RSAUtils.biShiftRight(y, lambda);
r = RSAUtils.biSubtract(y, r);
}
// Check for the unbelievably stupid degenerate case of r == -0.
if (r.digits[0] == 0 && RSAUtils.biHighIndex(r) == 0) r.isNeg = false;
return [q, r];
};
RSAUtils.biDivide = function(x, y) {
return RSAUtils.biDivideModulo(x, y)[0];
};
RSAUtils.biModulo = function(x, y) {
return RSAUtils.biDivideModulo(x, y)[1];
};
RSAUtils.biMultiplyMod = function(x, y, m) {
return RSAUtils.biModulo(RSAUtils.biMultiply(x, y), m);
};
RSAUtils.biPow = function(x, y) {
var result = bigOne;
var a = x;
while (true) {
if ((y & 1) != 0) result = RSAUtils.biMultiply(result, a);
y >>= 1;
if (y == 0) break;
a = RSAUtils.biMultiply(a, a);
}
return result;
};
RSAUtils.biPowMod = function(x, y, m) {
var result = bigOne;
var a = x;
var k = y;
while (true) {
if ((k.digits[0] & 1) != 0) result = RSAUtils.biMultiplyMod(result, a, m);
k = RSAUtils.biShiftRight(k, 1);
if (k.digits[0] == 0 && RSAUtils.biHighIndex(k) == 0) break;
a = RSAUtils.biMultiplyMod(a, a, m);
}
return result;
};
$w.BarrettMu = function(m) {
this.modulus = RSAUtils.biCopy(m);
this.k = RSAUtils.biHighIndex(this.modulus) + 1;
var b2k = new BigInt();
b2k.digits[2 * this.k] = 1; // b2k = b^(2k)
this.mu = RSAUtils.biDivide(b2k, this.modulus);
this.bkplus1 = new BigInt();
this.bkplus1.digits[this.k + 1] = 1; // bkplus1 = b^(k+1)
this.modulo = BarrettMu_modulo;
this.multiplyMod = BarrettMu_multiplyMod;
this.powMod = BarrettMu_powMod;
};
function BarrettMu_modulo(x) {
var $dmath = RSAUtils;
var q1 = $dmath.biDivideByRadixPower(x, this.k – 1);
var q2 = $dmath.biMultiply(q1, this.mu);
var q3 = $dmath.biDivideByRadixPower(q2, this.k + 1);
var r1 = $dmath.biModuloByRadixPower(x, this.k + 1);
var r2term = $dmath.biMultiply(q3, this.modulus);
var r2 = $dmath.biModuloByRadixPower(r2term, this.k + 1);
var r = $dmath.biSubtract(r1, r2);
if (r.isNeg) {
r = $dmath.biAdd(r, this.bkplus1);
}
var rgtem = $dmath.biCompare(r, this.modulus) >= 0;
while (rgtem) {
r = $dmath.biSubtract(r, this.modulus);
rgtem = $dmath.biCompare(r, this.modulus) >= 0;
}
return r;
}
function BarrettMu_multiplyMod(x, y) {
/*
x = this.modulo(x);
y = this.modulo(y);
*/
var xy = RSAUtils.biMultiply(x, y);
return this.modulo(xy);
}
function BarrettMu_powMod(x, y) {
var result = new BigInt();
result.digits[0] = 1;
var a = x;
var k = y;
while (true) {
if ((k.digits[0] & 1) != 0) result = this.multiplyMod(result, a);
k = RSAUtils.biShiftRight(k, 1);
if (k.digits[0] == 0 && RSAUtils.biHighIndex(k) == 0) break;
a = this.multiplyMod(a, a);
}
return result;
}
var RSAKeyPair = function(encryptionExponent, decryptionExponent, modulus) {
var $dmath = RSAUtils;
this.e = $dmath.biFromHex(encryptionExponent);
this.d = $dmath.biFromHex(decryptionExponent);
this.m = $dmath.biFromHex(modulus);
// We can do two bytes per digit, so
// chunkSize = 2 * (number of digits in modulus – 1).
// Since biHighIndex returns the high index, not the number of digits, 1 has
// already been subtracted.
this.chunkSize = 2 * $dmath.biHighIndex(this.m);
this.radix = 16;
this.barrett = new $w.BarrettMu(this.m);
};
RSAUtils.getKeyPair = function(encryptionExponent, decryptionExponent, modulus) {
return new RSAKeyPair(encryptionExponent, decryptionExponent, modulus);
};
if(typeof $w.twoDigit === 'undefined') {
$w.twoDigit = function(n) {
return (n < 10 ? "0" : "") + String(n);
};
}
// Altered by Rob Saunders (rob@robsaunders.net). New routine pads the
// string after it has been converted to an array. This fixes an
// incompatibility with Flash MX's ActionScript.
RSAUtils.encryptedString = function(key, s) {
var a = [];
var sl = s.length;
var i = 0;
while (i < sl) {
a[i] = s.charCodeAt(i);
i++;
}
while (a.length % key.chunkSize != 0) {
a[i++] = 0;
}
var al = a.length;
var result = "";
var j, k, block;
for (i = 0; i < al; i += key.chunkSize) {
block = new BigInt();
j = 0;
for (k = i; k < i + key.chunkSize; ++j) {
block.digits[j] = a[k++];
block.digits[j] += a[k++] << 8;
}
var crypt = key.barrett.powMod(block, key.e);
var text = key.radix == 16 ? RSAUtils.biToHex(crypt) : RSAUtils.biToString(crypt, key.radix);
result += text + " ";
}
return result.substring(0, result.length – 1); // Remove last space.
};
RSAUtils.decryptedString = function(key, s) {
var blocks = s.split(" ");
var result = "";
var i, j, block;
for (i = 0; i < blocks.length; ++i) {
var bi;
if (key.radix == 16) {
bi = RSAUtils.biFromHex(blocks[i]);
}
else {
bi = RSAUtils.biFromString(blocks[i], key.radix);
}
block = key.barrett.powMod(bi, key.d);
for (j = 0; j <= RSAUtils.biHighIndex(block); ++j) {
result += String.fromCharCode(block.digits[j] & 255,
block.digits[j] >> 8);
}
}
// Remove trailing null, if any.
if (result.charCodeAt(result.length – 1) == 0) {
result = result.substring(0, result.length – 1);
}
return result;
};
RSAUtils.setMaxDigits(130);
})(window);