hanewinpgp
Version:
PGP / GnuPG / OpenPGP Message Encryption in JavaScript by Herbert Hanewinkel.
202 lines (173 loc) • 5.05 kB
JavaScript
/* OpenPGP public key extraction
* Copyright 2005 Herbert Hanewinkel, www.haneWIN.de
* version 1.1, check www.haneWIN.de for the latest version
* This software is provided as-is, without express or implied warranty.
* Permission to use, copy, modify, distribute or sell this software, with or
* without fee, for any purpose and by any individual or organization, is hereby
* granted, provided that the above copyright notice and this paragraph appear
* in all copies. Distribution as a part of an application or binary must
* include the above copyright notice in the documentation and/or other materials
* provided with the application or distribution.
*/
'use strict';
function s2hex(s)
{
var result = '';
for(var i=0; i<s.length; i++)
{
var c = s.charCodeAt(i);
result += ((c<16) ? "0" : "") + c.toString(16);
}
return result;
}
function getPublicKey(text)
{
var found = 0, len;
var i= text.indexOf('-----BEGIN PGP PUBLIC KEY BLOCK-----');
if(i == -1)
{
alert('No PGP Public Key Block');
this.vers = '';
this.fp = '';
this.keyid = '';
this.user = '';
this.pkey = '';
return;
}
var a=text.indexOf('\n\n',i);
if(a>0) a += 2;
else
{
a = text.indexOf('\n\r\n', i);
if(a>0) a += 3;
}
var e=text.indexOf('\n=',i);
if(a>0 && e>0) text = text.slice(a,e);
else
{
alert('Invalid PGP Public Key Block');
this.vers = '';
this.fp = '';
this.keyid = '';
this.user = '';
this.pkey = '';
return;
}
var s=r2s(text);
for(var i=0; i < s.length;)
{
var tag = s.charCodeAt(i++);
if((tag&128) == 0) break;
if(tag&64)
{
tag&=63;
len=s.charCodeAt(i++);
if(len >191 && len <224) len=((len-192)<<8) + s.charCodeAt(i++);
else if(len==255) len = (s.charCodeAt(i++)<<24) + (s.charCodeAt(i++)<<16) + (s.charCodeAt(i++)<<8) + s.charCodeAt(i++);
else if(len>223 &&len<255) len = (1<<(len&0x1f));
}
else
{
len = tag&3;
tag = (tag>>2)&15;
if(len==0) len = s.charCodeAt(i++);
else if(len==1) len = (s.charCodeAt(i++)<<8) + s.charCodeAt(i++);
else if(len==2) len = (s.charCodeAt(i++)<<24) + (s.charCodeAt(i++)<<16) + (s.charCodeAt(i++)<<8) + s.charCodeAt(i++);
else len = s.length-1;
}
if(tag==6 || tag==14) // public key/subkey packet
{
var k = i;
var vers=s.charCodeAt(i++);
found = 1;
this.vers=vers;
var time=(s.charCodeAt(i++)<<24) + (s.charCodeAt(i++)<<16) + (s.charCodeAt(i++)<<8) + s.charCodeAt(i++);
if(vers==2 || vers==3) var valid=s.charCodeAt(i++)<<8 + s.charCodeAt(i++);
var algo=s.charCodeAt(i++);
if(algo == 1 || algo == 2)
{
var m = i;
var lm = Math.floor((s.charCodeAt(i)*256 + s.charCodeAt(i+1)+7)/8);
i+=lm+2;
var mod = s.substr(m,lm+2);
var le = Math.floor((s.charCodeAt(i)*256 + s.charCodeAt(i+1)+7)/8);
i+=le+2;
this.pkey=s2r(s.substr(m,lm+le+4));
this.type="RSA";
if(vers==3)
{
this.fp='';
this.keyid=s2hex(mod.substr(mod.length-8, 8));
}
else if(vers==4)
{
var pkt = String.fromCharCode(0x99) + String.fromCharCode(len>>8)
+ String.fromCharCode(len&255)+s.substr(k, len);
var fp = str_sha1(pkt);
this.fp=s2hex(fp);
this.keyid=s2hex(fp.substr(fp.length-8,8));
}
else
{
this.fp='';
this.keyid='';
}
found = 2;
}
else if((algo == 16 || algo == 20) && vers == 4)
{
var m = i;
var lp = Math.floor((s.charCodeAt(i)*256 + s.charCodeAt(i+1)+7)/8);
i+=lp+2;
var lg = Math.floor((s.charCodeAt(i)*256 + s.charCodeAt(i+1)+7)/8);
i+=lg+2;
var ly = Math.floor((s.charCodeAt(i)*256 + s.charCodeAt(i+1)+7)/8);
i+=ly+2;
this.pkey=s2r(s.substr(m,lp+lg+ly+6));
var pkt = String.fromCharCode(0x99) + String.fromCharCode(len>>8)
+ String.fromCharCode(len&255)+s.substr(k, len);
var fp = str_sha1(pkt);
this.fp=s2hex(fp);
this.keyid=s2hex(fp.substr(fp.length-8,8));
this.type="ELGAMAL";
found = 3;
}
else
{
i = k + len;
}
}
else if(tag==13) // user id
{
this.user=s.substr(i,len);
i+=len;
}
else
{
i+=len;
}
}
if(found < 2)
{
this.vers = '';
this.fp = '';
this.keyid = '';
if(found == 0)
this.user = "No public key packet found.";
else if(found == 1)
{
this.user = "public key algorithm is " + algo + " not RSA or ELGAMAL.";
}
this.pkey = "";
}
}
module.exports.extract = function (text) {
var key = new getPublicKey(text);
return {
version: key.vers,
user: key.user,
id: key.keyid,
type: key.type == 'RSA' ? 0 : 1, // 1=ELGAMAL
key: key.pkey.replace(/\n/g, '')
};
};