UNPKG

pomelo-client-node-ws

Version:
1,505 lines (1,366 loc) 71 kB
/* * RSA Encryption / Decryption with PKCS1 v2 Padding. * * Copyright (c) 2003-2005 Tom Wu * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * In addition, the following condition applies: * * All redistributions must retain an intact copy of this copyright notice * and disclaimer. */ var BigInteger = require("./jsbn.js"); var SecureRandom = require("./rng.js"); var B64 = require("./b64.js"); var ASN1HEX = require("./asn1hex-1.1.js"); // convert a (hex) string to a bignum object function parseBigInt(str, r) { return new BigInteger(str, r); } // display a string with max n characters per line // this is use to format the input for openssl function linebrk(buf, n) { var s = buf.toString('ascii'); var ret = ""; var i = 0; while (i + n < s.length) { ret += s.substring(i, i + n) + "\n"; i += n; } return ret + s.substring(i, s.length); } function byte2Hex(b) { if (b < 0x10) return "0" + b.toString(16); else return b.toString(16); } // PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint function pkcs1pad2(s, n) { if (n < s.length + 11) { // TODO: fix for utf-8 throw new Error("Message too long for RSA (n=" + n + ", l=" + s.length + ")"); return null; } var ba = new Array(); var i = s.length - 1; while (i >= 0 && n > 0) { var c = s.charCodeAt(i--); if (c < 128) { // encode using utf-8 ba[--n] = c; } else if ((c > 127) && (c < 2048)) { ba[--n] = (c & 63) | 128; ba[--n] = (c >> 6) | 192; } else { ba[--n] = (c & 63) | 128; ba[--n] = ((c >> 6) & 63) | 128; ba[--n] = (c >> 12) | 224; } } ba[--n] = 0; var rng = new SecureRandom(); var x = new Array(); while (n > 2) { // random non-zero pad x[0] = 0; while (x[0] == 0) rng.nextBytes(x); ba[--n] = x[0]; } ba[--n] = 2; ba[--n] = 0; return new BigInteger(ba); } // "empty" RSA key constructor function RSAKey() { this.n = null; this.e = 0; this.d = null; this.p = null; this.q = null; this.dmp1 = null; this.dmq1 = null; this.coeff = null; } // Set the public key fields N and e from hex strings function RSASetPublic(N, E) { if (N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N, 16); this.e = parseInt(E, 16); } else alert("Invalid RSA public key"); } // Perform raw public operation on "x": return x^e (mod n) function RSADoPublic(x) { return x.modPowInt(this.e, this.n); } // Return the PKCS#1 RSA encryption of "text" as an even-length hex string function RSAEncrypt(text) { var m = pkcs1pad2(text, (this.n.bitLength() + 7) >> 3); if (m == null) return null; var c = this.doPublic(m); if (c == null) return null; var h = c.toString(16); if ((h.length & 1) == 0) return h; else return "0" + h; } // Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string // function RSAEncryptB64(text) { // var h = this.encrypt(text); // if(h) return hex2b64(h); else return null; // } // Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext function pkcs1unpad2(d, n) { var b = d.toByteArray(); var i = 0; while (i < b.length && b[i] == 0) ++i; if (b.length - i != n - 1 || b[i] != 2) return null; ++i; while (b[i] != 0) if (++i >= b.length) return null; var ret = []; while (++i < b.length) { var c = b[i] & 255; ret.push(c); //This will need to be tested more, but Node doesn't like all of this! //if (c < 128) { // utf-8 decode //ret += String.fromCharCode(c); //} else if ((c > 191) && (c < 224)) { // ret += String.fromCharCode(((c & 31) << 6) | (b[i + 1] & 63)); // ++i; //} else { // ret += String.fromCharCode(((c & 15) << 12) // | ((b[i + 1] & 63) << 6) | (b[i + 2] & 63)); // i += 2; //} } return new Buffer(ret); } // Set the private key fields N, e, and d from hex strings function RSASetPrivate(N, E, D) { if (N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N, 16); this.e = parseInt(E, 16); this.d = parseBigInt(D, 16); } else alert("Invalid RSA private key"); } // Set the private key fields N, e, d and CRT params from hex strings function RSASetPrivateEx(N, E, D, P, Q, DP, DQ, C) { if (N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N, 16); this.e = parseInt(E, 16); this.d = parseBigInt(D, 16); this.p = parseBigInt(P, 16); this.q = parseBigInt(Q, 16); this.dmp1 = parseBigInt(DP, 16); this.dmq1 = parseBigInt(DQ, 16); this.coeff = parseBigInt(C, 16); } else alert("Invalid RSA private key"); } // Generate a new random private key B bits long, using public expt E function RSAGenerate(B, E) { var rng = new SecureRandom(); var qs = B >> 1; this.e = parseInt(E, 16); var ee = new BigInteger(E, 16); for (;;) { for (;;) { this.p = new BigInteger(B - qs, 1, rng); if (this.p.subtract(BigInteger.ONE).gcd(ee).compareTo( BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break; } for (;;) { this.q = new BigInteger(qs, 1, rng); if (this.q.subtract(BigInteger.ONE).gcd(ee).compareTo( BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break; } if (this.p.compareTo(this.q) <= 0) { var t = this.p; this.p = this.q; this.q = t; } var p1 = this.p.subtract(BigInteger.ONE); var q1 = this.q.subtract(BigInteger.ONE); var phi = p1.multiply(q1); if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { this.n = this.p.multiply(this.q); this.d = ee.modInverse(phi); this.dmp1 = this.d.mod(p1); this.dmq1 = this.d.mod(q1); this.coeff = this.q.modInverse(this.p); break; } } } // Perform raw private operation on "x": return x^d (mod n) function RSADoPrivate(x) { if (this.p == null || this.q == null) return x.modPow(this.d, this.n); // TODO: re-calculate any missing CRT params var xp = x.mod(this.p).modPow(this.dmp1, this.p); var xq = x.mod(this.q).modPow(this.dmq1, this.q); while (xp.compareTo(xq) < 0) xp = xp.add(this.p); return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq); } // Return the PKCS#1 RSA decryption of "ctext". // "ctext" is an even-length hex string and the output is a plain string. function RSADecrypt(ctext) { var c = parseBigInt(ctext, 16); var m = this.doPrivate(c); if (m == null) return null; return pkcs1unpad2(m, (this.n.bitLength() + 7) >> 3); } // Return the PKCS#1 RSA decryption of "ctext". // "ctext" is a Base64-encoded string and the output is a plain string. // function RSAB64Decrypt(ctext) { // var h = b64tohex(ctext); // if(h) return this.decrypt(h); else return null; // } // Added by @eschnou function baToString(b) { var ret = ""; for (var i = 0; i < b.length; i++) { var c = b[i] & 255; if (c < 128) { // utf-8 decode ret += String.fromCharCode(c); } else if ((c > 191) && (c < 224)) { ret += String.fromCharCode(((c & 31) << 6) | (b[i + 1] & 63)); ++i; } else { ret += String.fromCharCode(((c & 15) << 12) | ((b[i + 1] & 63) << 6) | (b[i + 2] & 63)); i += 2; } } return ret; } /*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license */ // // rsa-sign.js - adding signing functions to RSAKey class. // // // version: 1.2.1 (08 May 2012) // // Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com) // // This software is licensed under the terms of the MIT License. // http://kjur.github.com/jsrsasign/license/ // // The above copyright and license notice shall be // included in all copies or substantial portions of the Software. // // Depends on: // function sha1.hex(s) of sha1.js // jsbn.js // jsbn2.js // rsa.js // rsa2.js // // keysize / pmstrlen // 512 / 128 // 1024 / 256 // 2048 / 512 // 4096 / 1024 /** * @property {Dictionary} _RSASIGN_DIHEAD * @description Array of head part of hexadecimal DigestInfo value for hash algorithms. * You can add any DigestInfo hash algorith for signing. * See PKCS#1 v2.1 spec (p38). */ var _RSASIGN_DIHEAD = []; _RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414"; _RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420"; _RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430"; _RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440"; _RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410"; _RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410"; _RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414"; /** * @property {Dictionary} _RSASIGN_HASHHEXFUNC * @description Array of functions which calculate hash and returns it as hexadecimal. * You can add any hash algorithm implementations. */ /* var _RSASIGN_HASHHEXFUNC = []; _RSASIGN_HASHHEXFUNC['sha1'] = function(s){ var sha = crypto.createHash('sha1'); sha.update(s); var out = sha.digest('hex'); return out;}; _RSASIGN_HASHHEXFUNC['sha256'] = function(s){ var sha = crypto.createHash('sha256'); sha.update(s); var out = sha.digest('hex'); return out;}; _RSASIGN_HASHHEXFUNC['sha512'] = function(s){ var sha = crypto.createHash('sha512'); sha.update(s); var out = sha.digest('hex'); return out;}; _RSASIGN_HASHHEXFUNC['md5'] = function(s){ var sha = crypto.createHash('md5'); sha.update(s); var out = sha.digest('hex'); return out;}; _RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html */ var _RSASIGN_HASHHEXFUNC = []; _RSASIGN_HASHHEXFUNC['sha1'] = function (s) { return KJUR.crypto.Util.sha1(s); }; _RSASIGN_HASHHEXFUNC['sha256'] = function (s) { return KJUR.crypto.Util.sha256(s); } _RSASIGN_HASHHEXFUNC['sha512'] = function (s) { return KJUR.crypto.Util.sha512(s); } _RSASIGN_HASHHEXFUNC['md5'] = function (s) { return KJUR.crypto.Util.md5(s); }; _RSASIGN_HASHHEXFUNC['ripemd160'] = function (s) { return KJUR.crypto.Util.ripemd160(s); }; //_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html //_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html var _RE_HEXDECONLY = new RegExp(""); _RE_HEXDECONLY.compile("[^0-9a-f]", "gi"); // ======================================================================== // Signature Generation // ======================================================================== function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) { var pmStrLen = keySize / 4; var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg]; var sHashHex = hashFunc(s); var sHead = "0001"; var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex; var sMid = ""; var fLen = pmStrLen - sHead.length - sTail.length; for (var i = 0; i < fLen; i += 2) { sMid += "ff"; } sPaddedMessageHex = sHead + sMid + sTail; return sPaddedMessageHex; } function _zeroPaddingOfSignature(hex, bitLength) { var s = ""; var nZero = bitLength / 4 - hex.length; for (var i = 0; i < nZero; i++) { s = s + "0"; } return s + hex; } /** * sign for a message string with RSA private key.<br/> * @name signString * @memberOf RSAKey# * @function * @param {String} s message string to be signed. * @param {String} hashAlg hash algorithm name for signing.<br/> * @return returns hexadecimal string of signature value. */ function _rsasign_signString(s, hashAlg) { //alert("this.n.bitLength() = " + this.n.bitLength()); var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg); var biPaddedMessage = parseBigInt(hPM, 16); var biSign = this.doPrivate(biPaddedMessage); var hexSign = biSign.toString(16); return _zeroPaddingOfSignature(hexSign, this.n.bitLength()); } function _rsasign_signStringWithSHA1(s) { return _rsasign_signString(s, 'sha1'); } function _rsasign_signStringWithSHA256(s) { return _rsasign_signString(s, 'sha256'); } // ======================================================================== // Signature Verification // ======================================================================== function _rsasign_getDecryptSignatureBI(biSig, hN, hE) { var rsa = new RSAKey(); rsa.setPublic(hN, hE); var biDecryptedSig = rsa.doPublic(biSig); return biDecryptedSig; } function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) { var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE); var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); return hDigestInfo; } function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) { for (var algName in _RSASIGN_DIHEAD) { var head = _RSASIGN_DIHEAD[algName]; var len = head.length; if (hDigestInfo.substring(0, len) == head) { var a = [algName, hDigestInfo.substring(len)]; return a; } } return []; } function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) { var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE); var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); if (digestInfoAry.length == 0) return false; var algName = digestInfoAry[0]; var diHashValue = digestInfoAry[1]; var ff = _RSASIGN_HASHHEXFUNC[algName]; var msgHashValue = ff(sMsg); return (diHashValue == msgHashValue); } function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) { var biSig = parseBigInt(hSig, 16); var result = _rsasign_verifySignatureWithArgs(sMsg, biSig, this.n.toString(16), this.e.toString(16)); return result; } /** * verifies a sigature for a message string with RSA public key.<br/> * @name verifyString * @memberOf RSAKey# * @function * @param {String} sMsg message string to be verified. * @param {String} hSig hexadecimal string of siganture.<br/> * non-hexadecimal charactors including new lines will be ignored. * @return returns 1 if valid, otherwise 0 */ function _rsasign_verifyString(sMsg, hSig) { hSig = hSig.replace(_RE_HEXDECONLY, ''); if (hSig.length != Math.ceil(this.n.bitLength() / 4)) { return 0; } hSig = hSig.replace(/[ \n]+/g, ""); var biSig = parseBigInt(hSig, 16); var biDecryptedSig = this.doPublic(biSig); var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, ''); var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo); if (digestInfoAry.length == 0) return false; var algName = digestInfoAry[0]; var diHashValue = digestInfoAry[1]; var ff = _RSASIGN_HASHHEXFUNC[algName]; var msgHashValue = ff(sMsg); return (diHashValue == msgHashValue); } function _rsapem_pemToBase64(sPEMPrivateKey) { var s = sPEMPrivateKey; s = s.replace("-----BEGIN RSA PRIVATE KEY-----", ""); s = s.replace("-----END RSA PRIVATE KEY-----", ""); s = s.replace(/[ \n]+/g, ""); return s; } function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) { var a = new Array(); var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0); var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1); var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1); var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1); var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1); var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1); var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1); var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1); var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1); a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1); return a; } function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) { var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey); var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]); var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]); var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]); var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]); var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]); var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]); var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]); var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]); var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]); var a = new Array(); a.push(v, n, e, d, p, q, dp, dq, co); return a; } /** * read RSA private key from a ASN.1 hexadecimal string * @name readPrivateKeyFromASN1HexString * @memberOf RSAKey# * @function * @param {String} keyHex ASN.1 hexadecimal string of PKCS#1 private key. * @since 1.1.1 */ function _rsapem_readPrivateKeyFromASN1HexString(keyHex) { var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex); this.setPrivateEx(a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); } /** * read PKCS#1 private key from a string * @name readPrivateKeyFromPEMString * @memberOf RSAKey# * @function * @param {String} keyPEM string of PKCS#1 private key. */ function _rsapem_readPrivateKeyFromPEMString(keyPEM) { var keyB64 = _rsapem_pemToBase64(keyPEM); var keyHex = B64.b64tohex(keyB64) // depends base64.js var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex); this.setPrivateEx(a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); } // protected RSAKey.prototype.doPrivate = RSADoPrivate; RSAKey.prototype.doPublic = RSADoPublic; // public RSAKey.prototype.setPrivate = RSASetPrivate; RSAKey.prototype.setPrivateEx = RSASetPrivateEx; RSAKey.prototype.generate = RSAGenerate; RSAKey.prototype.decrypt = RSADecrypt; RSAKey.prototype.setPublic = RSASetPublic; RSAKey.prototype.encrypt = RSAEncrypt; // RSAKey.prototype.b64_decrypt = RSAB64Decrypt; // RSAKey.prototype.encrypt_b64 = RSAEncryptB64; RSAKey.prototype.signString = _rsasign_signString; RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1; RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256; RSAKey.prototype.sign = _rsasign_signString; RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1; RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256; RSAKey.prototype.verifyString = _rsasign_verifyString; RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage; RSAKey.prototype.verify = _rsasign_verifyString; RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage; RSAKey.prototype.linebrk = linebrk; RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString; RSAKey.prototype.readPrivateKeyFromASN1HexString = _rsapem_readPrivateKeyFromASN1HexString; // exports exports.Key = RSAKey; exports.BigInteger = BigInteger; exports.linebrk = linebrk; exports.byte2Hex = byte2Hex; exports.hex2b64 = B64.hex2b64; exports.b64tohex = B64.b64tohex; exports.b64toBA = B64.b64toBA; exports.batoString = baToString; /*! crypto-1.0.4.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license */ /* * crypto.js - Cryptographic Algorithm Provider class * * Copyright (c) 2013 Kenji Urushima (kenji.urushima@gmail.com) * * This software is licensed under the terms of the MIT License. * http://kjur.github.com/jsrsasign/license * * The above copyright and license notice shall be * included in all copies or substantial portions of the Software. */ /** * @fileOverview * @name crypto-1.0.js * @author Kenji Urushima kenji.urushima@gmail.com * @version 1.0.4 (2013-Mar-28) * @since 2.2 * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a> */ /** * kjur's class library name space * @name KJUR * @namespace kjur's class library name space */ if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; /** * kjur's cryptographic algorithm provider library name space * <p> * This namespace privides following crytpgrahic classes. * <ul> * <li>{@link KJUR.crypto.MessageDigest} - Java JCE(cryptograhic extension) style MessageDigest class</li> * <li>{@link KJUR.crypto.Signature} - Java JCE(cryptograhic extension) style Signature class</li> * <li>{@link KJUR.crypto.Util} - cryptographic utility functions and properties</li> * </ul> * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2. * </p> * @name KJUR.crypto * @namespace */ if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {}; /** * static object for cryptographic function utilities * @name KJUR.crypto.Util * @class static object for cryptographic function utilities * @property {Array} DIGESTINFOHEAD PKCS#1 DigestInfo heading hexadecimal bytes for each hash algorithms * @description */ KJUR.crypto.Util = new function () { this.DIGESTINFOHEAD = { 'sha1': "3021300906052b0e03021a05000414", 'sha224': "302d300d06096086480165030402040500041c", 'sha256': "3031300d060960864801650304020105000420", 'sha384': "3041300d060960864801650304020205000430", 'sha512': "3051300d060960864801650304020305000440", 'md2': "3020300c06082a864886f70d020205000410", 'md5': "3020300c06082a864886f70d020505000410", 'ripemd160': "3021300906052b2403020105000414" }; /** * get hexadecimal DigestInfo * @name getDigestInfoHex * @memberOf KJUR.crypto.Util * @function * @param {String} hHash hexadecimal hash value * @param {String} alg hash algorithm name (ex. 'sha1') * @return {String} hexadecimal string DigestInfo ASN.1 structure */ this.getDigestInfoHex = function (hHash, alg) { if (typeof this.DIGESTINFOHEAD[alg] == "undefined") throw "alg not supported in Util.DIGESTINFOHEAD: " + alg; return this.DIGESTINFOHEAD[alg] + hHash; }; /** * get PKCS#1 padded hexadecimal DigestInfo * @name getPaddedDigestInfoHex * @memberOf KJUR.crypto.Util * @function * @param {String} hHash hexadecimal hash value * @param {String} alg hash algorithm name (ex. 'sha1') * @param {Integer} keySize key bit length (ex. 1024) * @return {String} hexadecimal string of PKCS#1 padded DigestInfo */ this.getPaddedDigestInfoHex = function (hHash, alg, keySize) { var hDigestInfo = this.getDigestInfoHex(hHash, alg); var pmStrLen = keySize / 4; // minimum PM length if (hDigestInfo.length + 22 > pmStrLen) // len(0001+ff(*8)+00+hDigestInfo)=22 throw "key is too short for SigAlg: keylen=" + keySize + "," + alg; var hHead = "0001"; var hTail = "00" + hDigestInfo; var hMid = ""; var fLen = pmStrLen - hHead.length - hTail.length; for (var i = 0; i < fLen; i += 2) { hMid += "ff"; } var hPaddedMessage = hHead + hMid + hTail; return hPaddedMessage; }; /** * get hexadecimal SHA1 hash of string * @name sha1 * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @return {String} hexadecimal string of hash value * @since 1.0.3 */ this.sha1 = function (s) { var md = new KJUR.crypto.MessageDigest({ 'alg': 'sha1', 'prov': 'cryptojs' }); return md.digestString(s); }; /** * get hexadecimal SHA256 hash of string * @name sha256 * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @return {String} hexadecimal string of hash value * @since 1.0.3 */ this.sha256 = function (s) { var md = new KJUR.crypto.MessageDigest({ 'alg': 'sha256', 'prov': 'cryptojs' }); return md.digestString(s); }; /** * get hexadecimal SHA512 hash of string * @name sha512 * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @return {String} hexadecimal string of hash value * @since 1.0.3 */ this.sha512 = function (s) { var md = new KJUR.crypto.MessageDigest({ 'alg': 'sha512', 'prov': 'cryptojs' }); return md.digestString(s); }; /** * get hexadecimal MD5 hash of string * @name md5 * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @return {String} hexadecimal string of hash value * @since 1.0.3 */ this.md5 = function (s) { var md = new KJUR.crypto.MessageDigest({ 'alg': 'md5', 'prov': 'cryptojs' }); return md.digestString(s); }; /** * get hexadecimal RIPEMD160 hash of string * @name ripemd160 * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @return {String} hexadecimal string of hash value * @since 1.0.3 */ this.ripemd160 = function (s) { var md = new KJUR.crypto.MessageDigest({ 'alg': 'ripemd160', 'prov': 'cryptojs' }); return md.digestString(s); }; }; /** * MessageDigest class which is very similar to java.security.MessageDigest class * @name KJUR.crypto.MessageDigest * @class MessageDigest class which is very similar to java.security.MessageDigest class * @param {Array} params parameters for constructor * @description * <br/> * Currently this supports following algorithm and providers combination: * <ul> * <li>md5 - cryptojs</li> * <li>sha1 - cryptojs</li> * <li>sha224 - cryptojs</li> * <li>sha256 - cryptojs</li> * <li>sha384 - cryptojs</li> * <li>sha512 - cryptojs</li> * <li>ripemd160 - cryptojs</li> * <li>sha256 - sjcl (NEW from crypto.js 1.0.4)</li> * </ul> * @example * // CryptoJS provider sample * &lt;script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/core.js"&gt;&lt;/script&gt; * &lt;script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/sha1.js"&gt;&lt;/script&gt; * &lt;script src="crypto-1.0.js"&gt;&lt;/script&gt; * var md = new KJUR.crypto.MessageDigest({alg: "sha1", prov: "cryptojs"}); * md.updateString('aaa') * var mdHex = md.digest() * * // SJCL(Stanford JavaScript Crypto Library) provider sample * &lt;script src="http://bitwiseshiftleft.github.io/sjcl/sjcl.js"&gt;&lt;/script&gt; * &lt;script src="crypto-1.0.js"&gt;&lt;/script&gt; * var md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "sjcl"}); // sjcl supports sha256 only * md.updateString('aaa') * var mdHex = md.digest() */ KJUR.crypto.MessageDigest = function (params) { var md = null; var algName = null; var provName = null; var _CryptoJSMdName = { 'md5': 'CryptoJS.algo.MD5', 'sha1': 'CryptoJS.algo.SHA1', 'sha224': 'CryptoJS.algo.SHA224', 'sha256': 'CryptoJS.algo.SHA256', 'sha384': 'CryptoJS.algo.SHA384', 'sha512': 'CryptoJS.algo.SHA512', 'ripemd160': 'CryptoJS.algo.RIPEMD160' }; /** * set hash algorithm and provider * @name setAlgAndProvider * @memberOf KJUR.crypto.MessageDigest * @function * @param {String} alg hash algorithm name * @param {String} prov provider name * @description * @example * // for SHA1 * md.setAlgAndProvider('sha1', 'cryptojs'); * // for RIPEMD160 * md.setAlgAndProvider('ripemd160', 'cryptojs'); */ this.setAlgAndProvider = function (alg, prov) { if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(alg) != -1 && prov == 'cryptojs') { try { this.md = eval(_CryptoJSMdName[alg]).create(); } catch (ex) { throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; } this.updateString = function (str) { this.md.update(str); }; this.updateHex = function (hex) { var wHex = CryptoJS.enc.Hex.parse(hex); this.md.update(wHex); }; this.digest = function () { var hash = this.md.finalize(); return hash.toString(CryptoJS.enc.Hex); }; this.digestString = function (str) { this.updateString(str); return this.digest(); }; this.digestHex = function (hex) { this.updateHex(hex); return this.digest(); }; } if (':sha256:'.indexOf(alg) != -1 && prov == 'sjcl') { try { this.md = new sjcl.hash.sha256(); } catch (ex) { throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; } this.updateString = function (str) { this.md.update(str); }; this.updateHex = function (hex) { var baHex = sjcl.codec.hex.toBits(hex); this.md.update(baHex); }; this.digest = function () { var hash = this.md.finalize(); return sjcl.codec.hex.fromBits(hash); }; this.digestString = function (str) { this.updateString(str); return this.digest(); }; this.digestHex = function (hex) { this.updateHex(hex); return this.digest(); }; } }; /** * update digest by specified string * @name updateString * @memberOf KJUR.crypto.MessageDigest * @function * @param {String} str string to update * @description * @example * md.updateString('New York'); */ this.updateString = function (str) { throw "updateString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; }; /** * update digest by specified hexadecimal string * @name updateHex * @memberOf KJUR.crypto.MessageDigest * @function * @param {String} hex hexadecimal string to update * @description * @example * md.updateHex('0afe36'); */ this.updateHex = function (hex) { throw "updateHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; }; /** * completes hash calculation and returns hash result * @name digest * @memberOf KJUR.crypto.MessageDigest * @function * @description * @example * md.digest() */ this.digest = function () { throw "digest() not supported for this alg/prov: " + this.algName + "/" + this.provName; }; /** * performs final update on the digest using string, then completes the digest computation * @name digestString * @memberOf KJUR.crypto.MessageDigest * @function * @param {String} str string to final update * @description * @example * md.digestString('aaa') */ this.digestString = function (str) { throw "digestString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; }; /** * performs final update on the digest using hexadecimal string, then completes the digest computation * @name digestHex * @memberOf KJUR.crypto.MessageDigest * @function * @param {String} hex hexadecimal string to final update * @description * @example * md.digestHex('0f2abd') */ this.digestHex = function (hex) { throw "digestHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; }; if (typeof params != "undefined") { if (typeof params['alg'] != "undefined") { this.algName = params['alg']; this.provName = params['prov']; this.setAlgAndProvider(params['alg'], params['prov']); } } }; /** * Signature class which is very similar to java.security.Signature class * @name KJUR.crypto.Signature * @class Signature class which is very similar to java.security.Signature class * @param {Array} params parameters for constructor * @property {String} state Current state of this signature object whether 'SIGN', 'VERIFY' or null * @description * <br/> * As for params of constructor's argument, it can be specify following attributes: * <ul> * <li>alg - signature algorithm name (ex. {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160}withRSA)</li> * <li>provider - currently 'cryptojs/jsrsa' only</li> * <li>prvkeypem - PEM string of signer's private key. If this specified, no need to call initSign(prvKey).</li> * </ul> * <h4>SUPPORTED ALGORITHMS AND PROVIDERS</h4> * Signature class supports {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160} * withRSA algorithm in 'cryptojs/jsrsa' provider. * <h4>EXAMPLES</h4> * @example * // signature generation * var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA", "prov": "cryptojs/jsrsa"}); * sig.initSign(prvKey); * sig.updateString('aaa'); * var hSigVal = sig.sign(); * * // signature validation * var sig2 = new KJUR.crypto.Signature({"alg": "SHA1withRSA", "prov": "cryptojs/jsrsa"}); * sig2.initVerifyByCertificatePEM(cert) * sig.updateString('aaa'); * var isValid = sig2.verify(hSigVal); */ KJUR.crypto.Signature = function (params) { var prvKey = null; // RSAKey for signing var pubKey = null; // RSAKey for verifying var md = null; // KJUR.crypto.MessageDigest object var sig = null; var algName = null; var provName = null; var algProvName = null; var mdAlgName = null; var pubkeyAlgName = null; var state = null; var sHashHex = null; // hex hash value for hex var hDigestInfo = null; var hPaddedDigestInfo = null; var hSign = null; this._setAlgNames = function () { if (this.algName.match(/^(.+)with(.+)$/)) { this.mdAlgName = RegExp.$1.toLowerCase(); this.pubkeyAlgName = RegExp.$2.toLowerCase(); } }; this._zeroPaddingOfSignature = function (hex, bitLength) { var s = ""; var nZero = bitLength / 4 - hex.length; for (var i = 0; i < nZero; i++) { s = s + "0"; } return s + hex; }; /** * set signature algorithm and provider * @name setAlgAndProvider * @memberOf KJUR.crypto.Signature * @function * @param {String} alg signature algorithm name * @param {String} prov provider name * @description * @example * md.setAlgAndProvider('SHA1withRSA', 'cryptojs/jsrsa'); */ this.setAlgAndProvider = function (alg, prov) { this._setAlgNames(); if (prov != 'cryptojs/jsrsa') throw "provider not supported: " + prov; if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(this.mdAlgName) != -1) { try { this.md = new KJUR.crypto.MessageDigest({ 'alg': this.mdAlgName, 'prov': 'cryptojs' }); } catch (ex) { throw "setAlgAndProvider hash alg set fail alg=" + this.mdAlgName + "/" + ex; } this.initSign = function (prvKey) { this.prvKey = prvKey; this.state = "SIGN"; }; this.initVerifyByPublicKey = function (rsaPubKey) { this.pubKey = rsaPubKey; this.state = "VERIFY"; }; this.initVerifyByCertificatePEM = function (certPEM) { var x509 = new X509(); x509.readCertPEM(certPEM); this.pubKey = x509.subjectPublicKeyRSA; this.state = "VERIFY"; }; this.updateString = function (str) { this.md.updateString(str); }; this.updateHex = function (hex) { this.md.updateHex(hex); }; this.sign = function () { var util = KJUR.crypto.Util; var keyLen = this.prvKey.n.bitLength(); this.sHashHex = this.md.digest(); this.hDigestInfo = util.getDigestInfoHex(this.sHashHex, this.mdAlgName); this.hPaddedDigestInfo = util.getPaddedDigestInfoHex(this.sHashHex, this.mdAlgName, keyLen); var biPaddedDigestInfo = parseBigInt(this.hPaddedDigestInfo, 16); this.hoge = biPaddedDigestInfo.toString(16); var biSign = this.prvKey.doPrivate(biPaddedDigestInfo); this.hSign = this._zeroPaddingOfSignature(biSign.toString(16), keyLen); return this.hSign; }; this.signString = function (str) { this.updateString(str); this.sign(); }; this.signHex = function (hex) { this.updateHex(hex); this.sign(); }; this.verify = function (hSigVal) { var util = KJUR.crypto.Util; var keyLen = this.pubKey.n.bitLength(); this.sHashHex = this.md.digest(); var biSigVal = parseBigInt(hSigVal, 16); var biPaddedDigestInfo = this.pubKey.doPublic(biSigVal); this.hPaddedDigestInfo = biPaddedDigestInfo.toString(16); var s = this.hPaddedDigestInfo; s = s.replace(/^1ff+00/, ''); var hDIHEAD = KJUR.crypto.Util.DIGESTINFOHEAD[this.mdAlgName]; if (s.indexOf(hDIHEAD) != 0) { return false; } var hHashFromDI = s.substr(hDIHEAD.length); //alert(hHashFromDI + "\n" + this.sHashHex); return (hHashFromDI == this.sHashHex); }; } }; /** * Initialize this object for verifying with a public key * @name initVerifyByPublicKey * @memberOf KJUR.crypto.Signature * @function * @param {RSAKey} rsaPubKey RSAKey object of public key * @since 1.0.2 * @description * @example * sig.initVerifyByPublicKey(prvKey) */ this.initVerifyByPublicKey = function (rsaPubKey) { throw "initVerifyByPublicKey(rsaPubKeyy) not supported for this alg:prov=" + this.algProvName; }; /** * Initialize this object for verifying with a certficate * @name initVerifyByCertificatePEM * @memberOf KJUR.crypto.Signature * @function * @param {String} certPEM PEM formatted string of certificate * @since 1.0.2 * @description * @example * sig.initVerifyByCertificatePEM(certPEM) */ this.initVerifyByCertificatePEM = function (certPEM) { throw "initVerifyByCertificatePEM(certPEM) not supported for this alg:prov=" + this.algProvName; }; /** * Initialize this object for signing * @name initSign * @memberOf KJUR.crypto.Signature * @function * @param {RSAKey} prvKey RSAKey object of private key * @description * @example * sig.initSign(prvKey) */ this.initSign = function (prvKey) { throw "initSign(prvKey) not supported for this alg:prov=" + this.algProvName; }; /** * Updates the data to be signed or verified by a string * @name updateString * @memberOf KJUR.crypto.Signature * @function * @param {String} str string to use for the update * @description * @example * sig.updateString('aaa') */ this.updateString = function (str) { throw "updateString(str) not supported for this alg:prov=" + this.algProvName; }; /** * Updates the data to be signed or verified by a hexadecimal string * @name updateHex * @memberOf KJUR.crypto.Signature * @function * @param {String} hex hexadecimal string to use for the update * @description * @example * sig.updateHex('1f2f3f') */ this.updateHex = function (hex) { throw "updateHex(hex) not supported for this alg:prov=" + this.algProvName; }; /** * Returns the signature bytes of all data updates as a hexadecimal string * @name sign * @memberOf KJUR.crypto.Signature * @function * @return the signature bytes as a hexadecimal string * @description * @example * var hSigValue = sig.sign() */ this.sign = function () { throw "sign() not supported for this alg:prov=" + this.algProvName; }; /** * performs final update on the sign using string, then returns the signature bytes of all data updates as a hexadecimal string * @name signString * @memberOf KJUR.crypto.Signature * @function * @param {String} str string to final update * @return the signature bytes of a hexadecimal string * @description * @example * var hSigValue = sig.signString('aaa') */ this.signString = function (str) { throw "digestString(str) not supported for this alg:prov=" + this.algProvName; }; /** * performs final update on the sign using hexadecimal string, then returns the signature bytes of all data updates as a hexadecimal string * @name signHex * @memberOf KJUR.crypto.Signature * @function * @param {String} hex hexadecimal string to final update * @return the signature bytes of a hexadecimal string * @description * @example * var hSigValue = sig.signHex('1fdc33') */ this.signHex = function (hex) { throw "digestHex(hex) not supported for this alg:prov=" + this.algProvName; }; /** * verifies the passed-in signature. * @name verify * @memberOf KJUR.crypto.Signature * @function * @param {String} str string to final update * @return {Boolean} true if the signature was verified, otherwise false * @description * @example * var isValid = sig.verify('1fbcefdca4823a7(snip)') */ this.verify = function (hSigVal) { throw "verify(hSigVal) not supported for this alg:prov=" + this.algProvName; }; if (typeof params != "undefined") { if (typeof params['alg'] != "undefined") { this.algName = params['alg']; this.provName = params['prov']; this.algProvName = params['alg'] + ":" + params['prov']; this.setAlgAndProvider(params['alg'], params['prov']); this._setAlgNames(); } if (typeof params['prvkeypem'] != "undefined") { if (typeof params['prvkeypas'] != "undefined") { throw "both prvkeypem and prvkeypas parameters not supported"; } else { try { var prvKey = new RSAKey(); prvKey.readPrivateKeyFromPEMString(params['prvkeypem']); this.initSign(prvKey); } catch (ex) { throw "fatal error to load pem private key: " + ex; } } } } }; /* CryptoJS v3.1.2 code.google.com/p/crypto-js (c) 2009-2013 by Jeff Mott. All rights reserved. code.google.com/p/crypto-js/wiki/License */ /** * CryptoJS core components. */ var CryptoJS = CryptoJS || (function (Math, undefined) { /** * CryptoJS namespace. */ var C = {}; /** * Library namespace. */ var C_lib = C.lib = {}; /** * Base object for prototypal inheritance. */ var Base = C_lib.Base = (function () { function F() {} return { /** * Creates a new object that inherits from this object. * * @param {Object} overrides Properties to copy into the new object. * * @return {Object} The new object. * * @static * * @example * * var MyType = CryptoJS.lib.Base.extend({ * field: 'value', * * method: function () { * } * }); */ extend: function (overrides) { // Spawn F.prototype = this; var subtype = new F(); // Augment if (overrides) { subtype.mixIn(overrides); } // Create default initializer if (!subtype.hasOwnProperty('init')) { subtype.init = function () { subtype.$super.init.apply(this, arguments); }; } // Initializer's prototype is the subtype object subtype.init.prototype = subtype; // Reference supertype subtype.$super = this; return subtype; }, /** * Extends this object and runs the init method. * Arguments to create() will be passed to init(). * * @return {Object} The new object. * * @static * * @example * * var instance = MyType.create(); */ create: function () { var instance = this.extend(); instance.init.apply(instance, arguments); return instance; }, /** * Initializes a newly created object. * Override this method to add some logic when your objects are created. * * @example * * var MyType = CryptoJS.lib.Base.extend({ * init: function () { * // ... * } * }); */ init: function () {}, /** * Copies properties into this object. * * @param {Object} properties The properties to mix in. * * @example * * MyType.mixIn({ * field: 'value' * }); */ mixIn: function (properties) { for (var propertyName in properties) { if (properties.hasOwnProperty(propertyName)) { this[propertyName] = properties[propertyName]; } } // IE won't copy toString using the loop above if (properties.hasOwnProperty('toString')) { this.toString = properties.toString; } }, /** * Creates a copy of this object. * * @return {Object} The clone. * * @example * * var clone = instance.clone(); */ clone: function () { return this.init.prototype.extend(this); } }; }()); /** * An array of 32-bit words. * * @property {Array} words The array of 32-bit words. * @property {number} sigBytes The number of significant bytes in this word array. */ var WordArray = C_lib.WordArray = Base.extend({ /** * Initializes a newly created word array. * * @param {Array} words (Optional) An array of 32-bit words. * @param {number} sigBytes (Optional) The number of significant bytes in the words. * * @example * * var wordArray = CryptoJS.lib.WordArray.create(); * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); */ init: function (words, sigBytes) { words = this.words = words || []; if (sigBytes != undefined) {