Compare commits
	
		
			4 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d5cb30f6bc | |||
| 1deaf14f5c | |||
| b5c919b557 | |||
| 7a1d0bbe76 | 
							
								
								
									
										48
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								README.md
									
									
									
									
									
								
							| @ -5,23 +5,23 @@ and convert it into a public JWK. | |||||||
| 
 | 
 | ||||||
| Works for RSA and ECDSA public keys. | Works for RSA and ECDSA public keys. | ||||||
| 
 | 
 | ||||||
| Features | # Features | ||||||
| ======== |  | ||||||
| 
 | 
 | ||||||
| < 100 lines of code | <1kb gzipped | 1.8kb minified | 3.1kb with comments | < 100 lines of code | <1kb gzipped | 1.8kb minified | 3.1kb with comments | ||||||
| 
 | 
 | ||||||
| * [x] SSH Public Keys | * [x] SSH Public Keys ([RFC 4253](https://coolaj86.com/articles/the-ssh-public-key-format/)) | ||||||
|   * fingerprint |   * fingerprint | ||||||
| * [x] SSH EC Private Keys | * [x] OpenSSH Private Keys | ||||||
| * [ ] SSH RSA Private Keys | * [x] RSA | ||||||
|   * `dp` and `dq` values are unavailable |   * 2048, 3072, 4096 | ||||||
| * [x] RSA Public Keys |  | ||||||
| * [x] EC Public Keys | * [x] EC Public Keys | ||||||
|   * P-256 (prime256v1, secp256r1) |   * P-256 (prime256v1, secp256r1) | ||||||
|   * P-384 (secp384r1) |   * P-384 (secp384r1) | ||||||
| * [x] Browser Version | * [x] Browser Version | ||||||
|   * [Bluecrypt SSH to JWK](https://git.coolaj86.com/coolaj86/bluecrypt-ssh-to-jwk.js) |   * [Bluecrypt SSH to JWK](https://git.coolaj86.com/coolaj86/bluecrypt-ssh-to-jwk.js) | ||||||
| 
 | 
 | ||||||
|  | Note: Lines of code have increased by about 2x since adding private key support. | ||||||
|  | 
 | ||||||
| ### Need JWK to SSH? SSH to PEM? | ### Need JWK to SSH? SSH to PEM? | ||||||
| 
 | 
 | ||||||
| Try one of these: | Try one of these: | ||||||
| @ -36,9 +36,7 @@ Many SSH private keys are just normal PEM files, | |||||||
| so you can use Eckles or Rasha, as mentioned above. | so you can use Eckles or Rasha, as mentioned above. | ||||||
| 
 | 
 | ||||||
| As for the [OpenSSH-specific Private Keys](https://coolaj86.com/articles/the-openssh-private-key-format/), | As for the [OpenSSH-specific Private Keys](https://coolaj86.com/articles/the-openssh-private-key-format/), | ||||||
| EC is **fully supported**, but RSA has only partial support. | both EC and RSA are fully supported. | ||||||
| 
 |  | ||||||
| For more information see the "SSH Private Keys" section at the end of this file. |  | ||||||
| 
 | 
 | ||||||
| # CLI | # CLI | ||||||
| 
 | 
 | ||||||
| @ -52,6 +50,10 @@ npm install -g ssh-to-jwk | |||||||
| ssh-to-jwk ~/.ssh/id_rsa.pub | ssh-to-jwk ~/.ssh/id_rsa.pub | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | ```bash | ||||||
|  | ssh-to-jwk ~/.ssh/id_rsa | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| # Usage | # Usage | ||||||
| 
 | 
 | ||||||
| You can also use it from JavaScript: | You can also use it from JavaScript: | ||||||
| @ -61,10 +63,13 @@ You can also use it from JavaScript: | |||||||
| ```js | ```js | ||||||
| var fs = require('fs'); | var fs = require('fs'); | ||||||
| var sshtojwk = require('ssh-to-jwk'); | var sshtojwk = require('ssh-to-jwk'); | ||||||
|  | var ssh; | ||||||
| 
 | 
 | ||||||
| var pub = fs.readFileSync("./id_rsa.pub"); | ssh = sshtojwk.parse({ pub: fs.readFileSync("./id_rsa.pub") }); | ||||||
| var ssh = sshtojwk.parse({ pub: pub }); | console.info(ssh.jwk); | ||||||
| 
 | 
 | ||||||
|  | // For OpenSSH PEMs only, use Rasha for standard RSA or Eckles for standard EC | ||||||
|  | ssh = sshtojwk.parse({ pem: fs.readFileSync("./id_rsa") }); | ||||||
| console.info(ssh.jwk); | console.info(ssh.jwk); | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| @ -81,25 +86,6 @@ sshtojwk.fingerprint({ pub: pub }).then(function (fingerprint) { | |||||||
| }); | }); | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| # SSH Private Keys |  | ||||||
| 
 |  | ||||||
| As mentioned above, EC private keys are fully supported, |  | ||||||
| and RSA private keys are partially supported. |  | ||||||
| 
 |  | ||||||
| It's unlikely that we'll support full SSH-to-JWK conversion for private RSA keys |  | ||||||
| because OpenSSH omits the `dp` and `dq` values. |  | ||||||
| 
 |  | ||||||
| Although they are "optional" (they can be computed from the available values), |  | ||||||
| to compute them in JavaScript would require a large and expensive BigInt library - |  | ||||||
| and including (or writing) such a library would require contradicting the |  | ||||||
| "lightweight" and/or "zero dependency" goals for this library. |  | ||||||
| 
 |  | ||||||
| That said, for someone willing to include a BigInt library in their code |  | ||||||
| it should be trivial to perform the operations to derive `dp` and `dq`. |  | ||||||
| 
 |  | ||||||
| If that's you please open an issue because I am interested in creating |  | ||||||
| a `ssh-to-jwk-bigint` library... I just don't have a use case for it right now. |  | ||||||
| 
 |  | ||||||
| # Legal | # Legal | ||||||
| 
 | 
 | ||||||
| [ssh-to-jwk.js](https://git.coolaj86.com/coolaj86/ssh-to-jwk.js) | | [ssh-to-jwk.js](https://git.coolaj86.com/coolaj86/ssh-to-jwk.js) | | ||||||
|  | |||||||
| @ -6,17 +6,27 @@ var path = require('path'); | |||||||
| var sshtojwk = require('../index.js'); | var sshtojwk = require('../index.js'); | ||||||
| 
 | 
 | ||||||
| var pubfile = process.argv[2]; | var pubfile = process.argv[2]; | ||||||
|  | var pub = process.argv[3]; | ||||||
| 
 | 
 | ||||||
| if (!pubfile) { | if (!pubfile) { | ||||||
|   pubfile = path.join(require('os').homedir(), '.ssh/id_rsa.pub'); |   pubfile = path.join(require('os').homedir(), '.ssh/id_rsa.pub'); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var buf = fs.readFileSync(pubfile); | var buf = fs.readFileSync(pubfile); | ||||||
| var pub = buf.toString('ascii'); | var txt = buf.toString('ascii'); | ||||||
| var ssh = sshtojwk.parse({ pub: pub }); | var opts = { public: 'public' === pub }; | ||||||
|  | var ssh; | ||||||
|  | 
 | ||||||
|  | if ('-' === txt[0]) { | ||||||
|  |   opts.pem = txt; | ||||||
|  | } else { | ||||||
|  |   opts.pub = txt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ssh = sshtojwk.parse(opts); | ||||||
| 
 | 
 | ||||||
| // Finally! https://superuser.com/a/714195
 | // Finally! https://superuser.com/a/714195
 | ||||||
| sshtojwk.fingerprint({ pub: pub }).then(function (fingerprint) { | sshtojwk.fingerprint(ssh).then(function (fingerprint) { | ||||||
|   console.warn('The key fingerprint is:\n' + fingerprint + ' ' + ssh.comment); |   console.warn('The key fingerprint is:\n' + fingerprint + ' ' + ssh.comment); | ||||||
|   console.info(JSON.stringify(ssh.jwk, null, 2)); |   console.info(JSON.stringify(ssh.jwk, null, 2)); | ||||||
| }); | }); | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								fixtures/privkey-ec-p256.jwk.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								fixtures/privkey-ec-p256.jwk.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |   "kty": "EC", | ||||||
|  |   "crv": "P-256", | ||||||
|  |   "d": "iYydo27aNGO9DBUWeGEPD8oNi1LZDqfxPmQlieLBjVQ", | ||||||
|  |   "x": "IT1SWLxsacPiE5Z16jkopAn8_-85rMjgyCokrnjDft4", | ||||||
|  |   "y": "mP2JwOAOdMmXuwpxbKng3KZz27mz-nKWIlXJ3rzSGMo" | ||||||
|  | } | ||||||
| @ -1,9 +1,9 @@ | |||||||
| -----BEGIN OPENSSH PRIVATE KEY----- | -----BEGIN OPENSSH PRIVATE KEY----- | ||||||
| b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS | ||||||
| 1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQR9WZPeBSvixkhjQOh9yCXXlEx5CN9M | 1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQhPVJYvGxpw+ITlnXqOSikCfz/7zms | ||||||
| yh94CJJ1rigf8693gc90HmahIR5oMGHwlqMoS7kKrRw+4KpxqsF7LGvxAAAAqJZtgRuWbY | yODIKiSueMN+3pj9icDgDnTJl7sKcWyp4Nymc9u5s/pyliJVyd680hjKAAAAqGJjanNiY2 | ||||||
| EbAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH1Zk94FK+LGSGNA | pzAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCE9Uli8bGnD4hOW | ||||||
| 6H3IJdeUTHkI30zKH3gIknWuKB/zr3eBz3QeZqEhHmgwYfCWoyhLuQqtHD7gqnGqwXssa/ | deo5KKQJ/P/vOazI4MgqJK54w37emP2JwOAOdMmXuwpxbKng3KZz27mz+nKWIlXJ3rzSGM | ||||||
| EAAAAgBzKpRmMyXZ4jnSt3ARz0ul6R79AXAr5gQqDAmoFeEKwAAAAOYWpAYm93aWUubG9j | oAAAAhAImMnaNu2jRjvQwVFnhhDw/KDYtS2Q6n8T5kJYniwY1UAAAADnJvb3RAbG9jYWxo | ||||||
| YWwBAg== | b3N0AQ== | ||||||
| -----END OPENSSH PRIVATE KEY----- | -----END OPENSSH PRIVATE KEY----- | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								fixtures/privkey-ec-p384.jwk.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								fixtures/privkey-ec-p384.jwk.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |   "kty": "EC", | ||||||
|  |   "crv": "P-384", | ||||||
|  |   "d": "XlyuCEWSTTS8U79O_Mz05z18vh4kb10szvu_7pdXuGWV6lfEyPExyUYWsA6A2kdV", | ||||||
|  |   "x": "2zEU0bKCa7ejKLIJ8oPGnLhqhxyiv4_w38K2a0SPC6dsSd9_glNJ8lcqv0sff5Gb", | ||||||
|  |   "y": "VD4jnu83S6scn6_TeAj3EZOREGbOs6dzoVpaugn-XQMMyC9O4VLbDDFGBZTJlMsb" | ||||||
|  | } | ||||||
| @ -1,10 +1,10 @@ | |||||||
| -----BEGIN OPENSSH PRIVATE KEY----- | -----BEGIN OPENSSH PRIVATE KEY----- | ||||||
| b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS | ||||||
| 1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQTDNcLzjWUqG5H+grU/Z+RNOsvqH4V5 | 1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQTbMRTRsoJrt6Mosgnyg8acuGqHHKK/ | ||||||
| qU1UlkUzqTImYvm7ClYgYtXqbReCzLn1E+DOQw1N1f5E/YjPNduLlklsEv3q55k7BDTTiN | j/DfwrZrRI8Lp2xJ33+CU0nyVyq/Sx9/kZtUPiOe7zdLqxyfr9N4CPcRk5EQZs6zp3OhWl | ||||||
| k5c15CpCbIV4eWeLRSFSJBGQHlv+sAAADYZYs6wGWLOsAAAAATZWNkc2Etc2hhMi1uaXN0 | q6Cf5dAwzIL07hUtsMMUYFlMmUyxsAAADYYmNqc2JjanMAAAATZWNkc2Etc2hhMi1uaXN0 | ||||||
| cDM4NAAAAAhuaXN0cDM4NAAAAGEEwzXC841lKhuR/oK1P2fkTTrL6h+FealNVJZFM6kyJm | cDM4NAAAAAhuaXN0cDM4NAAAAGEE2zEU0bKCa7ejKLIJ8oPGnLhqhxyiv4/w38K2a0SPC6 | ||||||
| L5uwpWIGLV6m0Xgsy59RPgzkMNTdX+RP2IzzXbi5ZJbBL96ueZOwQ004jZOXNeQqQmyFeH | dsSd9/glNJ8lcqv0sff5GbVD4jnu83S6scn6/TeAj3EZOREGbOs6dzoVpaugn+XQMMyC9O | ||||||
| lni0UhUiQRkB5b/rAAAAMQDbyZ7XRFtCCvdmdYJPkPuMzQBO5VJ1g/9eeFjI2ZLyIhtPh3 | 4VLbDDFGBZTJlMsbAAAAMF5crghFkk00vFO/TvzM9Oc9fL4eJG9dLM77v+6XV7hllepXxM | ||||||
| tvrki2EjEi8X4iLroAAAAOYWpAYm93aWUubG9jYWwB | jxMclGFrAOgNpHVQAAAA5yb290QGxvY2FsaG9zdAEC | ||||||
| -----END OPENSSH PRIVATE KEY----- | -----END OPENSSH PRIVATE KEY----- | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								fixtures/privkey-rsa-2048.jwk.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								fixtures/privkey-rsa-2048.jwk.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | { | ||||||
|  |   "kty": "RSA", | ||||||
|  |   "n": "m2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhDNzUJefLukC-xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLICOFcCGMob6pSQ38P8LdAIlb0pqDHxEJ9adWomjuFf0SUhN1cP7s9m8Yk9trkpEqjskocn2BOnTB57qAZM6-I70on0_iDZm7-jcqOPgADAmbWHhy67BXkk4yy_YzD4yOGZFXZcNp915_TW5bRd__AKPHUHxJasPiyEFqlNKBR2DSD-LbX5eTmzCh2ikrwTMja7mUdBJf2bK3By5AB0Qi49OykUCfNZeQlEz7UNNj9RGps_50-CNw", | ||||||
|  |   "e": "AQAB", | ||||||
|  |   "d": "Cpfo7Mm9Nu8YMC_xrZ54W9mKHPkCG9rZ93Ds9PNp-RXUgb-ljTbFPZWsYxGNKLllFz8LNosr1pT2ZDMrwNk0Af1iWNvD6gkyXaiQdCyiDPSBsJyNv2LJZon-e85X74nv53UlIkmo9SYxdLz2JaJ-iIWEe8Qh-7llLktrTJV_xr98_tbhgSppz_IeOymq3SEZaQHM8pTU7w7XvCj2pb9r8fN0M0XcgWZIaf3LGEfkhF_WtX67XJ0C6-LbkT51jtlLRNGX6haGdscXS0OWWjKOJzKGuV-NbthEn5rmRtVnjRZ3yaxQ0ud8vC-NONn7yvGUlOur1IdDzJ_YfHPt9sHMQQ", | ||||||
|  |   "p": "ynG-t9HwKCN3MWRYFdnFzi9-02Qcy3p8B5pu3ary2E70hYn2pHlUG2a9BNE8c5xHQ3Hx43WoWf6s0zOunPV1G28LkU_UYEbAtPv_PxSmzpQp9n9XnYvBLBF8Y3z7gxgLn1vVFNARrQdRtj87qY3aw7E9S4DsGcAarIuOT2TsTCE", | ||||||
|  |   "q": "xIkAjgUzB1zaUzJtW2Zgvp9cYYr1DmpH30ePZl3c_8397_DZDDo46fnFYjs6uPa03HpmKUnbjwr14QHlfXlntJBEuXxcqLjkdKdJ4ob7xueLTK4suo9V8LSrkLChVxlZQwnFD2E5ll0sVeeDeMJHQw38ahSrBFEVnxjpnPh1Q1c", | ||||||
|  |   "dp": "tzDGjECFOU0ehqtuqhcuT63a7h8hj19-7MJqoFwY9HQ-ALkfXyYLXeBSGxHbyiIYuodZg6LsfMNgUJ3r3Eyhc_nAVfYPEC_2IdAG4WYmq7iXYF9LQV09qEsKbFykm7QekE3hO7wswo5k-q2tp3ieBYdVGAXJoGOdv5VpaZ7B1QE", | ||||||
|  |   "dq": "kh5dyDk7YCz7sUFbpsmuAeuPjoH2ghooh2u3xN7iUVmAg-ToKjwbVnG5-7eXiC779rQVwnrD_0yh1AFJ8wjRPqDIR7ObXGHikIxT1VSQWqiJm6AfZzDsL0LUD4YS3iPdhob7-NxLKWzqao_u4lhnDQaX9PKa12HFlny6K1daL48", | ||||||
|  |   "qi": "AlHWbx1gp6Z9pbw_1hlS7HuXAgWoX7IjbTUelldf4gkriDWLOrj3QCZcO4ZvZvEwJhVlsny9LO8IkbwGJEL6cXraK08ByVS2mwQyflgTgGNnpzixyEUL_mrQLx6y145FHcxfeqNInMhep-0Mxn1D5nlhmIOgRApS0t9VoXtHhFU" | ||||||
|  | } | ||||||
| @ -1,27 +1,27 @@ | |||||||
| -----BEGIN OPENSSH PRIVATE KEY----- | -----BEGIN OPENSSH PRIVATE KEY----- | ||||||
| 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 | ||||||
| -----END OPENSSH PRIVATE KEY----- | -----END OPENSSH PRIVATE KEY----- | ||||||
|  | |||||||
| @ -10,6 +10,20 @@ Enc.base64ToBuf = function (str) { | |||||||
|   return Buffer.from(str, 'base64'); |   return Buffer.from(str, 'base64'); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | Enc.base64ToHex = function (str) { | ||||||
|  |   return Buffer.from(str, 'base64').toString('hex'); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Enc.base64ToUrlBase64 = function (b64) { | ||||||
|  |   return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Enc.bnToUrlBase64 = function (bn) { | ||||||
|  |   var hex = bn.toString(16); | ||||||
|  |   if (hex.length % 2) { hex = '0' + hex; } | ||||||
|  |   return Enc.base64ToUrlBase64(Buffer.from(hex, 'hex').toString('base64')); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| Enc.bufToBase64 = function (u8) { | Enc.bufToBase64 = function (u8) { | ||||||
|   return Buffer.from(u8).toString('base64'); |   return Buffer.from(u8).toString('base64'); | ||||||
| }; | }; | ||||||
| @ -23,6 +37,5 @@ Enc.bufToHex = function (u8) { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Enc.bufToUrlBase64 = function (u8) { | Enc.bufToUrlBase64 = function (u8) { | ||||||
|   return Enc.bufToBase64(u8) |   return Enc.base64ToUrlBase64(Enc.bufToBase64(u8)); | ||||||
|     .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -1,14 +1,21 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
|  | /*global BigInt*/ | ||||||
| var SSH = module.exports; | var SSH = module.exports; | ||||||
| var Enc = require('./encoding.js'); | var Enc = require('./encoding.js'); | ||||||
| var PEM = require('./pem.js'); | var PEM = require('./pem.js'); | ||||||
|  | var bnwarn = false; | ||||||
| 
 | 
 | ||||||
| SSH.parse = function (opts) { | SSH.parse = function (opts) { | ||||||
|   var pub = opts.pub || opts; |   var pub = opts.pem || opts.pub || opts; | ||||||
|   var ssh = SSH.parseBlock(pub); |   var ssh = SSH.parseBlock(pub); | ||||||
|   if ('OPENSSH PRIVATE KEY' === ssh.type) { |   if ('OPENSSH PRIVATE KEY' === ssh.type) { | ||||||
|     ssh = SSH.parsePrivateElements(ssh); |     ssh = SSH.parsePrivateElements(ssh); | ||||||
|  |     if (7 === ssh.elements.length) { | ||||||
|  |       // RSA Private Keys have the `e` and `n` swapped (which is actually more normal)
 | ||||||
|  |       // but we have to reswap them to make them consistent with the public key format
 | ||||||
|  |       ssh.elements.splice(1, 0, ssh.elements.splice(2 ,1)[0]); | ||||||
|  |     } | ||||||
|     if (opts.public) { |     if (opts.public) { | ||||||
|       ssh.elements = ssh.elements.slice(0, 3); |       ssh.elements = ssh.elements.slice(0, 3); | ||||||
|     } |     } | ||||||
| @ -57,6 +64,7 @@ SSH.parsePrivateElements = function (ssh) { | |||||||
|   var index = 0; |   var index = 0; | ||||||
|   var padlen = 0; |   var padlen = 0; | ||||||
|   var len; |   var len; | ||||||
|  |   var pub; | ||||||
| 
 | 
 | ||||||
|   // The last byte will be either
 |   // The last byte will be either
 | ||||||
|   //   * a non-printable pad character
 |   //   * a non-printable pad character
 | ||||||
| @ -91,6 +99,7 @@ SSH.parsePrivateElements = function (ssh) { | |||||||
|   len = dv.getUint32(index, false); |   len = dv.getUint32(index, false); | ||||||
|   // throw away public key (it's in the private key)
 |   // throw away public key (it's in the private key)
 | ||||||
|   index += 4 + len; |   index += 4 + len; | ||||||
|  |   pub = ssh.bytes.slice(index - len, index); | ||||||
| 
 | 
 | ||||||
|   // length of dummy checksum + private key + padding
 |   // length of dummy checksum + private key + padding
 | ||||||
|   len = dv.getUint32(index, false) - padlen; |   len = dv.getUint32(index, false) - padlen; | ||||||
| @ -105,6 +114,7 @@ SSH.parsePrivateElements = function (ssh) { | |||||||
| 
 | 
 | ||||||
|   // comment will exist, even if it's an empty string
 |   // comment will exist, even if it's an empty string
 | ||||||
|   ssh.comment = Enc.bufToBin(ssh.elements.pop()); |   ssh.comment = Enc.bufToBin(ssh.elements.pop()); | ||||||
|  |   ssh.bytes = pub; | ||||||
|   return ssh; |   return ssh; | ||||||
| }; | }; | ||||||
| SSH.parseElements = function (buf) { | SSH.parseElements = function (buf) { | ||||||
| @ -156,7 +166,6 @@ SSH.parsePublicKey = function (ssh) { | |||||||
|       , e: Enc.bufToUrlBase64(els[1]) |       , e: Enc.bufToUrlBase64(els[1]) | ||||||
|       }; |       }; | ||||||
|     } else { |     } else { | ||||||
|       console.log('len:', els.length); |  | ||||||
|       ssh.jwk = { |       ssh.jwk = { | ||||||
|         kty: 'RSA' |         kty: 'RSA' | ||||||
|       , n: Enc.bufToUrlBase64(els[2]) |       , n: Enc.bufToUrlBase64(els[2]) | ||||||
| @ -164,10 +173,28 @@ SSH.parsePublicKey = function (ssh) { | |||||||
|       , d: Enc.bufToUrlBase64(els[3]) |       , d: Enc.bufToUrlBase64(els[3]) | ||||||
|       , p: Enc.bufToUrlBase64(els[5]) |       , p: Enc.bufToUrlBase64(els[5]) | ||||||
|       , q: Enc.bufToUrlBase64(els[6]) |       , q: Enc.bufToUrlBase64(els[6]) | ||||||
|       //, dp: Enc.bufToUrlBase64(els[x])
 |       , dp: 0 | ||||||
|       //, dq: Enc.bufToUrlBase64(els[x])
 |       , dq: 0 | ||||||
|       , qi: Enc.bufToUrlBase64(els[4]) |       , qi: Enc.bufToUrlBase64(els[4]) | ||||||
|       }; |       }; | ||||||
|  |       if ('undefined' !== typeof BigInt) { | ||||||
|  |         // BigInt doesn't use new
 | ||||||
|  |         /*jshint newcap: false*/ | ||||||
|  |         // d mod (p - 1)
 | ||||||
|  |         ssh.jwk.dp = Enc.bnToUrlBase64(BigInt('0x' + Enc.base64ToHex(ssh.jwk.d)) | ||||||
|  |           % (BigInt('0x' + Enc.base64ToHex(ssh.jwk.p)) - BigInt(1))); | ||||||
|  |         ssh.jwk.dq = Enc.bnToUrlBase64(BigInt('0x' + Enc.base64ToHex(ssh.jwk.d)) | ||||||
|  |           % (BigInt('0x' + Enc.base64ToHex(ssh.jwk.q)) - BigInt(1))); | ||||||
|  |       } else { | ||||||
|  |         if (!bnwarn) { | ||||||
|  |           bnwarn = true; | ||||||
|  |           // TODO maybe conditionally bring in BigInt polyfill?
 | ||||||
|  |           console.warn("ssh-to-jwk.js: Your version of node is outdated doesn't support BigInt"); | ||||||
|  |           console.log("JWKs will be missing `dp` and `dq` values. Update or use a BigInt polyfill."); | ||||||
|  |         } | ||||||
|  |         delete ssh.jwk.dp; | ||||||
|  |         delete ssh.jwk.dq; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|     return ssh; |     return ssh; | ||||||
|   } |   } | ||||||
| @ -194,7 +221,9 @@ SSH.parsePublicKey = function (ssh) { | |||||||
|   while (0x00 === y[0]) { y = y.slice(1); } |   while (0x00 === y[0]) { y = y.slice(1); } | ||||||
| 
 | 
 | ||||||
|   if (els[3]) { |   if (els[3]) { | ||||||
|     ssh.jwk.d = Enc.bufToUrlBase64(els[3]); |     d = els[3]; | ||||||
|  |     while (0x00 === d[0]) { d = d.slice(1); } | ||||||
|  |     ssh.jwk.d = Enc.bufToUrlBase64(d); | ||||||
|   } |   } | ||||||
|   ssh.jwk.x = Enc.bufToUrlBase64(x); |   ssh.jwk.x = Enc.bufToUrlBase64(x); | ||||||
|   ssh.jwk.y = Enc.bufToUrlBase64(y); |   ssh.jwk.y = Enc.bufToUrlBase64(y); | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "ssh-to-jwk", |   "name": "ssh-to-jwk", | ||||||
|   "version": "1.2.0", |   "version": "1.2.6", | ||||||
|   "description": "💯 SSH to JWK in a lightweight, zero-dependency library.", |   "description": "💯 SSH to JWK in a lightweight, zero-dependency library.", | ||||||
|   "homepage": "https://git.coolaj86.com/coolaj86/ssh-to-jwk.js", |   "homepage": "https://git.coolaj86.com/coolaj86/ssh-to-jwk.js", | ||||||
|   "main": "index.js", |   "main": "index.js", | ||||||
| @ -29,6 +29,7 @@ | |||||||
|     "RSA", |     "RSA", | ||||||
|     "EC", |     "EC", | ||||||
|     "SSH", |     "SSH", | ||||||
|  |     "OpenSSH", | ||||||
|     "fingerprint", |     "fingerprint", | ||||||
|     "JWK", |     "JWK", | ||||||
|     "ECDSA" |     "ECDSA" | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user