Name: js-handler/node_modules/restify/node_modules/http-signature/lib/util.js 
1:
// Copyright 2012 Joyent, Inc.  All rights reserved.
2:
 
3:
var assert = require('assert-plus');
4:
var crypto = require('crypto');
5:
 
6:
var asn1 = require('asn1');
7:
var ctype = require('ctype');
8:
 
9:
 
10:
 
11:
///--- Helpers
12:
 
13:
function readNext(buffer, offset) {
14:
  var len = ctype.ruint32(buffer, 'big', offset);
15:
  offset += 4;
16:
 
17:
  var newOffset = offset + len;
18:
 
19:
  return {
20:
    data: buffer.slice(offset, newOffset),
21:
    offset: newOffset
22:
  };
23:
}
24:
 
25:
 
26:
function writeInt(writer, buffer) {
27:
  writer.writeByte(0x02); // ASN1.Integer
28:
  writer.writeLength(buffer.length);
29:
 
30:
  for (var i = 0; i < buffer.length; i++)
31:
    writer.writeByte(buffer[i]);
32:
 
33:
  return writer;
34:
}
35:
 
36:
 
37:
function rsaToPEM(key) {
38:
  var buffer;
39:
  var der;
40:
  var exponent;
41:
  var i;
42:
  var modulus;
43:
  var newKey = '';
44:
  var offset = 0;
45:
  var type;
46:
  var tmp;
47:
 
48:
  try {
49:
    buffer = new Buffer(key.split(' ')[1], 'base64');
50:
 
51:
    tmp = readNext(buffer, offset);
52:
    type = tmp.data.toString();
53:
    offset = tmp.offset;
54:
 
55:
    if (type !== 'ssh-rsa')
56:
      throw new Error('Invalid ssh key type: ' + type);
57:
 
58:
    tmp = readNext(buffer, offset);
59:
    exponent = tmp.data;
60:
    offset = tmp.offset;
61:
 
62:
    tmp = readNext(buffer, offset);
63:
    modulus = tmp.data;
64:
  } catch (e) {
65:
    throw new Error('Invalid ssh key: ' + key);
66:
  }
67:
 
68:
  // DER is a subset of BER
69:
  der = new asn1.BerWriter();
70:
 
71:
  der.startSequence();
72:
 
73:
  der.startSequence();
74:
  der.writeOID('1.2.840.113549.1.1.1');
75:
  der.writeNull();
76:
  der.endSequence();
77:
 
78:
  der.startSequence(0x03); // bit string
79:
  der.writeByte(0x00);
80:
 
81:
  // Actual key
82:
  der.startSequence();
83:
  writeInt(der, modulus);
84:
  writeInt(der, exponent);
85:
  der.endSequence();
86:
 
87:
  // bit string
88:
  der.endSequence();
89:
 
90:
  der.endSequence();
91:
 
92:
  tmp = der.buffer.toString('base64');
93:
  for (i = 0; i < tmp.length; i++) {
94:
    if ((i % 64) === 0)
95:
      newKey += '\n';
96:
    newKey += tmp.charAt(i);
97:
  }
98:
 
99:
  if (!/\\n$/.test(newKey))
100:
    newKey += '\n';
101:
 
102:
  return '-----BEGIN PUBLIC KEY-----' + newKey + '-----END PUBLIC KEY-----\n';
103:
}
104:
 
105:
 
106:
function dsaToPEM(key) {
107:
  var buffer;
108:
  var offset = 0;
109:
  var tmp;
110:
  var der;
111:
  var newKey = '';
112:
 
113:
  var type;
114:
  var p;
115:
  var q;
116:
  var g;
117:
  var y;
118:
 
119:
  try {
120:
    buffer = new Buffer(key.split(' ')[1], 'base64');
121:
 
122:
    tmp = readNext(buffer, offset);
123:
    type = tmp.data.toString();
124:
    offset = tmp.offset;
125:
 
126:
    /* JSSTYLED */
127:
    if (!/^ssh-ds[as].*/.test(type))
128:
      throw new Error('Invalid ssh key type: ' + type);
129:
 
130:
    tmp = readNext(buffer, offset);
131:
    p = tmp.data;
132:
    offset = tmp.offset;
133:
 
134:
    tmp = readNext(buffer, offset);
135:
    q = tmp.data;
136:
    offset = tmp.offset;
137:
 
138:
    tmp = readNext(buffer, offset);
139:
    g = tmp.data;
140:
    offset = tmp.offset;
141:
 
142:
    tmp = readNext(buffer, offset);
143:
    y = tmp.data;
144:
  } catch (e) {
145:
    console.log(e.stack);
146:
    throw new Error('Invalid ssh key: ' + key);
147:
  }
148:
 
149:
  // DER is a subset of BER
150:
  der = new asn1.BerWriter();
151:
 
152:
  der.startSequence();
153:
 
154:
  der.startSequence();
155:
  der.writeOID('1.2.840.10040.4.1');
156:
 
157:
  der.startSequence();
158:
  writeInt(der, p);
159:
  writeInt(der, q);
160:
  writeInt(der, g);
161:
  der.endSequence();
162:
 
163:
  der.endSequence();
164:
 
165:
  der.startSequence(0x03); // bit string
166:
  der.writeByte(0x00);
167:
  writeInt(der, y);
168:
  der.endSequence();
169:
 
170:
  der.endSequence();
171:
 
172:
  tmp = der.buffer.toString('base64');
173:
  for (var i = 0; i < tmp.length; i++) {
174:
    if ((i % 64) === 0)
175:
      newKey += '\n';
176:
    newKey += tmp.charAt(i);
177:
  }
178:
 
179:
  if (!/\\n$/.test(newKey))
180:
    newKey += '\n';
181:
 
182:
  return '-----BEGIN PUBLIC KEY-----' + newKey + '-----END PUBLIC KEY-----\n';
183:
}
184:
 
185:
 
186:
///--- API
187:
 
188:
module.exports = {
189:
 
190:
  /**
191:
   * Converts an OpenSSH public key (rsa only) to a PKCS#8 PEM file.
192:
   *
193:
   * The intent of this module is to interoperate with OpenSSL only,
194:
   * specifically the node crypto module's `verify` method.
195:
   *
196:
   * @param {String} key an OpenSSH public key.
197:
   * @return {String} PEM encoded form of the RSA public key.
198:
   * @throws {TypeError} on bad input.
199:
   * @throws {Error} on invalid ssh key formatted data.
200:
   */
201:
  sshKeyToPEM: function sshKeyToPEM(key) {
202:
    assert.string(key, 'ssh_key');
203:
 
204:
    /* JSSTYLED */
205:
    if (/^ssh-rsa.*/.test(key))
206:
      return rsaToPEM(key);
207:
 
208:
    /* JSSTYLED */
209:
    if (/^ssh-ds[as].*/.test(key))
210:
      return dsaToPEM(key);
211:
 
212:
    throw new Error('Only RSA and DSA public keys are allowed');
213:
  },
214:
 
215:
 
216:
  /**
217:
   * Generates an OpenSSH fingerprint from an ssh public key.
218:
   *
219:
   * @param {String} key an OpenSSH public key.
220:
   * @return {String} key fingerprint.
221:
   * @throws {TypeError} on bad input.
222:
   * @throws {Error} if what you passed doesn't look like an ssh public key.
223:
   */
224:
  fingerprint: function fingerprint(key) {
225:
    assert.string(key, 'ssh_key');
226:
 
227:
    var pieces = key.split(' ');
228:
    if (!pieces || !pieces.length || pieces.length < 2)
229:
      throw new Error('invalid ssh key');
230:
 
231:
    var data = new Buffer(pieces[1], 'base64');
232:
 
233:
    var hash = crypto.createHash('md5');
234:
    hash.update(data);
235:
    var digest = hash.digest('hex');
236:
 
237:
    var fp = '';
238:
    for (var i = 0; i < digest.length; i++) {
239:
      if (i && i % 2 === 0)
240:
        fp += ':';
241:
 
242:
      fp += digest[i];
243:
    }
244:
 
245:
    return fp;
246:
  }
247:
 
248:
 
249:
};