| 
									
										
										
										
											2018-11-22 00:39:43 -07:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var SSH = module.exports; | 
					
						
							| 
									
										
										
										
											2018-11-22 04:05:00 -07:00
										 |  |  | var Enc = require('./encoding.js'); | 
					
						
							| 
									
										
										
										
											2018-11-22 00:39:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-22 04:05:00 -07:00
										 |  |  |               //  7  s  s  h  -  r  s  a
 | 
					
						
							| 
									
										
										
										
											2018-11-22 00:39:43 -07:00
										 |  |  | SSH.RSA = '00000007 73 73 68 2d 72 73 61'.replace(/\s+/g, '').toLowerCase(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-22 04:05:00 -07:00
										 |  |  | SSH.parse = function (pem, jwk) { | 
					
						
							| 
									
										
										
										
											2018-11-22 00:39:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-22 04:05:00 -07:00
										 |  |  |   var parts = pem.split(/\s+/); | 
					
						
							|  |  |  |   var buf = Enc.base64ToBuf(parts[1]); | 
					
						
							|  |  |  |   var els = []; | 
					
						
							|  |  |  |   var index = 0; | 
					
						
							|  |  |  |   var len; | 
					
						
							|  |  |  |   var i = 0; | 
					
						
							|  |  |  |   var offset = (buf.byteOffset || 0); | 
					
						
							|  |  |  |   // using dataview to be browser-compatible (I do want _some_ code reuse)
 | 
					
						
							|  |  |  |   var dv = new DataView(buf.buffer.slice(offset, offset + buf.byteLength)); | 
					
						
							| 
									
										
										
										
											2018-11-22 17:21:54 -07:00
										 |  |  |   var el; | 
					
						
							| 
									
										
										
										
											2018-11-22 04:05:00 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (SSH.RSA !== Enc.bufToHex(buf.slice(0, SSH.RSA.length/2))) { | 
					
						
							|  |  |  |     throw new Error("does not lead with ssh header"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (index < buf.byteLength) { | 
					
						
							|  |  |  |     i += 1; | 
					
						
							|  |  |  |     if (i > 3) { throw new Error("15+ elements, probably not a public ssh key"); } | 
					
						
							|  |  |  |     len = dv.getUint32(index, false); | 
					
						
							|  |  |  |     index += 4; | 
					
						
							| 
									
										
										
										
											2018-11-22 17:21:54 -07:00
										 |  |  |     el = buf.slice(index, index + len); | 
					
						
							|  |  |  |     // remove BigUInt '00' prefix
 | 
					
						
							|  |  |  |     if (0x00 === el[0]) { | 
					
						
							|  |  |  |       el = el.slice(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     els.push(el); | 
					
						
							| 
									
										
										
										
											2018-11-22 04:05:00 -07:00
										 |  |  |     index += len; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   jwk.n = Enc.bufToUrlBase64(els[2]); | 
					
						
							|  |  |  |   jwk.e = Enc.bufToUrlBase64(els[1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return jwk; | 
					
						
							| 
									
										
										
										
											2018-11-22 00:39:43 -07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-11-22 17:21:54 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | SSH.pack = function (opts) { | 
					
						
							|  |  |  |   var jwk = opts.jwk; | 
					
						
							|  |  |  |   var header = 'ssh-rsa'; | 
					
						
							|  |  |  |   var comment = opts.comment || 'rsa@localhost'; | 
					
						
							|  |  |  |   var e = SSH._padHexInt(Enc.base64ToHex(jwk.e)); | 
					
						
							|  |  |  |   var n = SSH._padHexInt(Enc.base64ToHex(jwk.n)); | 
					
						
							|  |  |  |   var hex = [ | 
					
						
							|  |  |  |     SSH._numToUint32Hex(header.length) | 
					
						
							|  |  |  |   , Enc.strToHex(header) | 
					
						
							|  |  |  |   , SSH._numToUint32Hex(e.length/2) | 
					
						
							|  |  |  |   , e | 
					
						
							|  |  |  |   , SSH._numToUint32Hex(n.length/2) | 
					
						
							|  |  |  |   , n | 
					
						
							|  |  |  |   ].join(''); | 
					
						
							|  |  |  |   return [ header, Enc.hexToBase64(hex), comment ].join(' '); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SSH._numToUint32Hex = function (num) { | 
					
						
							|  |  |  |   var hex = num.toString(16); | 
					
						
							|  |  |  |   while (hex.length < 8) { | 
					
						
							|  |  |  |     hex = '0' + hex; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return hex; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SSH._padHexInt = function (hex) { | 
					
						
							|  |  |  |   // BigInt is negative if the high order bit 0x80 is set,
 | 
					
						
							|  |  |  |   // so ASN1, SSH, and many other formats pad with '0x00'
 | 
					
						
							|  |  |  |   // to signifiy a positive number.
 | 
					
						
							|  |  |  |   var i = parseInt(hex.slice(0, 2), 16); | 
					
						
							|  |  |  |   if (0x80 & i) { | 
					
						
							|  |  |  |     return '00' + hex; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return hex; | 
					
						
							|  |  |  | }; |