├── README.md
├── rsa
├── base64.gs
├── rsapem-1.1.gs
├── crypto-comp-sha1.gs
├── rsa.gs
├── rsa2.gs
├── asn1hex-1.1.gs
├── x509-1.1.gs
├── rsasign-1.2.gs
├── jsbn.gs
├── jsbn2.gs
├── crypto-comp-core.gs
└── crypto-1.1.gs
├── Xero.gs
└── Code.gs
/README.md:
--------------------------------------------------------------------------------
1 | # xero-api-apps-script
2 | Integrating Xero.com REST API with Google Apps Script
3 |
4 | How to use this Script
5 | 1. Create a new Google Spreadsheet.
6 | 2. From Spreadsheet menu go to Tools >> Script Editor.
7 | 3. In the Script, copy and add following files. Add new script file for each of the following:
8 | a) rsa/jsbn.gs
9 | b) rsa/jsbn2.gs
10 | c) rsa/rsa.gs
11 | d) rsa/rsa2.gs
12 | e) rsa/base64.gs
13 | f) rsa/crypto-comp-core.gs
14 | g) rsa/crypto-comp-sha1.gs
15 | h) rsa/rsapem-1.1.gs
16 | i) rsa/rsasign-1.2.gs
17 | j) rsa/asn1hex-1.1.gs
18 | k) rsa/x509-1.1.gs
19 | l) rsa/crypto-1.1.gs
20 | m) Xero.gs
21 | 4. Add code in Code.gs to existing Code.gs file.
22 | 5. Refresh spreadsheet.
23 | 6. From Custom menu XERO go to Xero Settings. Add details for Private App.
24 | 7. We have only tested this script with Private App and "Manual Download Invoices".
25 |
--------------------------------------------------------------------------------
/rsa/base64.gs:
--------------------------------------------------------------------------------
1 | /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
2 | */
3 |
4 | var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5 | var b64pad="=";
6 |
7 | function hex2b64(h) {
8 | var i;
9 | var c;
10 | var ret = "";
11 | for(i = 0; i+3 <= h.length; i+=3) {
12 | c = parseInt(h.substring(i,i+3),16);
13 | ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
14 | }
15 | if(i+1 == h.length) {
16 | c = parseInt(h.substring(i,i+1),16);
17 | ret += b64map.charAt(c << 2);
18 | }
19 | else if(i+2 == h.length) {
20 | c = parseInt(h.substring(i,i+2),16);
21 | ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
22 | }
23 | if (b64pad) while((ret.length & 3) > 0) ret += b64pad;
24 | return ret;
25 | }
26 |
27 | // convert a base64 string to hex
28 | function b64tohex(s) {
29 | var ret = ""
30 | var i;
31 | var k = 0; // b64 state, 0-3
32 | var slop;
33 | var v;
34 | for(i = 0; i < s.length; ++i) {
35 | if(s.charAt(i) == b64pad) break;
36 | v = b64map.indexOf(s.charAt(i));
37 | if(v < 0) continue;
38 | if(k == 0) {
39 | ret += int2char(v >> 2);
40 | slop = v & 3;
41 | k = 1;
42 | }
43 | else if(k == 1) {
44 | ret += int2char((slop << 2) | (v >> 4));
45 | slop = v & 0xf;
46 | k = 2;
47 | }
48 | else if(k == 2) {
49 | ret += int2char(slop);
50 | ret += int2char(v >> 2);
51 | slop = v & 3;
52 | k = 3;
53 | }
54 | else {
55 | ret += int2char((slop << 2) | (v >> 4));
56 | ret += int2char(v & 0xf);
57 | k = 0;
58 | }
59 | }
60 | if(k == 1)
61 | ret += int2char(slop << 2);
62 | return ret;
63 | }
64 |
65 | // convert a base64 string to a byte/number array
66 | function b64toBA(s) {
67 | //piggyback on b64tohex for now, optimize later
68 | var h = b64tohex(s);
69 | var i;
70 | var a = new Array();
71 | for(i = 0; 2*i < h.length; ++i) {
72 | a[i] = parseInt(h.substring(2*i,2*i+2),16);
73 | }
74 | return a;
75 | }
76 |
--------------------------------------------------------------------------------
/rsa/rsapem-1.1.gs:
--------------------------------------------------------------------------------
1 | /*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
2 | */
3 | //
4 | // rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key
5 | // to RSAKey class.
6 | //
7 | // version: 1.1.1 (2013-Apr-12)
8 | //
9 | // Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com)
10 | //
11 | // This software is licensed under the terms of the MIT License.
12 | // http://kjur.github.com/jsrsasign/license/
13 | //
14 | // The above copyright and license notice shall be
15 | // included in all copies or substantial portions of the Software.
16 | //
17 | //
18 | // Depends on:
19 | //
20 | //
21 | //
22 | // _RSApem_pemToBase64(sPEM)
23 | //
24 | // removing PEM header, PEM footer and space characters including
25 | // new lines from PEM formatted RSA private key string.
26 | //
27 |
28 | /**
29 | * @fileOverview
30 | * @name rsapem-1.1.js
31 | * @author Kenji Urushima kenji.urushima@gmail.com
32 | * @version 1.1
33 | * @license MIT License
34 | */
35 | function _rsapem_pemToBase64(sPEMPrivateKey) {
36 | var s = sPEMPrivateKey;
37 | s = s.replace("-----BEGIN RSA PRIVATE KEY-----", "");
38 | s = s.replace("-----END RSA PRIVATE KEY-----", "");
39 | s = s.replace(/[ \n]+/g, "");
40 | return s;
41 | }
42 |
43 | function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
44 | var a = new Array();
45 | var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0);
46 | var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1);
47 | var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1);
48 | var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1);
49 | var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1);
50 | var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1);
51 | var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1);
52 | var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1);
53 | var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1);
54 | a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1);
55 | return a;
56 | }
57 |
58 | function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
59 | var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);
60 | var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]);
61 | var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]);
62 | var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]);
63 | var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]);
64 | var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]);
65 | var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]);
66 | var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]);
67 | var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]);
68 | var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]);
69 | var a = new Array();
70 | a.push(v, n, e, d, p, q, dp, dq, co);
71 | return a;
72 | }
73 |
74 | /**
75 | * read RSA private key from a ASN.1 hexadecimal string
76 | * @name readPrivateKeyFromASN1HexString
77 | * @memberOf RSAKey#
78 | * @function
79 | * @param {String} keyHex ASN.1 hexadecimal string of PKCS#1 private key.
80 | * @since 1.1.1
81 | */
82 | function _rsapem_readPrivateKeyFromASN1HexString(keyHex) {
83 | var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
84 | this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
85 | }
86 |
87 | /**
88 | * read PKCS#1 private key from a string
89 | * @name readPrivateKeyFromPEMString
90 | * @memberOf RSAKey#
91 | * @function
92 | * @param {String} keyPEM string of PKCS#1 private key.
93 | */
94 | function _rsapem_readPrivateKeyFromPEMString(keyPEM) {
95 | var keyB64 = _rsapem_pemToBase64(keyPEM);
96 | var keyHex = b64tohex(keyB64) // depends base64.js
97 | var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
98 | this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
99 | }
100 |
101 | RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString;
102 | RSAKey.prototype.readPrivateKeyFromASN1HexString = _rsapem_readPrivateKeyFromASN1HexString;
103 |
--------------------------------------------------------------------------------
/rsa/crypto-comp-sha1.gs:
--------------------------------------------------------------------------------
1 | /*
2 | CryptoJS v3.1.2
3 | code.google.com/p/crypto-js
4 | (c) 2009-2013 by Jeff Mott. All rights reserved.
5 | code.google.com/p/crypto-js/wiki/License
6 | */
7 | (function () {
8 | // Shortcuts
9 | var C = CryptoJS;
10 | var C_lib = C.lib;
11 | var WordArray = C_lib.WordArray;
12 | var Hasher = C_lib.Hasher;
13 | var C_algo = C.algo;
14 |
15 | // Reusable object
16 | var W = [];
17 |
18 | /**
19 | * SHA-1 hash algorithm.
20 | */
21 | var SHA1 = C_algo.SHA1 = Hasher.extend({
22 | _doReset: function () {
23 | this._hash = new WordArray.init([
24 | 0x67452301, 0xefcdab89,
25 | 0x98badcfe, 0x10325476,
26 | 0xc3d2e1f0
27 | ]);
28 | },
29 |
30 | _doProcessBlock: function (M, offset) {
31 | // Shortcut
32 | var H = this._hash.words;
33 |
34 | // Working variables
35 | var a = H[0];
36 | var b = H[1];
37 | var c = H[2];
38 | var d = H[3];
39 | var e = H[4];
40 |
41 | // Computation
42 | for (var i = 0; i < 80; i++) {
43 | if (i < 16) {
44 | W[i] = M[offset + i] | 0;
45 | } else {
46 | var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
47 | W[i] = (n << 1) | (n >>> 31);
48 | }
49 |
50 | var t = ((a << 5) | (a >>> 27)) + e + W[i];
51 | if (i < 20) {
52 | t += ((b & c) | (~b & d)) + 0x5a827999;
53 | } else if (i < 40) {
54 | t += (b ^ c ^ d) + 0x6ed9eba1;
55 | } else if (i < 60) {
56 | t += ((b & c) | (b & d) | (c & d)) - 0x70e44324;
57 | } else /* if (i < 80) */ {
58 | t += (b ^ c ^ d) - 0x359d3e2a;
59 | }
60 |
61 | e = d;
62 | d = c;
63 | c = (b << 30) | (b >>> 2);
64 | b = a;
65 | a = t;
66 | }
67 |
68 | // Intermediate hash value
69 | H[0] = (H[0] + a) | 0;
70 | H[1] = (H[1] + b) | 0;
71 | H[2] = (H[2] + c) | 0;
72 | H[3] = (H[3] + d) | 0;
73 | H[4] = (H[4] + e) | 0;
74 | },
75 |
76 | _doFinalize: function () {
77 | // Shortcuts
78 | var data = this._data;
79 | var dataWords = data.words;
80 |
81 | var nBitsTotal = this._nDataBytes * 8;
82 | var nBitsLeft = data.sigBytes * 8;
83 |
84 | // Add padding
85 | dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
86 | dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
87 | dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
88 | data.sigBytes = dataWords.length * 4;
89 |
90 | // Hash final blocks
91 | this._process();
92 |
93 | // Return final computed hash
94 | return this._hash;
95 | },
96 |
97 | clone: function () {
98 | var clone = Hasher.clone.call(this);
99 | clone._hash = this._hash.clone();
100 |
101 | return clone;
102 | }
103 | });
104 |
105 | /**
106 | * Shortcut function to the hasher's object interface.
107 | *
108 | * @param {WordArray|string} message The message to hash.
109 | *
110 | * @return {WordArray} The hash.
111 | *
112 | * @static
113 | *
114 | * @example
115 | *
116 | * var hash = CryptoJS.SHA1('message');
117 | * var hash = CryptoJS.SHA1(wordArray);
118 | */
119 | C.SHA1 = Hasher._createHelper(SHA1);
120 |
121 | /**
122 | * Shortcut function to the HMAC's object interface.
123 | *
124 | * @param {WordArray|string} message The message to hash.
125 | * @param {WordArray|string} key The secret key.
126 | *
127 | * @return {WordArray} The HMAC.
128 | *
129 | * @static
130 | *
131 | * @example
132 | *
133 | * var hmac = CryptoJS.HmacSHA1(message, key);
134 | */
135 | C.HmacSHA1 = Hasher._createHmacHelper(SHA1);
136 | }());
137 |
--------------------------------------------------------------------------------
/rsa/rsa.gs:
--------------------------------------------------------------------------------
1 | /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
2 | */
3 | // Depends on jsbn.js and rng.js
4 |
5 | // Version 1.1: support utf-8 encoding in pkcs1pad2
6 |
7 | // convert a (hex) string to a bignum object
8 | function parseBigInt(str,r) {
9 | return new BigInteger(str,r);
10 | }
11 |
12 | function linebrk(s,n) {
13 | var ret = "";
14 | var i = 0;
15 | while(i + n < s.length) {
16 | ret += s.substring(i,i+n) + "\n";
17 | i += n;
18 | }
19 | return ret + s.substring(i,s.length);
20 | }
21 |
22 | function byte2Hex(b) {
23 | if(b < 0x10)
24 | return "0" + b.toString(16);
25 | else
26 | return b.toString(16);
27 | }
28 |
29 | // PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
30 | function pkcs1pad2(s,n) {
31 | if(n < s.length + 11) { // TODO: fix for utf-8
32 | Browser.msgBox("Message too long for RSA");
33 | return null;
34 | }
35 | var ba = new Array();
36 | var i = s.length - 1;
37 | while(i >= 0 && n > 0) {
38 | var c = s.charCodeAt(i--);
39 | if(c < 128) { // encode using utf-8
40 | ba[--n] = c;
41 | }
42 | else if((c > 127) && (c < 2048)) {
43 | ba[--n] = (c & 63) | 128;
44 | ba[--n] = (c >> 6) | 192;
45 | }
46 | else {
47 | ba[--n] = (c & 63) | 128;
48 | ba[--n] = ((c >> 6) & 63) | 128;
49 | ba[--n] = (c >> 12) | 224;
50 | }
51 | }
52 | ba[--n] = 0;
53 | var rng = new SecureRandom();
54 | var x = new Array();
55 | while(n > 2) { // random non-zero pad
56 | x[0] = 0;
57 | while(x[0] == 0) rng.nextBytes(x);
58 | ba[--n] = x[0];
59 | }
60 | ba[--n] = 2;
61 | ba[--n] = 0;
62 | return new BigInteger(ba);
63 | }
64 |
65 | // PKCS#1 (OAEP) mask generation function
66 | function oaep_mgf1_arr(seed, len, hash)
67 | {
68 | var mask = '', i = 0;
69 |
70 | while (mask.length < len)
71 | {
72 | mask += hash(String.fromCharCode.apply(String, seed.concat([
73 | (i & 0xff000000) >> 24,
74 | (i & 0x00ff0000) >> 16,
75 | (i & 0x0000ff00) >> 8,
76 | i & 0x000000ff])));
77 | i += 1;
78 | }
79 |
80 | return mask;
81 | }
82 |
83 | var SHA1_SIZE = 20;
84 |
85 | // PKCS#1 (OAEP) pad input string s to n bytes, and return a bigint
86 | function oaep_pad(s, n, hash)
87 | {
88 | if (s.length + 2 * SHA1_SIZE + 2 > n)
89 | {
90 | throw "Message too long for RSA";
91 | }
92 |
93 | var PS = '', i;
94 |
95 | for (i = 0; i < n - s.length - 2 * SHA1_SIZE - 2; i += 1)
96 | {
97 | PS += '\x00';
98 | }
99 |
100 | var DB = rstr_sha1('') + PS + '\x01' + s;
101 | var seed = new Array(SHA1_SIZE);
102 | new SecureRandom().nextBytes(seed);
103 |
104 | var dbMask = oaep_mgf1_arr(seed, DB.length, hash || rstr_sha1);
105 | var maskedDB = [];
106 |
107 | for (i = 0; i < DB.length; i += 1)
108 | {
109 | maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i);
110 | }
111 |
112 | var seedMask = oaep_mgf1_arr(maskedDB, seed.length, rstr_sha1);
113 | var maskedSeed = [0];
114 |
115 | for (i = 0; i < seed.length; i += 1)
116 | {
117 | maskedSeed[i + 1] = seed[i] ^ seedMask.charCodeAt(i);
118 | }
119 |
120 | return new BigInteger(maskedSeed.concat(maskedDB));
121 | }
122 |
123 | // "empty" RSA key constructor
124 | function RSAKey() {
125 | this.n = null;
126 | this.e = 0;
127 | this.d = null;
128 | this.p = null;
129 | this.q = null;
130 | this.dmp1 = null;
131 | this.dmq1 = null;
132 | this.coeff = null;
133 | }
134 |
135 | // Set the public key fields N and e from hex strings
136 | function RSASetPublic(N,E) {
137 | this.isPublic = true;
138 | if (typeof N !== "string")
139 | {
140 | this.n = N;
141 | this.e = E;
142 | }
143 | else if(N != null && E != null && N.length > 0 && E.length > 0) {
144 | this.n = parseBigInt(N,16);
145 | this.e = parseInt(E,16);
146 | }
147 | else
148 | Browser.msgBox("Invalid RSA public key");
149 | }
150 |
151 | // Perform raw public operation on "x": return x^e (mod n)
152 | function RSADoPublic(x) {
153 | return x.modPowInt(this.e, this.n);
154 | }
155 |
156 | // Return the PKCS#1 RSA encryption of "text" as an even-length hex string
157 | function RSAEncrypt(text) {
158 | var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
159 | if(m == null) return null;
160 | var c = this.doPublic(m);
161 | if(c == null) return null;
162 | var h = c.toString(16);
163 | if((h.length & 1) == 0) return h; else return "0" + h;
164 | }
165 |
166 | // Return the PKCS#1 OAEP RSA encryption of "text" as an even-length hex string
167 | function RSAEncryptOAEP(text, hash) {
168 | var m = oaep_pad(text, (this.n.bitLength()+7)>>3, hash);
169 | if(m == null) return null;
170 | var c = this.doPublic(m);
171 | if(c == null) return null;
172 | var h = c.toString(16);
173 | if((h.length & 1) == 0) return h; else return "0" + h;
174 | }
175 |
176 | // Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
177 | //function RSAEncryptB64(text) {
178 | // var h = this.encrypt(text);
179 | // if(h) return hex2b64(h); else return null;
180 | //}
181 |
182 | // protected
183 | RSAKey.prototype.doPublic = RSADoPublic;
184 |
185 | // public
186 | RSAKey.prototype.setPublic = RSASetPublic;
187 | RSAKey.prototype.encrypt = RSAEncrypt;
188 | RSAKey.prototype.encryptOAEP = RSAEncryptOAEP;
189 | //RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
190 |
191 | RSAKey.prototype.type = "RSA";
192 |
--------------------------------------------------------------------------------
/rsa/rsa2.gs:
--------------------------------------------------------------------------------
1 | /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/
2 | */
3 | // Depends on rsa.js and jsbn2.js
4 |
5 | // Version 1.1: support utf-8 decoding in pkcs1unpad2
6 |
7 | // Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
8 | function pkcs1unpad2(d,n) {
9 | var b = d.toByteArray();
10 | var i = 0;
11 | while(i < b.length && b[i] == 0) ++i;
12 | if(b.length-i != n-1 || b[i] != 2)
13 | return null;
14 | ++i;
15 | while(b[i] != 0)
16 | if(++i >= b.length) return null;
17 | var ret = "";
18 | while(++i < b.length) {
19 | var c = b[i] & 255;
20 | if(c < 128) { // utf-8 decode
21 | ret += String.fromCharCode(c);
22 | }
23 | else if((c > 191) && (c < 224)) {
24 | ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
25 | ++i;
26 | }
27 | else {
28 | ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
29 | i += 2;
30 | }
31 | }
32 | return ret;
33 | }
34 |
35 | // PKCS#1 (OAEP) mask generation function
36 | function oaep_mgf1_str(seed, len, hash)
37 | {
38 | var mask = '', i = 0;
39 |
40 | while (mask.length < len)
41 | {
42 | mask += hash(seed + String.fromCharCode.apply(String, [
43 | (i & 0xff000000) >> 24,
44 | (i & 0x00ff0000) >> 16,
45 | (i & 0x0000ff00) >> 8,
46 | i & 0x000000ff]));
47 | i += 1;
48 | }
49 |
50 | return mask;
51 | }
52 |
53 | var SHA1_SIZE = 20;
54 |
55 | // Undo PKCS#1 (OAEP) padding and, if valid, return the plaintext
56 | function oaep_unpad(d, n, hash)
57 | {
58 | d = d.toByteArray();
59 |
60 | var i;
61 |
62 | for (i = 0; i < d.length; i += 1)
63 | {
64 | d[i] &= 0xff;
65 | }
66 |
67 | while (d.length < n)
68 | {
69 | d.unshift(0);
70 | }
71 |
72 | d = String.fromCharCode.apply(String, d);
73 |
74 | if (d.length < 2 * SHA1_SIZE + 2)
75 | {
76 | throw "Cipher too short";
77 | }
78 |
79 | var maskedSeed = d.substr(1, SHA1_SIZE)
80 | var maskedDB = d.substr(SHA1_SIZE + 1);
81 |
82 | var seedMask = oaep_mgf1_str(maskedDB, SHA1_SIZE, hash || rstr_sha1);
83 | var seed = [], i;
84 |
85 | for (i = 0; i < maskedSeed.length; i += 1)
86 | {
87 | seed[i] = maskedSeed.charCodeAt(i) ^ seedMask.charCodeAt(i);
88 | }
89 |
90 | var dbMask = oaep_mgf1_str(String.fromCharCode.apply(String, seed),
91 | d.length - SHA1_SIZE, rstr_sha1);
92 |
93 | var DB = [];
94 |
95 | for (i = 0; i < maskedDB.length; i += 1)
96 | {
97 | DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i);
98 | }
99 |
100 | DB = String.fromCharCode.apply(String, DB);
101 |
102 | if (DB.substr(0, SHA1_SIZE) !== rstr_sha1(''))
103 | {
104 | throw "Hash mismatch";
105 | }
106 |
107 | DB = DB.substr(SHA1_SIZE);
108 |
109 | var first_one = DB.indexOf('\x01');
110 | var last_zero = (first_one != -1) ? DB.substr(0, first_one).lastIndexOf('\x00') : -1;
111 |
112 | if (last_zero + 1 != first_one)
113 | {
114 | throw "Malformed data";
115 | }
116 |
117 | return DB.substr(first_one + 1);
118 | }
119 |
120 | // Set the private key fields N, e, and d from hex strings
121 | function RSASetPrivate(N,E,D) {
122 | this.isPrivate = true;
123 | if (typeof N !== "string")
124 | {
125 | this.n = N;
126 | this.e = E;
127 | this.d = D;
128 | }
129 | else if(N != null && E != null && N.length > 0 && E.length > 0) {
130 | this.n = parseBigInt(N,16);
131 | this.e = parseInt(E,16);
132 | this.d = parseBigInt(D,16);
133 | }
134 | else
135 | Browser.msgBox("Invalid RSA private key");
136 | }
137 |
138 | // Set the private key fields N, e, d and CRT params from hex strings
139 | function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
140 | this.isPrivate = true;
141 | var errorMsg = "Invalid RSA Private Key."
142 | if (N == null) throw errorMsg; //"RSASetPrivateEx N == null";
143 | if (E == null) throw errorMsg; //"RSASetPrivateEx E == null";
144 | if (N.length == 0) throw errorMsg //"RSASetPrivateEx N.length == 0";
145 | if (E.length == 0) throw errorMsg //"RSASetPrivateEx E.length == 0";
146 |
147 | if (N != null && E != null && N.length > 0 && E.length > 0) {
148 | this.n = parseBigInt(N,16);
149 | this.e = parseInt(E,16);
150 | this.d = parseBigInt(D,16);
151 | this.p = parseBigInt(P,16);
152 | this.q = parseBigInt(Q,16);
153 | this.dmp1 = parseBigInt(DP,16);
154 | this.dmq1 = parseBigInt(DQ,16);
155 | this.coeff = parseBigInt(C,16);
156 | } else {
157 | Browser.msgBox("Invalid RSA Private Key.");
158 | }
159 | }
160 |
161 | // Generate a new random private key B bits long, using public expt E
162 | function RSAGenerate(B,E) {
163 | var rng = new SecureRandom();
164 | var qs = B>>1;
165 | this.e = parseInt(E,16);
166 | var ee = new BigInteger(E,16);
167 | for(;;) {
168 | for(;;) {
169 | this.p = new BigInteger(B-qs,1,rng);
170 | if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
171 | }
172 | for(;;) {
173 | this.q = new BigInteger(qs,1,rng);
174 | if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
175 | }
176 | if(this.p.compareTo(this.q) <= 0) {
177 | var t = this.p;
178 | this.p = this.q;
179 | this.q = t;
180 | }
181 | var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1
182 | var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1
183 | var phi = p1.multiply(q1);
184 | if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
185 | this.n = this.p.multiply(this.q); // this.n = p * q
186 | this.d = ee.modInverse(phi); // this.d =
187 | this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1)
188 | this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1)
189 | this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p
190 | break;
191 | }
192 | }
193 | this.isPrivate = true;
194 | }
195 |
196 | // Perform raw private operation on "x": return x^d (mod n)
197 | function RSADoPrivate(x) {
198 | if(this.p == null || this.q == null)
199 | return x.modPow(this.d, this.n);
200 |
201 | // TODO: re-calculate any missing CRT params
202 | var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp?
203 | var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq?
204 |
205 | while(xp.compareTo(xq) < 0)
206 | xp = xp.add(this.p);
207 | // NOTE:
208 | // xp.subtract(xq) => cp -cq
209 | // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h
210 | // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M
211 | return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
212 | }
213 |
214 | // Return the PKCS#1 RSA decryption of "ctext".
215 | // "ctext" is an even-length hex string and the output is a plain string.
216 | function RSADecrypt(ctext) {
217 | var c = parseBigInt(ctext, 16);
218 | var m = this.doPrivate(c);
219 | if(m == null) return null;
220 | return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
221 | }
222 |
223 | // Return the PKCS#1 OAEP RSA decryption of "ctext".
224 | // "ctext" is an even-length hex string and the output is a plain string.
225 | function RSADecryptOAEP(ctext, hash) {
226 | var c = parseBigInt(ctext, 16);
227 | var m = this.doPrivate(c);
228 | if(m == null) return null;
229 | return oaep_unpad(m, (this.n.bitLength()+7)>>3, hash);
230 | }
231 |
232 | // Return the PKCS#1 RSA decryption of "ctext".
233 | // "ctext" is a Base64-encoded string and the output is a plain string.
234 | //function RSAB64Decrypt(ctext) {
235 | // var h = b64tohex(ctext);
236 | // if(h) return this.decrypt(h); else return null;
237 | //}
238 |
239 | // protected
240 | RSAKey.prototype.doPrivate = RSADoPrivate;
241 |
242 | // public
243 | RSAKey.prototype.setPrivate = RSASetPrivate;
244 | RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
245 | RSAKey.prototype.generate = RSAGenerate;
246 | RSAKey.prototype.decrypt = RSADecrypt;
247 | RSAKey.prototype.decryptOAEP = RSADecryptOAEP;
248 | //RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
249 |
--------------------------------------------------------------------------------
/Xero.gs:
--------------------------------------------------------------------------------
1 | var baseURL = 'https://api.xero.com';
2 | var requestTokenURL = baseURL + '/oauth/RequestToken';
3 | var authorizeURL = baseURL + '/oauth/Authorize';
4 | var accessTokenURL = baseURL + '/oauth/AccessToken';
5 | var apiEndPoint = baseURL + '/api.xro/2.0';
6 |
7 | var Xero = {
8 | appType: '', userAgent: '', consumerKey: '', consumerSecret: '', callbackURL: '', rsaKey: '', isConnected: false,
9 |
10 | getProperty: function(propName) {
11 | if (this[propName] != null)
12 | return this[propName];
13 | else
14 | return false;
15 | },
16 |
17 | getSettings: function() {
18 | var p = PropertiesService.getScriptProperties().getProperties();
19 | if (p.appType == null || p.appType == '') {
20 | Browser.msgBox('Please enter Xero Settings.');
21 | return false;
22 | }
23 | else if (p.userAgent == null || p.userAgent == '' || p.consumerKey == null || p.consumerKey == '' || p.consumerSecret == null || p.consumerSecret == '') {
24 | Browser.msgBox('Error: Missing Xero Settings (Apllication Name/ Consumer Key/ Consumer Secret).');
25 | return false;
26 | }
27 | else if (p.appType == 'Public') {
28 | if (p.callbackURL == null || p.callbackURL == '') {
29 | Browser.msgBox('Error: Missing Xero Settings (Callback URL.');
30 | return false;
31 | }
32 | }
33 | else if (p.appType == 'Partner') {
34 | if (p.callbackURL == null || p.callbackURL == '' || p.rsaKey == null || p.rsaKey == '' ) {
35 | Browser.msgBox('Error: Missing Xero Settings (Callback URL/ RSA Key');
36 | return false;
37 | }
38 | }
39 |
40 | this.appType = p.appType;
41 | this.userAgent = p.userAgent;
42 | this.consumerKey = p.consumerKey;
43 | this.consumerSecret = p.consumerSecret;
44 | this.rsaKey = p.rsaKey;
45 | this.callbackURL = p.callbackURL;
46 | this.requestTokenSecret = "";
47 | this.accessToken = "";
48 | this.accessTokenSecret = "";
49 | if (p.requestTokenSecret != null)
50 | this.requestTokenSecret = p.requestTokenSecret;
51 | if (p.accessToken != null)
52 | this.accessToken = p.accessToken;
53 | if (p.accessTokenSecret != null)
54 | this.accessTokenSecret = p.accessTokenSecret;
55 | if (p.isConnected != null)
56 | this.isConnected = p.isConnected;
57 | return true;
58 | },
59 |
60 | connect: function() {
61 | this.getSettings();
62 | if (this.appType != 'Private' /*&& !this.isConnected*/) {
63 | // Ask user to connect to Xero first
64 | // Step 1. Get an Unauthorised Request Token
65 | var payload = {"oauth_consumer_key": this.consumerKey,
66 | "oauth_signature_method": "PLAINTEXT",
67 | "oauth_signature": encodeURIComponent(this.consumerSecret + '&'),
68 | "oauth_timestamp": ((new Date().getTime())/1000).toFixed(0),
69 | "oauth_nonce": generateRandomString(Math.floor(Math.round(25))),
70 | "oauth_version": "1.0",
71 | "oauth_callback": this.callbackURL};
72 | var options = {"method": "post", "payload": payload};
73 | var response = UrlFetchApp.fetch(requestTokenURL, options);
74 | var reoAuthToken = /(oauth_token=)([a-zA-Z0-9]+)/;
75 | var tokenMatch = reoAuthToken.exec(response.getContentText());
76 | var oAuthRequestToken = tokenMatch[2];
77 | var reTokenSecret = /(oauth_token_secret=)([a-zA-Z0-9]+)/;
78 | var secretMatch = reTokenSecret.exec(response.getContentText()) ;
79 | var tokenSecret = secretMatch[2];
80 | PropertiesService.getScriptProperties().setProperty('requestTokenSecret', tokenSecret);
81 | return authorizeURL + '?oauth_token=' + oAuthRequestToken;
82 |
83 | // Step 2 Show user the link to connect to Xero
84 | /*
85 | var ss = SpreadsheetApp.getActiveSpreadsheet();
86 | var app = UiApp.createApplication();
87 | app.setHeight(50);app.setWidth(100);
88 | var link = app.createAnchor('Connect to Xero', true, authorizeURL + '?oauth_token=' + oAuthRequestToken);
89 | var handler = app.createServerHandler('closeApp');
90 | link.addClickHandler(handler);
91 | app.add(link);
92 | ss.show(app);
93 | */
94 | }
95 | },
96 |
97 | fetchPrivateAppData: function(item, pageNo) {
98 | /* FETCH PRIVATE APPLICATION DATA */
99 | var method = 'GET';
100 | var requestURL = apiEndPoint + '/' + item ;
101 | var oauth_signature_method = 'RSA-SHA1';
102 | var oauth_timestamp = (new Date().getTime()/1000).toFixed();
103 | var oauth_nonce = generateRandomString(Math.floor(Math.random() * 50));
104 | var oauth_version = '1.0';
105 | var signBase = 'GET' + '&' + encodeURIComponent(requestURL) + '&'
106 | + encodeURIComponent('oauth_consumer_key=' + this.consumerKey + '&oauth_nonce=' + oauth_nonce + '&oauth_signature_method='
107 | + oauth_signature_method + '&oauth_timestamp=' + oauth_timestamp + '&oauth_token=' + this.consumerKey + '&oauth_version='
108 | + oauth_version + '&page=' + pageNo);
109 | if (!this.rsa) {
110 | this.rsa = new RSAKey();
111 | this.rsa.readPrivateKeyFromPEMString(this.rsaKey);
112 | var sbSigned = this.rsa.signString(signBase, 'sha1');
113 | }
114 | else
115 | var sbSigned = this.rsa.signString(signBase, 'sha1');
116 |
117 | var data = new Array();
118 | for (var i =0; i < sbSigned.length; i += 2)
119 | data.push(parseInt("0x" + sbSigned.substr(i, 2)));
120 | var oauth_signature = hex2b64(sbSigned);
121 |
122 | var authHeader = "OAuth oauth_token=\"" + this.consumerKey + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_consumer_key=\"" + this.consumerKey
123 | + "\",oauth_signature_method=\"RSA-SHA1\",oauth_timestamp=\"" + oauth_timestamp + "\",oauth_version=\"1.0\",oauth_signature=\""
124 | + encodeURIComponent(oauth_signature) + "\"";
125 |
126 | var headers = { "User-Agent": this.userAgent, "Authorization": authHeader, "Accept": "application/json"};
127 | var options = { muteHttpExceptions: true, "headers": headers};
128 | var response = UrlFetchApp.fetch(requestURL + '?page=' + pageNo, options);
129 |
130 | if (response.getResponseCode() == 200)
131 | return JSON.parse(response.getContentText());
132 | else
133 | return false;
134 | },
135 |
136 | fetchData: function(item, pageNo) {
137 | this.getSettings();
138 | // lets find out which method to use for fetching data
139 | switch(this.appType) {
140 | case 'Private':
141 | return this.fetchPrivateAppData(item, pageNo);
142 | break;
143 | case 'Public':
144 | if (!this.isConnected)
145 | this.connect();
146 | else
147 | return this.fetchPublicAppData(item, pageNo);
148 | break;
149 | case 'Partner':
150 | if (!this.isConnected)
151 | this.connect();
152 | else
153 | return this.fetchPartnerAppData(item);
154 | break;
155 | }
156 | },
157 |
158 |
159 | fetchPublicAppData: function(item, pageNo) {
160 | /* For PUBLIC APPLICATION TYPE */
161 | this.getSettings(); // get latest settings
162 | var method = 'GET';
163 | var requestURL = apiEndPoint + '/' + item ;
164 | var oauth_signature_method = 'HMAC-SHA1';
165 | var oauth_timestamp = (new Date().getTime()/1000).toFixed();
166 | var oauth_nonce = generateRandomString(Math.floor(Math.random() * 50));
167 | var oauth_version = '1.0';
168 | var signBase = 'GET' + '&' + encodeURIComponent(requestURL) + '&'
169 | + encodeURIComponent('oauth_consumer_key=' + this.consumerKey + '&oauth_nonce=' + oauth_nonce + '&oauth_signature_method=' + oauth_signature_method
170 | + '&oauth_timestamp=' + oauth_timestamp + '&oauth_token=' + this.accessToken + '&oauth_version=' + oauth_version + '&page=' + pageNo);
171 | var sbSigned = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_1, signBase,
172 | encodeURIComponent(this.consumerSecret) + '&' + encodeURIComponent(this.accessTokenSecret));
173 | var oauth_signature = Utilities.base64Encode(sbSigned);
174 |
175 | var authHeader = "OAuth oauth_consumer_key=\"" + this.consumerKey + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_token=\"" + this.accessToken
176 | + "\",oauth_signature_method=\"" + oauth_signature_method +"\",oauth_timestamp=\"" + oauth_timestamp + "\",oauth_version=\"1.0\",oauth_signature=\""
177 | + encodeURIComponent(oauth_signature) + "\"";
178 |
179 | var headers = { "User-Agent": + this.userAgent, "Authorization": authHeader, "Accept": "application/json" };
180 | var options = { "headers": headers};
181 | try {
182 | var response = UrlFetchApp.fetch(requestURL + '?page='+ pageNo, options);
183 | return JSON.parse(response.getContentText());
184 | }
185 | catch(e) {
186 | Logger.log(e.message);
187 | Browser.msgBox(e.message);
188 | }
189 | },
190 |
191 | fetchPartnerAppData: function(item) {
192 | return false;
193 | },
194 |
195 | uploadData: function(item, xml, method) {
196 | var method = method || 'POST';
197 | var requestURL = apiEndPoint + '/' + item ;
198 | var oauth_signature_method = 'RSA-SHA1';
199 | var oauth_timestamp = (new Date().getTime()/1000).toFixed();
200 | var oauth_nonce = generateRandomString(Math.floor(Math.random() * 50));
201 | var oauth_version = '1.0';
202 | var signBase = method + '&' + encodeURIComponent(requestURL) + '&' + 'SummarizeErrors=false' +
203 | + encodeURIComponent('oauth_consumer_key=' + this.consumerKey + '&oauth_nonce=' + oauth_nonce + '&oauth_signature_method='
204 | + oauth_signature_method + '&oauth_timestamp=' + oauth_timestamp + '&oauth_token=' + this.consumerKey + '&oauth_version='
205 | + oauth_version + '&order=');
206 | if (method == 'POST')
207 | signBase += '&xml=' + xml;
208 |
209 | var rsa = new RSAKey();
210 | rsa.readPrivateKeyFromPEMString(this.rsaKey);
211 | var sbSigned = rsa.signString(signBase, 'sha1');
212 |
213 | var data = new Array();
214 | for (var i =0; i < sbSigned.length; i += 2)
215 | data.push(parseInt("0x" + sbSigned.substr(i, 2)));
216 | var oauth_signature = hex2b64(sbSigned);
217 |
218 | var authHeader = "OAuth oauth_token=\"" + this.consumerKey + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_consumer_key=\"" + this.consumerKey
219 | + "\",oauth_signature_method=\"RSA-SHA1\",oauth_timestamp=\"" + oauth_timestamp + "\",oauth_version=\"1.0\",oauth_signature=\""
220 | + encodeURIComponent(oauth_signature) + "\"";
221 | var payload = {"order": "", "xml": xml};
222 | var headers = { "User-Agent": this.userAgent, "Authorization": authHeader, "Accept": "application/json", "muteHttpExceptions": true };
223 | var options = { "headers": headers, "method": "post", "payload": payload };
224 | try {
225 | var response = UrlFetchApp.fetch(requestURL + '?SummarizeErrors=false', options);
226 | if (response.getResponseCode() == 200 && response.getHeaders().Status == "OK")
227 | return JSON.parse(response.getContentText());
228 | else
229 | throw "Request Failed: Response Code: " + response.getResponseCode();
230 | }
231 | catch(e) {
232 | throw e.message;
233 | }
234 | return false;
235 | }
236 | }
237 |
238 |
--------------------------------------------------------------------------------
/rsa/asn1hex-1.1.gs:
--------------------------------------------------------------------------------
1 | /*! asn1hex-1.1.5.js (c) 2012-2014 Kenji Urushima | kjur.github.com/jsrsasign/license
2 | */
3 | /*
4 | * asn1hex.js - Hexadecimal represented ASN.1 string library
5 | *
6 | * Copyright (c) 2010-2014 Kenji Urushima (kenji.urushima@gmail.com)
7 | *
8 | * This software is licensed under the terms of the MIT License.
9 | * http://kjur.github.com/jsrsasign/license/
10 | *
11 | * The above copyright and license notice shall be
12 | * included in all copies or substantial portions of the Software.
13 | */
14 |
15 | /**
16 | * @fileOverview
17 | * @name asn1hex-1.1.js
18 | * @author Kenji Urushima kenji.urushima@gmail.com
19 | * @version asn1hex 1.1.5 (2014-May-25)
20 | * @license MIT License
21 | */
22 |
23 | /*
24 | * MEMO:
25 | * f('3082025b02...', 2) ... 82025b ... 3bytes
26 | * f('020100', 2) ... 01 ... 1byte
27 | * f('0203001...', 2) ... 03 ... 1byte
28 | * f('02818003...', 2) ... 8180 ... 2bytes
29 | * f('3080....0000', 2) ... 80 ... -1
30 | *
31 | * Requirements:
32 | * - ASN.1 type octet length MUST be 1.
33 | * (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
34 | */
35 |
36 | /**
37 | * ASN.1 DER encoded hexadecimal string utility class
38 | * @name ASN1HEX
39 | * @class ASN.1 DER encoded hexadecimal string utility class
40 | * @since jsrsasign 1.1
41 | */
42 | var ASN1HEX = new function() {
43 | /**
44 | * get byte length for ASN.1 L(length) bytes
45 | * @name getByteLengthOfL_AtObj
46 | * @memberOf ASN1HEX
47 | * @function
48 | * @param {String} s hexadecimal string of ASN.1 DER encoded data
49 | * @param {Number} pos string index
50 | * @return byte length for ASN.1 L(length) bytes
51 | */
52 | this.getByteLengthOfL_AtObj = function(s, pos) {
53 | if (s.substring(pos + 2, pos + 3) != '8') return 1;
54 | var i = parseInt(s.substring(pos + 3, pos + 4));
55 | if (i == 0) return -1; // length octet '80' indefinite length
56 | if (0 < i && i < 10) return i + 1; // including '8?' octet;
57 | return -2; // malformed format
58 | };
59 |
60 | /**
61 | * get hexadecimal string for ASN.1 L(length) bytes
62 | * @name getHexOfL_AtObj
63 | * @memberOf ASN1HEX
64 | * @function
65 | * @param {String} s hexadecimal string of ASN.1 DER encoded data
66 | * @param {Number} pos string index
67 | * @return {String} hexadecimal string for ASN.1 L(length) bytes
68 | */
69 | this.getHexOfL_AtObj = function(s, pos) {
70 | var len = this.getByteLengthOfL_AtObj(s, pos);
71 | if (len < 1) return '';
72 | return s.substring(pos + 2, pos + 2 + len * 2);
73 | };
74 |
75 | // getting ASN.1 length value at the position 'idx' of
76 | // hexa decimal string 's'.
77 | //
78 | // f('3082025b02...', 0) ... 82025b ... ???
79 | // f('020100', 0) ... 01 ... 1
80 | // f('0203001...', 0) ... 03 ... 3
81 | // f('02818003...', 0) ... 8180 ... 128
82 | /**
83 | * get integer value of ASN.1 length for ASN.1 data
84 | * @name getIntOfL_AtObj
85 | * @memberOf ASN1HEX
86 | * @function
87 | * @param {String} s hexadecimal string of ASN.1 DER encoded data
88 | * @param {Number} pos string index
89 | * @return ASN.1 L(length) integer value
90 | */
91 | this.getIntOfL_AtObj = function(s, pos) {
92 | var hLength = this.getHexOfL_AtObj(s, pos);
93 | if (hLength == '') return -1;
94 | var bi;
95 | if (parseInt(hLength.substring(0, 1)) < 8) {
96 | bi = new BigInteger(hLength, 16);
97 | } else {
98 | bi = new BigInteger(hLength.substring(2), 16);
99 | }
100 | return bi.intValue();
101 | };
102 |
103 | /**
104 | * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
105 | * @name getStartPosOfV_AtObj
106 | * @memberOf ASN1HEX
107 | * @function
108 | * @param {String} s hexadecimal string of ASN.1 DER encoded data
109 | * @param {Number} pos string index
110 | */
111 | this.getStartPosOfV_AtObj = function(s, pos) {
112 | var l_len = this.getByteLengthOfL_AtObj(s, pos);
113 | if (l_len < 0) return l_len;
114 | return pos + (l_len + 1) * 2;
115 | };
116 |
117 | /**
118 | * get hexadecimal string of ASN.1 V(value)
119 | * @name getHexOfV_AtObj
120 | * @memberOf ASN1HEX
121 | * @function
122 | * @param {String} s hexadecimal string of ASN.1 DER encoded data
123 | * @param {Number} pos string index
124 | * @return {String} hexadecimal string of ASN.1 value.
125 | */
126 | this.getHexOfV_AtObj = function(s, pos) {
127 | var pos1 = this.getStartPosOfV_AtObj(s, pos);
128 | var len = this.getIntOfL_AtObj(s, pos);
129 | return s.substring(pos1, pos1 + len * 2);
130 | };
131 |
132 | /**
133 | * get hexadecimal string of ASN.1 TLV at
134 | * @name getHexOfTLV_AtObj
135 | * @memberOf ASN1HEX
136 | * @function
137 | * @param {String} s hexadecimal string of ASN.1 DER encoded data
138 | * @param {Number} pos string index
139 | * @return {String} hexadecimal string of ASN.1 TLV.
140 | * @since 1.1
141 | */
142 | this.getHexOfTLV_AtObj = function(s, pos) {
143 | var hT = s.substr(pos, 2);
144 | var hL = this.getHexOfL_AtObj(s, pos);
145 | var hV = this.getHexOfV_AtObj(s, pos);
146 | return hT + hL + hV;
147 | };
148 |
149 | /**
150 | * get next sibling starting index for ASN.1 object string
151 | * @name getPosOfNextSibling_AtObj
152 | * @memberOf ASN1HEX
153 | * @function
154 | * @param {String} s hexadecimal string of ASN.1 DER encoded data
155 | * @param {Number} pos string index
156 | * @return next sibling starting index for ASN.1 object string
157 | */
158 | this.getPosOfNextSibling_AtObj = function(s, pos) {
159 | var pos1 = this.getStartPosOfV_AtObj(s, pos);
160 | var len = this.getIntOfL_AtObj(s, pos);
161 | return pos1 + len * 2;
162 | };
163 |
164 | /**
165 | * get array of indexes of child ASN.1 objects
166 | * @name getPosArrayOfChildren_AtObj
167 | * @memberOf ASN1HEX
168 | * @function
169 | * @param {String} s hexadecimal string of ASN.1 DER encoded data
170 | * @param {Number} start string index of ASN.1 object
171 | * @return {Array of Number} array of indexes for childen of ASN.1 objects
172 | */
173 | this.getPosArrayOfChildren_AtObj = function(h, pos) {
174 | var a = new Array();
175 | var p0 = this.getStartPosOfV_AtObj(h, pos);
176 | a.push(p0);
177 |
178 | var len = this.getIntOfL_AtObj(h, pos);
179 | var p = p0;
180 | var k = 0;
181 | while (1) {
182 | var pNext = this.getPosOfNextSibling_AtObj(h, p);
183 | if (pNext == null || (pNext - p0 >= (len * 2))) break;
184 | if (k >= 200) break;
185 |
186 | a.push(pNext);
187 | p = pNext;
188 |
189 | k++;
190 | }
191 |
192 | return a;
193 | };
194 |
195 | /**
196 | * get string index of nth child object of ASN.1 object refered by h, idx
197 | * @name getNthChildIndex_AtObj
198 | * @memberOf ASN1HEX
199 | * @function
200 | * @param {String} h hexadecimal string of ASN.1 DER encoded data
201 | * @param {Number} idx start string index of ASN.1 object
202 | * @param {Number} nth for child
203 | * @return {Number} string index of nth child.
204 | * @since 1.1
205 | */
206 | this.getNthChildIndex_AtObj = function(h, idx, nth) {
207 | var a = this.getPosArrayOfChildren_AtObj(h, idx);
208 | return a[nth];
209 | };
210 |
211 | // ========== decendant methods ==============================
212 | /**
213 | * get string index of nth child object of ASN.1 object refered by h, idx
214 | * @name getDecendantIndexByNthList
215 | * @memberOf ASN1HEX
216 | * @function
217 | * @param {String} h hexadecimal string of ASN.1 DER encoded data
218 | * @param {Number} currentIndex start string index of ASN.1 object
219 | * @param {Array of Number} nthList array list of nth
220 | * @return {Number} string index refered by nthList
221 | * @since 1.1
222 | * @example
223 | * The "nthList" is a index list of structured ASN.1 object
224 | * reference. Here is a sample structure and "nthList"s which
225 | * refers each objects.
226 | *
227 | * SQUENCE -
228 | * SEQUENCE - [0]
229 | * IA5STRING 000 - [0, 0]
230 | * UTF8STRING 001 - [0, 1]
231 | * SET - [1]
232 | * IA5STRING 010 - [1, 0]
233 | * UTF8STRING 011 - [1, 1]
234 | */
235 | this.getDecendantIndexByNthList = function(h, currentIndex, nthList) {
236 | if (nthList.length == 0) {
237 | return currentIndex;
238 | }
239 | var firstNth = nthList.shift();
240 | var a = this.getPosArrayOfChildren_AtObj(h, currentIndex);
241 | return this.getDecendantIndexByNthList(h, a[firstNth], nthList);
242 | };
243 |
244 | /**
245 | * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
246 | * @name getDecendantHexTLVByNthList
247 | * @memberOf ASN1HEX
248 | * @function
249 | * @param {String} h hexadecimal string of ASN.1 DER encoded data
250 | * @param {Number} currentIndex start string index of ASN.1 object
251 | * @param {Array of Number} nthList array list of nth
252 | * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
253 | * @since 1.1
254 | */
255 | this.getDecendantHexTLVByNthList = function(h, currentIndex, nthList) {
256 | var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList);
257 | return this.getHexOfTLV_AtObj(h, idx);
258 | };
259 |
260 | /**
261 | * get hexadecimal string of ASN.1 V refered by current index and nth index list.
262 | * @name getDecendantHexVByNthList
263 | * @memberOf ASN1HEX
264 | * @function
265 | * @param {String} h hexadecimal string of ASN.1 DER encoded data
266 | * @param {Number} currentIndex start string index of ASN.1 object
267 | * @param {Array of Number} nthList array list of nth
268 | * @return {Number} hexadecimal string of ASN.1 V refered by nthList
269 | * @since 1.1
270 | */
271 | this.getDecendantHexVByNthList = function(h, currentIndex, nthList) {
272 | var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList);
273 | return this.getHexOfV_AtObj(h, idx);
274 | };
275 | };
276 |
277 | /*
278 | * @since asn1hex 1.1.4
279 | */
280 | ASN1HEX.getVbyList = function(h, currentIndex, nthList, checkingTag) {
281 | var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList);
282 | if (idx === undefined) {
283 | throw "can't find nthList object";
284 | }
285 | if (checkingTag !== undefined) {
286 | if (h.substr(idx, 2) != checkingTag) {
287 | throw "checking tag doesn't match: " +
288 | h.substr(idx,2) + "!=" + checkingTag;
289 | }
290 | }
291 | return this.getHexOfV_AtObj(h, idx);
292 | };
293 |
294 | /**
295 | * get OID string from hexadecimal encoded value
296 | * @name hextooidstr
297 | * @memberOf ASN1HEX
298 | * @function
299 | * @param {String} hex hexadecmal string of ASN.1 DER encoded OID value
300 | * @return {String} OID string (ex. '1.2.3.4.567')
301 | * @since asn1hex 1.1.5
302 | */
303 | ASN1HEX.hextooidstr = function(hex) {
304 | var zeroPadding = function(s, len) {
305 | if (s.length >= len) return s;
306 | return new Array(len - s.length + 1).join('0') + s;
307 | };
308 |
309 | var a = [];
310 |
311 | // a[0], a[1]
312 | var hex0 = hex.substr(0, 2);
313 | var i0 = parseInt(hex0, 16);
314 | a[0] = new String(Math.floor(i0 / 40));
315 | a[1] = new String(i0 % 40);
316 |
317 | // a[2]..a[n]
318 | var hex1 = hex.substr(2);
319 | var b = [];
320 | for (var i = 0; i < hex1.length / 2; i++) {
321 | b.push(parseInt(hex1.substr(i * 2, 2), 16));
322 | }
323 | var c = [];
324 | var cbin = "";
325 | for (var i = 0; i < b.length; i++) {
326 | if (b[i] & 0x80) {
327 | cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7);
328 | } else {
329 | cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7);
330 | c.push(new String(parseInt(cbin, 2)));
331 | cbin = "";
332 | }
333 | }
334 |
335 | var s = a.join(".");
336 | if (c.length > 0) s = s + "." + c.join(".");
337 | return s;
338 | };
339 |
--------------------------------------------------------------------------------
/rsa/x509-1.1.gs:
--------------------------------------------------------------------------------
1 | /*! x509-1.1.3.js (c) 2012-2014 Kenji Urushima | kjur.github.com/jsrsasign/license
2 | */
3 | /*
4 | * x509.js - X509 class to read subject public key from certificate.
5 | *
6 | * Copyright (c) 2010-2014 Kenji Urushima (kenji.urushima@gmail.com)
7 | *
8 | * This software is licensed under the terms of the MIT License.
9 | * http://kjur.github.com/jsrsasign/license
10 | *
11 | * The above copyright and license notice shall be
12 | * included in all copies or substantial portions of the Software.
13 | */
14 |
15 | /**
16 | * @fileOverview
17 | * @name x509-1.1.js
18 | * @author Kenji Urushima kenji.urushima@gmail.com
19 | * @version x509 1.1.3 (2014-May-17)
20 | * @since jsrsasign 1.x.x
21 | * @license MIT License
22 | */
23 |
24 | /*
25 | * Depends:
26 | * base64.js
27 | * rsa.js
28 | * asn1hex.js
29 | */
30 |
31 | /**
32 | * X.509 certificate class.
33 | * @class X.509 certificate class
34 | * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
35 | * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
36 | * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
37 | * @property {String} hex hexacedimal string for X.509 certificate.
38 | * @author Kenji Urushima
39 | * @version 1.0.1 (08 May 2012)
40 | * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/
41 | */
42 | function X509() {
43 | this.subjectPublicKeyRSA = null;
44 | this.subjectPublicKeyRSA_hN = null;
45 | this.subjectPublicKeyRSA_hE = null;
46 | this.hex = null;
47 |
48 | // ===== get basic fields from hex =====================================
49 |
50 | /**
51 | * get hexadecimal string of serialNumber field of certificate.
52 | * @name getSerialNumberHex
53 | * @memberOf X509#
54 | * @function
55 | */
56 | this.getSerialNumberHex = function() {
57 | return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
58 | };
59 |
60 | /**
61 | * get hexadecimal string of issuer field TLV of certificate.
62 | * @name getIssuerHex
63 | * @memberOf X509#
64 | * @function
65 | */
66 | this.getIssuerHex = function() {
67 | return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
68 | };
69 |
70 | /**
71 | * get string of issuer field of certificate.
72 | * @name getIssuerString
73 | * @memberOf X509#
74 | * @function
75 | */
76 | this.getIssuerString = function() {
77 | return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
78 | };
79 |
80 | /**
81 | * get hexadecimal string of subject field of certificate.
82 | * @name getSubjectHex
83 | * @memberOf X509#
84 | * @function
85 | */
86 | this.getSubjectHex = function() {
87 | return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
88 | };
89 |
90 | /**
91 | * get string of subject field of certificate.
92 | * @name getSubjectString
93 | * @memberOf X509#
94 | * @function
95 | */
96 | this.getSubjectString = function() {
97 | return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
98 | };
99 |
100 | /**
101 | * get notBefore field string of certificate.
102 | * @name getNotBefore
103 | * @memberOf X509#
104 | * @function
105 | */
106 | this.getNotBefore = function() {
107 | var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
108 | s = s.replace(/(..)/g, "%$1");
109 | s = decodeURIComponent(s);
110 | return s;
111 | };
112 |
113 | /**
114 | * get notAfter field string of certificate.
115 | * @name getNotAfter
116 | * @memberOf X509#
117 | * @function
118 | */
119 | this.getNotAfter = function() {
120 | var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
121 | s = s.replace(/(..)/g, "%$1");
122 | s = decodeURIComponent(s);
123 | return s;
124 | };
125 |
126 | // ===== read certificate public key ==========================
127 |
128 | // ===== read certificate =====================================
129 | /**
130 | * read PEM formatted X.509 certificate from string.
131 | * @name readCertPEM
132 | * @memberOf X509#
133 | * @function
134 | * @param {String} sCertPEM string for PEM formatted X.509 certificate
135 | */
136 | this.readCertPEM = function(sCertPEM) {
137 | var hCert = X509.pemToHex(sCertPEM);
138 | var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
139 | var rsa = new RSAKey();
140 | rsa.setPublic(a[0], a[1]);
141 | this.subjectPublicKeyRSA = rsa;
142 | this.subjectPublicKeyRSA_hN = a[0];
143 | this.subjectPublicKeyRSA_hE = a[1];
144 | this.hex = hCert;
145 | };
146 |
147 | this.readCertPEMWithoutRSAInit = function(sCertPEM) {
148 | var hCert = X509.pemToHex(sCertPEM);
149 | var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
150 | this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
151 | this.subjectPublicKeyRSA_hN = a[0];
152 | this.subjectPublicKeyRSA_hE = a[1];
153 | this.hex = hCert;
154 | };
155 | };
156 |
157 | X509.pemToBase64 = function(sCertPEM) {
158 | var s = sCertPEM;
159 | s = s.replace("-----BEGIN CERTIFICATE-----", "");
160 | s = s.replace("-----END CERTIFICATE-----", "");
161 | s = s.replace(/[ \n]+/g, "");
162 | return s;
163 | };
164 |
165 | X509.pemToHex = function(sCertPEM) {
166 | var b64Cert = X509.pemToBase64(sCertPEM);
167 | var hCert = b64tohex(b64Cert);
168 | return hCert;
169 | };
170 |
171 | // NOTE: Without BITSTRING encapsulation.
172 | X509.getSubjectPublicKeyPosFromCertHex = function(hCert) {
173 | var pInfo = X509.getSubjectPublicKeyInfoPosFromCertHex(hCert);
174 | if (pInfo == -1) return -1;
175 | var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
176 | if (a.length != 2) return -1;
177 | var pBitString = a[1];
178 | if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
179 | var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
180 |
181 | if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
182 | return pBitStringV + 2;
183 | };
184 |
185 | // NOTE: privateKeyUsagePeriod field of X509v2 not supported.
186 | // NOTE: v1 and v3 supported
187 | X509.getSubjectPublicKeyInfoPosFromCertHex = function(hCert) {
188 | var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
189 | var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
190 | if (a.length < 1) return -1;
191 | if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
192 | if (a.length < 6) return -1;
193 | return a[6];
194 | } else {
195 | if (a.length < 5) return -1;
196 | return a[5];
197 | }
198 | };
199 |
200 | X509.getPublicKeyHexArrayFromCertHex = function(hCert) {
201 | var p = X509.getSubjectPublicKeyPosFromCertHex(hCert);
202 | var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
203 | if (a.length != 2) return [];
204 | var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
205 | var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
206 | if (hN != null && hE != null) {
207 | return [hN, hE];
208 | } else {
209 | return [];
210 | }
211 | };
212 |
213 | X509.getHexTbsCertificateFromCert = function(hCert) {
214 | var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
215 | return pTbsCert;
216 | };
217 |
218 | X509.getPublicKeyHexArrayFromCertPEM = function(sCertPEM) {
219 | var hCert = X509.pemToHex(sCertPEM);
220 | var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
221 | return a;
222 | };
223 |
224 | X509.hex2dn = function(hDN) {
225 | var s = "";
226 | var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
227 | for (var i = 0; i < a.length; i++) {
228 | var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
229 | s = s + "/" + X509.hex2rdn(hRDN);
230 | }
231 | return s;
232 | };
233 |
234 | X509.hex2rdn = function(hRDN) {
235 | var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
236 | var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
237 | var type = "";
238 | try { type = X509.DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
239 | hValue = hValue.replace(/(..)/g, "%$1");
240 | var value = decodeURIComponent(hValue);
241 | return type + "=" + value;
242 | };
243 |
244 | X509.DN_ATTRHEX = {
245 | "0603550406": "C",
246 | "060355040a": "O",
247 | "060355040b": "OU",
248 | "0603550403": "CN",
249 | "0603550405": "SN",
250 | "0603550408": "ST",
251 | "0603550407": "L",
252 | };
253 |
254 | /**
255 | * get RSAKey/ECDSA public key object from PEM certificate string
256 | * @name getPublicKeyFromCertPEM
257 | * @memberOf X509
258 | * @function
259 | * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate
260 | * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key
261 | * @since x509 1.1.1
262 | * @description
263 | * NOTE: DSA is also supported since x509 1.1.2.
264 | */
265 | X509.getPublicKeyFromCertPEM = function(sCertPEM) {
266 | var info = X509.getPublicKeyInfoPropOfCertPEM(sCertPEM);
267 |
268 | if (info.algoid == "2a864886f70d010101") { // RSA
269 | var aRSA = KEYUTIL.parsePublicRawRSAKeyHex(info.keyhex);
270 | var key = new RSAKey();
271 | key.setPublic(aRSA.n, aRSA.e);
272 | return key;
273 | } else if (info.algoid == "2a8648ce3d0201") { // ECC
274 | var curveName = KJUR.crypto.OID.oidhex2name[info.algparam];
275 | var key = new KJUR.crypto.ECDSA({'curve': curveName, 'info': info.keyhex});
276 | key.setPublicKeyHex(info.keyhex);
277 | return key;
278 | } else if (info.algoid == "2a8648ce380401") { // DSA 1.2.840.10040.4.1
279 | var p = ASN1HEX.getVbyList(info.algparam, 0, [0], "02");
280 | var q = ASN1HEX.getVbyList(info.algparam, 0, [1], "02");
281 | var g = ASN1HEX.getVbyList(info.algparam, 0, [2], "02");
282 | var y = ASN1HEX.getHexOfV_AtObj(info.keyhex, 0);
283 | y = y.substr(2);
284 | var key = new KJUR.crypto.DSA();
285 | key.setPublic(new BigInteger(p, 16),
286 | new BigInteger(q, 16),
287 | new BigInteger(g, 16),
288 | new BigInteger(y, 16));
289 | return key;
290 | } else {
291 | throw "unsupported key";
292 | }
293 | };
294 |
295 | /**
296 | * get public key information from PEM certificate
297 | * @name getPublicKeyInfoPropOfCertPEM
298 | * @memberOf X509
299 | * @function
300 | * @param {String} sCertPEM string of PEM formatted certificate
301 | * @return {Hash} hash of information for public key
302 | * @since x509 1.1.1
303 | * @description
304 | * Resulted associative array has following properties:
305 | *
>(p+=this.DB-k);
195 | }
196 | else {
197 | d = (this[i]>>(p-=k))&km;
198 | if(p <= 0) { p += this.DB; --i; }
199 | }
200 | if(d > 0) m = true;
201 | if(m) r += int2char(d);
202 | }
203 | }
204 | return m?r:"0";
205 | }
206 |
207 | // (public) -this
208 | function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
209 |
210 | // (public) |this|
211 | function bnAbs() { return (this.s<0)?this.negate():this; }
212 |
213 | // (public) return + if this > a, - if this < a, 0 if equal
214 | function bnCompareTo(a) {
215 | var r = this.s-a.s;
216 | if(r != 0) return r;
217 | var i = this.t;
218 | r = i-a.t;
219 | if(r != 0) return (this.s<0)?-r:r;
220 | while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
221 | return 0;
222 | }
223 |
224 | // returns bit length of the integer x
225 | function nbits(x) {
226 | var r = 1, t;
227 | if((t=x>>>16) != 0) { x = t; r += 16; }
228 | if((t=x>>8) != 0) { x = t; r += 8; }
229 | if((t=x>>4) != 0) { x = t; r += 4; }
230 | if((t=x>>2) != 0) { x = t; r += 2; }
231 | if((t=x>>1) != 0) { x = t; r += 1; }
232 | return r;
233 | }
234 |
235 | // (public) return the number of bits in "this"
236 | function bnBitLength() {
237 | if(this.t <= 0) return 0;
238 | return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
239 | }
240 |
241 | // (protected) r = this << n*DB
242 | function bnpDLShiftTo(n,r) {
243 | var i;
244 | for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
245 | for(i = n-1; i >= 0; --i) r[i] = 0;
246 | r.t = this.t+n;
247 | r.s = this.s;
248 | }
249 |
250 | // (protected) r = this >> n*DB
251 | function bnpDRShiftTo(n,r) {
252 | for(var i = n; i < this.t; ++i) r[i-n] = this[i];
253 | r.t = Math.max(this.t-n,0);
254 | r.s = this.s;
255 | }
256 |
257 | // (protected) r = this << n
258 | function bnpLShiftTo(n,r) {
259 | var bs = n%this.DB;
260 | var cbs = this.DB-bs;
261 | var bm = (1< >(p+=this.DB-8);
123 | }
124 | else {
125 | d = (this[i]>>(p-=8))&0xff;
126 | if(p <= 0) { p += this.DB; --i; }
127 | }
128 | if((d&0x80) != 0) d |= -256;
129 | if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
130 | if(k > 0 || d != this.s) r[k++] = d;
131 | }
132 | }
133 | return r;
134 | }
135 |
136 | function bnEquals(a) { return(this.compareTo(a)==0); }
137 | function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
138 | function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
139 |
140 | // (protected) r = this op a (bitwise)
141 | function bnpBitwiseTo(a,op,r) {
142 | var i, f, m = Math.min(a.t,this.t);
143 | for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
144 | if(a.t < this.t) {
145 | f = a.s&this.DM;
146 | for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
147 | r.t = this.t;
148 | }
149 | else {
150 | f = this.s&this.DM;
151 | for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
152 | r.t = a.t;
153 | }
154 | r.s = op(this.s,a.s);
155 | r.clamp();
156 | }
157 |
158 | // (public) this & a
159 | function op_and(x,y) { return x&y; }
160 | function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
161 |
162 | // (public) this | a
163 | function op_or(x,y) { return x|y; }
164 | function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
165 |
166 | // (public) this ^ a
167 | function op_xor(x,y) { return x^y; }
168 | function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
169 |
170 | // (public) this & ~a
171 | function op_andnot(x,y) { return x&~y; }
172 | function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
173 |
174 | // (public) ~this
175 | function bnNot() {
176 | var r = nbi();
177 | for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
178 | r.t = this.t;
179 | r.s = ~this.s;
180 | return r;
181 | }
182 |
183 | // (public) this << n
184 | function bnShiftLeft(n) {
185 | var r = nbi();
186 | if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
187 | return r;
188 | }
189 |
190 | // (public) this >> n
191 | function bnShiftRight(n) {
192 | var r = nbi();
193 | if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
194 | return r;
195 | }
196 |
197 | // return index of lowest 1-bit in x, x < 2^31
198 | function lbit(x) {
199 | if(x == 0) return -1;
200 | var r = 0;
201 | if((x&0xffff) == 0) { x >>= 16; r += 16; }
202 | if((x&0xff) == 0) { x >>= 8; r += 8; }
203 | if((x&0xf) == 0) { x >>= 4; r += 4; }
204 | if((x&3) == 0) { x >>= 2; r += 2; }
205 | if((x&1) == 0) ++r;
206 | return r;
207 | }
208 |
209 | // (public) returns index of lowest 1-bit (or -1 if none)
210 | function bnGetLowestSetBit() {
211 | for(var i = 0; i < this.t; ++i)
212 | if(this[i] != 0) return i*this.DB+lbit(this[i]);
213 | if(this.s < 0) return this.t*this.DB;
214 | return -1;
215 | }
216 |
217 | // return number of 1 bits in x
218 | function cbit(x) {
219 | var r = 0;
220 | while(x != 0) { x &= x-1; ++r; }
221 | return r;
222 | }
223 |
224 | // (public) return number of set bits
225 | function bnBitCount() {
226 | var r = 0, x = this.s&this.DM;
227 | for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
228 | return r;
229 | }
230 |
231 | // (public) true iff nth bit is set
232 | function bnTestBit(n) {
233 | var j = Math.floor(n/this.DB);
234 | if(j >= this.t) return(this.s!=0);
235 | return((this[j]&(1<<(n%this.DB)))!=0);
236 | }
237 |
238 | // (protected) this op (1<
33 | * This namespace privides following crytpgrahic classes.
34 | * " + accCode + "
35 | *
39 | * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2.
40 | *
295 | * Currently this supports following algorithm and providers combination:
296 | *
297 | *
306 | * @example
307 | * // CryptoJS provider sample
308 | * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/core.js"></script>
309 | * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/sha1.js"></script>
310 | * <script src="crypto-1.0.js"></script>
311 | * var md = new KJUR.crypto.MessageDigest({alg: "sha1", prov: "cryptojs"});
312 | * md.updateString('aaa')
313 | * var mdHex = md.digest()
314 | *
315 | * // SJCL(Stanford JavaScript Crypto Library) provider sample
316 | * <script src="http://bitwiseshiftleft.github.io/sjcl/sjcl.js"></script>
317 | * <script src="crypto-1.0.js"></script>
318 | * var md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "sjcl"}); // sjcl supports sha256 only
319 | * md.updateString('aaa')
320 | * var mdHex = md.digest()
321 | */
322 | KJUR.crypto.MessageDigest = function(params) {
323 | var md = null;
324 | var algName = null;
325 | var provName = null;
326 |
327 | /**
328 | * set hash algorithm and provider
329 | * @name setAlgAndProvider
330 | * @memberOf KJUR.crypto.MessageDigest
331 | * @function
332 | * @param {String} alg hash algorithm name
333 | * @param {String} prov provider name
334 | * @description
335 | * @example
336 | * // for SHA1
337 | * md.setAlgAndProvider('sha1', 'cryptojs');
338 | * // for RIPEMD160
339 | * md.setAlgAndProvider('ripemd160', 'cryptojs');
340 | */
341 | this.setAlgAndProvider = function(alg, prov) {
342 | if (alg != null && prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg];
343 |
344 | // for cryptojs
345 | if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(alg) != -1 &&
346 | prov == 'cryptojs') {
347 | try {
348 | this.md = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[alg]).create();
349 | } catch (ex) {
350 | throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex;
351 | }
352 | this.updateString = function(str) {
353 | this.md.update(str);
354 | };
355 | this.updateHex = function(hex) {
356 | var wHex = CryptoJS.enc.Hex.parse(hex);
357 | this.md.update(wHex);
358 | };
359 | this.digest = function() {
360 | var hash = this.md.finalize();
361 | return hash.toString(CryptoJS.enc.Hex);
362 | };
363 | this.digestString = function(str) {
364 | this.updateString(str);
365 | return this.digest();
366 | };
367 | this.digestHex = function(hex) {
368 | this.updateHex(hex);
369 | return this.digest();
370 | };
371 | }
372 | if (':sha256:'.indexOf(alg) != -1 &&
373 | prov == 'sjcl') {
374 | try {
375 | this.md = new sjcl.hash.sha256();
376 | } catch (ex) {
377 | throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex;
378 | }
379 | this.updateString = function(str) {
380 | this.md.update(str);
381 | };
382 | this.updateHex = function(hex) {
383 | var baHex = sjcl.codec.hex.toBits(hex);
384 | this.md.update(baHex);
385 | };
386 | this.digest = function() {
387 | var hash = this.md.finalize();
388 | return sjcl.codec.hex.fromBits(hash);
389 | };
390 | this.digestString = function(str) {
391 | this.updateString(str);
392 | return this.digest();
393 | };
394 | this.digestHex = function(hex) {
395 | this.updateHex(hex);
396 | return this.digest();
397 | };
398 | }
399 | };
400 |
401 | /**
402 | * update digest by specified string
403 | * @name updateString
404 | * @memberOf KJUR.crypto.MessageDigest
405 | * @function
406 | * @param {String} str string to update
407 | * @description
408 | * @example
409 | * md.updateString('New York');
410 | */
411 | this.updateString = function(str) {
412 | throw "updateString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName;
413 | };
414 |
415 | /**
416 | * update digest by specified hexadecimal string
417 | * @name updateHex
418 | * @memberOf KJUR.crypto.MessageDigest
419 | * @function
420 | * @param {String} hex hexadecimal string to update
421 | * @description
422 | * @example
423 | * md.updateHex('0afe36');
424 | */
425 | this.updateHex = function(hex) {
426 | throw "updateHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName;
427 | };
428 |
429 | /**
430 | * completes hash calculation and returns hash result
431 | * @name digest
432 | * @memberOf KJUR.crypto.MessageDigest
433 | * @function
434 | * @description
435 | * @example
436 | * md.digest()
437 | */
438 | this.digest = function() {
439 | throw "digest() not supported for this alg/prov: " + this.algName + "/" + this.provName;
440 | };
441 |
442 | /**
443 | * performs final update on the digest using string, then completes the digest computation
444 | * @name digestString
445 | * @memberOf KJUR.crypto.MessageDigest
446 | * @function
447 | * @param {String} str string to final update
448 | * @description
449 | * @example
450 | * md.digestString('aaa')
451 | */
452 | this.digestString = function(str) {
453 | throw "digestString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName;
454 | };
455 |
456 | /**
457 | * performs final update on the digest using hexadecimal string, then completes the digest computation
458 | * @name digestHex
459 | * @memberOf KJUR.crypto.MessageDigest
460 | * @function
461 | * @param {String} hex hexadecimal string to final update
462 | * @description
463 | * @example
464 | * md.digestHex('0f2abd')
465 | */
466 | this.digestHex = function(hex) {
467 | throw "digestHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName;
468 | };
469 |
470 | if (params !== undefined) {
471 | if (params['alg'] !== undefined) {
472 | this.algName = params['alg'];
473 | if (params['prov'] === undefined)
474 | this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName];
475 | this.setAlgAndProvider(this.algName, this.provName);
476 | }
477 | }
478 | };
479 |
480 | /**
481 | * Mac(Message Authentication Code) class which is very similar to java.security.Mac class
482 | * @name KJUR.crypto.Mac
483 | * @class Mac class which is very similar to java.security.Mac class
484 | * @param {Array} params parameters for constructor
485 | * @description
486 | *
487 | * Currently this supports following algorithm and providers combination:
488 | *
489 | *
496 | * NOTE: HmacSHA224 and HmacSHA384 issue was fixed since jsrsasign 4.1.4.
497 | * Please use 'ext/cryptojs-312-core-fix*.js' instead of 'core.js' of original CryptoJS
498 | * to avoid those issue.
499 | * @example
500 | * var mac = new KJUR.crypto.Mac({alg: "HmacSHA1", prov: "cryptojs", "pass": "pass"});
501 | * mac.updateString('aaa')
502 | * var macHex = md.doFinal()
503 | */
504 | KJUR.crypto.Mac = function(params) {
505 | var mac = null;
506 | var pass = null;
507 | var algName = null;
508 | var provName = null;
509 | var algProv = null;
510 |
511 | this.setAlgAndProvider = function(alg, prov) {
512 | if (alg == null) alg = "hmacsha1";
513 |
514 | alg = alg.toLowerCase();
515 | if (alg.substr(0, 4) != "hmac") {
516 | throw "setAlgAndProvider unsupported HMAC alg: " + alg;
517 | }
518 |
519 | if (prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg];
520 | this.algProv = alg + "/" + prov;
521 |
522 | var hashAlg = alg.substr(4);
523 |
524 | // for cryptojs
525 | if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(hashAlg) != -1 &&
526 | prov == 'cryptojs') {
527 | try {
528 | var mdObj = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[hashAlg]);
529 | this.mac = CryptoJS.algo.HMAC.create(mdObj, this.pass);
530 | } catch (ex) {
531 | throw "setAlgAndProvider hash alg set fail hashAlg=" + hashAlg + "/" + ex;
532 | }
533 | this.updateString = function(str) {
534 | this.mac.update(str);
535 | };
536 | this.updateHex = function(hex) {
537 | var wHex = CryptoJS.enc.Hex.parse(hex);
538 | this.mac.update(wHex);
539 | };
540 | this.doFinal = function() {
541 | var hash = this.mac.finalize();
542 | return hash.toString(CryptoJS.enc.Hex);
543 | };
544 | this.doFinalString = function(str) {
545 | this.updateString(str);
546 | return this.doFinal();
547 | };
548 | this.doFinalHex = function(hex) {
549 | this.updateHex(hex);
550 | return this.doFinal();
551 | };
552 | }
553 | };
554 |
555 | /**
556 | * update digest by specified string
557 | * @name updateString
558 | * @memberOf KJUR.crypto.Mac
559 | * @function
560 | * @param {String} str string to update
561 | * @description
562 | * @example
563 | * md.updateString('New York');
564 | */
565 | this.updateString = function(str) {
566 | throw "updateString(str) not supported for this alg/prov: " + this.algProv;
567 | };
568 |
569 | /**
570 | * update digest by specified hexadecimal string
571 | * @name updateHex
572 | * @memberOf KJUR.crypto.Mac
573 | * @function
574 | * @param {String} hex hexadecimal string to update
575 | * @description
576 | * @example
577 | * md.updateHex('0afe36');
578 | */
579 | this.updateHex = function(hex) {
580 | throw "updateHex(hex) not supported for this alg/prov: " + this.algProv;
581 | };
582 |
583 | /**
584 | * completes hash calculation and returns hash result
585 | * @name doFinal
586 | * @memberOf KJUR.crypto.Mac
587 | * @function
588 | * @description
589 | * @example
590 | * md.digest()
591 | */
592 | this.doFinal = function() {
593 | throw "digest() not supported for this alg/prov: " + this.algProv;
594 | };
595 |
596 | /**
597 | * performs final update on the digest using string, then completes the digest computation
598 | * @name doFinalString
599 | * @memberOf KJUR.crypto.Mac
600 | * @function
601 | * @param {String} str string to final update
602 | * @description
603 | * @example
604 | * md.digestString('aaa')
605 | */
606 | this.doFinalString = function(str) {
607 | throw "digestString(str) not supported for this alg/prov: " + this.algProv;
608 | };
609 |
610 | /**
611 | * performs final update on the digest using hexadecimal string,
612 | * then completes the digest computation
613 | * @name doFinalHex
614 | * @memberOf KJUR.crypto.Mac
615 | * @function
616 | * @param {String} hex hexadecimal string to final update
617 | * @description
618 | * @example
619 | * md.digestHex('0f2abd')
620 | */
621 | this.doFinalHex = function(hex) {
622 | throw "digestHex(hex) not supported for this alg/prov: " + this.algProv;
623 | };
624 |
625 | if (params !== undefined) {
626 | if (params['pass'] !== undefined) {
627 | this.pass = params['pass'];
628 | }
629 | if (params['alg'] !== undefined) {
630 | this.algName = params['alg'];
631 | if (params['prov'] === undefined)
632 | this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName];
633 | this.setAlgAndProvider(this.algName, this.provName);
634 | }
635 | }
636 | };
637 |
638 | /**
639 | * Signature class which is very similar to java.security.Signature class
640 | * @name KJUR.crypto.Signature
641 | * @class Signature class which is very similar to java.security.Signature class
642 | * @param {Array} params parameters for constructor
643 | * @property {String} state Current state of this signature object whether 'SIGN', 'VERIFY' or null
644 | * @description
645 | *
646 | * As for params of constructor's argument, it can be specify following attributes:
647 | *
648 | *
651 | * SUPPORTED ALGORITHMS AND PROVIDERS
652 | * This Signature class supports following signature algorithm and provider names:
653 | *
654 | *
679 | * Here are supported elliptic cryptographic curve names and their aliases for ECDSA:
680 | *
681 | *
685 | * NOTE1: DSA signing algorithm is also supported since crypto 1.1.5.
686 | * EXAMPLES
687 | * @example
688 | * // RSA signature generation
689 | * var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA"});
690 | * sig.init(prvKeyPEM);
691 | * sig.updateString('aaa');
692 | * var hSigVal = sig.sign();
693 | *
694 | * // DSA signature validation
695 | * var sig2 = new KJUR.crypto.Signature({"alg": "SHA1withDSA"});
696 | * sig2.init(certPEM);
697 | * sig.updateString('aaa');
698 | * var isValid = sig2.verify(hSigVal);
699 | *
700 | * // ECDSA signing
701 | * var sig = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'});
702 | * sig.init(prvKeyPEM);
703 | * sig.updateString('aaa');
704 | * var sigValueHex = sig.sign();
705 | *
706 | * // ECDSA verifying
707 | * var sig2 = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'});
708 | * sig.init(certPEM);
709 | * sig.updateString('aaa');
710 | * var isValid = sig.verify(sigValueHex);
711 | */
712 | KJUR.crypto.Signature = function(params) {
713 | var prvKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for signing
714 | var pubKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for verifying
715 |
716 | var md = null; // KJUR.crypto.MessageDigest object
717 | var sig = null;
718 | var algName = null;
719 | var provName = null;
720 | var algProvName = null;
721 | var mdAlgName = null;
722 | var pubkeyAlgName = null; // rsa,ecdsa,rsaandmgf1(=rsapss)
723 | var state = null;
724 | var pssSaltLen = -1;
725 | var initParams = null;
726 |
727 | var sHashHex = null; // hex hash value for hex
728 | var hDigestInfo = null;
729 | var hPaddedDigestInfo = null;
730 | var hSign = null;
731 |
732 | this._setAlgNames = function() {
733 | if (this.algName.match(/^(.+)with(.+)$/)) {
734 | this.mdAlgName = RegExp.$1.toLowerCase();
735 | this.pubkeyAlgName = RegExp.$2.toLowerCase();
736 | }
737 | };
738 |
739 | this._zeroPaddingOfSignature = function(hex, bitLength) {
740 | var s = "";
741 | var nZero = bitLength / 4 - hex.length;
742 | for (var i = 0; i < nZero; i++) {
743 | s = s + "0";
744 | }
745 | return s + hex;
746 | };
747 |
748 | /**
749 | * set signature algorithm and provider
750 | * @name setAlgAndProvider
751 | * @memberOf KJUR.crypto.Signature
752 | * @function
753 | * @param {String} alg signature algorithm name
754 | * @param {String} prov provider name
755 | * @description
756 | * @example
757 | * md.setAlgAndProvider('SHA1withRSA', 'cryptojs/jsrsa');
758 | */
759 | this.setAlgAndProvider = function(alg, prov) {
760 | this._setAlgNames();
761 | if (prov != 'cryptojs/jsrsa')
762 | throw "provider not supported: " + prov;
763 |
764 | if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(this.mdAlgName) != -1) {
765 | try {
766 | this.md = new KJUR.crypto.MessageDigest({'alg':this.mdAlgName});
767 | } catch (ex) {
768 | throw "setAlgAndProvider hash alg set fail alg=" +
769 | this.mdAlgName + "/" + ex;
770 | }
771 |
772 | this.init = function(keyparam, pass) {
773 | var keyObj = null;
774 | try {
775 | if (pass === undefined) {
776 | keyObj = KEYUTIL.getKey(keyparam);
777 | } else {
778 | keyObj = KEYUTIL.getKey(keyparam, pass);
779 | }
780 | } catch (ex) {
781 | throw "init failed:" + ex;
782 | }
783 |
784 | if (keyObj.isPrivate === true) {
785 | this.prvKey = keyObj;
786 | this.state = "SIGN";
787 | } else if (keyObj.isPublic === true) {
788 | this.pubKey = keyObj;
789 | this.state = "VERIFY";
790 | } else {
791 | throw "init failed.:" + keyObj;
792 | }
793 | };
794 |
795 | this.initSign = function(params) {
796 | if (typeof params['ecprvhex'] == 'string' &&
797 | typeof params['eccurvename'] == 'string') {
798 | this.ecprvhex = params['ecprvhex'];
799 | this.eccurvename = params['eccurvename'];
800 | } else {
801 | this.prvKey = params;
802 | }
803 | this.state = "SIGN";
804 | };
805 |
806 | this.initVerifyByPublicKey = function(params) {
807 | if (typeof params['ecpubhex'] == 'string' &&
808 | typeof params['eccurvename'] == 'string') {
809 | this.ecpubhex = params['ecpubhex'];
810 | this.eccurvename = params['eccurvename'];
811 | } else if (params instanceof KJUR.crypto.ECDSA) {
812 | this.pubKey = params;
813 | } else if (params instanceof RSAKey) {
814 | this.pubKey = params;
815 | }
816 | this.state = "VERIFY";
817 | };
818 |
819 | this.initVerifyByCertificatePEM = function(certPEM) {
820 | var x509 = new X509();
821 | x509.readCertPEM(certPEM);
822 | this.pubKey = x509.subjectPublicKeyRSA;
823 | this.state = "VERIFY";
824 | };
825 |
826 | this.updateString = function(str) {
827 | this.md.updateString(str);
828 | };
829 | this.updateHex = function(hex) {
830 | this.md.updateHex(hex);
831 | };
832 |
833 | this.sign = function() {
834 | this.sHashHex = this.md.digest();
835 | if (typeof this.ecprvhex != "undefined" &&
836 | typeof this.eccurvename != "undefined") {
837 | var ec = new KJUR.crypto.ECDSA({'curve': this.eccurvename});
838 | this.hSign = ec.signHex(this.sHashHex, this.ecprvhex);
839 | } else if (this.pubkeyAlgName == "rsaandmgf1") {
840 | this.hSign = this.prvKey.signWithMessageHashPSS(this.sHashHex,
841 | this.mdAlgName,
842 | this.pssSaltLen);
843 | } else if (this.pubkeyAlgName == "rsa") {
844 | this.hSign = this.prvKey.signWithMessageHash(this.sHashHex,
845 | this.mdAlgName);
846 | } else if (this.prvKey instanceof KJUR.crypto.ECDSA) {
847 | this.hSign = this.prvKey.signWithMessageHash(this.sHashHex);
848 | } else if (this.prvKey instanceof KJUR.crypto.DSA) {
849 | this.hSign = this.prvKey.signWithMessageHash(this.sHashHex);
850 | } else {
851 | throw "Signature: unsupported public key alg: " + this.pubkeyAlgName;
852 | }
853 | return this.hSign;
854 | };
855 | this.signString = function(str) {
856 | this.updateString(str);
857 | return this.sign();
858 | };
859 | this.signHex = function(hex) {
860 | this.updateHex(hex);
861 | return this.sign();
862 | };
863 | this.verify = function(hSigVal) {
864 | this.sHashHex = this.md.digest();
865 | if (typeof this.ecpubhex != "undefined" &&
866 | typeof this.eccurvename != "undefined") {
867 | var ec = new KJUR.crypto.ECDSA({curve: this.eccurvename});
868 | return ec.verifyHex(this.sHashHex, hSigVal, this.ecpubhex);
869 | } else if (this.pubkeyAlgName == "rsaandmgf1") {
870 | return this.pubKey.verifyWithMessageHashPSS(this.sHashHex, hSigVal,
871 | this.mdAlgName,
872 | this.pssSaltLen);
873 | } else if (this.pubkeyAlgName == "rsa") {
874 | return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal);
875 | } else if (this.pubKey instanceof KJUR.crypto.ECDSA) {
876 | return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal);
877 | } else if (this.pubKey instanceof KJUR.crypto.DSA) {
878 | return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal);
879 | } else {
880 | throw "Signature: unsupported public key alg: " + this.pubkeyAlgName;
881 | }
882 | };
883 | }
884 | };
885 |
886 | /**
887 | * Initialize this object for signing or verifying depends on key
888 | * @name init
889 | * @memberOf KJUR.crypto.Signature
890 | * @function
891 | * @param {Object} key specifying public or private key as plain/encrypted PKCS#5/8 PEM file, certificate PEM or {@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA} object
892 | * @param {String} pass (OPTION) passcode for encrypted private key
893 | * @since crypto 1.1.3
894 | * @description
895 | * This method is very useful initialize method for Signature class since
896 | * you just specify key then this method will automatically initialize it
897 | * using {@link KEYUTIL.getKey} method.
898 | * As for 'key', following argument type are supported:
899 | * signing
900 | *
901 | *
909 | * verification
910 | *
911 | *
918 | * @example
919 | * sig.init(sCertPEM)
920 | */
921 | this.init = function(key, pass) {
922 | throw "init(key, pass) not supported for this alg:prov=" +
923 | this.algProvName;
924 | };
925 |
926 | /**
927 | * Initialize this object for verifying with a public key
928 | * @name initVerifyByPublicKey
929 | * @memberOf KJUR.crypto.Signature
930 | * @function
931 | * @param {Object} param RSAKey object of public key or associative array for ECDSA
932 | * @since 1.0.2
933 | * @deprecated from crypto 1.1.5. please use init() method instead.
934 | * @description
935 | * Public key information will be provided as 'param' parameter and the value will be
936 | * following:
937 | *
938 | *
943 | * @example
944 | * sig.initVerifyByPublicKey(rsaPrvKey)
945 | */
946 | this.initVerifyByPublicKey = function(rsaPubKey) {
947 | throw "initVerifyByPublicKey(rsaPubKeyy) not supported for this alg:prov=" +
948 | this.algProvName;
949 | };
950 |
951 | /**
952 | * Initialize this object for verifying with a certficate
953 | * @name initVerifyByCertificatePEM
954 | * @memberOf KJUR.crypto.Signature
955 | * @function
956 | * @param {String} certPEM PEM formatted string of certificate
957 | * @since 1.0.2
958 | * @deprecated from crypto 1.1.5. please use init() method instead.
959 | * @description
960 | * @example
961 | * sig.initVerifyByCertificatePEM(certPEM)
962 | */
963 | this.initVerifyByCertificatePEM = function(certPEM) {
964 | throw "initVerifyByCertificatePEM(certPEM) not supported for this alg:prov=" +
965 | this.algProvName;
966 | };
967 |
968 | /**
969 | * Initialize this object for signing
970 | * @name initSign
971 | * @memberOf KJUR.crypto.Signature
972 | * @function
973 | * @param {Object} param RSAKey object of public key or associative array for ECDSA
974 | * @deprecated from crypto 1.1.5. please use init() method instead.
975 | * @description
976 | * Private key information will be provided as 'param' parameter and the value will be
977 | * following:
978 | * {'ecpubhex': '041f..', 'eccurvename': 'secp256r1'})
941 | *
979 | *
983 | * @example
984 | * sig.initSign(prvKey)
985 | */
986 | this.initSign = function(prvKey) {
987 | throw "initSign(prvKey) not supported for this alg:prov=" + this.algProvName;
988 | };
989 |
990 | /**
991 | * Updates the data to be signed or verified by a string
992 | * @name updateString
993 | * @memberOf KJUR.crypto.Signature
994 | * @function
995 | * @param {String} str string to use for the update
996 | * @description
997 | * @example
998 | * sig.updateString('aaa')
999 | */
1000 | this.updateString = function(str) {
1001 | throw "updateString(str) not supported for this alg:prov=" + this.algProvName;
1002 | };
1003 |
1004 | /**
1005 | * Updates the data to be signed or verified by a hexadecimal string
1006 | * @name updateHex
1007 | * @memberOf KJUR.crypto.Signature
1008 | * @function
1009 | * @param {String} hex hexadecimal string to use for the update
1010 | * @description
1011 | * @example
1012 | * sig.updateHex('1f2f3f')
1013 | */
1014 | this.updateHex = function(hex) {
1015 | throw "updateHex(hex) not supported for this alg:prov=" + this.algProvName;
1016 | };
1017 |
1018 | /**
1019 | * Returns the signature bytes of all data updates as a hexadecimal string
1020 | * @name sign
1021 | * @memberOf KJUR.crypto.Signature
1022 | * @function
1023 | * @return the signature bytes as a hexadecimal string
1024 | * @description
1025 | * @example
1026 | * var hSigValue = sig.sign()
1027 | */
1028 | this.sign = function() {
1029 | throw "sign() not supported for this alg:prov=" + this.algProvName;
1030 | };
1031 |
1032 | /**
1033 | * performs final update on the sign using string, then returns the signature bytes of all data updates as a hexadecimal string
1034 | * @name signString
1035 | * @memberOf KJUR.crypto.Signature
1036 | * @function
1037 | * @param {String} str string to final update
1038 | * @return the signature bytes of a hexadecimal string
1039 | * @description
1040 | * @example
1041 | * var hSigValue = sig.signString('aaa')
1042 | */
1043 | this.signString = function(str) {
1044 | throw "digestString(str) not supported for this alg:prov=" + this.algProvName;
1045 | };
1046 |
1047 | /**
1048 | * performs final update on the sign using hexadecimal string, then returns the signature bytes of all data updates as a hexadecimal string
1049 | * @name signHex
1050 | * @memberOf KJUR.crypto.Signature
1051 | * @function
1052 | * @param {String} hex hexadecimal string to final update
1053 | * @return the signature bytes of a hexadecimal string
1054 | * @description
1055 | * @example
1056 | * var hSigValue = sig.signHex('1fdc33')
1057 | */
1058 | this.signHex = function(hex) {
1059 | throw "digestHex(hex) not supported for this alg:prov=" + this.algProvName;
1060 | };
1061 |
1062 | /**
1063 | * verifies the passed-in signature.
1064 | * @name verify
1065 | * @memberOf KJUR.crypto.Signature
1066 | * @function
1067 | * @param {String} str string to final update
1068 | * @return {Boolean} true if the signature was verified, otherwise false
1069 | * @description
1070 | * @example
1071 | * var isValid = sig.verify('1fbcefdca4823a7(snip)')
1072 | */
1073 | this.verify = function(hSigVal) {
1074 | throw "verify(hSigVal) not supported for this alg:prov=" + this.algProvName;
1075 | };
1076 |
1077 | this.initParams = params;
1078 |
1079 | if (params !== undefined) {
1080 | if (params['alg'] !== undefined) {
1081 | this.algName = params['alg'];
1082 | if (params['prov'] === undefined) {
1083 | this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName];
1084 | } else {
1085 | this.provName = params['prov'];
1086 | }
1087 | this.algProvName = this.algName + ":" + this.provName;
1088 | this.setAlgAndProvider(this.algName, this.provName);
1089 | this._setAlgNames();
1090 | }
1091 |
1092 | if (params['psssaltlen'] !== undefined) this.pssSaltLen = params['psssaltlen'];
1093 |
1094 | if (params['prvkeypem'] !== undefined) {
1095 | if (params['prvkeypas'] !== undefined) {
1096 | throw "both prvkeypem and prvkeypas parameters not supported";
1097 | } else {
1098 | try {
1099 | var prvKey = new RSAKey();
1100 | prvKey.readPrivateKeyFromPEMString(params['prvkeypem']);
1101 | this.initSign(prvKey);
1102 | } catch (ex) {
1103 | throw "fatal error to load pem private key: " + ex;
1104 | }
1105 | }
1106 | }
1107 | }
1108 | };
1109 |
1110 | /**
1111 | * static object for cryptographic function utilities
1112 | * @name KJUR.crypto.OID
1113 | * @class static object for cryptography related OIDs
1114 | * @property {Array} oidhex2name key value of hexadecimal OID and its name
1115 | * (ex. '2a8648ce3d030107' and 'secp256r1')
1116 | * @since crypto 1.1.3
1117 | * @description
1118 | */
1119 |
1120 |
1121 | KJUR.crypto.OID = new function() {
1122 | this.oidhex2name = {
1123 | '2a864886f70d010101': 'rsaEncryption',
1124 | '2a8648ce3d0201': 'ecPublicKey',
1125 | '2a8648ce380401': 'dsa',
1126 | '2a8648ce3d030107': 'secp256r1',
1127 | '2b8104001f': 'secp192k1',
1128 | '2b81040021': 'secp224r1',
1129 | '2b8104000a': 'secp256k1',
1130 | '2b81040023': 'secp521r1',
1131 | '2b81040022': 'secp384r1',
1132 | '2a8648ce380403': 'SHA1withDSA', // 1.2.840.10040.4.3
1133 | '608648016503040301': 'SHA224withDSA', // 2.16.840.1.101.3.4.3.1
1134 | '608648016503040302': 'SHA256withDSA', // 2.16.840.1.101.3.4.3.2
1135 | };
1136 | };
1137 |
--------------------------------------------------------------------------------
{'ecprvhex': '1d3f..', 'eccurvename': 'secp256r1'})