81 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			81 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| var SSH = module.exports;
 | |
| var Enc = require('./encoding.js');
 | |
| 
 | |
|               //  7  s  s  h  -  r  s  a
 | |
| SSH.RSA = '00000007 73 73 68 2d 72 73 61'.replace(/\s+/g, '').toLowerCase();
 | |
| 
 | |
| SSH.parse = function (pem, jwk) {
 | |
| 
 | |
|   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));
 | |
|   var el;
 | |
| 
 | |
|   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;
 | |
|     el = buf.slice(index, index + len);
 | |
|     // remove BigUInt '00' prefix
 | |
|     if (0x00 === el[0]) {
 | |
|       el = el.slice(1);
 | |
|     }
 | |
|     els.push(el);
 | |
|     index += len;
 | |
|   }
 | |
| 
 | |
|   jwk.n = Enc.bufToUrlBase64(els[2]);
 | |
|   jwk.e = Enc.bufToUrlBase64(els[1]);
 | |
| 
 | |
|   return jwk;
 | |
| };
 | |
| 
 | |
| 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;
 | |
| };
 |