├── .gitignore ├── .npmignore ├── Gemfile ├── Gemfile.lock ├── LICENSE.txt ├── README.md ├── _config.build.yml ├── _config.yml ├── _includes └── navbar.html ├── _layouts └── default.html ├── bin ├── jsencrypt.js └── jsencrypt.min.js ├── bower.json ├── declarations ├── lib │ ├── asn1js │ │ ├── asn1.d.ts │ │ ├── base64.d.ts │ │ ├── hex.d.ts │ │ └── int10.d.ts │ └── jsbn │ │ ├── base64.d.ts │ │ ├── jsbn.d.ts │ │ ├── prng4.d.ts │ │ ├── rng.d.ts │ │ ├── rsa.d.ts │ │ └── util.d.ts └── src │ ├── JSEncrypt.d.ts │ ├── JSEncryptRSAKey.d.ts │ └── index.d.ts ├── demo └── index.html ├── example.html ├── example_long.html ├── gulpfile.js ├── index.html ├── jquery.js ├── lib ├── asn1js │ ├── LICENSE.txt │ ├── asn1.ts │ ├── base64.ts │ ├── hex.ts │ ├── int10.ts │ └── oids.js ├── jsbn │ ├── LICENSE.txt │ ├── README.md │ ├── base64.ts │ ├── jsbn.ts │ ├── prng4.ts │ ├── rng.ts │ ├── rsa.ts │ └── util.ts └── jsrsasign │ ├── LICENSE.txt │ ├── asn1-1.0.d.ts │ ├── asn1-1.0.js │ └── yahoo.js ├── package.json ├── rollup.config.js ├── src ├── JSEncrypt.ts ├── JSEncryptRSAKey.ts ├── LICENSE.txt └── index.ts ├── stats.json ├── test ├── generate_test_keys.sh ├── index.html ├── libs │ ├── index.js │ ├── mocha.css │ └── mocha.js └── test.rsa.js ├── tsconfig.json ├── tslint.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .idea 3 | .DS_Store 4 | node_modules 5 | *.pem 6 | project.properties 7 | project.xml 8 | /nbproject/private/ 9 | 10 | src/*.js 11 | src/*.js.map 12 | 13 | lib/asn1js/*.js 14 | lib/asn1js/*.js.map 15 | !lib/asn1js/oids.js 16 | 17 | lib/jsbn/*.js 18 | lib/jsbn/*.js.map -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | _includes 2 | _layouts 3 | demo 4 | lib 5 | src 6 | test 7 | _config.build.yml 8 | _config.yml 9 | .gitignore 10 | bower.json 11 | example.html 12 | gulpfile.js 13 | index.html 14 | jquery.js 15 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'github-pages', group: :jekyll_plugins -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (4.2.9) 5 | i18n (~> 0.7) 6 | minitest (~> 5.1) 7 | thread_safe (~> 0.3, >= 0.3.4) 8 | tzinfo (~> 1.1) 9 | addressable (2.5.2) 10 | public_suffix (>= 2.0.2, < 4.0) 11 | coffee-script (2.4.1) 12 | coffee-script-source 13 | execjs 14 | coffee-script-source (1.11.1) 15 | colorator (1.1.0) 16 | commonmarker (0.17.9) 17 | ruby-enum (~> 0.5) 18 | concurrent-ruby (1.0.5) 19 | ethon (0.11.0) 20 | ffi (>= 1.3.0) 21 | execjs (2.7.0) 22 | faraday (0.14.0) 23 | multipart-post (>= 1.2, < 3) 24 | ffi (1.9.23) 25 | forwardable-extended (2.6.0) 26 | gemoji (3.0.0) 27 | github-pages (177) 28 | activesupport (= 4.2.9) 29 | github-pages-health-check (= 1.3.5) 30 | jekyll (= 3.6.2) 31 | jekyll-avatar (= 0.5.0) 32 | jekyll-coffeescript (= 1.0.2) 33 | jekyll-commonmark-ghpages (= 0.1.5) 34 | jekyll-default-layout (= 0.1.4) 35 | jekyll-feed (= 0.9.2) 36 | jekyll-gist (= 1.4.1) 37 | jekyll-github-metadata (= 2.9.3) 38 | jekyll-mentions (= 1.2.0) 39 | jekyll-optional-front-matter (= 0.3.0) 40 | jekyll-paginate (= 1.1.0) 41 | jekyll-readme-index (= 0.2.0) 42 | jekyll-redirect-from (= 0.12.1) 43 | jekyll-relative-links (= 0.5.2) 44 | jekyll-remote-theme (= 0.2.3) 45 | jekyll-sass-converter (= 1.5.0) 46 | jekyll-seo-tag (= 2.3.0) 47 | jekyll-sitemap (= 1.1.1) 48 | jekyll-swiss (= 0.4.0) 49 | jekyll-theme-architect (= 0.1.0) 50 | jekyll-theme-cayman (= 0.1.0) 51 | jekyll-theme-dinky (= 0.1.0) 52 | jekyll-theme-hacker (= 0.1.0) 53 | jekyll-theme-leap-day (= 0.1.0) 54 | jekyll-theme-merlot (= 0.1.0) 55 | jekyll-theme-midnight (= 0.1.0) 56 | jekyll-theme-minimal (= 0.1.0) 57 | jekyll-theme-modernist (= 0.1.0) 58 | jekyll-theme-primer (= 0.5.2) 59 | jekyll-theme-slate (= 0.1.0) 60 | jekyll-theme-tactile (= 0.1.0) 61 | jekyll-theme-time-machine (= 0.1.0) 62 | jekyll-titles-from-headings (= 0.5.0) 63 | jemoji (= 0.8.1) 64 | kramdown (= 1.16.2) 65 | liquid (= 4.0.0) 66 | listen (= 3.0.6) 67 | mercenary (~> 0.3) 68 | minima (= 2.1.1) 69 | nokogiri (>= 1.8.1, < 2.0) 70 | rouge (= 2.2.1) 71 | terminal-table (~> 1.4) 72 | github-pages-health-check (1.3.5) 73 | addressable (~> 2.3) 74 | net-dns (~> 0.8) 75 | octokit (~> 4.0) 76 | public_suffix (~> 2.0) 77 | typhoeus (~> 0.7) 78 | html-pipeline (2.7.1) 79 | activesupport (>= 2) 80 | nokogiri (>= 1.4) 81 | i18n (0.9.5) 82 | concurrent-ruby (~> 1.0) 83 | jekyll (3.6.2) 84 | addressable (~> 2.4) 85 | colorator (~> 1.0) 86 | jekyll-sass-converter (~> 1.0) 87 | jekyll-watch (~> 1.1) 88 | kramdown (~> 1.14) 89 | liquid (~> 4.0) 90 | mercenary (~> 0.3.3) 91 | pathutil (~> 0.9) 92 | rouge (>= 1.7, < 3) 93 | safe_yaml (~> 1.0) 94 | jekyll-avatar (0.5.0) 95 | jekyll (~> 3.0) 96 | jekyll-coffeescript (1.0.2) 97 | coffee-script (~> 2.2) 98 | coffee-script-source (~> 1.11.1) 99 | jekyll-commonmark (1.1.0) 100 | commonmarker (~> 0.14) 101 | jekyll (>= 3.0, < 4.0) 102 | jekyll-commonmark-ghpages (0.1.5) 103 | commonmarker (~> 0.17.6) 104 | jekyll-commonmark (~> 1) 105 | rouge (~> 2) 106 | jekyll-default-layout (0.1.4) 107 | jekyll (~> 3.0) 108 | jekyll-feed (0.9.2) 109 | jekyll (~> 3.3) 110 | jekyll-gist (1.4.1) 111 | octokit (~> 4.2) 112 | jekyll-github-metadata (2.9.3) 113 | jekyll (~> 3.1) 114 | octokit (~> 4.0, != 4.4.0) 115 | jekyll-mentions (1.2.0) 116 | activesupport (~> 4.0) 117 | html-pipeline (~> 2.3) 118 | jekyll (~> 3.0) 119 | jekyll-optional-front-matter (0.3.0) 120 | jekyll (~> 3.0) 121 | jekyll-paginate (1.1.0) 122 | jekyll-readme-index (0.2.0) 123 | jekyll (~> 3.0) 124 | jekyll-redirect-from (0.12.1) 125 | jekyll (~> 3.3) 126 | jekyll-relative-links (0.5.2) 127 | jekyll (~> 3.3) 128 | jekyll-remote-theme (0.2.3) 129 | jekyll (~> 3.5) 130 | rubyzip (>= 1.2.1, < 3.0) 131 | typhoeus (>= 0.7, < 2.0) 132 | jekyll-sass-converter (1.5.0) 133 | sass (~> 3.4) 134 | jekyll-seo-tag (2.3.0) 135 | jekyll (~> 3.3) 136 | jekyll-sitemap (1.1.1) 137 | jekyll (~> 3.3) 138 | jekyll-swiss (0.4.0) 139 | jekyll-theme-architect (0.1.0) 140 | jekyll (~> 3.5) 141 | jekyll-seo-tag (~> 2.0) 142 | jekyll-theme-cayman (0.1.0) 143 | jekyll (~> 3.5) 144 | jekyll-seo-tag (~> 2.0) 145 | jekyll-theme-dinky (0.1.0) 146 | jekyll (~> 3.5) 147 | jekyll-seo-tag (~> 2.0) 148 | jekyll-theme-hacker (0.1.0) 149 | jekyll (~> 3.5) 150 | jekyll-seo-tag (~> 2.0) 151 | jekyll-theme-leap-day (0.1.0) 152 | jekyll (~> 3.5) 153 | jekyll-seo-tag (~> 2.0) 154 | jekyll-theme-merlot (0.1.0) 155 | jekyll (~> 3.5) 156 | jekyll-seo-tag (~> 2.0) 157 | jekyll-theme-midnight (0.1.0) 158 | jekyll (~> 3.5) 159 | jekyll-seo-tag (~> 2.0) 160 | jekyll-theme-minimal (0.1.0) 161 | jekyll (~> 3.5) 162 | jekyll-seo-tag (~> 2.0) 163 | jekyll-theme-modernist (0.1.0) 164 | jekyll (~> 3.5) 165 | jekyll-seo-tag (~> 2.0) 166 | jekyll-theme-primer (0.5.2) 167 | jekyll (~> 3.5) 168 | jekyll-github-metadata (~> 2.9) 169 | jekyll-seo-tag (~> 2.2) 170 | jekyll-theme-slate (0.1.0) 171 | jekyll (~> 3.5) 172 | jekyll-seo-tag (~> 2.0) 173 | jekyll-theme-tactile (0.1.0) 174 | jekyll (~> 3.5) 175 | jekyll-seo-tag (~> 2.0) 176 | jekyll-theme-time-machine (0.1.0) 177 | jekyll (~> 3.5) 178 | jekyll-seo-tag (~> 2.0) 179 | jekyll-titles-from-headings (0.5.0) 180 | jekyll (~> 3.3) 181 | jekyll-watch (1.5.1) 182 | listen (~> 3.0) 183 | jemoji (0.8.1) 184 | activesupport (~> 4.0, >= 4.2.9) 185 | gemoji (~> 3.0) 186 | html-pipeline (~> 2.2) 187 | jekyll (>= 3.0) 188 | kramdown (1.16.2) 189 | liquid (4.0.0) 190 | listen (3.0.6) 191 | rb-fsevent (>= 0.9.3) 192 | rb-inotify (>= 0.9.7) 193 | mercenary (0.3.6) 194 | mini_portile2 (2.3.0) 195 | minima (2.1.1) 196 | jekyll (~> 3.3) 197 | minitest (5.11.3) 198 | multipart-post (2.0.0) 199 | net-dns (0.8.0) 200 | nokogiri (1.8.2) 201 | mini_portile2 (~> 2.3.0) 202 | octokit (4.8.0) 203 | sawyer (~> 0.8.0, >= 0.5.3) 204 | pathutil (0.16.1) 205 | forwardable-extended (~> 2.6) 206 | public_suffix (2.0.5) 207 | rb-fsevent (0.10.3) 208 | rb-inotify (0.9.10) 209 | ffi (>= 0.5.0, < 2) 210 | rouge (2.2.1) 211 | ruby-enum (0.7.2) 212 | i18n 213 | rubyzip (1.2.1) 214 | safe_yaml (1.0.4) 215 | sass (3.5.5) 216 | sass-listen (~> 4.0.0) 217 | sass-listen (4.0.0) 218 | rb-fsevent (~> 0.9, >= 0.9.4) 219 | rb-inotify (~> 0.9, >= 0.9.7) 220 | sawyer (0.8.1) 221 | addressable (>= 2.3.5, < 2.6) 222 | faraday (~> 0.8, < 1.0) 223 | terminal-table (1.8.0) 224 | unicode-display_width (~> 1.1, >= 1.1.1) 225 | thread_safe (0.3.6) 226 | typhoeus (0.8.0) 227 | ethon (>= 0.8.0) 228 | tzinfo (1.2.5) 229 | thread_safe (~> 0.1) 230 | unicode-display_width (1.3.0) 231 | 232 | PLATFORMS 233 | ruby 234 | 235 | DEPENDENCIES 236 | github-pages 237 | 238 | BUNDLED WITH 239 | 1.16.2 240 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | File: /src/LICENSE.txt 2 | The MIT License (MIT) 3 | Copyright (c) 2015 Form.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in the 7 | Software without restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 9 | Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 16 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 17 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 18 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | File: /lib/jsrsasign/LICENSE.txt 23 | 24 | 25 | CONTAINS CODE FROM YUI LIBRARY SEE LICENSE @ http://yuilibrary.com/license/ 26 | 27 | The 'jsrsasign'(RSA-Sign JavaScript Library) License 28 | 29 | Copyright (c) 2010-2013 Kenji Urushima 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining a copy 32 | of this software and associated documentation files (the "Software"), to deal 33 | in the Software without restriction, including without limitation the rights 34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35 | copies of the Software, and to permit persons to whom the Software is 36 | furnished to do so, subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be included in 39 | all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 42 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 43 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 44 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 45 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 46 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 47 | THE SOFTWARE. 48 | File: /lib/jsbn/LICENSE.txt 49 | 50 | 51 | Licensing 52 | --------- 53 | 54 | This software is covered under the following copyright: 55 | 56 | /* 57 | * Copyright (c) 2003-2005 Tom Wu 58 | * All Rights Reserved. 59 | * 60 | * Permission is hereby granted, free of charge, to any person obtaining 61 | * a copy of this software and associated documentation files (the 62 | * "Software"), to deal in the Software without restriction, including 63 | * without limitation the rights to use, copy, modify, merge, publish, 64 | * distribute, sublicense, and/or sell copies of the Software, and to 65 | * permit persons to whom the Software is furnished to do so, subject to 66 | * the following conditions: 67 | * 68 | * The above copyright notice and this permission notice shall be 69 | * included in all copies or substantial portions of the Software. 70 | * 71 | * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 72 | * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 73 | * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 74 | * 75 | * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, 76 | * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER 77 | * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF 78 | * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT 79 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 80 | * 81 | * In addition, the following condition applies: 82 | * 83 | * All redistributions must retain an intact copy of this copyright notice 84 | * and disclaimer. 85 | */ 86 | 87 | Address all questions regarding this license to: 88 | 89 | Tom Wu 90 | tjw@cs.Stanford.EDU 91 | File: /lib/asn1js/LICENSE.txt 92 | 93 | 94 | ASN.1 JavaScript decoder 95 | Copyright (c) 2008-2013 Lapo Luchini 96 | 97 | Permission to use, copy, modify, and/or distribute this software for any 98 | purpose with or without fee is hereby granted, provided that the above 99 | copyright notice and this permission notice appear in all copies. 100 | 101 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 102 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 103 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 104 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 105 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 106 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 107 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # encryptlong 2 | 3 | # 原版官方网站 4 | 5 | http://travistidwell.com/jsencrypt 6 | 7 | # 介绍 8 | 9 | 基于 jsencrypt 扩展长文本分段加解密功能 10 | 11 | npm 安装: 12 | 13 | ```bash 14 | npm i encryptlong -S 15 | ``` 16 | 17 | 浏览器使用: 18 | 19 | ```html 20 | 21 | ``` 22 | 23 | # 基本使用 24 | 25 | > 注意:使用长文本加密时最好公私钥都要设置,避免有概率加密失败 26 | 27 | 这里只扩展了长文本的分段加解密,其它 api 请查看官网 http://travistidwell.com/jsencrypt 28 | 29 | - `encryptLong()` 长文本加密 30 | - `decryptLong()` 长文本解密 31 | 32 | ```js 33 | let startTime = new Date(); 34 | //公钥 35 | const PUBLIC_KEY = ` 36 | -----BEGIN PUBLIC KEY----- 37 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKX1Fs2JUD25zrAEwPnjnZC0az 38 | rl1XjGzGrJ64eb1lr9QVVOO2zGKZdqDLZD4Ut4Mp6GHMaqqFXKm+zN7IAXu+mqZb 39 | UrqUziHE5YGC02wObiZEzfa6V9a8ZvqpB+Z8KO+hAkkjzjMl+E+hDORpZmez3SMz 40 | etn7mcCeLw8/vmxz3QIDAQAB 41 | -----END PUBLIC KEY-----`; 42 | //私钥 43 | const PRIVATE_KEY = ` 44 | -----BEGIN PUBLIC KEY----- 45 | MIICXgIBAAKBgQDKX1Fs2JUD25zrAEwPnjnZC0azrl1XjGzGrJ64eb1lr9QVVOO2 46 | zGKZdqDLZD4Ut4Mp6GHMaqqFXKm+zN7IAXu+mqZbUrqUziHE5YGC02wObiZEzfa6 47 | V9a8ZvqpB+Z8KO+hAkkjzjMl+E+hDORpZmez3SMzetn7mcCeLw8/vmxz3QIDAQAB 48 | AoGBAJBr6b4V6nJwXdHPyngy4PGl/HTqcK60BkTamALqzmEtU9tNU5z2yz7dy+6a 49 | wTsjo7Vao8CwNrUp5fHGXw65EEc1/3Iu2Fiix0XF7RP4NFSoxbBmzQW1nUK/5DFi 50 | 4VR1uhEmdbgLwGabsdqzeUqhRKkRGAPVCotBjaDBOu0J3Mu5AkEA+SM7Ctu7evOv 51 | ZwjWrp9a5MGxJ9yLLabbIuWL+420jr2G6ojaTZ2ROA2DWWQPx4JqWxDHttomrb38 52 | dk2emP2WAwJBAM/yU58YRQ+dTeuTzNYC1JdWcs35n9+hoVP7y+x29CmcqDTPp3nR 53 | Bbbq88yMb2nZdlwthWi7BurNHsRJFqj0GJ8CQF5gJCuW1UxcJ2PGi1yW7R2e6fcJ 54 | qoden8B2aDKgmXdBAGyz7s5cE/jB1bH1H60aECPzFVSFCwXh5FMEUEHwPfUCQQC7 55 | JqZ57lbhebrSRcA58GwzFFvY40wu8gIHWvwqgti2xsZgWW+qZCPXf9gSBWaUhmJP 56 | Da0fGAxesGN7VyhswNuTAkEAzCFNqL/zwHXcwh9YyHTdk/bRWIJq49jTA+vbgGv0 57 | szKIvGRKoRbub3NEUiI80TDsCAvbJ6R80J7RjnpmShOwcA== 58 | -----END PUBLIC KEY-----`; 59 | 60 | // 使用设置公私钥 61 | const enc = new JSEncrypt(); 62 | enc.setPublicKey(PUBLIC_KEY); 63 | enc.setPublicKey(PRIVATE_KEY); 64 | 65 | // 一段长文本json 66 | let data = { 67 | code: 200, 68 | result: { 69 | timestamp: 1572321851823, 70 | inter1: ["123123123", "123123123", "123123123", "123123123", "123123123"], 71 | inter2: ["123123123", "123123123", "123123123", "123123123", "123123123"], 72 | inter3: ["123123123", "123123123", "123123123", "123123123", "123123123"], 73 | inter4: ["123123123", "123123123", "123123123", "123123123", "123123123"], 74 | inter5: ["123123123", "123123123", "123123123", "123123123", "123123123"], 75 | inter6: ["123123123", "123123123", "123123123", "123123123", "123123123"], 76 | stream: {}, 77 | caton: {}, 78 | card: [] 79 | } 80 | }; 81 | data = JSON.stringify(data); 82 | let encrypted = enc.encryptLong(data); 83 | let endTime = new Date(); 84 | console.log("加密后数据:%o", encrypted); 85 | console.log("加密时间" + (endTime - startTime) + "ms"); 86 | //使用私钥解密 87 | let uncrypted = enc.decryptLong(encrypted); 88 | console.log("解密后数据:%o", uncrypted); 89 | ``` 90 | 91 | # 其它使用 92 | 93 | 这个库应该与 openssl 一起使用 94 | 95 | - 在终端(基于 Unix 的操作系统) 96 | 97 | ```bash 98 | openssl genrsa -out rsa_1024_priv.pem 1024 99 | ``` 100 | 101 | - 会生成一个私钥,您可以通过执行以下操作查看 102 | 103 | ```bash 104 | cat rsa_1024_priv.pem 105 | ``` 106 | 107 | - 然后,您可以将其复制到 index.html 内的私钥处 108 | - 接下来,您可以通过执行以下命令来获取公钥 109 | 110 | ```bash 111 | openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem 112 | ``` 113 | 114 | - 查看公钥 115 | 116 | ```bash 117 | cat rsa_1024_pub.pem 118 | ``` 119 | 120 | - 将其复制到 index.html 中的 Public 键中 121 | - 现在,您可以通过在代码中执行以下操作来转换加密解密文本转换 122 | 123 | ```html 124 | 125 | 126 | 127 | 128 | 使用jsencrypt执行长文本加密,解密 129 | 130 | 131 | 132 |
长文本加解密
133 | 134 | 135 | 136 | 194 | 195 | ``` 196 | 197 | - 您必须提供哈希函数。在本例中,我们使用的是[CryptoJS](<[CryptoJS](https://github.com/brix/crypto-js)>)库 198 | - 此外,除非使用自定义散列函数,否则应该为`sign`方法提供散列类型。可能的值有:`md2`, `md5`, `sha1`, `sha224`, `sha256`, `sha384`, `sha512`, `ripemd160`. 199 | 200 | # 其它信息 201 | 202 | ## Base64 格式的 1024 位 RSA 私钥 203 | 204 | ```txt 205 | -----BEGIN RSA PRIVATE KEY----- 206 | MIICXgIBAAKBgQDHikastc8+I81zCg/qWW8dMr8mqvXQ3qbPAmu0RjxoZVI47tvs 207 | kYlFAXOf0sPrhO2nUuooJngnHV0639iTTEYG1vckNaW2R6U5QTdQ5Rq5u+uV3pMk 208 | 7w7Vs4n3urQ6jnqt2rTXbC1DNa/PFeAZatbf7ffBBy0IGO0zc128IshYcwIDAQAB 209 | AoGBALTNl2JxTvq4SDW/3VH0fZkQXWH1MM10oeMbB2qO5beWb11FGaOO77nGKfWc 210 | bYgfp5Ogrql4yhBvLAXnxH8bcqqwORtFhlyV68U1y4R+8WxDNh0aevxH8hRS/1X5 211 | 031DJm1JlU0E+vStiktN0tC3ebH5hE+1OxbIHSZ+WOWLYX7JAkEA5uigRgKp8ScG 212 | auUijvdOLZIhHWq7y5Wz+nOHUuDw8P7wOTKU34QJAoWEe771p9Pf/GTA/kr0BQnP 213 | QvWUDxGzJwJBAN05C6krwPeryFKrKtjOGJIniIoY72wRnoNcdEEs3HDRhf48YWFo 214 | riRbZylzzzNFy/gmzT6XJQTfktGqq+FZD9UCQGIJaGrxHJgfmpDuAhMzGsUsYtTr 215 | iRox0D1Iqa7dhE693t5aBG010OF6MLqdZA1CXrn5SRtuVVaCSLZEL/2J5UcCQQDA 216 | d3MXucNnN4NPuS/L9HMYJWD7lPoosaORcgyK77bSSNgk+u9WSjbH1uYIAIPSffUZ 217 | bti+jc1dUg5wb+aeZlgJAkEAurrpmpqj5vg087ZngKfFGR5rozDiTsK5DceTV97K 218 | a3Y+Nzl+XWTxDBWk4YPh2ZlKv402hZEfWBYxUDn5ZkH/bw== 219 | -----END RSA PRIVATE KEY----- 220 | ``` 221 | -------------------------------------------------------------------------------- /_config.build.yml: -------------------------------------------------------------------------------- 1 | url: 2 | baseurl: 3 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | url: /jsencrypt 2 | baseurl: /jsencrypt 3 | -------------------------------------------------------------------------------- /_includes/navbar.html: -------------------------------------------------------------------------------- 1 | 33 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ page.title }} 5 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 29 | 30 | 31 | 32 | {% include navbar.html %} 33 |
34 | {{ content }} 35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsencrypt", 3 | "version": "3.0.0-rc.1", 4 | "main": "bin/jsencrypt.js", 5 | "description": "A Javascript library to perform OpenSSL RSA Encryption, Decryption, and Key Generation.", 6 | "license": "MIT", 7 | "ignore": [], 8 | "dependencies": { 9 | }, 10 | "devDependencies": { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /declarations/lib/asn1js/asn1.d.ts: -------------------------------------------------------------------------------- 1 | import { Int10 } from "./int10"; 2 | export declare class Stream { 3 | constructor(enc: Stream | number[], pos?: number); 4 | private enc; 5 | pos: number; 6 | get(pos?: number): number; 7 | hexDigits: string; 8 | hexByte(b: number): string; 9 | hexDump(start: number, end: number, raw: boolean): string; 10 | isASCII(start: number, end: number): boolean; 11 | parseStringISO(start: number, end: number): string; 12 | parseStringUTF(start: number, end: number): string; 13 | parseStringBMP(start: number, end: number): string; 14 | parseTime(start: number, end: number, shortYear: boolean): string; 15 | parseInteger(start: number, end: number): string | 0 | -1; 16 | parseBitString(start: number, end: number, maxLength: number): string; 17 | parseOctetString(start: number, end: number, maxLength: number): string; 18 | parseOID(start: number, end: number, maxLength: number): string; 19 | } 20 | export declare class ASN1 { 21 | constructor(stream: Stream, header: number, length: number, tag: ASN1Tag, sub: ASN1[]); 22 | private stream; 23 | private header; 24 | private length; 25 | private tag; 26 | sub: ASN1[]; 27 | typeName(): string; 28 | content(maxLength: number): string | 0 | -1; 29 | toString(): string; 30 | toPrettyString(indent: string): string; 31 | posStart(): number; 32 | posContent(): number; 33 | posEnd(): number; 34 | toHexString(): string; 35 | static decodeLength(stream: Stream): number; 36 | /** 37 | * Retrieve the hexadecimal value (as a string) of the current ASN.1 element 38 | * @returns {string} 39 | * @public 40 | */ 41 | getHexStringValue(): string; 42 | static decode(str: Stream | number[]): ASN1; 43 | } 44 | export declare class ASN1Tag { 45 | constructor(stream: Stream); 46 | tagClass: number; 47 | tagConstructed: boolean; 48 | tagNumber: number | Int10; 49 | isUniversal(): boolean; 50 | isEOC(): boolean; 51 | } 52 | -------------------------------------------------------------------------------- /declarations/lib/asn1js/base64.d.ts: -------------------------------------------------------------------------------- 1 | export declare const Base64: { 2 | decode(a: string): number[]; 3 | re: RegExp; 4 | unarmor(a: string): number[]; 5 | }; 6 | -------------------------------------------------------------------------------- /declarations/lib/asn1js/hex.d.ts: -------------------------------------------------------------------------------- 1 | export declare const Hex: { 2 | decode(a: string): number[]; 3 | }; 4 | -------------------------------------------------------------------------------- /declarations/lib/asn1js/int10.d.ts: -------------------------------------------------------------------------------- 1 | export declare class Int10 { 2 | constructor(value?: string | number); 3 | mulAdd(m: number, c: number): void; 4 | sub(c: number): void; 5 | toString(base?: number): string; 6 | valueOf(): number; 7 | simplify(): number | this; 8 | private buf; 9 | } 10 | -------------------------------------------------------------------------------- /declarations/lib/jsbn/base64.d.ts: -------------------------------------------------------------------------------- 1 | export declare function hex2b64(h: string): string; 2 | export declare function b64tohex(s: string): string; 3 | export declare function b64toBA(s: string): number[]; 4 | -------------------------------------------------------------------------------- /declarations/lib/jsbn/jsbn.d.ts: -------------------------------------------------------------------------------- 1 | import { SecureRandom } from "./rng"; 2 | export declare class BigInteger { 3 | constructor(a: number | number[] | string, b?: number | SecureRandom, c?: number | SecureRandom); 4 | toString(b: number): string; 5 | protected negate(): BigInteger; 6 | abs(): BigInteger; 7 | compareTo(a: BigInteger): number; 8 | bitLength(): number; 9 | mod(a: BigInteger): BigInteger; 10 | modPowInt(e: number, m: BigInteger): BigInteger; 11 | protected clone(): BigInteger; 12 | protected intValue(): number; 13 | protected byteValue(): number; 14 | protected shortValue(): number; 15 | protected signum(): 0 | 1 | -1; 16 | toByteArray(): number[]; 17 | protected equals(a: BigInteger): boolean; 18 | protected min(a: BigInteger): BigInteger; 19 | protected max(a: BigInteger): BigInteger; 20 | protected and(a: BigInteger): BigInteger; 21 | protected or(a: BigInteger): BigInteger; 22 | protected xor(a: BigInteger): BigInteger; 23 | protected andNot(a: BigInteger): BigInteger; 24 | protected not(): BigInteger; 25 | protected shiftLeft(n: number): BigInteger; 26 | protected shiftRight(n: number): BigInteger; 27 | protected getLowestSetBit(): number; 28 | protected bitCount(): number; 29 | protected testBit(n: number): boolean; 30 | protected setBit(n: number): BigInteger; 31 | protected clearBit(n: number): BigInteger; 32 | protected flipBit(n: number): BigInteger; 33 | add(a: BigInteger): BigInteger; 34 | subtract(a: BigInteger): BigInteger; 35 | multiply(a: BigInteger): BigInteger; 36 | divide(a: BigInteger): BigInteger; 37 | protected remainder(a: BigInteger): BigInteger; 38 | protected divideAndRemainder(a: BigInteger): BigInteger[]; 39 | modPow(e: BigInteger, m: BigInteger): BigInteger; 40 | modInverse(m: BigInteger): BigInteger; 41 | protected pow(e: number): BigInteger; 42 | gcd(a: BigInteger): BigInteger; 43 | isProbablePrime(t: number): boolean; 44 | copyTo(r: BigInteger): void; 45 | fromInt(x: number): void; 46 | protected fromString(s: string | number[], b: number): void; 47 | clamp(): void; 48 | dlShiftTo(n: number, r: BigInteger): void; 49 | drShiftTo(n: number, r: BigInteger): void; 50 | protected lShiftTo(n: number, r: BigInteger): void; 51 | protected rShiftTo(n: number, r: BigInteger): void; 52 | subTo(a: BigInteger, r: BigInteger): void; 53 | multiplyTo(a: BigInteger, r: BigInteger): void; 54 | squareTo(r: BigInteger): void; 55 | divRemTo(m: BigInteger, q: BigInteger, r: BigInteger): void; 56 | invDigit(): number; 57 | protected isEven(): boolean; 58 | protected exp(e: number, z: IReduction): BigInteger; 59 | protected chunkSize(r: number): number; 60 | protected toRadix(b: number): string; 61 | fromRadix(s: string, b: number): void; 62 | protected fromNumber(a: number, b: number | SecureRandom, c?: number | SecureRandom): void; 63 | protected bitwiseTo(a: BigInteger, op: (a: number, b: number) => number, r: BigInteger): void; 64 | protected changeBit(n: number, op: (a: number, b: number) => number): BigInteger; 65 | protected addTo(a: BigInteger, r: BigInteger): void; 66 | protected dMultiply(n: number): void; 67 | dAddOffset(n: number, w: number): void; 68 | multiplyLowerTo(a: BigInteger, n: number, r: BigInteger): void; 69 | multiplyUpperTo(a: BigInteger, n: number, r: BigInteger): void; 70 | protected modInt(n: number): number; 71 | protected millerRabin(t: number): boolean; 72 | protected square(): BigInteger; 73 | gcda(a: BigInteger, callback: (x: BigInteger) => void): void; 74 | fromNumberAsync(a: number, b: number | SecureRandom, c: number | SecureRandom, callback: () => void): void; 75 | s: number; 76 | t: number; 77 | DB: number; 78 | DM: number; 79 | DV: number; 80 | FV: number; 81 | F1: number; 82 | F2: number; 83 | am: (i: number, x: number, w: BigInteger, j: number, c: number, n: number) => number; 84 | [index: number]: number; 85 | static ONE: BigInteger; 86 | static ZERO: BigInteger; 87 | } 88 | export interface IReduction { 89 | convert(x: BigInteger): BigInteger; 90 | revert(x: BigInteger): BigInteger; 91 | mulTo(x: BigInteger, y: BigInteger, r: BigInteger): void; 92 | sqrTo(x: BigInteger, r: BigInteger): void; 93 | } 94 | export declare function nbi(): BigInteger; 95 | export declare function parseBigInt(str: string, r: number): BigInteger; 96 | export declare function intAt(s: string, i: number): number; 97 | export declare function nbv(i: number): BigInteger; 98 | export declare function nbits(x: number): number; 99 | -------------------------------------------------------------------------------- /declarations/lib/jsbn/prng4.d.ts: -------------------------------------------------------------------------------- 1 | export declare class Arcfour { 2 | constructor(); 3 | init(key: number[]): void; 4 | next(): number; 5 | private i; 6 | private j; 7 | private S; 8 | } 9 | export declare function prng_newstate(): Arcfour; 10 | export declare let rng_psize: number; 11 | -------------------------------------------------------------------------------- /declarations/lib/jsbn/rng.d.ts: -------------------------------------------------------------------------------- 1 | export declare class SecureRandom { 2 | nextBytes(ba: number[]): void; 3 | } 4 | -------------------------------------------------------------------------------- /declarations/lib/jsbn/rsa.d.ts: -------------------------------------------------------------------------------- 1 | import { BigInteger } from "./jsbn"; 2 | export declare class RSAKey { 3 | constructor(); 4 | doPublic(x: BigInteger): BigInteger; 5 | doPrivate(x: BigInteger): BigInteger; 6 | setPublic(N: string, E: string): void; 7 | encrypt(text: string): string; 8 | setPrivate(N: string, E: string, D: string): void; 9 | setPrivateEx(N: string, E: string, D: string, P: string, Q: string, DP: string, DQ: string, C: string): void; 10 | generate(B: number, E: string): void; 11 | decrypt(ctext: string): string; 12 | generateAsync(B: number, E: string, callback: () => void): void; 13 | protected n: BigInteger; 14 | protected e: number; 15 | protected d: BigInteger; 16 | protected p: BigInteger; 17 | protected q: BigInteger; 18 | protected dmp1: BigInteger; 19 | protected dmq1: BigInteger; 20 | protected coeff: BigInteger; 21 | } 22 | -------------------------------------------------------------------------------- /declarations/lib/jsbn/util.d.ts: -------------------------------------------------------------------------------- 1 | export declare function int2char(n: number): string; 2 | export declare function op_and(x: number, y: number): number; 3 | export declare function op_or(x: number, y: number): number; 4 | export declare function op_xor(x: number, y: number): number; 5 | export declare function op_andnot(x: number, y: number): number; 6 | export declare function lbit(x: number): number; 7 | export declare function cbit(x: number): number; 8 | -------------------------------------------------------------------------------- /declarations/src/JSEncrypt.d.ts: -------------------------------------------------------------------------------- 1 | import { JSEncryptRSAKey } from "./JSEncryptRSAKey"; 2 | export interface IJSEncryptOptions { 3 | default_key_size?: string; 4 | default_public_exponent?: string; 5 | log?: boolean; 6 | } 7 | /** 8 | * 9 | * @param {Object} [options = {}] - An object to customize JSEncrypt behaviour 10 | * possible parameters are: 11 | * - default_key_size {number} default: 1024 the key size in bit 12 | * - default_public_exponent {string} default: '010001' the hexadecimal representation of the public exponent 13 | * - log {boolean} default: false whether log warn/error or not 14 | * @constructor 15 | */ 16 | export declare class JSEncrypt { 17 | constructor(options: IJSEncryptOptions); 18 | private default_key_size; 19 | private default_public_exponent; 20 | private log; 21 | private key; 22 | static version: string; 23 | /** 24 | * Method to set the rsa key parameter (one method is enough to set both the public 25 | * and the private key, since the private key contains the public key paramenters) 26 | * Log a warning if logs are enabled 27 | * @param {Object|string} key the pem encoded string or an object (with or without header/footer) 28 | * @public 29 | */ 30 | setKey(key: string): void; 31 | /** 32 | * Proxy method for setKey, for api compatibility 33 | * @see setKey 34 | * @public 35 | */ 36 | setPrivateKey(privkey: string): void; 37 | /** 38 | * Proxy method for setKey, for api compatibility 39 | * @see setKey 40 | * @public 41 | */ 42 | setPublicKey(pubkey: string): void; 43 | /** 44 | * Proxy method for RSAKey object's decrypt, decrypt the string using the private 45 | * components of the rsa key object. Note that if the object was not set will be created 46 | * on the fly (by the getKey method) using the parameters passed in the JSEncrypt constructor 47 | * @param {string} str base64 encoded crypted string to decrypt 48 | * @return {string} the decrypted string 49 | * @public 50 | */ 51 | decrypt(str: string): string | false; 52 | /** 53 | * Proxy method for RSAKey object's encrypt, encrypt the string using the public 54 | * components of the rsa key object. Note that if the object was not set will be created 55 | * on the fly (by the getKey method) using the parameters passed in the JSEncrypt constructor 56 | * @param {string} str the string to encrypt 57 | * @return {string} the encrypted string encoded in base64 58 | * @public 59 | */ 60 | encrypt(str: string): string | false; 61 | /** 62 | * Getter for the current JSEncryptRSAKey object. If it doesn't exists a new object 63 | * will be created and returned 64 | * @param {callback} [cb] the callback to be called if we want the key to be generated 65 | * in an async fashion 66 | * @returns {JSEncryptRSAKey} the JSEncryptRSAKey object 67 | * @public 68 | */ 69 | getKey(cb?: () => void): JSEncryptRSAKey; 70 | /** 71 | * Returns the pem encoded representation of the private key 72 | * If the key doesn't exists a new key will be created 73 | * @returns {string} pem encoded representation of the private key WITH header and footer 74 | * @public 75 | */ 76 | getPrivateKey(): string; 77 | /** 78 | * Returns the pem encoded representation of the private key 79 | * If the key doesn't exists a new key will be created 80 | * @returns {string} pem encoded representation of the private key WITHOUT header and footer 81 | * @public 82 | */ 83 | getPrivateKeyB64(): string; 84 | /** 85 | * Returns the pem encoded representation of the public key 86 | * If the key doesn't exists a new key will be created 87 | * @returns {string} pem encoded representation of the public key WITH header and footer 88 | * @public 89 | */ 90 | getPublicKey(): string; 91 | /** 92 | * Returns the pem encoded representation of the public key 93 | * If the key doesn't exists a new key will be created 94 | * @returns {string} pem encoded representation of the public key WITHOUT header and footer 95 | * @public 96 | */ 97 | getPublicKeyB64(): string; 98 | } 99 | -------------------------------------------------------------------------------- /declarations/src/JSEncryptRSAKey.d.ts: -------------------------------------------------------------------------------- 1 | import { RSAKey } from "../lib/jsbn/rsa"; 2 | /** 3 | * Create a new JSEncryptRSAKey that extends Tom Wu's RSA key object. 4 | * This object is just a decorator for parsing the key parameter 5 | * @param {string|Object} key - The key in string format, or an object containing 6 | * the parameters needed to build a RSAKey object. 7 | * @constructor 8 | */ 9 | export declare class JSEncryptRSAKey extends RSAKey { 10 | constructor(key?: string); 11 | /** 12 | * Method to parse a pem encoded string containing both a public or private key. 13 | * The method will translate the pem encoded string in a der encoded string and 14 | * will parse private key and public key parameters. This method accepts public key 15 | * in the rsaencryption pkcs #1 format (oid: 1.2.840.113549.1.1.1). 16 | * 17 | * @todo Check how many rsa formats use the same format of pkcs #1. 18 | * 19 | * The format is defined as: 20 | * PublicKeyInfo ::= SEQUENCE { 21 | * algorithm AlgorithmIdentifier, 22 | * PublicKey BIT STRING 23 | * } 24 | * Where AlgorithmIdentifier is: 25 | * AlgorithmIdentifier ::= SEQUENCE { 26 | * algorithm OBJECT IDENTIFIER, the OID of the enc algorithm 27 | * parameters ANY DEFINED BY algorithm OPTIONAL (NULL for PKCS #1) 28 | * } 29 | * and PublicKey is a SEQUENCE encapsulated in a BIT STRING 30 | * RSAPublicKey ::= SEQUENCE { 31 | * modulus INTEGER, -- n 32 | * publicExponent INTEGER -- e 33 | * } 34 | * it's possible to examine the structure of the keys obtained from openssl using 35 | * an asn.1 dumper as the one used here to parse the components: http://lapo.it/asn1js/ 36 | * @argument {string} pem the pem encoded string, can include the BEGIN/END header/footer 37 | * @private 38 | */ 39 | parseKey(pem: string): boolean; 40 | /** 41 | * Translate rsa parameters in a hex encoded string representing the rsa key. 42 | * 43 | * The translation follow the ASN.1 notation : 44 | * RSAPrivateKey ::= SEQUENCE { 45 | * version Version, 46 | * modulus INTEGER, -- n 47 | * publicExponent INTEGER, -- e 48 | * privateExponent INTEGER, -- d 49 | * prime1 INTEGER, -- p 50 | * prime2 INTEGER, -- q 51 | * exponent1 INTEGER, -- d mod (p1) 52 | * exponent2 INTEGER, -- d mod (q-1) 53 | * coefficient INTEGER, -- (inverse of q) mod p 54 | * } 55 | * @returns {string} DER Encoded String representing the rsa private key 56 | * @private 57 | */ 58 | getPrivateBaseKey(): string; 59 | /** 60 | * base64 (pem) encoded version of the DER encoded representation 61 | * @returns {string} pem encoded representation without header and footer 62 | * @public 63 | */ 64 | getPrivateBaseKeyB64(): string; 65 | /** 66 | * Translate rsa parameters in a hex encoded string representing the rsa public key. 67 | * The representation follow the ASN.1 notation : 68 | * PublicKeyInfo ::= SEQUENCE { 69 | * algorithm AlgorithmIdentifier, 70 | * PublicKey BIT STRING 71 | * } 72 | * Where AlgorithmIdentifier is: 73 | * AlgorithmIdentifier ::= SEQUENCE { 74 | * algorithm OBJECT IDENTIFIER, the OID of the enc algorithm 75 | * parameters ANY DEFINED BY algorithm OPTIONAL (NULL for PKCS #1) 76 | * } 77 | * and PublicKey is a SEQUENCE encapsulated in a BIT STRING 78 | * RSAPublicKey ::= SEQUENCE { 79 | * modulus INTEGER, -- n 80 | * publicExponent INTEGER -- e 81 | * } 82 | * @returns {string} DER Encoded String representing the rsa public key 83 | * @private 84 | */ 85 | getPublicBaseKey(): string; 86 | /** 87 | * base64 (pem) encoded version of the DER encoded representation 88 | * @returns {string} pem encoded representation without header and footer 89 | * @public 90 | */ 91 | getPublicBaseKeyB64(): string; 92 | /** 93 | * wrap the string in block of width chars. The default value for rsa keys is 64 94 | * characters. 95 | * @param {string} str the pem encoded string without header and footer 96 | * @param {Number} [width=64] - the length the string has to be wrapped at 97 | * @returns {string} 98 | * @private 99 | */ 100 | static wordwrap(str: string, width?: number): string; 101 | /** 102 | * Retrieve the pem encoded private key 103 | * @returns {string} the pem encoded private key with header/footer 104 | * @public 105 | */ 106 | getPrivateKey(): string; 107 | /** 108 | * Retrieve the pem encoded public key 109 | * @returns {string} the pem encoded public key with header/footer 110 | * @public 111 | */ 112 | getPublicKey(): string; 113 | /** 114 | * Check if the object contains the necessary parameters to populate the rsa modulus 115 | * and public exponent parameters. 116 | * @param {Object} [obj={}] - An object that may contain the two public key 117 | * parameters 118 | * @returns {boolean} true if the object contains both the modulus and the public exponent 119 | * properties (n and e) 120 | * @todo check for types of n and e. N should be a parseable bigInt object, E should 121 | * be a parseable integer number 122 | * @private 123 | */ 124 | static hasPublicKeyProperty(obj: object): boolean; 125 | /** 126 | * Check if the object contains ALL the parameters of an RSA key. 127 | * @param {Object} [obj={}] - An object that may contain nine rsa key 128 | * parameters 129 | * @returns {boolean} true if the object contains all the parameters needed 130 | * @todo check for types of the parameters all the parameters but the public exponent 131 | * should be parseable bigint objects, the public exponent should be a parseable integer number 132 | * @private 133 | */ 134 | static hasPrivateKeyProperty(obj: object): boolean; 135 | /** 136 | * Parse the properties of obj in the current rsa object. Obj should AT LEAST 137 | * include the modulus and public exponent (n, e) parameters. 138 | * @param {Object} obj - the object containing rsa parameters 139 | * @private 140 | */ 141 | parsePropertiesFrom(obj: any): void; 142 | } 143 | -------------------------------------------------------------------------------- /declarations/src/index.d.ts: -------------------------------------------------------------------------------- 1 | export { JSEncrypt } from "./JSEncrypt"; 2 | import { JSEncrypt } from "./JSEncrypt"; 3 | export default JSEncrypt; 4 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Online RSA Key Generator 4 | --- 5 |
6 |
7 |

Online RSA Key Generator

8 |
9 |
10 |
11 | 12 | 13 | 17 | 20 |
21 |
22 |
23 |
24 |
25 | Key Size 26 | 28 | 34 |
35 |
36 |
 
37 | 38 |
 
39 | 40 |
 
41 | 42 |
43 |
44 |
45 |
46 |
47 | 48 | 49 | 50 |
51 |
52 |
53 | 54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |

RSA Encryption Test

63 |
64 |
65 |
66 | 67 |
68 |
69 |
70 | 71 |
72 |
73 |
74 | 75 |
76 |
77 |
78 |
79 | 163 | -------------------------------------------------------------------------------- /example.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: JSEncrypt Example 3 | layout: default 4 | --- 5 |
6 | 33 |
34 |
49 |
50 |
56 |
57 |
58 |
59 |
60 | -------------------------------------------------------------------------------- /example_long.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 使用jsencrypt执行长文本加密,解密 6 | 7 | 8 | 9 | 10 | 16 | 31 | 32 | 33 | 34 | 35 | 102 | 103 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"); 2 | var tslint = require("gulp-tslint"); 3 | var concat = require("gulp-concat"); 4 | var insert = require("gulp-insert"); 5 | var gulpCopy = require("gulp-copy"); 6 | var uglify = require("gulp-uglify"); 7 | var rename = require("gulp-rename"); 8 | var ts = require("gulp-typescript"); 9 | var through = require("through2"); 10 | var rollup = require("rollup"); 11 | 12 | var lintFiles = ["src/*.ts", "lib/*/**.ts"]; 13 | 14 | var licenses = [ 15 | "src/LICENSE.txt", 16 | "lib/jsrsasign/LICENSE.txt", 17 | "lib/jsbn/LICENSE.txt", 18 | "lib/asn1js/LICENSE.txt" 19 | ]; 20 | 21 | var libs_for_test = [ 22 | "node_modules/mocha/mocha.css", 23 | "node_modules/expect.js/index.js", 24 | "node_modules/mocha/mocha.js" 25 | ]; 26 | 27 | gulp.task("lint", function() { 28 | return gulp 29 | .src(lintFiles) 30 | .pipe( 31 | tslint({ 32 | fix: true 33 | }) 34 | ) 35 | .pipe(tslint.report({ summarizeFailureOutput: true })); 36 | }); 37 | 38 | gulp.task("license", function() { 39 | return gulp 40 | .src(licenses) 41 | .pipe( 42 | insert.transform(function(contents, file) { 43 | return "File: " + file.path.replace(__dirname, "") + "\n" + contents; 44 | }) 45 | ) 46 | .pipe(concat("LICENSE.txt")) 47 | .pipe(gulp.dest("")); 48 | }); 49 | 50 | /** 51 | * Build ts to js for rollup 52 | */ 53 | gulp.task("tsc", function() { 54 | var tsProject = ts.createProject("./tsconfig.json"); 55 | 56 | var typescript_error_count = 0; 57 | 58 | var tsResult = tsProject.src().pipe( 59 | tsProject({ 60 | reporter: ts.reporter.longReporter(), 61 | error: function() { 62 | typescript_error_count++; 63 | this.reporter.error.apply(this.reporter, arguments); 64 | }, 65 | finish: function() { 66 | this.reporter.finish.apply(this.reporter, arguments); 67 | } 68 | }) 69 | ); 70 | 71 | return tsResult.js.pipe(gulp.dest("./")).pipe( 72 | through.obj(function(chunk, enc, cb) { 73 | if (typescript_error_count) { 74 | this.emit( 75 | "error", 76 | "TypeScript compile errors (count:" + typescript_error_count + ")" 77 | ); 78 | } 79 | cb(null, chunk); 80 | }) 81 | ); 82 | }); 83 | 84 | /** 85 | * build library with rollup 86 | */ 87 | gulp.task("assemble", ["tsc"], function() { 88 | var config = require("./rollup.config"); 89 | 90 | return rollup.rollup(config).then(function(bundle) { 91 | return bundle.write(config.output); 92 | }); 93 | }); 94 | 95 | /** 96 | * copy mocha files from node modules to test directory (for gh-pages serving) 97 | */ 98 | gulp.task("prepare_test", function() { 99 | return gulp.src(libs_for_test).pipe(gulpCopy("test/libs/", { prefix: 2 })); 100 | }); 101 | 102 | gulp.task("compress", function(cb) { 103 | return gulp 104 | .src("bin/jsencrypt.js") 105 | .pipe(uglify()) 106 | .pipe(rename("jsencrypt.min.js")) 107 | .pipe(gulp.dest("bin")); 108 | }); 109 | 110 | gulp.task("build", ["prepare_test", "lint", "assemble", "license", "compress"]); 111 | gulp.task("default", ["build"]); 112 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: JSEncrypt 3 | layout: default 4 | --- 5 |
6 |

JSEncrypt

7 |
8 |
9 |
10 |

Introduction

11 |

When browsing the internet looking for a good solution to RSA Javascript encryption, there is a whole slew of libraries that basically take the fantastic work done by Tom Wu @ http://www-cs-students.stanford.edu/~tjw/jsbn/ and then modify that code to do what they want.

12 |

What I couldn't find, however, was a simple wrapper around this library that basically uses the library practically untouched, but adds a wrapper to provide parsing of actual Private and Public key-pairs generated with OpenSSL.

13 |

This library is the result of these efforts.

14 |
15 | 16 | 17 | 21 | 24 |
25 |

26 | Download 27 | Github Project 28 |

29 |
30 |
31 |
32 |
33 |

How to use this library.


34 |

This library should work hand-in-hand with openssl. With that said, here is how to use this library.

35 |
    36 |
  • Within your terminal (Unix based OS) type the following:
  • 37 |
38 |
openssl genrsa -out rsa_1024_priv.pem 1024
39 |
    40 |
  • This generates a private key, which you can see by doing the following...
  • 41 |
42 |
cat rsa_1024_priv.pem #if you are on mac you can | pbcopy to copy to the clipboard
43 |
    44 |
  • You can then copy and paste this in the Private Key section of the demo page.
  • 45 |
  • Next, you can then get the public key by executing the following command.
  • 46 |
47 |
openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem
48 |
    49 |
  • You can see the public key by typing...
  • 50 |
51 |
cat rsa_1024_pub.pem
52 |
    53 |
  • Now you can compare with the one generated in the demo page..
  • 54 |
  • Now you can then convert to and from encrypted text by doing the following in code.
  • 55 |
56 |
// Create the encryption object and set the key.
 57 | var crypt = new JSEncrypt();
 58 | crypt.setKey(__YOUR_OPENSSL_PRIVATE_OR_PUBLIC_KEY__); //You can use also setPrivateKey and setPublicKey, they are both alias to setKey
 59 | 
 60 | //Eventhough the methods are called setPublicKey and setPrivateKey, remember
 61 | //that they are only alias to setKey, so you can pass them both a private or
 62 | //a public openssl key, just remember that setting a public key allows you to only encrypt.
 63 | 
 64 | var text = 'test';
 65 | // Encrypt the data with the public key.
 66 | var enc = crypt.encrypt(text);
 67 | // Now decrypt the crypted text with the private key.
 68 | var dec = crypt.decrypt(enc);
 69 | 
 70 | // Now a simple check to see if the round-trip worked.
 71 | if (dec === text){
 72 |     alert('It works!!!');
 73 | } else {
 74 |     alert('Something went wrong....');
 75 | }
 76 |     
77 | 78 |
79 |
80 |
81 |
82 |

Other Information


83 |

This library heavily utilizes the wonderful work of Tom Wu found at http://www-cs-students.stanford.edu/~tjw/jsbn/.

84 |

This jsbn library was written using the raw variables to perform encryption. This is great for encryption, but most private keys use a Private Key in the PEM format seen below.

85 |

1024 bit RSA Private Key in Base64 Format

86 |
-----BEGIN RSA PRIVATE KEY-----
 87 | MIICXgIBAAKBgQDHikastc8+I81zCg/qWW8dMr8mqvXQ3qbPAmu0RjxoZVI47tvs
 88 | kYlFAXOf0sPrhO2nUuooJngnHV0639iTTEYG1vckNaW2R6U5QTdQ5Rq5u+uV3pMk
 89 | 7w7Vs4n3urQ6jnqt2rTXbC1DNa/PFeAZatbf7ffBBy0IGO0zc128IshYcwIDAQAB
 90 | AoGBALTNl2JxTvq4SDW/3VH0fZkQXWH1MM10oeMbB2qO5beWb11FGaOO77nGKfWc
 91 | bYgfp5Ogrql4yhBvLAXnxH8bcqqwORtFhlyV68U1y4R+8WxDNh0aevxH8hRS/1X5
 92 | 031DJm1JlU0E+vStiktN0tC3ebH5hE+1OxbIHSZ+WOWLYX7JAkEA5uigRgKp8ScG
 93 | auUijvdOLZIhHWq7y5Wz+nOHUuDw8P7wOTKU34QJAoWEe771p9Pf/GTA/kr0BQnP
 94 | QvWUDxGzJwJBAN05C6krwPeryFKrKtjOGJIniIoY72wRnoNcdEEs3HDRhf48YWFo
 95 | riRbZylzzzNFy/gmzT6XJQTfktGqq+FZD9UCQGIJaGrxHJgfmpDuAhMzGsUsYtTr
 96 | iRox0D1Iqa7dhE693t5aBG010OF6MLqdZA1CXrn5SRtuVVaCSLZEL/2J5UcCQQDA
 97 | d3MXucNnN4NPuS/L9HMYJWD7lPoosaORcgyK77bSSNgk+u9WSjbH1uYIAIPSffUZ
 98 | bti+jc1dUg5wb+aeZlgJAkEAurrpmpqj5vg087ZngKfFGR5rozDiTsK5DceTV97K
 99 | a3Y+Nzl+XWTxDBWk4YPh2ZlKv402hZEfWBYxUDn5ZkH/bw==
100 | -----END RSA PRIVATE KEY-----
101 |     
102 |

This library simply takes keys in the preceding format, and translates it to those variables needed to perform the encryptions used in Tom Wu's library.

103 |

Here are some good resources to investigate further.

104 | 109 |

With this information, we can translate a private key format to the variables required with the jsbn library from Tom Wu by using the following mappings.

110 |
modulus => n
111 | public exponent => e
112 | private exponent => d
113 | prime1 => p
114 | prime2 => q
115 | exponent1 => dmp1
116 | exponent2 => dmq1
117 | coefficient => coeff
118 |     
119 |
120 |
121 | -------------------------------------------------------------------------------- /lib/asn1js/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | ASN.1 JavaScript decoder 4 | Copyright (c) 2008-2013 Lapo Luchini 5 | 6 | Permission to use, copy, modify, and/or distribute this software for any 7 | purpose with or without fee is hereby granted, provided that the above 8 | copyright notice and this permission notice appear in all copies. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- /lib/asn1js/asn1.ts: -------------------------------------------------------------------------------- 1 | // ASN.1 JavaScript decoder 2 | // Copyright (c) 2008-2014 Lapo Luchini 3 | 4 | // Permission to use, copy, modify, and/or distribute this software for any 5 | // purpose with or without fee is hereby granted, provided that the above 6 | // copyright notice and this permission notice appear in all copies. 7 | // 8 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | 16 | /*jshint browser: true, strict: true, immed: true, latedef: true, undef: true, regexdash: false */ 17 | /*global oids */ 18 | 19 | import {Int10} from "./int10"; 20 | 21 | const ellipsis = "\u2026"; 22 | const reTimeS = /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/; 23 | const reTimeL = /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/; 24 | 25 | function stringCut(str:string, len:number) { 26 | if (str.length > len) { 27 | str = str.substring(0, len) + ellipsis; 28 | } 29 | return str; 30 | } 31 | 32 | export class Stream { 33 | constructor(enc:Stream|number[], pos?:number) { 34 | if (enc instanceof Stream) { 35 | this.enc = enc.enc; 36 | this.pos = enc.pos; 37 | } else { 38 | // enc should be an array or a binary string 39 | this.enc = enc; 40 | this.pos = pos; 41 | } 42 | } 43 | 44 | private enc:string|number[]; 45 | public pos:number; 46 | 47 | public get(pos?:number) { 48 | if (pos === undefined) { 49 | pos = this.pos++; 50 | } 51 | if (pos >= this.enc.length) { 52 | throw new Error(`Requesting byte offset ${pos} on a stream of length ${this.enc.length}`); 53 | } 54 | return ("string" === typeof this.enc) ? this.enc.charCodeAt(pos) : this.enc[pos]; 55 | } 56 | 57 | public hexDigits = "0123456789ABCDEF"; 58 | 59 | public hexByte(b:number) { 60 | return this.hexDigits.charAt((b >> 4) & 0xF) + this.hexDigits.charAt(b & 0xF); 61 | } 62 | 63 | public hexDump(start:number, end:number, raw:boolean) { 64 | let s = ""; 65 | for (let i = start; i < end; ++i) { 66 | s += this.hexByte(this.get(i)); 67 | if (raw !== true) { 68 | switch (i & 0xF) { 69 | case 0x7: 70 | s += " "; 71 | break; 72 | case 0xF: 73 | s += "\n"; 74 | break; 75 | default: 76 | s += " "; 77 | } 78 | } 79 | } 80 | return s; 81 | } 82 | 83 | public isASCII(start:number, end:number) { 84 | for (let i = start; i < end; ++i) { 85 | const c = this.get(i); 86 | if (c < 32 || c > 176) { 87 | return false; 88 | } 89 | } 90 | return true; 91 | } 92 | 93 | public parseStringISO(start:number, end:number) { 94 | let s = ""; 95 | for (let i = start; i < end; ++i) { 96 | s += String.fromCharCode(this.get(i)); 97 | } 98 | return s; 99 | } 100 | 101 | public parseStringUTF(start:number, end:number) { 102 | let s = ""; 103 | for (let i = start; i < end;) { 104 | const c = this.get(i++); 105 | if (c < 128) { 106 | s += String.fromCharCode(c); 107 | } else if ((c > 191) && (c < 224)) { 108 | s += String.fromCharCode(((c & 0x1F) << 6) | (this.get(i++) & 0x3F)); 109 | } else { 110 | s += String.fromCharCode(((c & 0x0F) << 12) | ((this.get(i++) & 0x3F) << 6) | (this.get(i++) & 0x3F)); 111 | } 112 | } 113 | return s; 114 | } 115 | 116 | public parseStringBMP(start:number, end:number) { 117 | let str = ""; 118 | let hi; 119 | let lo; 120 | for (let i = start; i < end;) { 121 | hi = this.get(i++); 122 | lo = this.get(i++); 123 | str += String.fromCharCode((hi << 8) | lo); 124 | } 125 | return str; 126 | } 127 | 128 | public parseTime(start:number, end:number, shortYear:boolean) { 129 | let s = this.parseStringISO(start, end); 130 | const m:Array = (shortYear ? reTimeS : reTimeL).exec(s); 131 | if (!m) { 132 | return "Unrecognized time: " + s; 133 | } 134 | if (shortYear) { 135 | // to avoid querying the timer, use the fixed range [1970, 2069] 136 | // it will conform with ITU X.400 [-10, +40] sliding window until 2030 137 | m[1] = +m[1]; 138 | (m[1] as number) += (+m[1] < 70) ? 2000 : 1900; 139 | } 140 | s = m[1] + "-" + m[2] + "-" + m[3] + " " + m[4]; 141 | if (m[5]) { 142 | s += ":" + m[5]; 143 | if (m[6]) { 144 | s += ":" + m[6]; 145 | if (m[7]) { 146 | s += "." + m[7]; 147 | } 148 | } 149 | } 150 | if (m[8]) { 151 | s += " UTC"; 152 | if (m[8] != "Z") { 153 | s += m[8]; 154 | if (m[9]) { 155 | s += ":" + m[9]; 156 | } 157 | } 158 | } 159 | return s; 160 | } 161 | 162 | public parseInteger(start:number, end:number) { 163 | let v = this.get(start); 164 | const neg = (v > 127); 165 | const pad = neg ? 255 : 0; 166 | let len; 167 | let s:string | number = ""; 168 | // skip unuseful bits (not allowed in DER) 169 | while (v == pad && ++start < end) { 170 | v = this.get(start); 171 | } 172 | len = end - start; 173 | if (len === 0) { 174 | return neg ? -1 : 0; 175 | } 176 | // show bit length of huge integers 177 | if (len > 4) { 178 | s = v; 179 | len <<= 3; 180 | while (((+s ^ pad) & 0x80) == 0) { 181 | s = +s << 1; 182 | --len; 183 | } 184 | s = "(" + len + " bit)\n"; 185 | } 186 | // decode the integer 187 | if (neg) { 188 | v = v - 256; 189 | } 190 | const n = new Int10(v); 191 | for (let i = start + 1; i < end; ++i) { 192 | n.mulAdd(256, this.get(i)); 193 | } 194 | return s + n.toString(); 195 | } 196 | 197 | public parseBitString(start:number, end:number, maxLength:number) { 198 | const unusedBit = this.get(start); 199 | const lenBit = ((end - start - 1) << 3) - unusedBit; 200 | const intro = "(" + lenBit + " bit)\n"; 201 | let s = ""; 202 | for (let i = start + 1; i < end; ++i) { 203 | const b = this.get(i); 204 | const skip = (i == end - 1) ? unusedBit : 0; 205 | for (let j = 7; j >= skip; --j) { 206 | s += (b >> j) & 1 ? "1" : "0"; 207 | } 208 | if (s.length > maxLength) { 209 | return intro + stringCut(s, maxLength); 210 | } 211 | } 212 | return intro + s; 213 | } 214 | 215 | public parseOctetString(start:number, end:number, maxLength:number) { 216 | if (this.isASCII(start, end)) { 217 | return stringCut(this.parseStringISO(start, end), maxLength); 218 | } 219 | const len = end - start; 220 | let s = "(" + len + " byte)\n"; 221 | maxLength /= 2; // we work in bytes 222 | if (len > maxLength) { 223 | end = start + maxLength; 224 | } 225 | for (let i = start; i < end; ++i) { 226 | s += this.hexByte(this.get(i)); 227 | } 228 | if (len > maxLength) { 229 | s += ellipsis; 230 | } 231 | return s; 232 | } 233 | 234 | public parseOID(start:number, end:number, maxLength:number) { 235 | let s = ""; 236 | let n:number|Int10 = new Int10(); 237 | let bits = 0; 238 | for (let i = start; i < end; ++i) { 239 | const v = this.get(i); 240 | n.mulAdd(128, v & 0x7F); 241 | bits += 7; 242 | if (!(v & 0x80)) { // finished 243 | if (s === "") { 244 | n = n.simplify(); 245 | if (n instanceof Int10) { 246 | n.sub(80); 247 | s = "2." + n.toString(); 248 | } else { 249 | const m = n < 80 ? n < 40 ? 0 : 1 : 2; 250 | s = m + "." + (n - m * 40); 251 | } 252 | } else { 253 | s += "." + n.toString(); 254 | } 255 | if (s.length > maxLength) { 256 | return stringCut(s, maxLength); 257 | } 258 | n = new Int10(); 259 | bits = 0; 260 | } 261 | } 262 | if (bits > 0) { 263 | s += ".incomplete"; 264 | } 265 | return s; 266 | } 267 | } 268 | export class ASN1 { 269 | constructor(stream:Stream, header:number, length:number, tag:ASN1Tag, sub:ASN1[]) { 270 | if (!(tag instanceof ASN1Tag)) { 271 | throw new Error("Invalid tag value."); 272 | } 273 | this.stream = stream; 274 | this.header = header; 275 | this.length = length; 276 | this.tag = tag; 277 | this.sub = sub; 278 | } 279 | 280 | private stream:Stream; 281 | private header:number; 282 | private length:number; 283 | private tag:ASN1Tag; 284 | public sub:ASN1[]; 285 | 286 | public typeName() { 287 | switch (this.tag.tagClass) { 288 | case 0: // universal 289 | switch (this.tag.tagNumber) { 290 | case 0x00: 291 | return "EOC"; 292 | case 0x01: 293 | return "BOOLEAN"; 294 | case 0x02: 295 | return "INTEGER"; 296 | case 0x03: 297 | return "BIT_STRING"; 298 | case 0x04: 299 | return "OCTET_STRING"; 300 | case 0x05: 301 | return "NULL"; 302 | case 0x06: 303 | return "OBJECT_IDENTIFIER"; 304 | case 0x07: 305 | return "ObjectDescriptor"; 306 | case 0x08: 307 | return "EXTERNAL"; 308 | case 0x09: 309 | return "REAL"; 310 | case 0x0A: 311 | return "ENUMERATED"; 312 | case 0x0B: 313 | return "EMBEDDED_PDV"; 314 | case 0x0C: 315 | return "UTF8String"; 316 | case 0x10: 317 | return "SEQUENCE"; 318 | case 0x11: 319 | return "SET"; 320 | case 0x12: 321 | return "NumericString"; 322 | case 0x13: 323 | return "PrintableString"; // ASCII subset 324 | case 0x14: 325 | return "TeletexString"; // aka T61String 326 | case 0x15: 327 | return "VideotexString"; 328 | case 0x16: 329 | return "IA5String"; // ASCII 330 | case 0x17: 331 | return "UTCTime"; 332 | case 0x18: 333 | return "GeneralizedTime"; 334 | case 0x19: 335 | return "GraphicString"; 336 | case 0x1A: 337 | return "VisibleString"; // ASCII subset 338 | case 0x1B: 339 | return "GeneralString"; 340 | case 0x1C: 341 | return "UniversalString"; 342 | case 0x1E: 343 | return "BMPString"; 344 | } 345 | return "Universal_" + this.tag.tagNumber.toString(); 346 | case 1: 347 | return "Application_" + this.tag.tagNumber.toString(); 348 | case 2: 349 | return "[" + this.tag.tagNumber.toString() + "]"; // Context 350 | case 3: 351 | return "Private_" + this.tag.tagNumber.toString(); 352 | } 353 | } 354 | 355 | public content(maxLength:number) { // a preview of the content (intended for humans) 356 | if (this.tag === undefined) { 357 | return null; 358 | } 359 | if (maxLength === undefined) { 360 | maxLength = Infinity; 361 | } 362 | const content = this.posContent(); 363 | const len = Math.abs(this.length); 364 | if (!this.tag.isUniversal()) { 365 | if (this.sub !== null) { 366 | return "(" + this.sub.length + " elem)"; 367 | } 368 | return this.stream.parseOctetString(content, content + len, maxLength); 369 | } 370 | switch (this.tag.tagNumber) { 371 | case 0x01: // BOOLEAN 372 | return (this.stream.get(content) === 0) ? "false" : "true"; 373 | case 0x02: // INTEGER 374 | return this.stream.parseInteger(content, content + len); 375 | case 0x03: // BIT_STRING 376 | return this.sub ? "(" + this.sub.length + " elem)" : 377 | this.stream.parseBitString(content, content + len, maxLength); 378 | case 0x04: // OCTET_STRING 379 | return this.sub ? "(" + this.sub.length + " elem)" : 380 | this.stream.parseOctetString(content, content + len, maxLength); 381 | // case 0x05: // NULL 382 | case 0x06: // OBJECT_IDENTIFIER 383 | return this.stream.parseOID(content, content + len, maxLength); 384 | // case 0x07: // ObjectDescriptor 385 | // case 0x08: // EXTERNAL 386 | // case 0x09: // REAL 387 | // case 0x0A: // ENUMERATED 388 | // case 0x0B: // EMBEDDED_PDV 389 | case 0x10: // SEQUENCE 390 | case 0x11: // SET 391 | if (this.sub !== null) { 392 | return "(" + this.sub.length + " elem)"; 393 | } else { 394 | return "(no elem)"; 395 | } 396 | case 0x0C: // UTF8String 397 | return stringCut(this.stream.parseStringUTF(content, content + len), maxLength); 398 | case 0x12: // NumericString 399 | case 0x13: // PrintableString 400 | case 0x14: // TeletexString 401 | case 0x15: // VideotexString 402 | case 0x16: // IA5String 403 | // case 0x19: // GraphicString 404 | case 0x1A: // VisibleString 405 | // case 0x1B: // GeneralString 406 | // case 0x1C: // UniversalString 407 | return stringCut(this.stream.parseStringISO(content, content + len), maxLength); 408 | case 0x1E: // BMPString 409 | return stringCut(this.stream.parseStringBMP(content, content + len), maxLength); 410 | case 0x17: // UTCTime 411 | case 0x18: // GeneralizedTime 412 | return this.stream.parseTime(content, content + len, (this.tag.tagNumber == 0x17)); 413 | } 414 | return null; 415 | } 416 | 417 | public toString() { 418 | return this.typeName() + "@" + this.stream.pos + "[header:" + this.header + ",length:" + this.length + ",sub:" + ((this.sub === null) ? "null" : this.sub.length) + "]"; 419 | } 420 | 421 | public toPrettyString(indent:string) { 422 | if (indent === undefined) { 423 | indent = ""; 424 | } 425 | let s = indent + this.typeName() + " @" + this.stream.pos; 426 | if (this.length >= 0) { 427 | s += "+"; 428 | } 429 | s += this.length; 430 | if (this.tag.tagConstructed) { 431 | s += " (constructed)"; 432 | } else if ((this.tag.isUniversal() && ((this.tag.tagNumber == 0x03) || (this.tag.tagNumber == 0x04))) && (this.sub !== null)) { 433 | s += " (encapsulates)"; 434 | } 435 | s += "\n"; 436 | if (this.sub !== null) { 437 | indent += " "; 438 | for (let i = 0, max = this.sub.length; i < max; ++i) { 439 | s += this.sub[i].toPrettyString(indent); 440 | } 441 | } 442 | return s; 443 | } 444 | 445 | public posStart() { 446 | return this.stream.pos; 447 | } 448 | 449 | public posContent() { 450 | return this.stream.pos + this.header; 451 | } 452 | 453 | public posEnd() { 454 | return this.stream.pos + this.header + Math.abs(this.length); 455 | } 456 | 457 | public toHexString() { 458 | return this.stream.hexDump(this.posStart(), this.posEnd(), true); 459 | } 460 | 461 | public static decodeLength(stream:Stream):number { 462 | let buf = stream.get(); 463 | const len = buf & 0x7F; 464 | if (len == buf) { 465 | return len; 466 | } 467 | 468 | // no reason to use Int10, as it would be a huge buffer anyways 469 | if (len > 6) { 470 | throw new Error("Length over 48 bits not supported at position " + (stream.pos - 1)); 471 | } 472 | if (len === 0) { 473 | return null; 474 | } // undefined 475 | buf = 0; 476 | for (let i = 0; i < len; ++i) { 477 | buf = (buf * 256) + stream.get(); 478 | } 479 | return buf; 480 | } 481 | 482 | /** 483 | * Retrieve the hexadecimal value (as a string) of the current ASN.1 element 484 | * @returns {string} 485 | * @public 486 | */ 487 | public getHexStringValue():string { 488 | const hexString = this.toHexString(); 489 | const offset = this.header * 2; 490 | const length = this.length * 2; 491 | return hexString.substr(offset, length); 492 | } 493 | 494 | public static decode(str:Stream|number[]) { 495 | let stream:Stream; 496 | 497 | if (!(str instanceof Stream)) { 498 | stream = new Stream(str, 0); 499 | } else { 500 | stream = str; 501 | } 502 | 503 | const streamStart = new Stream(stream); 504 | const tag = new ASN1Tag(stream); 505 | let len = ASN1.decodeLength(stream); 506 | const start = stream.pos; 507 | const header = start - streamStart.pos; 508 | let sub = null; 509 | const getSub:() => ASN1[] = function () { 510 | const ret = []; 511 | if (len !== null) { 512 | // definite length 513 | const end = start + len; 514 | while (stream.pos < end) { 515 | ret[ret.length] = ASN1.decode(stream); 516 | } 517 | if (stream.pos != end) { 518 | throw new Error("Content size is not correct for container starting at offset " + start); 519 | } 520 | } else { 521 | // undefined length 522 | try { 523 | for (; ;) { 524 | const s = ASN1.decode(stream); 525 | if (s.tag.isEOC()) { 526 | break; 527 | } 528 | ret[ret.length] = s; 529 | } 530 | len = start - stream.pos; // undefined lengths are represented as negative values 531 | } catch (e) { 532 | throw new Error("Exception while decoding undefined length content: " + e); 533 | } 534 | } 535 | 536 | return ret; 537 | }; 538 | if (tag.tagConstructed) { 539 | // must have valid content 540 | sub = getSub(); 541 | } else if (tag.isUniversal() && ((tag.tagNumber == 0x03) || (tag.tagNumber == 0x04))) { 542 | // sometimes BitString and OctetString are used to encapsulate ASN.1 543 | try { 544 | if (tag.tagNumber == 0x03) { 545 | if (stream.get() != 0) { 546 | throw new Error("BIT STRINGs with unused bits cannot encapsulate."); 547 | } 548 | } 549 | sub = getSub(); 550 | for (let i = 0; i < sub.length; ++i) { 551 | if (sub[i].tag.isEOC()) { 552 | throw new Error("EOC is not supposed to be actual content."); 553 | } 554 | } 555 | } catch (e) { 556 | // but silently ignore when they don't 557 | sub = null; 558 | } 559 | } 560 | if (sub === null) { 561 | if (len === null) { 562 | throw new Error("We can't skip over an invalid tag with undefined length at offset " + start); 563 | } 564 | stream.pos = start + Math.abs(len); 565 | } 566 | return new ASN1(streamStart, header, len, tag, sub); 567 | } 568 | } 569 | 570 | 571 | export class ASN1Tag { 572 | constructor(stream:Stream) { 573 | let buf = stream.get(); 574 | this.tagClass = buf >> 6; 575 | this.tagConstructed = ((buf & 0x20) !== 0); 576 | this.tagNumber = buf & 0x1F; 577 | if (this.tagNumber == 0x1F) { // long tag 578 | const n = new Int10(); 579 | do { 580 | buf = stream.get(); 581 | n.mulAdd(128, buf & 0x7F); 582 | } while (buf & 0x80); 583 | this.tagNumber = n.simplify(); 584 | } 585 | } 586 | 587 | public tagClass:number; 588 | public tagConstructed:boolean; 589 | public tagNumber:number | Int10; 590 | 591 | public isUniversal() { 592 | return this.tagClass === 0x00; 593 | } 594 | 595 | public isEOC() { 596 | return this.tagClass === 0x00 && this.tagNumber === 0x00; 597 | } 598 | } 599 | -------------------------------------------------------------------------------- /lib/asn1js/base64.ts: -------------------------------------------------------------------------------- 1 | // Base64 JavaScript decoder 2 | // Copyright (c) 2008-2013 Lapo Luchini 3 | 4 | // Permission to use, copy, modify, and/or distribute this software for any 5 | // purpose with or without fee is hereby granted, provided that the above 6 | // copyright notice and this permission notice appear in all copies. 7 | // 8 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | 16 | /*jshint browser: true, strict: true, immed: true, latedef: true, undef: true, regexdash: false */ 17 | let decoder:{ [index:string]:number | string }; 18 | export const Base64 = { 19 | decode(a:string) { 20 | let i; 21 | if (decoder === undefined) { 22 | const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 23 | const ignore = "= \f\n\r\t\u00A0\u2028\u2029"; 24 | decoder = Object.create(null); 25 | for (i = 0; i < 64; ++i) { 26 | decoder[b64.charAt(i)] = i; 27 | } 28 | for (i = 0; i < ignore.length; ++i) { 29 | decoder[ignore.charAt(i)] = -1; 30 | } 31 | } 32 | const out = []; 33 | let bits = 0; 34 | let char_count = 0; 35 | for (i = 0; i < a.length; ++i) { 36 | let c:string|number = a.charAt(i); 37 | if (c == "=") { 38 | break; 39 | } 40 | c = decoder[c]; 41 | if (c == -1) { 42 | continue; 43 | } 44 | if (c === undefined) { 45 | throw new Error("Illegal character at offset " + i); 46 | } 47 | bits |= c as number; 48 | if (++char_count >= 4) { 49 | out[out.length] = (bits >> 16); 50 | out[out.length] = (bits >> 8) & 0xFF; 51 | out[out.length] = bits & 0xFF; 52 | bits = 0; 53 | char_count = 0; 54 | } else { 55 | bits <<= 6; 56 | } 57 | } 58 | switch (char_count) { 59 | case 1: 60 | throw new Error("Base64 encoding incomplete: at least 2 bits missing"); 61 | case 2: 62 | out[out.length] = (bits >> 10); 63 | break; 64 | case 3: 65 | out[out.length] = (bits >> 16); 66 | out[out.length] = (bits >> 8) & 0xFF; 67 | break; 68 | } 69 | return out; 70 | }, 71 | re: /-----BEGIN [^-]+-----([A-Za-z0-9+\/=\s]+)-----END [^-]+-----|begin-base64[^\n]+\n([A-Za-z0-9+\/=\s]+)====/, 72 | unarmor(a:string):number[] { 73 | const m = Base64.re.exec(a); 74 | if (m) { 75 | if (m[1]) { 76 | a = m[1]; 77 | } else if (m[2]) { 78 | a = m[2]; 79 | } else { 80 | throw new Error("RegExp out of sync"); 81 | } 82 | } 83 | return Base64.decode(a); 84 | } 85 | }; 86 | -------------------------------------------------------------------------------- /lib/asn1js/hex.ts: -------------------------------------------------------------------------------- 1 | // Hex JavaScript decoder 2 | // Copyright (c) 2008-2013 Lapo Luchini 3 | 4 | // Permission to use, copy, modify, and/or distribute this software for any 5 | // purpose with or without fee is hereby granted, provided that the above 6 | // copyright notice and this permission notice appear in all copies. 7 | // 8 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | 16 | /*jshint browser: true, strict: true, immed: true, latedef: true, undef: true, regexdash: false */ 17 | 18 | let decoder:{ [index:string]:number }; 19 | export const Hex = { 20 | decode(a:string):number[] { 21 | let i; 22 | if (decoder === undefined) { 23 | let hex = "0123456789ABCDEF"; 24 | const ignore = " \f\n\r\t\u00A0\u2028\u2029"; 25 | decoder = {}; 26 | for (i = 0; i < 16; ++i) { 27 | decoder[hex.charAt(i)] = i; 28 | } 29 | hex = hex.toLowerCase(); 30 | for (i = 10; i < 16; ++i) { 31 | decoder[hex.charAt(i)] = i; 32 | } 33 | for (i = 0; i < ignore.length; ++i) { 34 | decoder[ignore.charAt(i)] = -1; 35 | } 36 | } 37 | const out = []; 38 | let bits = 0; 39 | let char_count = 0; 40 | for (i = 0; i < a.length; ++i) { 41 | let c:number|string = a.charAt(i); 42 | if (c == "=") { 43 | break; 44 | } 45 | c = decoder[c]; 46 | if (c == -1) { 47 | continue; 48 | } 49 | if (c === undefined) { 50 | throw new Error("Illegal character at offset " + i); 51 | } 52 | bits |= c; 53 | if (++char_count >= 2) { 54 | out[out.length] = bits; 55 | bits = 0; 56 | char_count = 0; 57 | } else { 58 | bits <<= 4; 59 | } 60 | } 61 | if (char_count) { 62 | throw new Error("Hex encoding incomplete: 4 bits missing"); 63 | } 64 | return out; 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /lib/asn1js/int10.ts: -------------------------------------------------------------------------------- 1 | // Big integer base-10 printing library 2 | // Copyright (c) 2014 Lapo Luchini 3 | 4 | // Permission to use, copy, modify, and/or distribute this software for any 5 | // purpose with or without fee is hereby granted, provided that the above 6 | // copyright notice and this permission notice appear in all copies. 7 | // 8 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | 16 | /*jshint browser: true, strict: true, immed: true, latedef: true, undef: true, regexdash: false */ 17 | 18 | 19 | const max = 10000000000000; // biggest integer that can still fit 2^53 when multiplied by 256 20 | 21 | export class Int10 { 22 | constructor(value?:string | number) { 23 | this.buf = [+value || 0]; 24 | } 25 | 26 | 27 | public mulAdd(m:number, c:number) { 28 | // assert(m <= 256) 29 | const b = this.buf; 30 | const l = b.length; 31 | let i; 32 | let t; 33 | for (i = 0; i < l; ++i) { 34 | t = b[i] * m + c; 35 | if (t < max) { 36 | c = 0; 37 | } else { 38 | c = 0 | (t / max); 39 | t -= c * max; 40 | } 41 | b[i] = t; 42 | } 43 | if (c > 0) { 44 | b[i] = c; 45 | } 46 | } 47 | 48 | public sub(c:number) { 49 | // assert(m <= 256) 50 | const b = this.buf; 51 | const l = b.length; 52 | let i; 53 | let t; 54 | for (i = 0; i < l; ++i) { 55 | t = b[i] - c; 56 | if (t < 0) { 57 | t += max; 58 | c = 1; 59 | } else { 60 | c = 0; 61 | } 62 | b[i] = t; 63 | } 64 | while (b[b.length - 1] === 0) { 65 | b.pop(); 66 | } 67 | } 68 | 69 | public toString(base?:number) { 70 | if ((base || 10) != 10) { 71 | throw new Error("only base 10 is supported"); 72 | } 73 | const b = this.buf; 74 | let s = b[b.length - 1].toString(); 75 | for (let i = b.length - 2; i >= 0; --i) { 76 | s += (max + b[i]).toString().substring(1); 77 | } 78 | return s; 79 | } 80 | 81 | public valueOf() { 82 | const b = this.buf; 83 | let v = 0; 84 | for (let i = b.length - 1; i >= 0; --i) { 85 | v = v * max + b[i]; 86 | } 87 | return v; 88 | } 89 | 90 | public simplify() { 91 | const b = this.buf; 92 | return (b.length == 1) ? b[0] : this; 93 | } 94 | 95 | private buf:number[]; 96 | } 97 | 98 | -------------------------------------------------------------------------------- /lib/jsbn/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Licensing 4 | --------- 5 | 6 | This software is covered under the following copyright: 7 | 8 | /* 9 | * Copyright (c) 2003-2005 Tom Wu 10 | * All Rights Reserved. 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining 13 | * a copy of this software and associated documentation files (the 14 | * "Software"), to deal in the Software without restriction, including 15 | * without limitation the rights to use, copy, modify, merge, publish, 16 | * distribute, sublicense, and/or sell copies of the Software, and to 17 | * permit persons to whom the Software is furnished to do so, subject to 18 | * the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be 21 | * included in all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 24 | * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 25 | * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 26 | * 27 | * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, 28 | * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER 29 | * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF 30 | * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT 31 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 32 | * 33 | * In addition, the following condition applies: 34 | * 35 | * All redistributions must retain an intact copy of this copyright notice 36 | * and disclaimer. 37 | */ 38 | 39 | Address all questions regarding this license to: 40 | 41 | Tom Wu 42 | tjw@cs.Stanford.EDU -------------------------------------------------------------------------------- /lib/jsbn/README.md: -------------------------------------------------------------------------------- 1 | These files are downloaded from http://www-cs-students.stanford.edu/~tjw/jsbn/ 2 | 3 | Here is a list of changes made to this library: 4 | 5 | - https://github.com/travist/jsencrypt/pull/6 6 | 7 | -------------------------------------------------------------------------------- /lib/jsbn/base64.ts: -------------------------------------------------------------------------------- 1 | import {int2char} from "./util"; 2 | 3 | const b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 4 | const b64pad = "="; 5 | 6 | export function hex2b64(h:string) { 7 | let i; 8 | let c; 9 | let ret = ""; 10 | for (i = 0; i + 3 <= h.length; i += 3) { 11 | c = parseInt(h.substring(i, i + 3), 16); 12 | ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63); 13 | } 14 | if (i + 1 == h.length) { 15 | c = parseInt(h.substring(i, i + 1), 16); 16 | ret += b64map.charAt(c << 2); 17 | } else if (i + 2 == h.length) { 18 | c = parseInt(h.substring(i, i + 2), 16); 19 | ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4); 20 | } 21 | while ((ret.length & 3) > 0) { 22 | ret += b64pad; 23 | } 24 | return ret; 25 | } 26 | 27 | // convert a base64 string to hex 28 | export function b64tohex(s:string) { 29 | let ret = ""; 30 | let i; 31 | let k = 0; // b64 state, 0-3 32 | let slop = 0; 33 | for (i = 0; i < s.length; ++i) { 34 | if (s.charAt(i) == b64pad) { 35 | break; 36 | } 37 | const v = b64map.indexOf(s.charAt(i)); 38 | if (v < 0) { 39 | continue; 40 | } 41 | if (k == 0) { 42 | ret += int2char(v >> 2); 43 | slop = v & 3; 44 | k = 1; 45 | } else if (k == 1) { 46 | ret += int2char((slop << 2) | (v >> 4)); 47 | slop = v & 0xf; 48 | k = 2; 49 | } else if (k == 2) { 50 | ret += int2char(slop); 51 | ret += int2char(v >> 2); 52 | slop = v & 3; 53 | k = 3; 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 | } 63 | return ret; 64 | } 65 | 66 | // convert a base64 string to a byte/number array 67 | export function b64toBA(s:string) { 68 | // piggyback on b64tohex for now, optimize later 69 | const h = b64tohex(s); 70 | let i; 71 | const a = []; 72 | for (i = 0; 2 * i < h.length; ++i) { 73 | a[i] = parseInt(h.substring(2 * i, 2 * i + 2), 16); 74 | } 75 | return a; 76 | } 77 | -------------------------------------------------------------------------------- /lib/jsbn/prng4.ts: -------------------------------------------------------------------------------- 1 | // prng4.js - uses Arcfour as a PRNG 2 | 3 | export class Arcfour { 4 | constructor() { 5 | this.i = 0; 6 | this.j = 0; 7 | this.S = []; 8 | } 9 | 10 | // Arcfour.prototype.init = ARC4init; 11 | // Initialize arcfour context from key, an array of ints, each from [0..255] 12 | public init(key:number[]) { 13 | let i; 14 | let j; 15 | let t; 16 | for (i = 0; i < 256; ++i) { 17 | this.S[i] = i; 18 | } 19 | j = 0; 20 | for (i = 0; i < 256; ++i) { 21 | j = (j + this.S[i] + key[i % key.length]) & 255; 22 | t = this.S[i]; 23 | this.S[i] = this.S[j]; 24 | this.S[j] = t; 25 | } 26 | this.i = 0; 27 | this.j = 0; 28 | } 29 | 30 | // Arcfour.prototype.next = ARC4next; 31 | public next() { 32 | let t; 33 | this.i = (this.i + 1) & 255; 34 | this.j = (this.j + this.S[this.i]) & 255; 35 | t = this.S[this.i]; 36 | this.S[this.i] = this.S[this.j]; 37 | this.S[this.j] = t; 38 | return this.S[(t + this.S[this.i]) & 255]; 39 | } 40 | 41 | private i:number; 42 | private j:number; 43 | private S:number[]; 44 | } 45 | 46 | 47 | // Plug in your RNG constructor here 48 | export function prng_newstate() { 49 | return new Arcfour(); 50 | } 51 | 52 | // Pool size must be a multiple of 4 and greater than 32. 53 | // An array of bytes the size of the pool will be passed to init() 54 | export let rng_psize = 256; 55 | -------------------------------------------------------------------------------- /lib/jsbn/rng.ts: -------------------------------------------------------------------------------- 1 | // Random number generator - requires a PRNG backend, e.g. prng4.js 2 | import {Arcfour, prng_newstate, rng_psize} from "./prng4"; 3 | 4 | let rng_state:Arcfour; 5 | let rng_pool:number[] = null; 6 | let rng_pptr:number; 7 | 8 | // Initialize the pool with junk if needed. 9 | if (rng_pool == null) { 10 | rng_pool = []; 11 | rng_pptr = 0; 12 | let t; 13 | if (window.crypto && window.crypto.getRandomValues) { 14 | // Extract entropy (2048 bits) from RNG if available 15 | const z = new Uint32Array(256); 16 | window.crypto.getRandomValues(z); 17 | for (t = 0; t < z.length; ++t) { 18 | rng_pool[rng_pptr++] = z[t] & 255; 19 | } 20 | } 21 | 22 | // Use mouse events for entropy, if we do not have enough entropy by the time 23 | // we need it, entropy will be generated by Math.random. 24 | const onMouseMoveListener = function (ev:Event & {x:number; y:number; }) { 25 | this.count = this.count || 0; 26 | if (this.count >= 256 || rng_pptr >= rng_psize) { 27 | if (window.removeEventListener) { 28 | window.removeEventListener("mousemove", onMouseMoveListener, false); 29 | } else if ((window as any).detachEvent) { 30 | (window as any).detachEvent("onmousemove", onMouseMoveListener); 31 | } 32 | return; 33 | } 34 | try { 35 | const mouseCoordinates = ev.x + ev.y; 36 | rng_pool[rng_pptr++] = mouseCoordinates & 255; 37 | this.count += 1; 38 | } catch (e) { 39 | // Sometimes Firefox will deny permission to access event properties for some reason. Ignore. 40 | } 41 | }; 42 | if (window.addEventListener) { 43 | window.addEventListener("mousemove", onMouseMoveListener, false); 44 | } else if ((window as any).attachEvent) { 45 | (window as any).attachEvent("onmousemove", onMouseMoveListener); 46 | } 47 | 48 | } 49 | 50 | function rng_get_byte() { 51 | if (rng_state == null) { 52 | rng_state = prng_newstate(); 53 | // At this point, we may not have collected enough entropy. If not, fall back to Math.random 54 | while (rng_pptr < rng_psize) { 55 | const random = Math.floor(65536 * Math.random()); 56 | rng_pool[rng_pptr++] = random & 255; 57 | } 58 | rng_state.init(rng_pool); 59 | for (rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr) { 60 | rng_pool[rng_pptr] = 0; 61 | } 62 | rng_pptr = 0; 63 | } 64 | // TODO: allow reseeding after first request 65 | return rng_state.next(); 66 | } 67 | 68 | 69 | export class SecureRandom { 70 | 71 | public nextBytes(ba:number[]) { 72 | for (let i = 0; i < ba.length; ++i) { 73 | ba[i] = rng_get_byte(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/jsbn/rsa.ts: -------------------------------------------------------------------------------- 1 | // Depends on jsbn.js and rng.js 2 | 3 | // Version 1.1: support utf-8 encoding in pkcs1pad2 4 | 5 | // convert a (hex) string to a bignum object 6 | 7 | import { BigInteger, nbi, parseBigInt } from "./jsbn"; 8 | import { SecureRandom } from "./rng"; 9 | import { hex2b64, b64tohex } from "./base64"; 10 | 11 | // function linebrk(s,n) { 12 | // var ret = ""; 13 | // var i = 0; 14 | // while(i + n < s.length) { 15 | // ret += s.substring(i,i+n) + "\n"; 16 | // i += n; 17 | // } 18 | // return ret + s.substring(i,s.length); 19 | // } 20 | 21 | // function byte2Hex(b) { 22 | // if(b < 0x10) 23 | // return "0" + b.toString(16); 24 | // else 25 | // return b.toString(16); 26 | // } 27 | 28 | function pkcs1pad1(s:string, n:number) { 29 | if (n < s.length + 22) { 30 | console.error("Message too long for RSA"); 31 | return null; 32 | } 33 | const len = n - s.length - 6; 34 | let filler = ""; 35 | for (let f = 0; f < len; f += 2) { 36 | filler += "ff"; 37 | } 38 | const m = "0001" + filler + "00" + s; 39 | return parseBigInt(m, 16); 40 | } 41 | 42 | // PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint 43 | function pkcs1pad2(s:string, n:number) { 44 | if (n < s.length + 11) { 45 | // TODO: fix for utf-8 46 | 47 | console.error("Message too long for RSA"); 48 | return null; 49 | } 50 | const ba = []; 51 | let i = s.length - 1; 52 | while (i >= 0 && n > 0) { 53 | const c = s.charCodeAt(i--); 54 | if (c < 128) { 55 | // encode using utf-8 56 | ba[--n] = c; 57 | } else if (c > 127 && c < 2048) { 58 | ba[--n] = (c & 63) | 128; 59 | ba[--n] = (c >> 6) | 192; 60 | } else { 61 | ba[--n] = (c & 63) | 128; 62 | ba[--n] = ((c >> 6) & 63) | 128; 63 | ba[--n] = (c >> 12) | 224; 64 | } 65 | } 66 | ba[--n] = 0; 67 | const rng = new SecureRandom(); 68 | const x = []; 69 | while (n > 2) { 70 | // random non-zero pad 71 | x[0] = 0; 72 | while (x[0] == 0) { 73 | rng.nextBytes(x); 74 | } 75 | ba[--n] = x[0]; 76 | } 77 | ba[--n] = 2; 78 | ba[--n] = 0; 79 | return new BigInteger(ba); 80 | } 81 | 82 | // "empty" RSA key constructor 83 | export class RSAKey { 84 | constructor() { 85 | this.n = null; 86 | this.e = 0; 87 | this.d = null; 88 | this.p = null; 89 | this.q = null; 90 | this.dmp1 = null; 91 | this.dmq1 = null; 92 | this.coeff = null; 93 | } 94 | 95 | //#region PROTECTED 96 | // protected 97 | // RSAKey.prototype.doPublic = RSADoPublic; 98 | // Perform raw public operation on "x": return x^e (mod n) 99 | public doPublic(x:BigInteger) { 100 | return x.modPowInt(this.e, this.n); 101 | } 102 | 103 | // RSAKey.prototype.doPrivate = RSADoPrivate; 104 | // Perform raw private operation on "x": return x^d (mod n) 105 | public doPrivate(x:BigInteger) { 106 | if (this.p == null || this.q == null) { 107 | return x.modPow(this.d, this.n); 108 | } 109 | 110 | // TODO: re-calculate any missing CRT params 111 | let xp = x.mod(this.p).modPow(this.dmp1, this.p); 112 | const xq = x.mod(this.q).modPow(this.dmq1, this.q); 113 | 114 | while (xp.compareTo(xq) < 0) { 115 | xp = xp.add(this.p); 116 | } 117 | return xp 118 | .subtract(xq) 119 | .multiply(this.coeff) 120 | .mod(this.p) 121 | .multiply(this.q) 122 | .add(xq); 123 | } 124 | 125 | //#endregion PROTECTED 126 | 127 | //#region PUBLIC 128 | 129 | // RSAKey.prototype.setPublic = RSASetPublic; 130 | // Set the public key fields N and e from hex strings 131 | public setPublic(N:string, E:string) { 132 | if (N != null && E != null && N.length > 0 && E.length > 0) { 133 | this.n = parseBigInt(N, 16); 134 | this.e = parseInt(E, 16); 135 | } else { 136 | console.error("Invalid RSA public key"); 137 | } 138 | } 139 | 140 | // RSAKey.prototype.encrypt = RSAEncrypt; 141 | // Return the PKCS#1 RSA encryption of "text" as an even-length hex string 142 | public encrypt(text:string) { 143 | const m = pkcs1pad2(text, (this.n.bitLength() + 7) >> 3); 144 | 145 | if (m == null) { 146 | return null; 147 | } 148 | const c = this.doPublic(m); 149 | if (c == null) { 150 | return null; 151 | } 152 | const h = c.toString(16); 153 | if ((h.length & 1) == 0) { 154 | return h; 155 | } else { 156 | return "0" + h; 157 | } 158 | } 159 | 160 | /** 161 | * 长文本加密 162 | * @param {string} string 待加密长文本 163 | * @returns {string} 加密后的base64编码 164 | */ 165 | public encryptLong(text:string) { 166 | const maxLength = ((this.n.bitLength() + 7) >> 3) - 11; 167 | 168 | try { 169 | let ct = ""; 170 | 171 | if (text.length > maxLength) { 172 | const lt = text.match(/.{1,117}/g); 173 | lt.forEach((entry:string) => { 174 | const t1 = this.encrypt(entry); 175 | ct += t1; 176 | }); 177 | return hex2b64(ct); 178 | } 179 | const t = this.encrypt(text); 180 | const y = hex2b64(t); 181 | return y; 182 | } catch (ex) { 183 | return false; 184 | } 185 | } 186 | 187 | /** 188 | * 长文本解密 189 | * @param {string} string 加密后的base64编码 190 | * @returns {string} 解密后的原文 191 | */ 192 | public decryptLong(text:string) { 193 | const maxLength = (this.n.bitLength() + 7) >> 3; 194 | text = b64tohex(text); 195 | try { 196 | if (text.length > maxLength) { 197 | let ct = ""; 198 | const lt = text.match(/.{1,256}/g); // 128位解密。取256位 199 | lt.forEach((entry) => { 200 | const t1 = this.decrypt(entry); 201 | ct += t1; 202 | }); 203 | return ct; 204 | } 205 | const y = this.decrypt(text); 206 | return y; 207 | } catch (ex) { 208 | return false; 209 | } 210 | } 211 | 212 | // RSAKey.prototype.setPrivate = RSASetPrivate; 213 | // Set the private key fields N, e, and d from hex strings 214 | public setPrivate(N:string, E:string, D:string) { 215 | if (N != null && E != null && N.length > 0 && E.length > 0) { 216 | this.n = parseBigInt(N, 16); 217 | this.e = parseInt(E, 16); 218 | this.d = parseBigInt(D, 16); 219 | } else { 220 | console.error("Invalid RSA private key"); 221 | } 222 | } 223 | 224 | // RSAKey.prototype.setPrivateEx = RSASetPrivateEx; 225 | // Set the private key fields N, e, d and CRT params from hex strings 226 | public setPrivateEx( 227 | N:string, 228 | E:string, 229 | D:string, 230 | P:string, 231 | Q:string, 232 | DP:string, 233 | DQ:string, 234 | C:string 235 | ) { 236 | if (N != null && E != null && N.length > 0 && E.length > 0) { 237 | this.n = parseBigInt(N, 16); 238 | this.e = parseInt(E, 16); 239 | this.d = parseBigInt(D, 16); 240 | this.p = parseBigInt(P, 16); 241 | this.q = parseBigInt(Q, 16); 242 | this.dmp1 = parseBigInt(DP, 16); 243 | this.dmq1 = parseBigInt(DQ, 16); 244 | this.coeff = parseBigInt(C, 16); 245 | } else { 246 | console.error("Invalid RSA private key"); 247 | } 248 | } 249 | 250 | // RSAKey.prototype.generate = RSAGenerate; 251 | // Generate a new random private key B bits long, using public expt E 252 | public generate(B:number, E:string) { 253 | const rng = new SecureRandom(); 254 | const qs = B >> 1; 255 | this.e = parseInt(E, 16); 256 | const ee = new BigInteger(E, 16); 257 | for (;;) { 258 | for (;;) { 259 | this.p = new BigInteger(B - qs, 1, rng); 260 | if ( 261 | this.p 262 | .subtract(BigInteger.ONE) 263 | .gcd(ee) 264 | .compareTo(BigInteger.ONE) == 0 && 265 | this.p.isProbablePrime(10) 266 | ) { 267 | break; 268 | } 269 | } 270 | for (;;) { 271 | this.q = new BigInteger(qs, 1, rng); 272 | if ( 273 | this.q 274 | .subtract(BigInteger.ONE) 275 | .gcd(ee) 276 | .compareTo(BigInteger.ONE) == 0 && 277 | this.q.isProbablePrime(10) 278 | ) { 279 | break; 280 | } 281 | } 282 | if (this.p.compareTo(this.q) <= 0) { 283 | const t = this.p; 284 | this.p = this.q; 285 | this.q = t; 286 | } 287 | const p1 = this.p.subtract(BigInteger.ONE); 288 | const q1 = this.q.subtract(BigInteger.ONE); 289 | const phi = p1.multiply(q1); 290 | if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { 291 | this.n = this.p.multiply(this.q); 292 | this.d = ee.modInverse(phi); 293 | this.dmp1 = this.d.mod(p1); 294 | this.dmq1 = this.d.mod(q1); 295 | this.coeff = this.q.modInverse(this.p); 296 | break; 297 | } 298 | } 299 | } 300 | 301 | // RSAKey.prototype.decrypt = RSADecrypt; 302 | // Return the PKCS#1 RSA decryption of "ctext". 303 | // "ctext" is an even-length hex string and the output is a plain string. 304 | public decrypt(ctext:string) { 305 | const c = parseBigInt(ctext, 16); 306 | const m = this.doPrivate(c); 307 | if (m == null) { 308 | return null; 309 | } 310 | return pkcs1unpad2(m, (this.n.bitLength() + 7) >> 3); 311 | } 312 | 313 | // Generate a new random private key B bits long, using public expt E 314 | public generateAsync(B:number, E:string, callback:() => void) { 315 | const rng = new SecureRandom(); 316 | const qs = B >> 1; 317 | this.e = parseInt(E, 16); 318 | const ee = new BigInteger(E, 16); 319 | const rsa = this; 320 | // These functions have non-descript names because they were originally for(;;) loops. 321 | // I don't know about cryptography to give them better names than loop1-4. 322 | const loop1 = function () { 323 | const loop4 = function () { 324 | if (rsa.p.compareTo(rsa.q) <= 0) { 325 | const t = rsa.p; 326 | rsa.p = rsa.q; 327 | rsa.q = t; 328 | } 329 | const p1 = rsa.p.subtract(BigInteger.ONE); 330 | const q1 = rsa.q.subtract(BigInteger.ONE); 331 | const phi = p1.multiply(q1); 332 | if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { 333 | rsa.n = rsa.p.multiply(rsa.q); 334 | rsa.d = ee.modInverse(phi); 335 | rsa.dmp1 = rsa.d.mod(p1); 336 | rsa.dmq1 = rsa.d.mod(q1); 337 | rsa.coeff = rsa.q.modInverse(rsa.p); 338 | setTimeout(function () { 339 | callback(); 340 | }, 0); // escape 341 | } else { 342 | setTimeout(loop1, 0); 343 | } 344 | }; 345 | const loop3 = function () { 346 | rsa.q = nbi(); 347 | rsa.q.fromNumberAsync(qs, 1, rng, function () { 348 | rsa.q.subtract(BigInteger.ONE).gcda(ee, function (r) { 349 | if (r.compareTo(BigInteger.ONE) == 0 && rsa.q.isProbablePrime(10)) { 350 | setTimeout(loop4, 0); 351 | } else { 352 | setTimeout(loop3, 0); 353 | } 354 | }); 355 | }); 356 | }; 357 | const loop2 = function () { 358 | rsa.p = nbi(); 359 | rsa.p.fromNumberAsync(B - qs, 1, rng, function () { 360 | rsa.p.subtract(BigInteger.ONE).gcda(ee, function (r) { 361 | if (r.compareTo(BigInteger.ONE) == 0 && rsa.p.isProbablePrime(10)) { 362 | setTimeout(loop3, 0); 363 | } else { 364 | setTimeout(loop2, 0); 365 | } 366 | }); 367 | }); 368 | }; 369 | setTimeout(loop2, 0); 370 | }; 371 | setTimeout(loop1, 0); 372 | } 373 | 374 | public sign(text:string, digestMethod:(str:string) => string, digestName:string):string { 375 | const header = getDigestHeader(digestName); 376 | const digest = header + digestMethod(text).toString(); 377 | const m = pkcs1pad1(digest, this.n.bitLength() / 4); 378 | if (m == null) { 379 | return null; 380 | } 381 | const c = this.doPrivate(m); 382 | if (c == null) { 383 | return null; 384 | } 385 | const h = c.toString(16); 386 | if ((h.length & 1) == 0) { 387 | return h; 388 | } else { 389 | return "0" + h; 390 | } 391 | } 392 | 393 | public verify(text:string, signature:string, digestMethod:(str:string) => string):boolean { 394 | const c = parseBigInt(signature, 16); 395 | const m = this.doPublic(c); 396 | if (m == null) { 397 | return null; 398 | } 399 | const unpadded = m.toString(16).replace(/^1f+00/, ""); 400 | const digest = removeDigestHeader(unpadded); 401 | return digest == digestMethod(text).toString(); 402 | } 403 | 404 | //#endregion PUBLIC 405 | 406 | protected n:BigInteger; 407 | protected e:number; 408 | protected d:BigInteger; 409 | protected p:BigInteger; 410 | protected q:BigInteger; 411 | protected dmp1:BigInteger; 412 | protected dmq1:BigInteger; 413 | protected coeff:BigInteger; 414 | } 415 | 416 | // Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext 417 | function pkcs1unpad2(d:BigInteger, n:number):string { 418 | const b = d.toByteArray(); 419 | let i = 0; 420 | while (i < b.length && b[i] == 0) { 421 | ++i; 422 | } 423 | if (b.length - i != n - 1 || b[i] != 2) { 424 | return null; 425 | } 426 | ++i; 427 | while (b[i] != 0) { 428 | if (++i >= b.length) { 429 | return null; 430 | } 431 | } 432 | let ret = ""; 433 | while (++i < b.length) { 434 | const c = b[i] & 255; 435 | if (c < 128) { 436 | // utf-8 decode 437 | ret += String.fromCharCode(c); 438 | } else if (c > 191 && c < 224) { 439 | ret += String.fromCharCode(((c & 31) << 6) | (b[i + 1] & 63)); 440 | ++i; 441 | } else { 442 | ret += String.fromCharCode(((c & 15) << 12) | ((b[i + 1] & 63) << 6) | (b[i + 2] & 63)); 443 | i += 2; 444 | } 445 | } 446 | return ret; 447 | } 448 | 449 | // https://tools.ietf.org/html/rfc3447#page-43 450 | const DIGEST_HEADERS:{ [name:string]:string } = { 451 | md2: "3020300c06082a864886f70d020205000410", 452 | md5: "3020300c06082a864886f70d020505000410", 453 | sha1: "3021300906052b0e03021a05000414", 454 | sha224: "302d300d06096086480165030402040500041c", 455 | sha256: "3031300d060960864801650304020105000420", 456 | sha384: "3041300d060960864801650304020205000430", 457 | sha512: "3051300d060960864801650304020305000440", 458 | ripemd160: "3021300906052b2403020105000414" 459 | }; 460 | 461 | function getDigestHeader(name:string):string { 462 | return DIGEST_HEADERS[name] || ""; 463 | } 464 | 465 | function removeDigestHeader(str:string):string { 466 | for (const name in DIGEST_HEADERS) { 467 | if (DIGEST_HEADERS.hasOwnProperty(name)) { 468 | const header = DIGEST_HEADERS[name]; 469 | const len = header.length; 470 | if (str.substr(0, len) == header) { 471 | return str.substr(len); 472 | } 473 | } 474 | } 475 | return str; 476 | } 477 | 478 | // Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string 479 | // function RSAEncryptB64(text) { 480 | // var h = this.encrypt(text); 481 | // if(h) return hex2b64(h); else return null; 482 | // } 483 | 484 | // public 485 | 486 | // RSAKey.prototype.encrypt_b64 = RSAEncryptB64; 487 | -------------------------------------------------------------------------------- /lib/jsbn/util.ts: -------------------------------------------------------------------------------- 1 | const BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; 2 | 3 | export function int2char(n:number) { 4 | return BI_RM.charAt(n); 5 | } 6 | 7 | //#region BIT_OPERATIONS 8 | 9 | // (public) this & a 10 | export function op_and(x:number, y:number):number { 11 | return x & y; 12 | } 13 | 14 | 15 | // (public) this | a 16 | export function op_or(x:number, y:number):number { 17 | return x | y; 18 | } 19 | 20 | // (public) this ^ a 21 | export function op_xor(x:number, y:number):number { 22 | return x ^ y; 23 | } 24 | 25 | 26 | // (public) this & ~a 27 | export function op_andnot(x:number, y:number):number { 28 | return x & ~y; 29 | } 30 | 31 | // return index of lowest 1-bit in x, x < 2^31 32 | export function lbit(x:number) { 33 | if (x == 0) { 34 | return -1; 35 | } 36 | let r = 0; 37 | if ((x & 0xffff) == 0) { 38 | x >>= 16; 39 | r += 16; 40 | } 41 | if ((x & 0xff) == 0) { 42 | x >>= 8; 43 | r += 8; 44 | } 45 | if ((x & 0xf) == 0) { 46 | x >>= 4; 47 | r += 4; 48 | } 49 | if ((x & 3) == 0) { 50 | x >>= 2; 51 | r += 2; 52 | } 53 | if ((x & 1) == 0) { 54 | ++r; 55 | } 56 | return r; 57 | } 58 | 59 | // return number of 1 bits in x 60 | export function cbit(x:number) { 61 | let r = 0; 62 | while (x != 0) { 63 | x &= x - 1; 64 | ++r; 65 | } 66 | return r; 67 | } 68 | 69 | //#endregion BIT_OPERATIONS 70 | -------------------------------------------------------------------------------- /lib/jsrsasign/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | CONTAINS CODE FROM YUI LIBRARY SEE LICENSE @ http://yuilibrary.com/license/ 4 | 5 | The 'jsrsasign'(RSA-Sign JavaScript Library) License 6 | 7 | Copyright (c) 2010-2013 Kenji Urushima 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. -------------------------------------------------------------------------------- /lib/jsrsasign/asn1-1.0.d.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | declare interface IDERIntegerParams { 4 | bigint?:any; 5 | int?:number; 6 | hex?:number; 7 | } 8 | 9 | declare class DERInteger { 10 | /**/ 11 | } 12 | 13 | declare interface IDERIntegerConstructor { 14 | new(params:IDERIntegerParams):DERInteger; 15 | } 16 | 17 | declare class DERSequence { 18 | /**/ 19 | public getEncodedHex():string; 20 | } 21 | declare interface IDERSequenceConstructor { 22 | new(params:{ 23 | array:DERInteger[]; 24 | }):DERSequence; 25 | } 26 | 27 | 28 | declare class DERObjectIdentifier { 29 | /**/ 30 | } 31 | declare interface IDERObjectIdentifierConstructor { 32 | new(params:{ 33 | oid?:string; 34 | hex?:string; 35 | name?:string; 36 | }|string):DERObjectIdentifier; 37 | } 38 | 39 | 40 | declare class DERNull { 41 | /**/ 42 | } 43 | declare interface IDERNullConstructor { 44 | new():DERNull; 45 | } 46 | 47 | 48 | declare class DERBitString { 49 | /**/ 50 | } 51 | declare interface IDERBitStringConstructor { 52 | new(params:{ 53 | hex?:string; 54 | array?:boolean[]; 55 | bin?:string; 56 | }|string):DERBitString; 57 | } 58 | 59 | 60 | declare interface Iasn1 { 61 | readonly DERInteger:IDERIntegerConstructor; 62 | 63 | readonly DERSequence:IDERSequenceConstructor; 64 | 65 | readonly DERObjectIdentifier:IDERObjectIdentifierConstructor; 66 | 67 | readonly DERNull:IDERNullConstructor; 68 | 69 | readonly DERBitString:IDERBitStringConstructor; 70 | } 71 | 72 | declare interface IKJUR { 73 | readonly asn1:Iasn1; 74 | } 75 | 76 | 77 | export const KJUR:IKJUR; 78 | -------------------------------------------------------------------------------- /lib/jsrsasign/yahoo.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Copyright (c) 2011, Yahoo! Inc. All rights reserved. 3 | Code licensed under the BSD License: 4 | http://developer.yahoo.com/yui/license.html 5 | version: 2.9.0 6 | */ 7 | export var YAHOO = {}; 8 | YAHOO.lang = { 9 | /** 10 | * Utility to set up the prototype, constructor and superclass properties to 11 | * support an inheritance strategy that can chain constructors and methods. 12 | * Static members will not be inherited. 13 | * 14 | * @method extend 15 | * @static 16 | * @param {Function} subc the object to modify 17 | * @param {Function} superc the object to inherit 18 | * @param {Object} overrides additional properties/methods to add to the 19 | * subclass prototype. These will override the 20 | * matching items obtained from the superclass 21 | * if present. 22 | */ 23 | extend: function(subc, superc, overrides) { 24 | if (! superc || ! subc) { 25 | throw new Error("YAHOO.lang.extend failed, please check that " + 26 | "all dependencies are included."); 27 | } 28 | 29 | var F = function() {}; 30 | F.prototype = superc.prototype; 31 | subc.prototype = new F(); 32 | subc.prototype.constructor = subc; 33 | subc.superclass = superc.prototype; 34 | 35 | if (superc.prototype.constructor == Object.prototype.constructor) { 36 | superc.prototype.constructor = superc; 37 | } 38 | 39 | if (overrides) { 40 | var i; 41 | for (i in overrides) { 42 | subc.prototype[i] = overrides[i]; 43 | } 44 | 45 | /* 46 | * IE will not enumerate native functions in a derived object even if the 47 | * function was overridden. This is a workaround for specific functions 48 | * we care about on the Object prototype. 49 | * @property _IEEnumFix 50 | * @param {Function} r the object to receive the augmentation 51 | * @param {Function} s the object that supplies the properties to augment 52 | * @static 53 | * @private 54 | */ 55 | var _IEEnumFix = function() {}, 56 | ADD = ["toString", "valueOf"]; 57 | try { 58 | if (/MSIE/.test(navigator.userAgent)) { 59 | _IEEnumFix = function(r, s) { 60 | for (i = 0; i < ADD.length; i = i + 1) { 61 | var fname = ADD[i], f = s[fname]; 62 | if (typeof f === 'function' && f != Object.prototype[fname]) { 63 | r[fname] = f; 64 | } 65 | } 66 | }; 67 | } 68 | } catch (ex) {}; 69 | _IEEnumFix(subc.prototype, overrides); 70 | } 71 | } 72 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "encryptlong", 3 | "version": "3.1.3", 4 | "description": "基于jsencrypt扩展的可支持长文本加解密的库", 5 | "license": "MIT", 6 | "main": "bin/jsencrypt.js", 7 | "scripts": { 8 | "prepublish": "node_modules/gulp/bin/gulp.js" 9 | }, 10 | "contributors": [ 11 | { 12 | "name": "Travis Tidwell", 13 | "email": "travis@form.io", 14 | "url": "http://github.com/travist" 15 | }, 16 | { 17 | "name": "Antonio", 18 | "url": "https://github.com/zoloft" 19 | }, 20 | { 21 | "name": "Julio", 22 | "url": "https://github.com/jmgaya" 23 | } 24 | ], 25 | "homepage": "http://www.travistidwell.com/jsencrypt", 26 | "repository": { 27 | "type": "git", 28 | "url": "git://github.com/lsxlsxxslxsl/encryptlong.git" 29 | }, 30 | "bugs": { 31 | "url": "http://github.com/lsxlsxxslxsl/encryptlong/issues" 32 | }, 33 | "keywords": [ 34 | "encrypt", 35 | "jsencrypt", 36 | "jsencryptlong", 37 | "rsa", 38 | "encryptlong" 39 | ], 40 | "devDependencies": { 41 | "expect.js": "^0.3.1", 42 | "gulp": "^3.9.1", 43 | "gulp-concat": "^2.6.1", 44 | "gulp-copy": "^1.0.1", 45 | "gulp-eslint": "^4.0.2", 46 | "gulp-insert": "^0.5.0", 47 | "gulp-rename": "^1.2.2", 48 | "gulp-tslint": "^8.1.2", 49 | "gulp-typescript": "^4.0.1", 50 | "gulp-uglify": "^3.0.0", 51 | "gulp-watch": "^5.0.0", 52 | "gulp-wrap": "^0.13.0", 53 | "mocha": "^5.0.1", 54 | "rollup": "^0.56.1", 55 | "rollup-plugin-node-resolve": "^3.0.0", 56 | "rollup-plugin-replace": "^2.0.0", 57 | "rollup-plugin-uglify": "^3.0.0", 58 | "ts-loader": "^3.2.0", 59 | "tslib": "^1.8.1", 60 | "tslint": "^5.8.0", 61 | "typescript": "^2.6.2", 62 | "webpack": "^3.10.0" 63 | }, 64 | "dependencies": {}, 65 | "typings": "declarations/src/index.d.ts" 66 | } 67 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const resolve = require('rollup-plugin-node-resolve'); 3 | const uglify = require('rollup-plugin-uglify'); 4 | const replace = require('rollup-plugin-replace'); 5 | const pkg = require('./package.json'); 6 | 7 | var plugins = [ 8 | resolve(), 9 | // uglify({ 10 | // mangle: true, 11 | // warnings: true, 12 | // output: { 13 | // beautify: false, 14 | // }, 15 | // compress: { 16 | // join_vars: true, 17 | // if_return: true, 18 | // properties: true, 19 | // conditionals: true, 20 | // warnings: true, 21 | // dead_code: true, 22 | // drop_console: true, 23 | // drop_debugger: true, 24 | // } 25 | // }), 26 | replace({ 27 | 'JSENCRYPT_VERSION': JSON.stringify(pkg.version) 28 | }) 29 | 30 | ]; 31 | 32 | 33 | module.exports = { 34 | input: "./src/index.js", 35 | plugins: plugins, 36 | name: "JSEncrypt", 37 | output: { 38 | file: pkg.main, 39 | format: 'umd', 40 | name: "JSEncrypt", 41 | exports: "named" 42 | }, 43 | // { file: pkg.module, format: 'es' } 44 | 45 | 46 | }; 47 | -------------------------------------------------------------------------------- /src/JSEncrypt.ts: -------------------------------------------------------------------------------- 1 | import { b64tohex, hex2b64 } from "../lib/jsbn/base64"; 2 | import { JSEncryptRSAKey } from "./JSEncryptRSAKey"; 3 | 4 | declare var JSENCRYPT_VERSION:string; 5 | 6 | export interface IJSEncryptOptions { 7 | default_key_size?:string; 8 | default_public_exponent?:string; 9 | log?:boolean; 10 | } 11 | 12 | /** 13 | * 14 | * @param {Object} [options = {}] - An object to customize JSEncrypt behaviour 15 | * possible parameters are: 16 | * - default_key_size {number} default: 1024 the key size in bit 17 | * - default_public_exponent {string} default: '010001' the hexadecimal representation of the public exponent 18 | * - log {boolean} default: false whether log warn/error or not 19 | * @constructor 20 | */ 21 | export default class JSEncrypt { 22 | constructor(options:IJSEncryptOptions) { 23 | options = options || {}; 24 | this.default_key_size = parseInt(options.default_key_size, 10) || 1024; 25 | this.default_public_exponent = options.default_public_exponent || "010001"; // 65537 default openssl public exponent for rsa key type 26 | this.log = options.log || false; 27 | // The private and public key. 28 | this.key = null; 29 | } 30 | 31 | private default_key_size:number; 32 | private default_public_exponent:string; 33 | private log:boolean; 34 | private key:JSEncryptRSAKey; 35 | 36 | public static version:string = JSENCRYPT_VERSION; 37 | 38 | /** 39 | * Method to set the rsa key parameter (one method is enough to set both the public 40 | * and the private key, since the private key contains the public key paramenters) 41 | * Log a warning if logs are enabled 42 | * @param {Object|string} key the pem encoded string or an object (with or without header/footer) 43 | * @public 44 | */ 45 | public setKey(key:string) { 46 | if (this.log && this.key) { 47 | console.warn("A key was already set, overriding existing."); 48 | } 49 | this.key = new JSEncryptRSAKey(key); 50 | } 51 | 52 | /** 53 | * Proxy method for setKey, for api compatibility 54 | * @see setKey 55 | * @public 56 | */ 57 | public setPrivateKey(privkey:string) { 58 | // Create the key. 59 | this.setKey(privkey); 60 | } 61 | 62 | /** 63 | * Proxy method for setKey, for api compatibility 64 | * @see setKey 65 | * @public 66 | */ 67 | public setPublicKey(pubkey:string) { 68 | // Sets the public key. 69 | this.setKey(pubkey); 70 | } 71 | 72 | /** 73 | * Proxy method for RSAKey object's decrypt, decrypt the string using the private 74 | * components of the rsa key object. Note that if the object was not set will be created 75 | * on the fly (by the getKey method) using the parameters passed in the JSEncrypt constructor 76 | * @param {string} str base64 encoded crypted string to decrypt 77 | * @return {string} the decrypted string 78 | * @public 79 | */ 80 | public decrypt(str:string) { 81 | // Return the decrypted string. 82 | try { 83 | return this.getKey().decrypt(b64tohex(str)); 84 | } catch (ex) { 85 | return false; 86 | } 87 | } 88 | 89 | /** 90 | * Proxy method for RSAKey object's encrypt, encrypt the string using the public 91 | * components of the rsa key object. Note that if the object was not set will be created 92 | * on the fly (by the getKey method) using the parameters passed in the JSEncrypt constructor 93 | * @param {string} str the string to encrypt 94 | * @return {string} the encrypted string encoded in base64 95 | * @public 96 | */ 97 | public encrypt(str:string) { 98 | // Return the encrypted string. 99 | try { 100 | return hex2b64(this.getKey().encrypt(str)); 101 | } catch (ex) { 102 | return false; 103 | } 104 | } 105 | 106 | /** 107 | * 分段加密长字符串 108 | * @param {string} str the string to encrypt 109 | * @return {string} the encrypted string encoded in base64 110 | * @public 111 | */ 112 | public encryptLong(str:string) { 113 | try { 114 | let encrypted = this.getKey().encryptLong(str) || ""; 115 | let uncrypted = this.getKey().decryptLong(encrypted) || ""; 116 | let count = 0; 117 | const reg = /null$/g; 118 | while (reg.test(uncrypted)) { 119 | // 如果加密出错,重新加密 120 | count++; 121 | encrypted = this.getKey().encryptLong(str) || ""; 122 | uncrypted = this.getKey().decryptLong(encrypted) || ""; 123 | // console.log('加密出错次数', count) 124 | if (count > 10) { 125 | // 重复加密不能大于10次 126 | // console.log('加密次数过多') 127 | break; 128 | } 129 | } 130 | return encrypted; 131 | } catch (ex) { 132 | return false; 133 | } 134 | } 135 | 136 | /** 137 | * 分段解密长字符串 138 | * @param {string} str base64 encoded crypted string to decrypt 139 | * @return {string} the decrypted string 140 | * @public 141 | */ 142 | public decryptLong(str:string) { 143 | try { 144 | return this.getKey().decryptLong(str); 145 | } catch (ex) { 146 | return false; 147 | } 148 | } 149 | 150 | /** 151 | * Proxy method for RSAKey object's sign. 152 | * @param {string} str the string to sign 153 | * @param {function} digestMethod hash method 154 | * @param {string} digestName the name of the hash algorithm 155 | * @return {string} the signature encoded in base64 156 | * @public 157 | */ 158 | public sign( 159 | str:string, 160 | digestMethod:(str:string) => string, 161 | digestName:string 162 | ):string | false { 163 | // return the RSA signature of 'str' in 'hex' format. 164 | try { 165 | return hex2b64(this.getKey().sign(str, digestMethod, digestName)); 166 | } catch (ex) { 167 | return false; 168 | } 169 | } 170 | 171 | /** 172 | * Proxy method for RSAKey object's verify. 173 | * @param {string} str the string to verify 174 | * @param {string} signature the signature encoded in base64 to compare the string to 175 | * @param {function} digestMethod hash method 176 | * @return {boolean} whether the data and signature match 177 | * @public 178 | */ 179 | public verify(str:string, signature:string, digestMethod:(str:string) => string):boolean { 180 | // Return the decrypted 'digest' of the signature. 181 | try { 182 | return this.getKey().verify(str, b64tohex(signature), digestMethod); 183 | } catch (ex) { 184 | return false; 185 | } 186 | } 187 | 188 | /** 189 | * Getter for the current JSEncryptRSAKey object. If it doesn't exists a new object 190 | * will be created and returned 191 | * @param {callback} [cb] the callback to be called if we want the key to be generated 192 | * in an async fashion 193 | * @returns {JSEncryptRSAKey} the JSEncryptRSAKey object 194 | * @public 195 | */ 196 | public getKey(cb?:() => void) { 197 | // Only create new if it does not exist. 198 | if (!this.key) { 199 | // Get a new private key. 200 | this.key = new JSEncryptRSAKey(); 201 | if (cb && {}.toString.call(cb) === "[object Function]") { 202 | this.key.generateAsync(this.default_key_size, this.default_public_exponent, cb); 203 | return; 204 | } 205 | // Generate the key. 206 | this.key.generate(this.default_key_size, this.default_public_exponent); 207 | } 208 | return this.key; 209 | } 210 | 211 | /** 212 | * Returns the pem encoded representation of the private key 213 | * If the key doesn't exists a new key will be created 214 | * @returns {string} pem encoded representation of the private key WITH header and footer 215 | * @public 216 | */ 217 | public getPrivateKey() { 218 | // Return the private representation of this key. 219 | return this.getKey().getPrivateKey(); 220 | } 221 | 222 | /** 223 | * Returns the pem encoded representation of the private key 224 | * If the key doesn't exists a new key will be created 225 | * @returns {string} pem encoded representation of the private key WITHOUT header and footer 226 | * @public 227 | */ 228 | public getPrivateKeyB64() { 229 | // Return the private representation of this key. 230 | return this.getKey().getPrivateBaseKeyB64(); 231 | } 232 | 233 | /** 234 | * Returns the pem encoded representation of the public key 235 | * If the key doesn't exists a new key will be created 236 | * @returns {string} pem encoded representation of the public key WITH header and footer 237 | * @public 238 | */ 239 | public getPublicKey() { 240 | // Return the private representation of this key. 241 | return this.getKey().getPublicKey(); 242 | } 243 | 244 | /** 245 | * Returns the pem encoded representation of the public key 246 | * If the key doesn't exists a new key will be created 247 | * @returns {string} pem encoded representation of the public key WITHOUT header and footer 248 | * @public 249 | */ 250 | public getPublicKeyB64() { 251 | // Return the private representation of this key. 252 | return this.getKey().getPublicBaseKeyB64(); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/JSEncryptRSAKey.ts: -------------------------------------------------------------------------------- 1 | import { hex2b64 } from "../lib/jsbn/base64"; 2 | import { Hex } from "../lib/asn1js/hex"; 3 | import { Base64 } from "../lib/asn1js/base64"; 4 | import { ASN1 } from "../lib/asn1js/asn1"; 5 | import { RSAKey } from "../lib/jsbn/rsa"; 6 | import { parseBigInt } from "../lib/jsbn/jsbn"; 7 | import { KJUR } from "../lib/jsrsasign/asn1-1.0"; 8 | 9 | /** 10 | * Create a new JSEncryptRSAKey that extends Tom Wu's RSA key object. 11 | * This object is just a decorator for parsing the key parameter 12 | * @param {string|Object} key - The key in string format, or an object containing 13 | * the parameters needed to build a RSAKey object. 14 | * @constructor 15 | */ 16 | export class JSEncryptRSAKey extends RSAKey { 17 | constructor(key?:string) { 18 | super(); 19 | // Call the super constructor. 20 | // RSAKey.call(this); 21 | // If a key key was provided. 22 | if (key) { 23 | // If this is a string... 24 | if (typeof key === "string") { 25 | this.parseKey(key); 26 | } else if ( 27 | JSEncryptRSAKey.hasPrivateKeyProperty(key) || 28 | JSEncryptRSAKey.hasPublicKeyProperty(key) 29 | ) { 30 | // Set the values for the key. 31 | this.parsePropertiesFrom(key); 32 | } 33 | } 34 | } 35 | 36 | /** 37 | * Method to parse a pem encoded string containing both a public or private key. 38 | * The method will translate the pem encoded string in a der encoded string and 39 | * will parse private key and public key parameters. This method accepts public key 40 | * in the rsaencryption pkcs #1 format (oid: 1.2.840.113549.1.1.1). 41 | * 42 | * @todo Check how many rsa formats use the same format of pkcs #1. 43 | * 44 | * The format is defined as: 45 | * PublicKeyInfo ::= SEQUENCE { 46 | * algorithm AlgorithmIdentifier, 47 | * PublicKey BIT STRING 48 | * } 49 | * Where AlgorithmIdentifier is: 50 | * AlgorithmIdentifier ::= SEQUENCE { 51 | * algorithm OBJECT IDENTIFIER, the OID of the enc algorithm 52 | * parameters ANY DEFINED BY algorithm OPTIONAL (NULL for PKCS #1) 53 | * } 54 | * and PublicKey is a SEQUENCE encapsulated in a BIT STRING 55 | * RSAPublicKey ::= SEQUENCE { 56 | * modulus INTEGER, -- n 57 | * publicExponent INTEGER -- e 58 | * } 59 | * it's possible to examine the structure of the keys obtained from openssl using 60 | * an asn.1 dumper as the one used here to parse the components: http://lapo.it/asn1js/ 61 | * @argument {string} pem the pem encoded string, can include the BEGIN/END header/footer 62 | * @private 63 | */ 64 | public parseKey(pem:string) { 65 | try { 66 | let modulus:string | number = 0; 67 | let public_exponent:string | number = 0; 68 | const reHex = /^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/; 69 | const der = reHex.test(pem) ? Hex.decode(pem) : Base64.unarmor(pem); 70 | let asn1 = ASN1.decode(der); 71 | 72 | // Fixes a bug with OpenSSL 1.0+ private keys 73 | if (asn1.sub.length === 3) { 74 | asn1 = asn1.sub[2].sub[0]; 75 | } 76 | if (asn1.sub.length === 9) { 77 | // Parse the private key. 78 | modulus = asn1.sub[1].getHexStringValue(); // bigint 79 | this.n = parseBigInt(modulus, 16); 80 | 81 | public_exponent = asn1.sub[2].getHexStringValue(); // int 82 | this.e = parseInt(public_exponent, 16); 83 | 84 | const private_exponent = asn1.sub[3].getHexStringValue(); // bigint 85 | this.d = parseBigInt(private_exponent, 16); 86 | 87 | const prime1 = asn1.sub[4].getHexStringValue(); // bigint 88 | this.p = parseBigInt(prime1, 16); 89 | 90 | const prime2 = asn1.sub[5].getHexStringValue(); // bigint 91 | this.q = parseBigInt(prime2, 16); 92 | 93 | const exponent1 = asn1.sub[6].getHexStringValue(); // bigint 94 | this.dmp1 = parseBigInt(exponent1, 16); 95 | 96 | const exponent2 = asn1.sub[7].getHexStringValue(); // bigint 97 | this.dmq1 = parseBigInt(exponent2, 16); 98 | 99 | const coefficient = asn1.sub[8].getHexStringValue(); // bigint 100 | this.coeff = parseBigInt(coefficient, 16); 101 | } else if (asn1.sub.length === 2) { 102 | // Parse the public key. 103 | const bit_string = asn1.sub[1]; 104 | const sequence = bit_string.sub[0]; 105 | 106 | modulus = sequence.sub[0].getHexStringValue(); 107 | this.n = parseBigInt(modulus, 16); 108 | public_exponent = sequence.sub[1].getHexStringValue(); 109 | this.e = parseInt(public_exponent, 16); 110 | } else { 111 | return false; 112 | } 113 | return true; 114 | } catch (ex) { 115 | return false; 116 | } 117 | } 118 | 119 | /** 120 | * Translate rsa parameters in a hex encoded string representing the rsa key. 121 | * 122 | * The translation follow the ASN.1 notation : 123 | * RSAPrivateKey ::= SEQUENCE { 124 | * version Version, 125 | * modulus INTEGER, -- n 126 | * publicExponent INTEGER, -- e 127 | * privateExponent INTEGER, -- d 128 | * prime1 INTEGER, -- p 129 | * prime2 INTEGER, -- q 130 | * exponent1 INTEGER, -- d mod (p1) 131 | * exponent2 INTEGER, -- d mod (q-1) 132 | * coefficient INTEGER, -- (inverse of q) mod p 133 | * } 134 | * @returns {string} DER Encoded String representing the rsa private key 135 | * @private 136 | */ 137 | public getPrivateBaseKey() { 138 | const options = { 139 | array: [ 140 | new KJUR.asn1.DERInteger({ int: 0 }), 141 | new KJUR.asn1.DERInteger({ bigint: this.n }), 142 | new KJUR.asn1.DERInteger({ int: this.e }), 143 | new KJUR.asn1.DERInteger({ bigint: this.d }), 144 | new KJUR.asn1.DERInteger({ bigint: this.p }), 145 | new KJUR.asn1.DERInteger({ bigint: this.q }), 146 | new KJUR.asn1.DERInteger({ bigint: this.dmp1 }), 147 | new KJUR.asn1.DERInteger({ bigint: this.dmq1 }), 148 | new KJUR.asn1.DERInteger({ bigint: this.coeff }) 149 | ] 150 | }; 151 | const seq = new KJUR.asn1.DERSequence(options); 152 | return seq.getEncodedHex(); 153 | } 154 | 155 | /** 156 | * base64 (pem) encoded version of the DER encoded representation 157 | * @returns {string} pem encoded representation without header and footer 158 | * @public 159 | */ 160 | public getPrivateBaseKeyB64() { 161 | return hex2b64(this.getPrivateBaseKey()); 162 | } 163 | 164 | /** 165 | * Translate rsa parameters in a hex encoded string representing the rsa public key. 166 | * The representation follow the ASN.1 notation : 167 | * PublicKeyInfo ::= SEQUENCE { 168 | * algorithm AlgorithmIdentifier, 169 | * PublicKey BIT STRING 170 | * } 171 | * Where AlgorithmIdentifier is: 172 | * AlgorithmIdentifier ::= SEQUENCE { 173 | * algorithm OBJECT IDENTIFIER, the OID of the enc algorithm 174 | * parameters ANY DEFINED BY algorithm OPTIONAL (NULL for PKCS #1) 175 | * } 176 | * and PublicKey is a SEQUENCE encapsulated in a BIT STRING 177 | * RSAPublicKey ::= SEQUENCE { 178 | * modulus INTEGER, -- n 179 | * publicExponent INTEGER -- e 180 | * } 181 | * @returns {string} DER Encoded String representing the rsa public key 182 | * @private 183 | */ 184 | public getPublicBaseKey() { 185 | const first_sequence = new KJUR.asn1.DERSequence({ 186 | array: [ 187 | new KJUR.asn1.DERObjectIdentifier({ oid: "1.2.840.113549.1.1.1" }), // RSA Encryption pkcs #1 oid 188 | new KJUR.asn1.DERNull() 189 | ] 190 | }); 191 | 192 | const second_sequence = new KJUR.asn1.DERSequence({ 193 | array: [ 194 | new KJUR.asn1.DERInteger({ bigint: this.n }), 195 | new KJUR.asn1.DERInteger({ int: this.e }) 196 | ] 197 | }); 198 | 199 | const bit_string = new KJUR.asn1.DERBitString({ 200 | hex: "00" + second_sequence.getEncodedHex() 201 | }); 202 | 203 | const seq = new KJUR.asn1.DERSequence({ 204 | array: [first_sequence, bit_string] 205 | }); 206 | return seq.getEncodedHex(); 207 | } 208 | 209 | /** 210 | * base64 (pem) encoded version of the DER encoded representation 211 | * @returns {string} pem encoded representation without header and footer 212 | * @public 213 | */ 214 | public getPublicBaseKeyB64() { 215 | return hex2b64(this.getPublicBaseKey()); 216 | } 217 | 218 | /** 219 | * wrap the string in block of width chars. The default value for rsa keys is 64 220 | * characters. 221 | * @param {string} str the pem encoded string without header and footer 222 | * @param {Number} [width=64] - the length the string has to be wrapped at 223 | * @returns {string} 224 | * @private 225 | */ 226 | public static wordwrap(str:string, width?:number) { 227 | width = width || 64; 228 | if (!str) { 229 | return str; 230 | } 231 | const regex = "(.{1," + width + "})( +|$\n?)|(.{1," + width + "})"; 232 | return str.match(RegExp(regex, "g")).join("\n"); 233 | } 234 | 235 | /** 236 | * Retrieve the pem encoded private key 237 | * @returns {string} the pem encoded private key with header/footer 238 | * @public 239 | */ 240 | public getPrivateKey() { 241 | let key = "-----BEGIN RSA PRIVATE KEY-----\n"; 242 | key += JSEncryptRSAKey.wordwrap(this.getPrivateBaseKeyB64()) + "\n"; 243 | key += "-----END RSA PRIVATE KEY-----"; 244 | return key; 245 | } 246 | 247 | /** 248 | * Retrieve the pem encoded public key 249 | * @returns {string} the pem encoded public key with header/footer 250 | * @public 251 | */ 252 | public getPublicKey() { 253 | let key = "-----BEGIN PUBLIC KEY-----\n"; 254 | key += JSEncryptRSAKey.wordwrap(this.getPublicBaseKeyB64()) + "\n"; 255 | key += "-----END PUBLIC KEY-----"; 256 | return key; 257 | } 258 | 259 | /** 260 | * Check if the object contains the necessary parameters to populate the rsa modulus 261 | * and public exponent parameters. 262 | * @param {Object} [obj={}] - An object that may contain the two public key 263 | * parameters 264 | * @returns {boolean} true if the object contains both the modulus and the public exponent 265 | * properties (n and e) 266 | * @todo check for types of n and e. N should be a parseable bigInt object, E should 267 | * be a parseable integer number 268 | * @private 269 | */ 270 | public static hasPublicKeyProperty(obj:object) { 271 | obj = obj || {}; 272 | return obj.hasOwnProperty("n") && obj.hasOwnProperty("e"); 273 | } 274 | 275 | /** 276 | * Check if the object contains ALL the parameters of an RSA key. 277 | * @param {Object} [obj={}] - An object that may contain nine rsa key 278 | * parameters 279 | * @returns {boolean} true if the object contains all the parameters needed 280 | * @todo check for types of the parameters all the parameters but the public exponent 281 | * should be parseable bigint objects, the public exponent should be a parseable integer number 282 | * @private 283 | */ 284 | public static hasPrivateKeyProperty(obj:object) { 285 | obj = obj || {}; 286 | return ( 287 | obj.hasOwnProperty("n") && 288 | obj.hasOwnProperty("e") && 289 | obj.hasOwnProperty("d") && 290 | obj.hasOwnProperty("p") && 291 | obj.hasOwnProperty("q") && 292 | obj.hasOwnProperty("dmp1") && 293 | obj.hasOwnProperty("dmq1") && 294 | obj.hasOwnProperty("coeff") 295 | ); 296 | } 297 | 298 | /** 299 | * Parse the properties of obj in the current rsa object. Obj should AT LEAST 300 | * include the modulus and public exponent (n, e) parameters. 301 | * @param {Object} obj - the object containing rsa parameters 302 | * @private 303 | */ 304 | public parsePropertiesFrom(obj:any) { 305 | this.n = obj.n; 306 | this.e = obj.e; 307 | 308 | if (obj.hasOwnProperty("d")) { 309 | this.d = obj.d; 310 | this.p = obj.p; 311 | this.q = obj.q; 312 | this.dmp1 = obj.dmp1; 313 | this.dmq1 = obj.dmq1; 314 | this.coeff = obj.coeff; 315 | } 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2015 Form.io 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in the 6 | Software without restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import JSEncrypt from "./JSEncrypt"; 2 | (window as any).JSEncrypt = JSEncrypt; 3 | export { JSEncrypt }; 4 | export default JSEncrypt; 5 | -------------------------------------------------------------------------------- /test/generate_test_keys.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | KEYS=(128 256 512 1024 2048); 3 | 4 | for KEY in "${KEYS[@]}" 5 | do 6 | openssl genrsa -out "rsa_"$KEY"_priv.pem" $KEY 7 | openssl rsa -pubout -in "rsa_"$KEY"_priv.pem" -out "rsa_"$KEY"_pub.pem" 8 | done 9 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Testing JSEncrypt 3 | layout: default 4 | --- 5 | 6 |
7 | 8 | 9 | 10 | 11 | 15 | -------------------------------------------------------------------------------- /test/libs/mocha.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | body { 4 | margin:0; 5 | } 6 | 7 | #mocha { 8 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | margin: 60px 50px; 10 | } 11 | 12 | #mocha ul, 13 | #mocha li { 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | #mocha ul { 19 | list-style: none; 20 | } 21 | 22 | #mocha h1, 23 | #mocha h2 { 24 | margin: 0; 25 | } 26 | 27 | #mocha h1 { 28 | margin-top: 15px; 29 | font-size: 1em; 30 | font-weight: 200; 31 | } 32 | 33 | #mocha h1 a { 34 | text-decoration: none; 35 | color: inherit; 36 | } 37 | 38 | #mocha h1 a:hover { 39 | text-decoration: underline; 40 | } 41 | 42 | #mocha .suite .suite h1 { 43 | margin-top: 0; 44 | font-size: .8em; 45 | } 46 | 47 | #mocha .hidden { 48 | display: none; 49 | } 50 | 51 | #mocha h2 { 52 | font-size: 12px; 53 | font-weight: normal; 54 | cursor: pointer; 55 | } 56 | 57 | #mocha .suite { 58 | margin-left: 15px; 59 | } 60 | 61 | #mocha .test { 62 | margin-left: 15px; 63 | overflow: hidden; 64 | } 65 | 66 | #mocha .test.pending:hover h2::after { 67 | content: '(pending)'; 68 | font-family: arial, sans-serif; 69 | } 70 | 71 | #mocha .test.pass.medium .duration { 72 | background: #c09853; 73 | } 74 | 75 | #mocha .test.pass.slow .duration { 76 | background: #b94a48; 77 | } 78 | 79 | #mocha .test.pass::before { 80 | content: '✓'; 81 | font-size: 12px; 82 | display: block; 83 | float: left; 84 | margin-right: 5px; 85 | color: #00d6b2; 86 | } 87 | 88 | #mocha .test.pass .duration { 89 | font-size: 9px; 90 | margin-left: 5px; 91 | padding: 2px 5px; 92 | color: #fff; 93 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 94 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 95 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 96 | -webkit-border-radius: 5px; 97 | -moz-border-radius: 5px; 98 | -ms-border-radius: 5px; 99 | -o-border-radius: 5px; 100 | border-radius: 5px; 101 | } 102 | 103 | #mocha .test.pass.fast .duration { 104 | display: none; 105 | } 106 | 107 | #mocha .test.pending { 108 | color: #0b97c4; 109 | } 110 | 111 | #mocha .test.pending::before { 112 | content: '◦'; 113 | color: #0b97c4; 114 | } 115 | 116 | #mocha .test.fail { 117 | color: #c00; 118 | } 119 | 120 | #mocha .test.fail pre { 121 | color: black; 122 | } 123 | 124 | #mocha .test.fail::before { 125 | content: '✖'; 126 | font-size: 12px; 127 | display: block; 128 | float: left; 129 | margin-right: 5px; 130 | color: #c00; 131 | } 132 | 133 | #mocha .test pre.error { 134 | color: #c00; 135 | max-height: 300px; 136 | overflow: auto; 137 | } 138 | 139 | #mocha .test .html-error { 140 | overflow: auto; 141 | color: black; 142 | line-height: 1.5; 143 | display: block; 144 | float: left; 145 | clear: left; 146 | font: 12px/1.5 monaco, monospace; 147 | margin: 5px; 148 | padding: 15px; 149 | border: 1px solid #eee; 150 | max-width: 85%; /*(1)*/ 151 | max-width: -webkit-calc(100% - 42px); 152 | max-width: -moz-calc(100% - 42px); 153 | max-width: calc(100% - 42px); /*(2)*/ 154 | max-height: 300px; 155 | word-wrap: break-word; 156 | border-bottom-color: #ddd; 157 | -webkit-box-shadow: 0 1px 3px #eee; 158 | -moz-box-shadow: 0 1px 3px #eee; 159 | box-shadow: 0 1px 3px #eee; 160 | -webkit-border-radius: 3px; 161 | -moz-border-radius: 3px; 162 | border-radius: 3px; 163 | } 164 | 165 | #mocha .test .html-error pre.error { 166 | border: none; 167 | -webkit-border-radius: 0; 168 | -moz-border-radius: 0; 169 | border-radius: 0; 170 | -webkit-box-shadow: 0; 171 | -moz-box-shadow: 0; 172 | box-shadow: 0; 173 | padding: 0; 174 | margin: 0; 175 | margin-top: 18px; 176 | max-height: none; 177 | } 178 | 179 | /** 180 | * (1): approximate for browsers not supporting calc 181 | * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) 182 | * ^^ seriously 183 | */ 184 | #mocha .test pre { 185 | display: block; 186 | float: left; 187 | clear: left; 188 | font: 12px/1.5 monaco, monospace; 189 | margin: 5px; 190 | padding: 15px; 191 | border: 1px solid #eee; 192 | max-width: 85%; /*(1)*/ 193 | max-width: -webkit-calc(100% - 42px); 194 | max-width: -moz-calc(100% - 42px); 195 | max-width: calc(100% - 42px); /*(2)*/ 196 | word-wrap: break-word; 197 | border-bottom-color: #ddd; 198 | -webkit-box-shadow: 0 1px 3px #eee; 199 | -moz-box-shadow: 0 1px 3px #eee; 200 | box-shadow: 0 1px 3px #eee; 201 | -webkit-border-radius: 3px; 202 | -moz-border-radius: 3px; 203 | border-radius: 3px; 204 | } 205 | 206 | #mocha .test h2 { 207 | position: relative; 208 | } 209 | 210 | #mocha .test a.replay { 211 | position: absolute; 212 | top: 3px; 213 | right: 0; 214 | text-decoration: none; 215 | vertical-align: middle; 216 | display: block; 217 | width: 15px; 218 | height: 15px; 219 | line-height: 15px; 220 | text-align: center; 221 | background: #eee; 222 | font-size: 15px; 223 | -webkit-border-radius: 15px; 224 | -moz-border-radius: 15px; 225 | border-radius: 15px; 226 | -webkit-transition:opacity 200ms; 227 | -moz-transition:opacity 200ms; 228 | -o-transition:opacity 200ms; 229 | transition: opacity 200ms; 230 | opacity: 0.3; 231 | color: #888; 232 | } 233 | 234 | #mocha .test:hover a.replay { 235 | opacity: 1; 236 | } 237 | 238 | #mocha-report.pass .test.fail { 239 | display: none; 240 | } 241 | 242 | #mocha-report.fail .test.pass { 243 | display: none; 244 | } 245 | 246 | #mocha-report.pending .test.pass, 247 | #mocha-report.pending .test.fail { 248 | display: none; 249 | } 250 | #mocha-report.pending .test.pass.pending { 251 | display: block; 252 | } 253 | 254 | #mocha-error { 255 | color: #c00; 256 | font-size: 1.5em; 257 | font-weight: 100; 258 | letter-spacing: 1px; 259 | } 260 | 261 | #mocha-stats { 262 | position: fixed; 263 | top: 15px; 264 | right: 10px; 265 | font-size: 12px; 266 | margin: 0; 267 | color: #888; 268 | z-index: 1; 269 | } 270 | 271 | #mocha-stats .progress { 272 | float: right; 273 | padding-top: 0; 274 | 275 | /** 276 | * Set safe initial values, so mochas .progress does not inherit these 277 | * properties from Bootstrap .progress (which causes .progress height to 278 | * equal line height set in Bootstrap). 279 | */ 280 | height: auto; 281 | -webkit-box-shadow: none; 282 | -moz-box-shadow: none; 283 | box-shadow: none; 284 | background-color: initial; 285 | } 286 | 287 | #mocha-stats em { 288 | color: black; 289 | } 290 | 291 | #mocha-stats a { 292 | text-decoration: none; 293 | color: inherit; 294 | } 295 | 296 | #mocha-stats a:hover { 297 | border-bottom: 1px solid #eee; 298 | } 299 | 300 | #mocha-stats li { 301 | display: inline-block; 302 | margin: 0 5px; 303 | list-style: none; 304 | padding-top: 11px; 305 | } 306 | 307 | #mocha-stats canvas { 308 | width: 40px; 309 | height: 40px; 310 | } 311 | 312 | #mocha code .comment { color: #ddd; } 313 | #mocha code .init { color: #2f6fad; } 314 | #mocha code .string { color: #5890ad; } 315 | #mocha code .keyword { color: #8a6343; } 316 | #mocha code .number { color: #2f6fad; } 317 | 318 | @media screen and (max-device-width: 480px) { 319 | #mocha { 320 | margin: 60px 0px; 321 | } 322 | 323 | #mocha #stats { 324 | position: absolute; 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /test/test.rsa.js: -------------------------------------------------------------------------------- 1 | // import {JSEncrypt} from "../src/JSEncrypt"; 2 | 3 | var keySizes = [128, 256, 512, 1024, 2048]; 4 | 5 | var pbkeys = [ 6 | "-----BEGIN PUBLIC KEY-----\n" + 7 | "MCwwDQYJKoZIhvcNAQEBBQADGwAwGAIRAMfE82X6tlpNK7Bxbhg6nEECAwEAAQ==\n" + 8 | "-----END PUBLIC KEY-----", 9 | "-----BEGIN PUBLIC KEY-----\n" + 10 | "MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMLw0mRGv5KF+P0LsgNvfrM5AJdVBWqr\n" + 11 | "Q6Bf2gES5gwPAgMBAAE=\n" + 12 | "-----END PUBLIC KEY-----", 13 | "-----BEGIN PUBLIC KEY-----\n" + 14 | "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKEpu21RDTXxEly55HdkVV9SlFL3Hgpl\n" + 15 | "i6+IohAsnaqFnApsKi1R7fAd3tBLmeHV2tlxYIogtxpzfpcc+QBVDx8CAwEAAQ==\n" + 16 | "-----END PUBLIC KEY-----", 17 | "-----BEGIN PUBLIC KEY-----\n" + 18 | "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5LO5xVlO9g4PL1xdWudnihIAP\n" + 19 | "bMsixr396bIbBIwKBul98UWQ3UALbqByq2bXVuoIbl48UokxOVstenGCyyo026NF\n" + 20 | "h3Fg6Cnvj9ptvbmqk2i3eTOBrt+e26Z1sepsnQL5OojiVIbrWwS6v1pFCXpnnLLv\n" + 21 | "yy6GPt/kftbhazH3oQIDAQAB\n" + 22 | "-----END PUBLIC KEY-----", 23 | "-----BEGIN PUBLIC KEY-----\n" + 24 | "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtKrsFSnzYl19m5wTwYdu\n" + 25 | "/r1UVZJV+zkAFud6+XTInAy8HbCR9n59H9+54P+Af/fUE6rvEPc4H09Z63vQzIGM\n" + 26 | "iL6GlqzMmptv/KRDIhj7Mk3MXomvEVfUsXrz5IpO0lf6NSeGhz4PGZUkHZ30VRx3\n" + 27 | "Jd/a0KIhgftZHxzmMsh8iB/n781B18pCP2eOPTF+5gRCaW+0fVPBlb/mBlg8MJrd\n" + 28 | "ScGCAReQ9NfTq8slJ0aO1NWaaRRANPQcCMljnTIK1ssyXBaSHKfoWeGx141mWMRx\n" + 29 | "/LxyZ13Zc3lqgmICiKFqMrQl5UeV1IUXYpj5hO9f60LGpZVHDqqo/JdF3+VAheaf\n" + 30 | "QwIDAQAB\n" + 31 | "-----END PUBLIC KEY-----" 32 | ]; 33 | 34 | var prkeys = [ 35 | "-----BEGIN RSA PRIVATE KEY-----\n" + 36 | "MGMCAQACEQDHxPNl+rZaTSuwcW4YOpxBAgMBAAECEQCqk6mhsmpyv17fK1dPeD3h\n" + 37 | "AgkA9Lo1aGRom0sCCQDQ+JpqE6KDIwIJAKstyIfBnA3rAggOsWwqCTdkAQIIOP95\n" + 38 | "RV9y2iQ=\n" + 39 | "-----END RSA PRIVATE KEY-----\n", 40 | "-----BEGIN RSA PRIVATE KEY-----\n" + 41 | "MIGqAgEAAiEAwvDSZEa/koX4/QuyA29+szkAl1UFaqtDoF/aARLmDA8CAwEAAQIh\n" + 42 | "AME2Z5Ez/hR/7PUBboKxM2U7hSaavytvocBdQjLvOUWhAhEA8HgiLHRk9KjJ2hp0\n" + 43 | "5q3BfQIRAM+H7dYUXRnKXjYoqiKueXsCEGnaaCirf/lXB6vzs3wMBr0CEHT2Xwzw\n" + 44 | "nSgT7dUIRhsVylECEFQRGFtZcKRmL8lqTBwECWI=\n" + 45 | "-----END RSA PRIVATE KEY-----\n", 46 | "-----BEGIN RSA PRIVATE KEY-----\n" + 47 | "MIIBOQIBAAJBAKEpu21RDTXxEly55HdkVV9SlFL3Hgpli6+IohAsnaqFnApsKi1R\n" + 48 | "7fAd3tBLmeHV2tlxYIogtxpzfpcc+QBVDx8CAwEAAQJAFn0VS07JEiLelhPWfpaA\n" + 49 | "lzmVuvICvh6nXEormygupBGiIPSXfIsTFid26yxt9wu4JHeRF0lq+Ozo55XpBQED\n" + 50 | "4QIhAM0E7ikuEa2bDsR2hQJhIz3SvzzyhE5dJcqFjRtKtMQvAiEAyT0C0gUyqCdN\n" + 51 | "YuRON1T7FUffarMdQXR+8tgRkhoCeBECID+ZKfAoVF+QXDJhub0VOQNyntRfPt+4\n" + 52 | "UYLTjwRKVm0NAiBuOCtuSoiHTxd0naU1aycmbboxn67bZeoOKkfdZL+LcQIgK6Xh\n" + 53 | "1wb9I/sNYv9ByJEGBNJRwtUEZrk5babLEdkUq90=\n" + 54 | "-----END RSA PRIVATE KEY-----\n", 55 | "-----BEGIN RSA PRIVATE KEY-----\n" + 56 | "MIICXgIBAAKBgQC5LO5xVlO9g4PL1xdWudnihIAPbMsixr396bIbBIwKBul98UWQ\n" + 57 | "3UALbqByq2bXVuoIbl48UokxOVstenGCyyo026NFh3Fg6Cnvj9ptvbmqk2i3eTOB\n" + 58 | "rt+e26Z1sepsnQL5OojiVIbrWwS6v1pFCXpnnLLvyy6GPt/kftbhazH3oQIDAQAB\n" + 59 | "AoGAA+EiGbPCS10e/L1D2uhH3UwDVs9jrhXV0yT7Oz+sI2WjrKTKXU+VUOf/aoeW\n" + 60 | "vvouKwEM7lyYTTSzaU+AY0oYVzv7HN9hWoVwi0NoPpd4V1RFfFb4+4DmXh+NZS7E\n" + 61 | "DX9+WY435Yc9Qj7uHoc8EoRk3QfWaZTXd69b/9tS4Yy/tnECQQDxHsSe7Qxd+6tf\n" + 62 | "/f4eO+bENCxIMbPU8GPWQCvq9eT9Av2I0LTTchmlhG1TSatq62zq+Unef8M/IOBs\n" + 63 | "j5z3issdAkEAxJpYiuAVXulViUOLdS3QX72owIQLxpFBAKQ9cPTafqc47ms4Swy2\n" + 64 | "FCa4MZfTJXrDX5pur+PNeP/ce6xZN5DzVQJBAJI1kgy8uU8UGKswnTNAJ4K6EFAG\n" + 65 | "s4Ff82orp3XmfWBeu9aGl9/PxHV1g8WJWoSPFZC2cXCWEJLrIKszun7wjpECQQCs\n" + 66 | "Z+mjh1RWUepHn+rozE9B1jDo+iLVc8V8CYszxhThIkWjlnTcI358d2PpYYmxAVHZ\n" + 67 | "QbU1G2CxbjZsYbwvJTatAkEAspmMlIyKWgrQkLJ4rbPespMJCGe6VYharl1Qc5CF\n" + 68 | "/2SgKSCuLfhA/Cur0nO3dxt6XJijk/r3+j+8L/m+wqud+A==\n" + 69 | "-----END RSA PRIVATE KEY-----\n", 70 | "-----BEGIN RSA PRIVATE KEY-----\n" + 71 | "MIIEpAIBAAKCAQEAtKrsFSnzYl19m5wTwYdu/r1UVZJV+zkAFud6+XTInAy8HbCR\n" + 72 | "9n59H9+54P+Af/fUE6rvEPc4H09Z63vQzIGMiL6GlqzMmptv/KRDIhj7Mk3MXomv\n" + 73 | "EVfUsXrz5IpO0lf6NSeGhz4PGZUkHZ30VRx3Jd/a0KIhgftZHxzmMsh8iB/n781B\n" + 74 | "18pCP2eOPTF+5gRCaW+0fVPBlb/mBlg8MJrdScGCAReQ9NfTq8slJ0aO1NWaaRRA\n" + 75 | "NPQcCMljnTIK1ssyXBaSHKfoWeGx141mWMRx/LxyZ13Zc3lqgmICiKFqMrQl5UeV\n" + 76 | "1IUXYpj5hO9f60LGpZVHDqqo/JdF3+VAheafQwIDAQABAoIBAQCS/++PWM7bXk5x\n" + 77 | "apD4ioXZZ5tS9PpYqoxUFoyMpGUF86asUZqyAUE1ygen9rxLYw5/4jkaiMx1TU9Q\n" + 78 | "tzGw9Eewi7Veq8LemVKJMe4dtE3PJFYBJe34IorAzdXcQlzX8RV4YmynZetLWXpF\n" + 79 | "Ttwa1Ept2rJjx0eURzrAgfcbot0Qs+c8bB0qnGC67PoL3DyYg8vX5PDmiiA2VZMG\n" + 80 | "EylVQS09toJn5ReaKCtjxJb/XFQjBeSP0xLjvZZftGDJgpwmmi7Sy/zAZoF4+7wf\n" + 81 | "8nihXk4ZfYC+beBj5U9pcUcs6LdNobUofWFRLSjueseRQBI0sKUslr3Ye4zhkrWM\n" + 82 | "CDnsSxBhAoGBANi0spS/Mc6xH1189mR7dJV9gy7KkGxheAstwCJr7WzbXqglhFm2\n" + 83 | "SvY9hrpE9OYWir5EqX6jM6VipSobTn0RpCsYUC/J1ISMyEA5UkPLP4jHQw6UUDN2\n" + 84 | "1fNAXffEyuju5ShP9Mk2unZstlUweKlFF7d1k7YAzWDIKnF6bOL06YC9AoGBANVt\n" + 85 | "XM4OH0zw8M97W04WwYGoa5s1Y5JYc4RMV200cr3iONVfLZgSP8thP1qPuoMM3OJg\n" + 86 | "Bqe6MRmo/VXhgVvpke04ZJ83LSz/SoqfVRNwxuCHqp3beJQPxrAp1d/L7Ey7f41U\n" + 87 | "QBE8pibFb8bbgOTUW5iyZbg7lLS8nghsn+BqYp//AoGBAJO/574o+YGOG+92wttR\n" + 88 | "nPRLhgSCEaQDdIBSqhwN7+v3SXtlUO6FrmhjHJelaj/yAJinYdS42v6Y2jlyMrpt\n" + 89 | "K7xCMHHUrzPMdL/tFRyp1+Ce0yZ+kov0Kv1V1nuWzi2wq8cndKM30Dvr9QjyKmJm\n" + 90 | "fDwWSyadN2oUL3P9X34CM64VAoGAbajAW1skN/tAL8r48dl9WWo4x8mZvJLX36z9\n" + 91 | "6q1dGzVF8FPz8EPIJW51B8n7keQlBedC5CElo0KRz/OK7LfI87La+Hd4LbuKCEmv\n" + 92 | "g8qZVLpALtWaUbD9bHxCWLfFVPOtqOcV+AVKdXdSZEFaK7j0yzM2Un/Ce07CgB+X\n" + 93 | "0c23mO8CgYAOqnUR/uPIzkvj/eIbO7pnhHoKZ4Ji2TrIBqjskzaFd0Tox9i3SWKa\n" + 94 | "cRdQciRIT1wkMdywnHFrJT1rwYXxcgfQXAku/vnYqAfvIzY7TyoL3pWX55O0Zrs7\n" + 95 | "05R9mA5TZmzUU9m/PzUrRjasOGYSKkCz4Y2qGlrKI3H0aE+p+R56kQ==\n" + 96 | "-----END RSA PRIVATE KEY-----\n" 97 | ]; 98 | 99 | keySizes.forEach(function(keySize, index){ 100 | 101 | var jse = new JSEncrypt({default_key_size:keySize}); 102 | var openssl_public_key = pbkeys[index]; 103 | var openssl_private_key = prkeys[index]; 104 | 105 | describe('JSEncrypt - '+keySize+' bit', function(){ 106 | //this.timeout(0); //Timout for test cases, zero means infinite. Needed for key sizes > 1024 107 | 108 | describe('#getKey()', function(){ 109 | 110 | it('should be '+keySize+' bit long', function () { 111 | 112 | var key = jse.getKey(); 113 | var length = key.n.bitLength(); 114 | length = length%2===0 ? length: length+1; 115 | expect(length).to.equal(keySize); 116 | 117 | }); 118 | 119 | }); 120 | 121 | describe('#getKey() async', function(done) { 122 | 123 | it('should be '+keySize+' bit long', function () { 124 | 125 | jse.getKey(function () { 126 | var key = jse.getKey(); 127 | var length = key.n.bitLength(); 128 | length = length%2===0 ? length: length+1; 129 | expect(length).to.equal(keySize); 130 | 131 | done(); 132 | }); 133 | 134 | 135 | }); 136 | 137 | }); 138 | 139 | describe('#encrypt() | #decrypt()', function(){ 140 | 141 | //Tom Wu's RSA Object use paddingpkcs #1, type 2 142 | var maxLength = (((jse.getKey().n.bitLength()+7)>>3)-11); 143 | var maxLengthBit = maxLength << 3; 144 | 145 | it('should encrypt/decrypt up to '+maxLengthBit+' bit', function () { 146 | 147 | var test = []; 148 | for (var i=0; i>3)-11); 177 | var maxLengthBit = maxLength << 3; 178 | 179 | it('should sign/verify up to '+maxLengthBit+' bit', function () { 180 | 181 | var digest = function(data){ return data; }; 182 | 183 | var test = []; 184 | for (var i=0; i