Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 1 | // Depends on jsbn.js and rng.js
|
| 2 |
|
| 3 | // Version 1.1: support utf-8 encoding in pkcs1pad2
|
| 4 |
|
| 5 | // convert a (hex) string to a bignum object
|
| 6 | function parseBigInt(str,r) {
|
| 7 | return new BigInteger(str,r);
|
| 8 | }
|
| 9 |
|
| 10 | function linebrk(s,n) {
|
| 11 | var ret = "";
|
| 12 | var i = 0;
|
| 13 | while(i + n < s.length) {
|
| 14 | ret += s.substring(i,i+n) + "\n";
|
| 15 | i += n;
|
| 16 | }
|
| 17 | return ret + s.substring(i,s.length);
|
| 18 | }
|
| 19 |
|
| 20 | function byte2Hex(b) {
|
| 21 | if(b < 0x10)
|
| 22 | return "0" + b.toString(16);
|
| 23 | else
|
| 24 | return b.toString(16);
|
| 25 | }
|
| 26 |
|
Meki Cherkaoui | 8f17361 | 2012-06-06 01:05:40 -0700 | [diff] [blame] | 27 | /**
|
| 28 | * PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
|
| 29 | * @param s: the string to encode
|
| 30 | * @param n: the size in byte
|
| 31 | */
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 32 | function pkcs1pad2(s,n) {
|
| 33 | if(n < s.length + 11) { // TODO: fix for utf-8
|
| 34 | alert("Message too long for RSA");
|
| 35 | return null;
|
| 36 | }
|
| 37 | var ba = new Array();
|
| 38 | var i = s.length - 1;
|
| 39 | while(i >= 0 && n > 0) {
|
| 40 | var c = s.charCodeAt(i--);
|
| 41 | if(c < 128) { // encode using utf-8
|
| 42 | ba[--n] = c;
|
| 43 | }
|
| 44 | else if((c > 127) && (c < 2048)) {
|
| 45 | ba[--n] = (c & 63) | 128;
|
| 46 | ba[--n] = (c >> 6) | 192;
|
| 47 | }
|
| 48 | else {
|
| 49 | ba[--n] = (c & 63) | 128;
|
| 50 | ba[--n] = ((c >> 6) & 63) | 128;
|
| 51 | ba[--n] = (c >> 12) | 224;
|
| 52 | }
|
| 53 | }
|
| 54 | ba[--n] = 0;
|
| 55 | var rng = new SecureRandom();
|
| 56 | var x = new Array();
|
| 57 | while(n > 2) { // random non-zero pad
|
| 58 | x[0] = 0;
|
| 59 | while(x[0] == 0) rng.nextBytes(x);
|
| 60 | ba[--n] = x[0];
|
| 61 | }
|
| 62 | ba[--n] = 2;
|
| 63 | ba[--n] = 0;
|
| 64 | return new BigInteger(ba);
|
| 65 | }
|
| 66 |
|
Meki Cherkaoui | 8f17361 | 2012-06-06 01:05:40 -0700 | [diff] [blame] | 67 | /**
|
| 68 | * "empty" RSA key constructor
|
| 69 | * @returns {RSAKey}
|
| 70 | */
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 71 | function RSAKey() {
|
| 72 | this.n = null;
|
| 73 | this.e = 0;
|
| 74 | this.d = null;
|
| 75 | this.p = null;
|
| 76 | this.q = null;
|
| 77 | this.dmp1 = null;
|
| 78 | this.dmq1 = null;
|
| 79 | this.coeff = null;
|
| 80 | }
|
| 81 |
|
Meki Cherkaoui | 8f17361 | 2012-06-06 01:05:40 -0700 | [diff] [blame] | 82 | /**
|
| 83 | * Set the public key fields N and e from hex strings
|
| 84 | * @param N
|
| 85 | * @param E
|
| 86 | * @returns {RSASetPublic}
|
| 87 | */
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 88 | function RSASetPublic(N,E) {
|
| 89 | if(N != null && E != null && N.length > 0 && E.length > 0) {
|
| 90 | this.n = parseBigInt(N,16);
|
| 91 | this.e = parseInt(E,16);
|
| 92 | }
|
| 93 | else
|
| 94 | alert("Invalid RSA public key");
|
| 95 | }
|
| 96 |
|
Meki Cherkaoui | 8f17361 | 2012-06-06 01:05:40 -0700 | [diff] [blame] | 97 | /**
|
| 98 | * Perform raw public operation on "x": return x^e (mod n)
|
| 99 | * @param x
|
| 100 | * @returns x^e (mod n)
|
| 101 | */
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 102 | function RSADoPublic(x) {
|
| 103 | return x.modPowInt(this.e, this.n);
|
| 104 | }
|
| 105 |
|
Meki Cherkaoui | 8f17361 | 2012-06-06 01:05:40 -0700 | [diff] [blame] | 106 | /**
|
| 107 | * Return the PKCS#1 RSA encryption of "text" as an even-length hex string
|
| 108 | */
|
Meki Cherkaoui | 88d59cd | 2012-05-14 07:34:58 -0700 | [diff] [blame] | 109 | function RSAEncrypt(text) {
|
| 110 | var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
|
| 111 | if(m == null) return null;
|
| 112 | var c = this.doPublic(m);
|
| 113 | if(c == null) return null;
|
| 114 | var h = c.toString(16);
|
| 115 | if((h.length & 1) == 0) return h; else return "0" + h;
|
| 116 | }
|
| 117 |
|
| 118 | // Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
|
| 119 | //function RSAEncryptB64(text) {
|
| 120 | // var h = this.encrypt(text);
|
| 121 | // if(h) return hex2b64(h); else return null;
|
| 122 | //}
|
| 123 |
|
| 124 | // protected
|
| 125 | RSAKey.prototype.doPublic = RSADoPublic;
|
| 126 |
|
| 127 | // public
|
| 128 | RSAKey.prototype.setPublic = RSASetPublic;
|
| 129 | RSAKey.prototype.encrypt = RSAEncrypt;
|
| 130 | //RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
|