Work on bending the signature packet to my will.
This commit is contained in:
parent
dd5d0c801c
commit
3d25fdf8bf
|
@ -11502,7 +11502,48 @@ function openpgp_packet_secret_key() {
|
||||||
this.encrypted = null;
|
this.encrypted = null;
|
||||||
this.iv = null;
|
this.iv = null;
|
||||||
|
|
||||||
|
|
||||||
|
function get_hash_len(hash) {
|
||||||
|
if(hash == openpgp.hash.sha1)
|
||||||
|
return 20;
|
||||||
|
else
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_hash_fn(hash) {
|
||||||
|
if(hash == openpgp.hash.sha1)
|
||||||
|
return str_sha1;
|
||||||
|
else
|
||||||
|
return function(c) {
|
||||||
|
return openpgp_packet_number_write(util.calc_checksum(c), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function
|
||||||
|
function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) {
|
||||||
|
var hashlen = get_hash_len(hash_algorithm),
|
||||||
|
hashfn = get_hash_fn(hash_algorithm);
|
||||||
|
|
||||||
|
var hashtext = cleartext.substr(cleartext.length - hashlen);
|
||||||
|
cleartext = cleartext.substr(0, cleartext.length - hashlen);
|
||||||
|
|
||||||
|
var hash = hashfn(cleartext);
|
||||||
|
|
||||||
|
if(hash != hashtext)
|
||||||
|
throw "Hash mismatch!";
|
||||||
|
|
||||||
|
var mpis = openpgp_crypto_getPrivateMpiCount(algorithm);
|
||||||
|
|
||||||
|
var j = 0;
|
||||||
|
var mpi = [];
|
||||||
|
for(var i = 0; i < mpis && j < cleartext.length; i++) {
|
||||||
|
mpi[i] = new openpgp_type_mpi();
|
||||||
|
j += mpi[i].read(cleartext.substr(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
return mpi;
|
||||||
|
}
|
||||||
|
|
||||||
// 5.5.3. Secret-Key Packet Formats
|
// 5.5.3. Secret-Key Packet Formats
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11574,18 +11615,8 @@ function openpgp_packet_secret_key() {
|
||||||
this.encrypted = bytes.substr(i);
|
this.encrypted = bytes.substr(i);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var mpis = openpgp_crypto_getPrivateMpiCount(this.public_key.algorithm);
|
this.mpi = parse_cleartext_mpi(this.hash_algorithm, bytes.substr(i),
|
||||||
this.mpi = [];
|
this.public_key.algorithm);
|
||||||
|
|
||||||
for(var j = 0; j < mpis; j++) {
|
|
||||||
this.mpi[j] = new openpgp_type_mpi();
|
|
||||||
i += this.mpi[j].read(bytes.substr(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// checksum because s2k usage convention is 0
|
|
||||||
this.checksum = [];
|
|
||||||
this.checksum[0] = bytes[i++].charCodeAt();
|
|
||||||
this.checksum[1] = bytes[i++].charCodeAt();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11608,12 +11639,15 @@ function openpgp_packet_secret_key() {
|
||||||
if(this.encrypted == null) {
|
if(this.encrypted == null) {
|
||||||
bytes += String.fromCharCode(0);
|
bytes += String.fromCharCode(0);
|
||||||
|
|
||||||
|
var mpi = '';
|
||||||
for(var i in this.mpi) {
|
for(var i in this.mpi) {
|
||||||
bytes += this.mpi[i].write();
|
mpi += this.mpi[i].write();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytes += mpi;
|
||||||
|
|
||||||
// TODO check the cheksum!
|
// TODO check the cheksum!
|
||||||
bytes += '00'
|
bytes += openpgp_packet_number_write(util.calc_checksum(mpi), 2);
|
||||||
} else if(this.s2k == null) {
|
} else if(this.s2k == null) {
|
||||||
bytes += String.fromCharCode(this.symmetric_algorithm);
|
bytes += String.fromCharCode(this.symmetric_algorithm);
|
||||||
bytes += this.encrypted;
|
bytes += this.encrypted;
|
||||||
|
@ -11769,27 +11803,9 @@ function openpgp_packet_secret_key() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this.hash_algorithm == openpgp.hash.sha1) {
|
|
||||||
var hash = str_sha1(cleartext.substring(0,cleartext.length - 20));
|
|
||||||
|
|
||||||
if(hash != cleartext.substring(cleartext.length - 20))
|
this.mpi = parse_cleartext_mpi(this.hash_algorithm, cleartext,
|
||||||
throw "Hash mismatch!";
|
this.public_key.algorithm);
|
||||||
cleartext = cleartext.substr(0, cleartext.length - 20);
|
|
||||||
} else {
|
|
||||||
var hash = util.calc_checksum(cleartext.substring(0, cleartext.length - 2));
|
|
||||||
|
|
||||||
if(hash != cleartext.substring(cleartext.length -2))
|
|
||||||
throw "Hash mismatch!";
|
|
||||||
cleartext = cleartext.substr(0, cleartext.length - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
var mpis = openpgp_crypto_getPrivateMpiCount(this.public_key.algorithm);
|
|
||||||
|
|
||||||
var j = 0;
|
|
||||||
for(var i = 0; i < mpis && j < cleartext.length; i++) {
|
|
||||||
this.mpi[i] = new openpgp_type_mpi();
|
|
||||||
j += this.mpi[i].read(cleartext.substr(j));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
20
resources/openpgp.min.js
vendored
20
resources/openpgp.min.js
vendored
|
@ -405,16 +405,16 @@ b[0].byteLength()));this.encrypted=openpgp_crypto_asymetricEncrypt(this.public_k
|
||||||
function(){for(var b="5.1. Public-Key Encrypted Session Key Packets (Tag 1)\n KeyId: "+this.keyId.toString()+"\n length: "+this.packetLength+"\n version:"+this.version+"\n pubAlgUs:"+this.publicKeyAlgorithmUsed+"\n",a=0;a<this.encrypted.length;a++)b+=this.encrypted[a].toString();return b}}
|
function(){for(var b="5.1. Public-Key Encrypted Session Key Packets (Tag 1)\n KeyId: "+this.keyId.toString()+"\n length: "+this.packetLength+"\n version:"+this.version+"\n pubAlgUs:"+this.publicKeyAlgorithmUsed+"\n",a=0;a<this.encrypted.length;a++)b+=this.encrypted[a].toString();return b}}
|
||||||
function openpgp_packet_public_key(){this.tag=6;this.version=4;this.created=null;this.mpi=[];this.algorithm=openpgp.publickey.rsa_sign;this.read=function(b){this.version=b[0].charCodeAt();if(3!=this.version){if(4==this.version){this.created=openpgp_packet_time_read(b.substr(1,4));this.algorithm=b[5].charCodeAt();var a=0<this.algorithm&&4>this.algorithm?2:16==this.algorithm?3:17==this.algorithm?4:0;this.mpi=[];for(var b=b.substr(6),c=0,d=0;d<a&&c<b.length;d++)this.mpi[d]=new openpgp_type_mpi,c+=this.mpi[d].read(b.substr(c)),
|
function openpgp_packet_public_key(){this.tag=6;this.version=4;this.created=null;this.mpi=[];this.algorithm=openpgp.publickey.rsa_sign;this.read=function(b){this.version=b[0].charCodeAt();if(3!=this.version){if(4==this.version){this.created=openpgp_packet_time_read(b.substr(1,4));this.algorithm=b[5].charCodeAt();var a=0<this.algorithm&&4>this.algorithm?2:16==this.algorithm?3:17==this.algorithm?4:0;this.mpi=[];for(var b=b.substr(6),c=0,d=0;d<a&&c<b.length;d++)this.mpi[d]=new openpgp_type_mpi,c+=this.mpi[d].read(b.substr(c)),
|
||||||
c>b.length&&util.print_error("openpgp.packet.keymaterial.js\nerror reading MPI @:"+c);return c+6}util.print_error("Unknown packet version")}};this.write=function(){var b=String.fromCharCode(4),b=b+openpgp_packet_time_write(this.created),b=b+String.fromCharCode(this.algorithm),a;for(a in this.mpi)b+=this.mpi[a].write();return b}}function openpgp_packet_public_subkey(){openpgp_packet_public_key.call(this);this.tag=14}
|
c>b.length&&util.print_error("openpgp.packet.keymaterial.js\nerror reading MPI @:"+c);return c+6}util.print_error("Unknown packet version")}};this.write=function(){var b=String.fromCharCode(4),b=b+openpgp_packet_time_write(this.created),b=b+String.fromCharCode(this.algorithm),a;for(a in this.mpi)b+=this.mpi[a].write();return b}}function openpgp_packet_public_subkey(){openpgp_packet_public_key.call(this);this.tag=14}
|
||||||
function openpgp_packet_secret_key(){this.tag=5;this.public_key=new openpgp_packet_public_key;this.mpi=[];this.symmetric_algorithm=openpgp.symmetric.plaintext;this.hash_algorithm=openpgp.hash.sha1;this.iv=this.encrypted=this.s2k=null;this.read=function(b){var a=this.public_key.read(b),b=b.substr(a),c=b[0].charCodeAt(),a=1;if(255==c||254==c)this.symmetric_algorithm=b[a++].charCodeAt(),this.s2k=new openpgp_type_s2k,a+=this.s2k.read(b.substr(a));if(0!=c&&255!=c&&254!=c)this.symmetric_algorithm=c;if(0!=
|
function openpgp_packet_secret_key(){function b(a){return a==openpgp.hash.sha1?str_sha1:function(a){return openpgp_packet_number_write(util.calc_checksum(a),2)}}function a(a,d,e){var f=a==openpgp.hash.sha1?20:2,a=b(a),g=d.substr(d.length-f),d=d.substr(0,d.length-f);if(a(d)!=g)throw"Hash mismatch!";e=openpgp_crypto_getPrivateMpiCount(e);f=0;a=[];for(g=0;g<e&&f<d.length;g++)a[g]=new openpgp_type_mpi,f+=a[g].read(d.substr(f));return a}this.tag=5;this.public_key=new openpgp_packet_public_key;this.mpi=
|
||||||
c&&1001!=this.s2k.type)this.iv=b.substr(a,openpgp_crypto_getBlockLength(this.symmetric_algorithm)),a+=this.iv.length;this.hash_algorithm=254==c?openpgp.hash.sha1:"checksum";if(0!=c&&1001==this.s2k.type)this.encrypted=this.mpi=null;else if(0!=c)this.encrypted=b.substr(a);else{c=openpgp_crypto_getPrivateMpiCount(this.public_key.algorithm);this.mpi=[];for(var d=0;d<c;d++)this.mpi[d]=new openpgp_type_mpi,a+=this.mpi[d].read(b.substr(a));this.checksum=[];this.checksum[0]=b[a++].charCodeAt();this.checksum[1]=
|
[];this.symmetric_algorithm=openpgp.symmetric.plaintext;this.hash_algorithm=openpgp.hash.sha1;this.iv=this.encrypted=this.s2k=null;this.read=function(b){var d=this.public_key.read(b),b=b.substr(d),d=b[0].charCodeAt(),e=1;if(255==d||254==d)this.symmetric_algorithm=b[e++].charCodeAt(),this.s2k=new openpgp_type_s2k,e+=this.s2k.read(b.substr(e));if(0!=d&&255!=d&&254!=d)this.symmetric_algorithm=d;if(0!=d&&1001!=this.s2k.type)this.iv=b.substr(e,openpgp_crypto_getBlockLength(this.symmetric_algorithm)),e+=
|
||||||
b[a++].charCodeAt()}};this.write=function(){var b=this.public_key.write();if(null==this.encrypted){var b=b+String.fromCharCode(0),a;for(a in this.mpi)b+=this.mpi[a].write();b+="00"}else null==this.s2k?b+=String.fromCharCode(this.symmetric_algorithm):(b+=String.fromCharCode(254),b+=String.fromCharCode(this.symmetric_algorithm),b+=this.s2k.write()),b+=this.encrypted;return b};this.encrypt=function(b){switch(keyType){case 1:body+=String.fromCharCode(keyType);body+=key.n.toMPI();body+=key.ee.toMPI();
|
this.iv.length;this.hash_algorithm=254==d?openpgp.hash.sha1:"checksum";0!=d&&1001==this.s2k.type?this.encrypted=this.mpi=null:0!=d?this.encrypted=b.substr(e):this.mpi=a(this.hash_algorithm,b.substr(e),this.public_key.algorithm)};this.write=function(){var a=this.public_key.write();if(null==this.encrypted){var a=a+String.fromCharCode(0),b="",e;for(e in this.mpi)b+=this.mpi[e].write();a=a+b+openpgp_packet_number_write(util.calc_checksum(b),2)}else null==this.s2k?a+=String.fromCharCode(this.symmetric_algorithm):
|
||||||
if(b){body+=String.fromCharCode(254);body+=String.fromCharCode(this.symmetric_algorithm);body+=String.fromCharCode(3);body+=String.fromCharCode(s2kHash);var a=key.d.toMPI()+key.p.toMPI()+key.q.toMPI()+key.u.toMPI(),c=str_sha1(a);util.print_debug_hexstr_dump("write_private_key sha1: ",c);var d=openpgp_crypto_getRandomBytes(8);util.print_debug_hexstr_dump("write_private_key Salt: ",d);body+=d;body+=String.fromCharCode(96);util.print_debug("write_private_key c: 96");b=(new openpgp_type_s2k).write(3,
|
(a+=String.fromCharCode(254),a+=String.fromCharCode(this.symmetric_algorithm),a+=this.s2k.write()),a+=this.encrypted;return a};this.encrypt=function(a){switch(keyType){case 1:body+=String.fromCharCode(keyType);body+=key.n.toMPI();body+=key.ee.toMPI();if(a){body+=String.fromCharCode(254);body+=String.fromCharCode(this.symmetric_algorithm);body+=String.fromCharCode(3);body+=String.fromCharCode(s2kHash);var b=key.d.toMPI()+key.p.toMPI()+key.q.toMPI()+key.u.toMPI(),e=str_sha1(b);util.print_debug_hexstr_dump("write_private_key sha1: ",
|
||||||
s2kHash,b,d,96);switch(this.symmetric_algorithm){case 3:this.iv.length=8;this.iv=openpgp_crypto_getRandomBytes(this.iv.length);ciphertextMPIs=normal_cfb_encrypt(function(a,b){var c=new openpgp_symenc_cast5;c.setKey(b);return c.encrypt(util.str2bin(a))},this.iv.length,util.str2bin(b.substring(0,16)),a+c,this.iv);body+=this.iv+ciphertextMPIs;break;case 7:case 8:case 9:this.iv.length=16,this.iv=openpgp_crypto_getRandomBytes(this.iv.length),ciphertextMPIs=normal_cfb_encrypt(AESencrypt,this.iv.length,
|
e);var f=openpgp_crypto_getRandomBytes(8);util.print_debug_hexstr_dump("write_private_key Salt: ",f);body+=f;body+=String.fromCharCode(96);util.print_debug("write_private_key c: 96");a=(new openpgp_type_s2k).write(3,s2kHash,a,f,96);switch(this.symmetric_algorithm){case 3:this.iv.length=8;this.iv=openpgp_crypto_getRandomBytes(this.iv.length);ciphertextMPIs=normal_cfb_encrypt(function(a,b){var c=new openpgp_symenc_cast5;c.setKey(b);return c.encrypt(util.str2bin(a))},this.iv.length,util.str2bin(a.substring(0,
|
||||||
b,a+c,this.iv),body+=this.iv+ciphertextMPIs}}else body+=String.fromCharCode(0),body+=key.d.toMPI()+key.p.toMPI()+key.q.toMPI()+key.u.toMPI(),a=util.calc_checksum(key.d.toMPI()+key.p.toMPI()+key.q.toMPI()+key.u.toMPI()),body+=String.fromCharCode(a/256)+String.fromCharCode(a%256),util.print_debug_hexstr_dump("write_private_key basic checksum: "+a);break;default:body="",util.print_error("openpgp.packet.keymaterial.js\nerror writing private key, unknown type :"+keyType)}a=openpgp_packet.write_packet_header(tag,
|
16)),b+e,this.iv);body+=this.iv+ciphertextMPIs;break;case 7:case 8:case 9:this.iv.length=16,this.iv=openpgp_crypto_getRandomBytes(this.iv.length),ciphertextMPIs=normal_cfb_encrypt(AESencrypt,this.iv.length,a,b+e,this.iv),body+=this.iv+ciphertextMPIs}}else body+=String.fromCharCode(0),body+=key.d.toMPI()+key.p.toMPI()+key.q.toMPI()+key.u.toMPI(),b=util.calc_checksum(key.d.toMPI()+key.p.toMPI()+key.q.toMPI()+key.u.toMPI()),body+=String.fromCharCode(b/256)+String.fromCharCode(b%256),util.print_debug_hexstr_dump("write_private_key basic checksum: "+
|
||||||
body.length);return{string:a+body,header:a,body:body}};this.decrypt=function(b){if(null!=this.encrypted){var a=this.s2k.produce_key(b,openpgp_crypto_getKeyLength(this.symmetric_algorithm)),b="";switch(this.symmetric_algorithm){case 1:return util.print_error("openpgp.packet.keymaterial.js\nsymmetric encryption algorithim: IDEA is not implemented"),!1;case 2:b=normal_cfb_decrypt(function(a,b){return des(b,a,1,null,0)},this.iv.length,a,this.encrypted,this.iv);break;case 3:b=normal_cfb_decrypt(function(a,
|
b);break;default:body="",util.print_error("openpgp.packet.keymaterial.js\nerror writing private key, unknown type :"+keyType)}b=openpgp_packet.write_packet_header(tag,body.length);return{string:b+body,header:b,body:body}};this.decrypt=function(b){if(null!=this.encrypted){var b=this.s2k.produce_key(b,openpgp_crypto_getKeyLength(this.symmetric_algorithm)),d="";switch(this.symmetric_algorithm){case 1:return util.print_error("openpgp.packet.keymaterial.js\nsymmetric encryption algorithim: IDEA is not implemented"),
|
||||||
b){var c=new openpgp_symenc_cast5;c.setKey(b);return c.encrypt(util.str2bin(a))},this.iv.length,util.str2bin(a.substring(0,16)),this.encrypted,this.iv);break;case 4:b=normal_cfb_decrypt(function(a,b){return(new Blowfish(b)).encrypt(a)},this.iv.length,a,this.encrypted,this.iv);break;case 7:case 8:case 9:b=normal_cfb_decrypt(function(a,b){return AESencrypt(util.str2bin(a),b)},this.iv.length,keyExpansion(a),this.encrypted,this.iv);break;case 10:return util.print_error("openpgp.packet.keymaterial.js\nKey material is encrypted with twofish: not implemented"),
|
!1;case 2:d=normal_cfb_decrypt(function(a,b){return des(b,a,1,null,0)},this.iv.length,b,this.encrypted,this.iv);break;case 3:d=normal_cfb_decrypt(function(a,b){var c=new openpgp_symenc_cast5;c.setKey(b);return c.encrypt(util.str2bin(a))},this.iv.length,util.str2bin(b.substring(0,16)),this.encrypted,this.iv);break;case 4:d=normal_cfb_decrypt(function(a,b){return(new Blowfish(b)).encrypt(a)},this.iv.length,b,this.encrypted,this.iv);break;case 7:case 8:case 9:d=normal_cfb_decrypt(function(a,b){return AESencrypt(util.str2bin(a),
|
||||||
!1;default:return util.print_error("openpgp.packet.keymaterial.js\nunknown encryption algorithm for secret key :"+this.symmetric_algorithm),!1}if(null==b)return util.print_error("openpgp.packet.keymaterial.js\ncleartext was null"),!1;if(this.hash_algorithm==openpgp.hash.sha1){a=str_sha1(b.substring(0,b.length-20));if(a!=b.substring(b.length-20))throw"Hash mismatch!";b=b.substr(0,b.length-20)}else{a=util.calc_checksum(b.substring(0,b.length-2));if(a!=b.substring(b.length-2))throw"Hash mismatch!";b=
|
b)},this.iv.length,keyExpansion(b),this.encrypted,this.iv);break;case 10:return util.print_error("openpgp.packet.keymaterial.js\nKey material is encrypted with twofish: not implemented"),!1;default:return util.print_error("openpgp.packet.keymaterial.js\nunknown encryption algorithm for secret key :"+this.symmetric_algorithm),!1}if(null==d)return util.print_error("openpgp.packet.keymaterial.js\ncleartext was null"),!1;this.mpi=a(this.hash_algorithm,d,this.public_key.algorithm)}}}
|
||||||
b.substr(0,b.length-2)}for(var a=openpgp_crypto_getPrivateMpiCount(this.public_key.algorithm),c=0,d=0;d<a&&c<b.length;d++)this.mpi[d]=new openpgp_type_mpi,c+=this.mpi[d].read(b.substr(c))}}}function openpgp_packet_secret_subkey(){openpgp_packet_secret_key.call(this);this.tag=7}function openpgp_packet_signature(){this.tag=2;this.write=function(){};this.read=function(){}}
|
function openpgp_packet_secret_subkey(){openpgp_packet_secret_key.call(this);this.tag=7}function openpgp_packet_signature(){this.tag=2;this.write=function(){};this.read=function(){}}
|
||||||
function openpgp_packet_sym_encrypted_integrity_protected(){this.tag=18;this.version=1;this.encrypted=null;this.modification=!1;this.packets=new openpgp_packetlist;this.read=function(b){this.version=b[0].charCodeAt();if(1!=this.version)return util.print_error("openpgp.packet.encryptedintegrityprotecteddata.js\nunknown encrypted integrity protected data packet version: "+this.version+"hex:"+util.hexstrdump(b)),null;this.encrypted=b.substr(1)};this.write=function(){return String.fromCharCode(this.version)+
|
function openpgp_packet_sym_encrypted_integrity_protected(){this.tag=18;this.version=1;this.encrypted=null;this.modification=!1;this.packets=new openpgp_packetlist;this.read=function(b){this.version=b[0].charCodeAt();if(1!=this.version)return util.print_error("openpgp.packet.encryptedintegrityprotecteddata.js\nunknown encrypted integrity protected data packet version: "+this.version+"hex:"+util.hexstrdump(b)),null;this.encrypted=b.substr(1)};this.write=function(){return String.fromCharCode(this.version)+
|
||||||
this.encrypted};this.encrypt=function(b,a){var c=this.packets.write(),d=openpgp_crypto_getPrefixRandom(b),e=d+d.charAt(d.length-2)+d.charAt(d.length-1),c=c+String.fromCharCode(211),c=c+String.fromCharCode(20);util.print_debug_hexstr_dump("data to be hashed:",e+c);c+=str_sha1(e+c);util.print_debug_hexstr_dump("hash:",c.substring(c.length-20,c.length));this.encrypted=openpgp_crypto_symmetricEncrypt(d,b,a,c,!1).substring(0,e.length+c.length)};this.decrypt=function(b,a){var c=openpgp_crypto_symmetricDecrypt(b,
|
this.encrypted};this.encrypt=function(b,a){var c=this.packets.write(),d=openpgp_crypto_getPrefixRandom(b),e=d+d.charAt(d.length-2)+d.charAt(d.length-1),c=c+String.fromCharCode(211),c=c+String.fromCharCode(20);util.print_debug_hexstr_dump("data to be hashed:",e+c);c+=str_sha1(e+c);util.print_debug_hexstr_dump("hash:",c.substring(c.length-20,c.length));this.encrypted=openpgp_crypto_symmetricEncrypt(d,b,a,c,!1).substring(0,e.length+c.length)};this.decrypt=function(b,a){var c=openpgp_crypto_symmetricDecrypt(b,
|
||||||
a,this.encrypted,!1);this.hash=str_sha1(openpgp_crypto_MDCSystemBytes(b,a,this.encrypted)+c.substring(0,c.length-20));util.print_debug_hexstr_dump("calc hash = ",this.hash);this.hash!=c.substr(c.length-20,20)?(this.packets=new openpgp_packetlist,util.print_error("Decryption stopped: discovered a modification of encrypted data.")):this.packets.read(c.substr(0,c.length-22))};this.toString=function(){var b="";openpgp.config.debug&&(b=" data: Bytes ["+util.hexstrdump(this.encrypted)+"]");return"5.13. Sym. Encrypted Integrity Protected Data Packet (Tag 18)\n\n version: "+
|
a,this.encrypted,!1);this.hash=str_sha1(openpgp_crypto_MDCSystemBytes(b,a,this.encrypted)+c.substring(0,c.length-20));util.print_debug_hexstr_dump("calc hash = ",this.hash);this.hash!=c.substr(c.length-20,20)?(this.packets=new openpgp_packetlist,util.print_error("Decryption stopped: discovered a modification of encrypted data.")):this.packets.read(c.substr(0,c.length-22))};this.toString=function(){var b="";openpgp.config.debug&&(b=" data: Bytes ["+util.hexstrdump(this.encrypted)+"]");return"5.13. Sym. Encrypted Integrity Protected Data Packet (Tag 18)\n\n version: "+
|
||||||
|
|
|
@ -1,729 +0,0 @@
|
||||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
|
||||||
// Copyright (C) 2011 Recurity Labs GmbH
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class
|
|
||||||
* @classdesc Implementation of the Signature Packet (Tag 2)
|
|
||||||
*
|
|
||||||
* RFC4480 5.2:
|
|
||||||
* A Signature packet describes a binding between some public key and
|
|
||||||
* some data. The most common signatures are a signature of a file or a
|
|
||||||
* block of text, and a signature that is a certification of a User ID.
|
|
||||||
*/
|
|
||||||
function openpgp_packet_signature() {
|
|
||||||
this.tagType = 2;
|
|
||||||
this.signatureType = null;
|
|
||||||
this.creationTime = null;
|
|
||||||
this.keyId = null;
|
|
||||||
this.signatureData = null;
|
|
||||||
this.signatureExpirationTime = null;
|
|
||||||
this.signatureNeverExpires = null;
|
|
||||||
this.signedHashValue = null;
|
|
||||||
this.MPIs = null;
|
|
||||||
this.publicKeyAlgorithm = null;
|
|
||||||
this.hashAlgorithm = null;
|
|
||||||
this.exportable = null;
|
|
||||||
this.trustLevel = null;
|
|
||||||
this.trustAmount = null;
|
|
||||||
this.regular_expression = null;
|
|
||||||
this.revocable = null;
|
|
||||||
this.keyExpirationTime = null;
|
|
||||||
this.keyNeverExpires = null;
|
|
||||||
this.preferredSymmetricAlgorithms = null;
|
|
||||||
this.revocationKeyClass = null;
|
|
||||||
this.revocationKeyAlgorithm = null;
|
|
||||||
this.revocationKeyFingerprint = null;
|
|
||||||
this.issuerKeyId = null;
|
|
||||||
this.notationFlags = null;
|
|
||||||
this.notationName = null;
|
|
||||||
this.notationValue = null;
|
|
||||||
this.preferredHashAlgorithms = null;
|
|
||||||
this.preferredCompressionAlgorithms = null;
|
|
||||||
this.keyServerPreferences = null;
|
|
||||||
this.preferredKeyServer = null;
|
|
||||||
this.isPrimaryUserID = null;
|
|
||||||
this.policyURI = null;
|
|
||||||
this.keyFlags = null;
|
|
||||||
this.signersUserId = null;
|
|
||||||
this.reasonForRevocationFlag = null;
|
|
||||||
this.reasonForRevocationString = null;
|
|
||||||
this.signatureTargetPublicKeyAlgorithm = null;
|
|
||||||
this.signatureTargetHashAlgorithm = null;
|
|
||||||
this.signatureTargetHash = null;
|
|
||||||
this.embeddedSignature = null;
|
|
||||||
this.verified = false;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* parsing function for a signature packet (tag 2).
|
|
||||||
* @param {String} input payload of a tag 2 packet
|
|
||||||
* @param {Integer} position position to start reading from the input string
|
|
||||||
* @param {Integer} len length of the packet or the remaining length of input at position
|
|
||||||
* @return {openpgp_packet_encrypteddata} object representation
|
|
||||||
*/
|
|
||||||
function read_packet(input, position, len) {
|
|
||||||
this.data = input.substring (position, position+len);
|
|
||||||
if (len < 0) {
|
|
||||||
util.print_debug("openpgp.packet.signature.js\n"+"openpgp_packet_signature read_packet length < 0 @:"+position);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
var mypos = position;
|
|
||||||
this.packetLength = len;
|
|
||||||
// alert('starting parsing signature: '+position+' '+this.packetLength);
|
|
||||||
this.version = input[mypos++].charCodeAt();
|
|
||||||
// switch on version (3 and 4)
|
|
||||||
switch (this.version) {
|
|
||||||
case 3:
|
|
||||||
// One-octet length of following hashed material. MUST be 5.
|
|
||||||
if (input[mypos++].charCodeAt() != 5)
|
|
||||||
util.print_debug("openpgp.packet.signature.js\n"+'invalid One-octet length of following hashed material. MUST be 5. @:'+(mypos-1));
|
|
||||||
var sigpos = mypos;
|
|
||||||
// One-octet signature type.
|
|
||||||
this.signatureType = input[mypos++].charCodeAt();
|
|
||||||
|
|
||||||
// Four-octet creation time.
|
|
||||||
this.creationTime = new Date(((input[mypos++].charCodeAt()) << 24 |
|
|
||||||
(input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8) |
|
|
||||||
input[mypos++].charCodeAt())* 1000);
|
|
||||||
|
|
||||||
// storing data appended to data which gets verified
|
|
||||||
this.signatureData = input.substring(position, mypos);
|
|
||||||
|
|
||||||
// Eight-octet Key ID of signer.
|
|
||||||
this.keyId = input.substring(mypos, mypos +8);
|
|
||||||
mypos += 8;
|
|
||||||
|
|
||||||
// One-octet public-key algorithm.
|
|
||||||
this.publicKeyAlgorithm = input[mypos++].charCodeAt();
|
|
||||||
|
|
||||||
// One-octet hash algorithm.
|
|
||||||
this.hashAlgorithm = input[mypos++].charCodeAt();
|
|
||||||
|
|
||||||
// Two-octet field holding left 16 bits of signed hash value.
|
|
||||||
this.signedHashValue = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
|
|
||||||
var mpicount = 0;
|
|
||||||
// Algorithm-Specific Fields for RSA signatures:
|
|
||||||
// - multiprecision integer (MPI) of RSA signature value m**d mod n.
|
|
||||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
|
||||||
mpicount = 1;
|
|
||||||
// Algorithm-Specific Fields for DSA signatures:
|
|
||||||
// - MPI of DSA value r.
|
|
||||||
// - MPI of DSA value s.
|
|
||||||
else if (this.publicKeyAlgorithm == 17)
|
|
||||||
mpicount = 2;
|
|
||||||
|
|
||||||
this.MPIs = new Array();
|
|
||||||
for (var i = 0; i < mpicount; i++) {
|
|
||||||
this.MPIs[i] = new openpgp_type_mpi();
|
|
||||||
if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
|
|
||||||
!this.packetLength < (mypos-position)) {
|
|
||||||
mypos += this.MPIs[i].packetLength;
|
|
||||||
} else {
|
|
||||||
util.print_error('signature contains invalid MPI @:'+mypos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
this.signatureType = input[mypos++].charCodeAt();
|
|
||||||
this.publicKeyAlgorithm = input[mypos++].charCodeAt();
|
|
||||||
this.hashAlgorithm = input[mypos++].charCodeAt();
|
|
||||||
|
|
||||||
// Two-octet scalar octet count for following hashed subpacket
|
|
||||||
// data.
|
|
||||||
var hashed_subpacket_count = (input[mypos++].charCodeAt() << 8) + input[mypos++].charCodeAt();
|
|
||||||
|
|
||||||
// Hashed subpacket data set (zero or more subpackets)
|
|
||||||
var subpacket_length = 0;
|
|
||||||
while (hashed_subpacket_count != subpacket_length) {
|
|
||||||
if (hashed_subpacket_count < subpacket_length) {
|
|
||||||
util.print_debug("openpgp.packet.signature.js\n"+"hashed missed something: "+mypos+" c:"+hashed_subpacket_count+" l:"+subpacket_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
subpacket_length += this._raw_read_signature_sub_packet(input,
|
|
||||||
mypos + subpacket_length, hashed_subpacket_count
|
|
||||||
- subpacket_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
mypos += hashed_subpacket_count;
|
|
||||||
this.signatureData = input.substring(position, mypos);
|
|
||||||
|
|
||||||
// alert("signatureData: "+util.hexstrdump(this.signatureData));
|
|
||||||
|
|
||||||
// Two-octet scalar octet count for the following unhashed subpacket
|
|
||||||
var subpacket_count = (input[mypos++].charCodeAt() << 8) + input[mypos++].charCodeAt();
|
|
||||||
|
|
||||||
// Unhashed subpacket data set (zero or more subpackets).
|
|
||||||
subpacket_length = 0;
|
|
||||||
while (subpacket_count != subpacket_length) {
|
|
||||||
if (subpacket_count < subpacket_length) {
|
|
||||||
util.print_debug("openpgp.packet.signature.js\n"+"missed something: "+subpacket_length+" c:"+subpacket_count+" "+" l:"+subpacket_length);
|
|
||||||
}
|
|
||||||
subpacket_length += this._raw_read_signature_sub_packet(input,
|
|
||||||
mypos + subpacket_length, subpacket_count
|
|
||||||
- subpacket_length);
|
|
||||||
|
|
||||||
}
|
|
||||||
mypos += subpacket_count;
|
|
||||||
// Two-octet field holding the left 16 bits of the signed hash
|
|
||||||
// value.
|
|
||||||
this.signedHashValue = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
|
|
||||||
// One or more multiprecision integers comprising the signature.
|
|
||||||
// This portion is algorithm specific, as described above.
|
|
||||||
var mpicount = 0;
|
|
||||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
|
||||||
mpicount = 1;
|
|
||||||
else if (this.publicKeyAlgorithm == 17)
|
|
||||||
mpicount = 2;
|
|
||||||
|
|
||||||
this.MPIs = new Array();
|
|
||||||
for (var i = 0; i < mpicount; i++) {
|
|
||||||
this.MPIs[i] = new openpgp_type_mpi();
|
|
||||||
if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
|
|
||||||
!this.packetLength < (mypos-position)) {
|
|
||||||
mypos += this.MPIs[i].packetLength;
|
|
||||||
} else {
|
|
||||||
util.print_error('signature contains invalid MPI @:'+mypos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
util.print_error("openpgp.packet.signature.js\n"+'unknown signature packet version'+this.version);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// util.print_message("openpgp.packet.signature.js\n"+"end signature: l: "+this.packetLength+"m: "+mypos+" m-p: "+(mypos-position));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* creates a string representation of a message signature packet (tag 2).
|
|
||||||
* This can be only used on text data
|
|
||||||
* @param {Integer} signature_type should be 1 (one)
|
|
||||||
* @param {String} data data to be signed
|
|
||||||
* @param {openpgp_msg_privatekey} privatekey private key used to sign the message. (secMPIs MUST be unlocked)
|
|
||||||
* @return {String} string representation of a signature packet
|
|
||||||
*/
|
|
||||||
function write_message_signature(signature_type, data, privatekey) {
|
|
||||||
var publickey = privatekey.privateKeyPacket.publicKey;
|
|
||||||
var hash_algo = privatekey.getPreferredSignatureHashAlgorithm();
|
|
||||||
var result = String.fromCharCode(4);
|
|
||||||
result += String.fromCharCode(signature_type);
|
|
||||||
result += String.fromCharCode(publickey.publicKeyAlgorithm);
|
|
||||||
result += String.fromCharCode(hash_algo);
|
|
||||||
var d = Math.round(new Date().getTime() / 1000);
|
|
||||||
var datesubpacket = write_sub_signature_packet(2,""+
|
|
||||||
String.fromCharCode((d >> 24) & 0xFF) +
|
|
||||||
String.fromCharCode((d >> 16) & 0xFF) +
|
|
||||||
String.fromCharCode((d >> 8) & 0xFF) +
|
|
||||||
String.fromCharCode(d & 0xFF));
|
|
||||||
var issuersubpacket = write_sub_signature_packet(16, privatekey.getKeyId());
|
|
||||||
result += String.fromCharCode(((datesubpacket.length + issuersubpacket.length) >> 8) & 0xFF);
|
|
||||||
result += String.fromCharCode ((datesubpacket.length + issuersubpacket.length) & 0xFF);
|
|
||||||
result += datesubpacket;
|
|
||||||
result += issuersubpacket;
|
|
||||||
var trailer = '';
|
|
||||||
|
|
||||||
trailer += String.fromCharCode(4);
|
|
||||||
trailer += String.fromCharCode(0xFF);
|
|
||||||
trailer += String.fromCharCode((result.length) >> 24);
|
|
||||||
trailer += String.fromCharCode(((result.length) >> 16) & 0xFF);
|
|
||||||
trailer += String.fromCharCode(((result.length) >> 8) & 0xFF);
|
|
||||||
trailer += String.fromCharCode((result.length) & 0xFF);
|
|
||||||
var result2 = String.fromCharCode(0);
|
|
||||||
result2 += String.fromCharCode(0);
|
|
||||||
var hash = openpgp_crypto_hashData(hash_algo, data+result+trailer);
|
|
||||||
util.print_debug("DSA Signature is calculated with:|"+data+result+trailer+"|\n"+util.hexstrdump(data+result+trailer)+"\n hash:"+util.hexstrdump(hash));
|
|
||||||
result2 += hash.charAt(0);
|
|
||||||
result2 += hash.charAt(1);
|
|
||||||
result2 += openpgp_crypto_signData(hash_algo,privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm,
|
|
||||||
publickey.MPIs,
|
|
||||||
privatekey.privateKeyPacket.secMPIs,
|
|
||||||
data+result+trailer);
|
|
||||||
return {openpgp: (openpgp_packet.write_packet_header(2, (result+result2).length)+result + result2),
|
|
||||||
hash: util.get_hashAlgorithmString(hash_algo)};
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1)
|
|
||||||
* @param {Integer} type subpacket signature type. Signature types as described in RFC4880 Section 5.2.3.2
|
|
||||||
* @param {String} data data to be included
|
|
||||||
* @return {String} a string-representation of a sub signature packet (See RFC 4880 5.2.3.1)
|
|
||||||
*/
|
|
||||||
function write_sub_signature_packet(type, data) {
|
|
||||||
var result = "";
|
|
||||||
result += openpgp_packet.encode_length(data.length+1);
|
|
||||||
result += String.fromCharCode(type);
|
|
||||||
result += data;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// V4 signature sub packets
|
|
||||||
|
|
||||||
this._raw_read_signature_sub_packet = function(input, position, len) {
|
|
||||||
if (len < 0)
|
|
||||||
util.print_debug("openpgp.packet.signature.js\n"+"_raw_read_signature_sub_packet length < 0 @:"+position);
|
|
||||||
var mypos = position;
|
|
||||||
var subplen = 0;
|
|
||||||
// alert('starting signature subpackage read at position:'+position+' length:'+len);
|
|
||||||
if (input[mypos].charCodeAt() < 192) {
|
|
||||||
subplen = input[mypos++].charCodeAt();
|
|
||||||
} else if (input[mypos].charCodeAt() >= 192 && input[mypos].charCodeAt() < 224) {
|
|
||||||
subplen = ((input[mypos++].charCodeAt() - 192) << 8) + (input[mypos++].charCodeAt()) + 192;
|
|
||||||
} else if (input[mypos].charCodeAt() > 223 && input[mypos].charCodeAt() < 255) {
|
|
||||||
subplen = 1 << (input[mypos++].charCodeAt() & 0x1F);
|
|
||||||
} else if (input[mypos].charCodeAt() < 255) {
|
|
||||||
mypos++;
|
|
||||||
subplen = (input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
|
|
||||||
| (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
|
|
||||||
}
|
|
||||||
|
|
||||||
var type = input[mypos++].charCodeAt() & 0x7F;
|
|
||||||
// alert('signature subpacket type '+type+" with length: "+subplen);
|
|
||||||
// subpacket type
|
|
||||||
switch (type) {
|
|
||||||
case 2: // Signature Creation Time
|
|
||||||
this.creationTime = new Date(((input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
|
|
||||||
| (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt())*1000);
|
|
||||||
break;
|
|
||||||
case 3: // Signature Expiration Time
|
|
||||||
this.signatureExpirationTime = (input[mypos++].charCodeAt() << 24)
|
|
||||||
| (input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8)
|
|
||||||
| input[mypos++].charCodeAt();
|
|
||||||
this.signatureNeverExpires = (this.signature_expiration_time == 0);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 4: // Exportable Certification
|
|
||||||
this.exportable = input[mypos++].charCodeAt() == 1;
|
|
||||||
break;
|
|
||||||
case 5: // Trust Signature
|
|
||||||
this.trustLevel = input[mypos++].charCodeAt();
|
|
||||||
this.trustAmount = input[mypos++].charCodeAt();
|
|
||||||
break;
|
|
||||||
case 6: // Regular Expression
|
|
||||||
this.regular_expression = new String();
|
|
||||||
for (var i = 0; i < subplen - 1; i++)
|
|
||||||
this.regular_expression += (input[mypos++]);
|
|
||||||
break;
|
|
||||||
case 7: // Revocable
|
|
||||||
this.revocable = input[mypos++].charCodeAt() == 1;
|
|
||||||
break;
|
|
||||||
case 9: // Key Expiration Time
|
|
||||||
this.keyExpirationTime = (input[mypos++].charCodeAt() << 24)
|
|
||||||
| (input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8)
|
|
||||||
| input[mypos++].charCodeAt();
|
|
||||||
this.keyNeverExpires = (this.keyExpirationTime == 0);
|
|
||||||
break;
|
|
||||||
case 11: // Preferred Symmetric Algorithms
|
|
||||||
this.preferredSymmetricAlgorithms = new Array();
|
|
||||||
for (var i = 0; i < subplen-1; i++) {
|
|
||||||
this.preferredSymmetricAlgorithms = input[mypos++].charCodeAt();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 12: // Revocation Key
|
|
||||||
// (1 octet of class, 1 octet of public-key algorithm ID, 20
|
|
||||||
// octets of
|
|
||||||
// fingerprint)
|
|
||||||
this.revocationKeyClass = input[mypos++].charCodeAt();
|
|
||||||
this.revocationKeyAlgorithm = input[mypos++].charCodeAt();
|
|
||||||
this.revocationKeyFingerprint = new Array();
|
|
||||||
for ( var i = 0; i < 20; i++) {
|
|
||||||
this.revocationKeyFingerprint = input[mypos++].charCodeAt();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 16: // Issuer
|
|
||||||
this.issuerKeyId = input.substring(mypos,mypos+8);
|
|
||||||
mypos += 8;
|
|
||||||
break;
|
|
||||||
case 20: // Notation Data
|
|
||||||
this.notationFlags = (input[mypos++].charCodeAt() << 24) |
|
|
||||||
(input[mypos++].charCodeAt() << 16) |
|
|
||||||
(input[mypos++].charCodeAt() << 8) |
|
|
||||||
(input[mypos++].charCodeAt());
|
|
||||||
var nameLength = (input[mypos++].charCodeAt() << 8) | (input[mypos++].charCodeAt());
|
|
||||||
var valueLength = (input[mypos++].charCodeAt() << 8) | (input[mypos++].charCodeAt());
|
|
||||||
this.notationName = "";
|
|
||||||
for (var i = 0; i < nameLength; i++) {
|
|
||||||
this.notationName += input[mypos++];
|
|
||||||
}
|
|
||||||
this.notationValue = "";
|
|
||||||
for (var i = 0; i < valueLength; i++) {
|
|
||||||
this.notationValue += input[mypos++];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 21: // Preferred Hash Algorithms
|
|
||||||
this.preferredHashAlgorithms = new Array();
|
|
||||||
for (var i = 0; i < subplen-1; i++) {
|
|
||||||
this.preferredHashAlgorithms = input[mypos++].charCodeAt();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 22: // Preferred Compression Algorithms
|
|
||||||
this.preferredCompressionAlgorithms = new Array();
|
|
||||||
for ( var i = 0; i < subplen-1; i++) {
|
|
||||||
this.preferredCompressionAlgorithms = input[mypos++].charCodeAt();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 23: // Key Server Preferences
|
|
||||||
this.keyServerPreferences = new Array();
|
|
||||||
for ( var i = 0; i < subplen-1; i++) {
|
|
||||||
this.keyServerPreferences = input[mypos++].charCodeAt();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 24: // Preferred Key Server
|
|
||||||
this.preferredKeyServer = new String();
|
|
||||||
for ( var i = 0; i < subplen-1; i++) {
|
|
||||||
this.preferredKeyServer += input[mypos++];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 25: // Primary User ID
|
|
||||||
this.isPrimaryUserID = input[mypos++] != 0;
|
|
||||||
break;
|
|
||||||
case 26: // Policy URI
|
|
||||||
this.policyURI = new String();
|
|
||||||
for ( var i = 0; i < subplen-1; i++) {
|
|
||||||
this.policyURI += input[mypos++];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 27: // Key Flags
|
|
||||||
this.keyFlags = new Array();
|
|
||||||
for ( var i = 0; i < subplen-1; i++) {
|
|
||||||
this.keyFlags = input[mypos++].charCodeAt();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 28: // Signer's User ID
|
|
||||||
this.signersUserId = new String();
|
|
||||||
for ( var i = 0; i < subplen-1; i++) {
|
|
||||||
this.signersUserId += input[mypos++];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 29: // Reason for Revocation
|
|
||||||
this.reasonForRevocationFlag = input[mypos++].charCodeAt();
|
|
||||||
this.reasonForRevocationString = new String();
|
|
||||||
for ( var i = 0; i < subplen -2; i++) {
|
|
||||||
this.reasonForRevocationString += input[mypos++];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 30: // Features
|
|
||||||
// TODO: to be implemented
|
|
||||||
return subplen+1;
|
|
||||||
case 31: // Signature Target
|
|
||||||
// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
|
|
||||||
this.signatureTargetPublicKeyAlgorithm = input[mypos++].charCodeAt();
|
|
||||||
this.signatureTargetHashAlgorithm = input[mypos++].charCodeAt();
|
|
||||||
var signatureTargetHashAlgorithmLength = 0;
|
|
||||||
switch(this.signatureTargetHashAlgorithm) {
|
|
||||||
case 1: // - MD5 [HAC] "MD5"
|
|
||||||
case 2: // - SHA-1 [FIPS180] "SHA1"
|
|
||||||
signatureTargetHashAlgorithmLength = 20;
|
|
||||||
break;
|
|
||||||
case 3: // - RIPE-MD/160 [HAC] "RIPEMD160"
|
|
||||||
case 8: // - SHA256 [FIPS180] "SHA256"
|
|
||||||
case 9: // - SHA384 [FIPS180] "SHA384"
|
|
||||||
case 10: // - SHA512 [FIPS180] "SHA512"
|
|
||||||
case 11: // - SHA224 [FIPS180] "SHA224"
|
|
||||||
break;
|
|
||||||
// 100 to 110 - Private/Experimental algorithm
|
|
||||||
default:
|
|
||||||
util.print_error("openpgp.packet.signature.js\n"+"unknown signature target hash algorithm:"+this.signatureTargetHashAlgorithm);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
this.signatureTargetHash = new Array();
|
|
||||||
for (var i = 0; i < signatureTargetHashAlgorithmLength; i++) {
|
|
||||||
this.signatureTargetHash[i] = input[mypos++];
|
|
||||||
}
|
|
||||||
case 32: // Embedded Signature
|
|
||||||
this.embeddedSignature = new openpgp_packet_signature();
|
|
||||||
this.embeddedSignature.read_packet(input, mypos, len -(mypos-position));
|
|
||||||
return ((mypos+ this.embeddedSignature.packetLength) - position);
|
|
||||||
break;
|
|
||||||
case 100: // Private or experimental
|
|
||||||
case 101: // Private or experimental
|
|
||||||
case 102: // Private or experimental
|
|
||||||
case 103: // Private or experimental
|
|
||||||
case 104: // Private or experimental
|
|
||||||
case 105: // Private or experimental
|
|
||||||
case 106: // Private or experimental
|
|
||||||
case 107: // Private or experimental
|
|
||||||
case 108: // Private or experimental
|
|
||||||
case 109: // Private or experimental
|
|
||||||
case 110: // Private or experimental
|
|
||||||
util.print_error("openpgp.packet.signature.js\n"+'private or experimental signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
|
|
||||||
return subplen+1;
|
|
||||||
break;
|
|
||||||
case 0: // Reserved
|
|
||||||
case 1: // Reserved
|
|
||||||
case 8: // Reserved
|
|
||||||
case 10: // Placeholder for backward compatibility
|
|
||||||
case 13: // Reserved
|
|
||||||
case 14: // Reserved
|
|
||||||
case 15: // Reserved
|
|
||||||
case 17: // Reserved
|
|
||||||
case 18: // Reserved
|
|
||||||
case 19: // Reserved
|
|
||||||
default:
|
|
||||||
util.print_error("openpgp.packet.signature.js\n"+'unknown signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
|
|
||||||
return subplen+1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return mypos -position;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* verifys the signature packet. Note: not signature types are implemented
|
|
||||||
* @param {String} data data which on the signature applies
|
|
||||||
* @param {openpgp_msg_privatekey} key the public key to verify the signature
|
|
||||||
* @return {boolean} True if message is verified, else false.
|
|
||||||
*/
|
|
||||||
function verify(data, key) {
|
|
||||||
// calculating the trailer
|
|
||||||
var trailer = '';
|
|
||||||
trailer += String.fromCharCode(this.version);
|
|
||||||
trailer += String.fromCharCode(0xFF);
|
|
||||||
trailer += String.fromCharCode(this.signatureData.length >> 24);
|
|
||||||
trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
|
|
||||||
trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
|
|
||||||
trailer += String.fromCharCode(this.signatureData.length & 0xFF);
|
|
||||||
switch(this.signatureType) {
|
|
||||||
case 0: // 0x00: Signature of a binary document.
|
|
||||||
if (this.version == 4) {
|
|
||||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
|
||||||
this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData+trailer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: // 0x01: Signature of a canonical text document.
|
|
||||||
if (this.version == 4) {
|
|
||||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
|
||||||
this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData+trailer);
|
|
||||||
return this.verified;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: // 0x02: Standalone signature.
|
|
||||||
// This signature is a signature of only its own subpacket contents.
|
|
||||||
// It is calculated identically to a signature over a zero-length
|
|
||||||
// binary document. Note that it doesn't make sense to have a V3
|
|
||||||
// standalone signature.
|
|
||||||
if (this.version == 3) {
|
|
||||||
this.verified = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
|
||||||
this.MPIs, key.obj.publicKeyPacket.MPIs, this.signatureData+trailer);
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
// 0x10: Generic certification of a User ID and Public-Key packet.
|
|
||||||
// The issuer of this certification does not make any particular
|
|
||||||
// assertion as to how well the certifier has checked that the owner
|
|
||||||
// of the key is in fact the person described by the User ID.
|
|
||||||
case 17:
|
|
||||||
// 0x11: Persona certification of a User ID and Public-Key packet.
|
|
||||||
// The issuer of this certification has not done any verification of
|
|
||||||
// the claim that the owner of this key is the User ID specified.
|
|
||||||
case 18:
|
|
||||||
// 0x12: Casual certification of a User ID and Public-Key packet.
|
|
||||||
// The issuer of this certification has done some casual
|
|
||||||
// verification of the claim of identity.
|
|
||||||
case 19:
|
|
||||||
// 0x13: Positive certification of a User ID and Public-Key packet.
|
|
||||||
// The issuer of this certification has done substantial
|
|
||||||
// verification of the claim of identity.
|
|
||||||
//
|
|
||||||
// Most OpenPGP implementations make their "key signatures" as 0x10
|
|
||||||
// certifications. Some implementations can issue 0x11-0x13
|
|
||||||
// certifications, but few differentiate between the types.
|
|
||||||
case 48:
|
|
||||||
// 0x30: Certification revocation signature
|
|
||||||
// This signature revokes an earlier User ID certification signature
|
|
||||||
// (signature class 0x10 through 0x13) or direct-key signature
|
|
||||||
// (0x1F). It should be issued by the same key that issued the
|
|
||||||
// revoked signature or an authorized revocation key. The signature
|
|
||||||
// is computed over the same data as the certificate that it
|
|
||||||
// revokes, and should have a later creation date than that
|
|
||||||
// certificate.
|
|
||||||
|
|
||||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
|
||||||
this.MPIs, key.MPIs, data+this.signatureData+trailer);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 24:
|
|
||||||
// 0x18: Subkey Binding Signature
|
|
||||||
// This signature is a statement by the top-level signing key that
|
|
||||||
// indicates that it owns the subkey. This signature is calculated
|
|
||||||
// directly on the primary key and subkey, and not on any User ID or
|
|
||||||
// other packets. A signature that binds a signing subkey MUST have
|
|
||||||
// an Embedded Signature subpacket in this binding signature that
|
|
||||||
// contains a 0x19 signature made by the signing subkey on the
|
|
||||||
// primary key and subkey.
|
|
||||||
if (this.version == 3) {
|
|
||||||
this.verified = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
|
||||||
this.MPIs, key.MPIs, data+this.signatureData+trailer);
|
|
||||||
break;
|
|
||||||
case 25:
|
|
||||||
// 0x19: Primary Key Binding Signature
|
|
||||||
// This signature is a statement by a signing subkey, indicating
|
|
||||||
// that it is owned by the primary key and subkey. This signature
|
|
||||||
// is calculated the same way as a 0x18 signature: directly on the
|
|
||||||
// primary key and subkey, and not on any User ID or other packets.
|
|
||||||
|
|
||||||
// When a signature is made over a key, the hash data starts with the
|
|
||||||
// octet 0x99, followed by a two-octet length of the key, and then body
|
|
||||||
// of the key packet. (Note that this is an old-style packet header for
|
|
||||||
// a key packet with two-octet length.) A subkey binding signature
|
|
||||||
// (type 0x18) or primary key binding signature (type 0x19) then hashes
|
|
||||||
// the subkey using the same format as the main key (also using 0x99 as
|
|
||||||
// the first octet).
|
|
||||||
case 31:
|
|
||||||
// 0x1F: Signature directly on a key
|
|
||||||
// This signature is calculated directly on a key. It binds the
|
|
||||||
// information in the Signature subpackets to the key, and is
|
|
||||||
// appropriate to be used for subpackets that provide information
|
|
||||||
// about the key, such as the Revocation Key subpacket. It is also
|
|
||||||
// appropriate for statements that non-self certifiers want to make
|
|
||||||
// about the key itself, rather than the binding between a key and a
|
|
||||||
// name.
|
|
||||||
case 32:
|
|
||||||
// 0x20: Key revocation signature
|
|
||||||
// The signature is calculated directly on the key being revoked. A
|
|
||||||
// revoked key is not to be used. Only revocation signatures by the
|
|
||||||
// key being revoked, or by an authorized revocation key, should be
|
|
||||||
// considered valid revocation signatures.
|
|
||||||
case 40:
|
|
||||||
// 0x28: Subkey revocation signature
|
|
||||||
// The signature is calculated directly on the subkey being revoked.
|
|
||||||
// A revoked subkey is not to be used. Only revocation signatures
|
|
||||||
// by the top-level signature key that is bound to this subkey, or
|
|
||||||
// by an authorized revocation key, should be considered valid
|
|
||||||
// revocation signatures.
|
|
||||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
|
||||||
this.MPIs, key.MPIs, data+this.signatureData+trailer);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Key revocation signatures (types 0x20 and 0x28)
|
|
||||||
// hash only the key being revoked.
|
|
||||||
case 64:
|
|
||||||
// 0x40: Timestamp signature.
|
|
||||||
// This signature is only meaningful for the timestamp contained in
|
|
||||||
// it.
|
|
||||||
case 80:
|
|
||||||
// 0x50: Third-Party Confirmation signature.
|
|
||||||
// This signature is a signature over some other OpenPGP Signature
|
|
||||||
// packet(s). It is analogous to a notary seal on the signed data.
|
|
||||||
// A third-party signature SHOULD include Signature Target
|
|
||||||
// subpacket(s) to give easy identification. Note that we really do
|
|
||||||
// mean SHOULD. There are plausible uses for this (such as a blind
|
|
||||||
// party that only sees the signature, not the key or source
|
|
||||||
// document) that cannot include a target subpacket.
|
|
||||||
default:
|
|
||||||
util.print_error("openpgp.packet.signature.js\n"+"signature verification for type"+ this.signatureType+" not implemented");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return this.verified;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* generates debug output (pretty print)
|
|
||||||
* @return {String} String which gives some information about the signature packet
|
|
||||||
*/
|
|
||||||
|
|
||||||
function toString () {
|
|
||||||
if (this.version == 3) {
|
|
||||||
var result = '5.2. Signature Packet (Tag 2)\n'+
|
|
||||||
"Packet Length: :"+this.packetLength+'\n'+
|
|
||||||
"Packet version: :"+this.version+'\n'+
|
|
||||||
"One-octet signature type :"+this.signatureType+'\n'+
|
|
||||||
"Four-octet creation time. :"+this.creationTime+'\n'+
|
|
||||||
"Eight-octet Key ID of signer. :"+util.hexidump(this.keyId)+'\n'+
|
|
||||||
"One-octet public-key algorithm. :"+this.publicKeyAlgorithm+'\n'+
|
|
||||||
"One-octet hash algorithm. :"+this.hashAlgorithm+'\n'+
|
|
||||||
"Two-octet field holding left\n" +
|
|
||||||
" 16 bits of signed hash value. :"+this.signedHashValue+'\n';
|
|
||||||
} else {
|
|
||||||
var result = '5.2. Signature Packet (Tag 2)\n'+
|
|
||||||
"Packet Length: :"+this.packetLength+'\n'+
|
|
||||||
"Packet version: :"+this.version+'\n'+
|
|
||||||
"One-octet signature type :"+this.signatureType+'\n'+
|
|
||||||
"One-octet public-key algorithm. :"+this.publicKeyAlgorithm+'\n'+
|
|
||||||
"One-octet hash algorithm. :"+this.hashAlgorithm+'\n'+
|
|
||||||
"Two-octet field holding left\n" +
|
|
||||||
" 16 bits of signed hash value. :"+this.signedHashValue+'\n'+
|
|
||||||
"Signature Creation Time :"+this.creationTime+'\n'+
|
|
||||||
"Signature Expiration Time :"+this.signatureExpirationTime+'\n'+
|
|
||||||
"Signature Never Expires :"+this.signatureNeverExpires+'\n'+
|
|
||||||
"Exportable Certification :"+this.exportable+'\n'+
|
|
||||||
"Trust Signature level: :"+this.trustLevel+' amount'+this.trustAmount+'\n'+
|
|
||||||
"Regular Expression :"+this.regular_expression+'\n'+
|
|
||||||
"Revocable :"+this.revocable+'\n'+
|
|
||||||
"Key Expiration Time :"+this.keyExpirationTime+" "+this.keyNeverExpires+'\n'+
|
|
||||||
"Preferred Symmetric Algorithms :"+this.preferredSymmetricAlgorithms+'\n'+
|
|
||||||
"Revocation Key"+'\n'+
|
|
||||||
" ( 1 octet of class, :"+this.revocationKeyClass +'\n'+
|
|
||||||
" 1 octet of public-key ID, :" +this.revocationKeyAlgorithm+'\n'+
|
|
||||||
" 20 octets of fingerprint) :"+this.revocationKeyFingerprint+'\n'+
|
|
||||||
"Issuer :"+util.hexstrdump(this.issuerKeyId)+'\n'+
|
|
||||||
"Preferred Hash Algorithms :"+this.preferredHashAlgorithms+'\n'+
|
|
||||||
"Preferred Compression Alg. :"+this.preferredCompressionAlgorithms+'\n'+
|
|
||||||
"Key Server Preferences :"+this.keyServerPreferences+'\n'+
|
|
||||||
"Preferred Key Server :"+this.preferredKeyServer+'\n'+
|
|
||||||
"Primary User ID :"+this.isPrimaryUserID+'\n'+
|
|
||||||
"Policy URI :"+this.policyURI+'\n'+
|
|
||||||
"Key Flags :"+this.keyFlags+'\n'+
|
|
||||||
"Signer's User ID :"+this.signersUserId+'\n'+
|
|
||||||
"Notation :"+this.notationName+" = "+this.notationValue+"\n"+
|
|
||||||
"Reason for Revocation\n"+
|
|
||||||
" Flag :"+this.reasonForRevocationFlag+'\n'+
|
|
||||||
" Reason :"+this.reasonForRevocationString+'\nMPI:\n';
|
|
||||||
}
|
|
||||||
for (var i = 0; i < this.MPIs.length; i++) {
|
|
||||||
result += this.MPIs[i].toString();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gets the issuer key id of this signature
|
|
||||||
* @return {String} issuer key id as string (8bytes)
|
|
||||||
*/
|
|
||||||
function getIssuer() {
|
|
||||||
if (this.version == 4)
|
|
||||||
return this.issuerKeyId;
|
|
||||||
if (this.verions == 4)
|
|
||||||
return this.keyId;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to get the corresponding public key out of the public keyring for the issuer created this signature
|
|
||||||
* @return {Object} {obj: [openpgp_msg_publickey], text: [String]} if found the public key will be returned. null otherwise
|
|
||||||
*/
|
|
||||||
function getIssuerKey() {
|
|
||||||
var result = null;
|
|
||||||
if (this.version == 4) {
|
|
||||||
result = openpgp.keyring.getPublicKeysForKeyId(this.issuerKeyId);
|
|
||||||
} else if (this.version == 3) {
|
|
||||||
result = openpgp.keyring.getPublicKeysForKeyId(this.keyId);
|
|
||||||
} else return null;
|
|
||||||
if (result.length == 0)
|
|
||||||
return null;
|
|
||||||
return result[0];
|
|
||||||
}
|
|
||||||
this.getIssuerKey = getIssuerKey;
|
|
||||||
this.getIssuer = getIssuer;
|
|
||||||
this.write_message_signature = write_message_signature;
|
|
||||||
this.verify = verify;
|
|
||||||
this.read_packet = read_packet;
|
|
||||||
this.toString = toString;
|
|
||||||
}
|
|
|
@ -21,7 +21,26 @@
|
||||||
* packet types and packet header.
|
* packet types and packet header.
|
||||||
*/
|
*/
|
||||||
function _openpgp_packet() {
|
function _openpgp_packet() {
|
||||||
/**
|
|
||||||
|
var read_simple_length = function(bytes) {
|
||||||
|
var len = 0;
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
if (bytes[i].charCodeAt() < 192) {
|
||||||
|
len = bytes[i++].charCodeAt();
|
||||||
|
} else if (bytes[i].charCodeAt() >= 192 && bytes[i].charCodeAt() < 224) {
|
||||||
|
len = ((bytes[i++].charCodeAt() - 192) << 8) + (bytes[i++].charCodeAt()) + 192;
|
||||||
|
} else if (bytes[i].charCodeAt() > 223 && bytes[i].charCodeAt() < 255) {
|
||||||
|
len = 1 << (bytes[i++].charCodeAt() & 0x1F);
|
||||||
|
} else if (bytes[i].charCodeAt() < 255) {
|
||||||
|
i++;
|
||||||
|
len = (bytes[i++].charCodeAt() << 24) | (bytes[i++].charCodeAt() << 16)
|
||||||
|
| (bytes[i++].charCodeAt() << 8) | bytes[i++].charCodeAt();
|
||||||
|
}
|
||||||
|
|
||||||
|
return { len: len, offset: i };
|
||||||
|
}
|
||||||
|
/**
|
||||||
* Encodes a given integer of length to the openpgp length specifier to a
|
* Encodes a given integer of length to the openpgp length specifier to a
|
||||||
* string
|
* string
|
||||||
*
|
*
|
||||||
|
|
|
@ -34,7 +34,48 @@ function openpgp_packet_secret_key() {
|
||||||
this.encrypted = null;
|
this.encrypted = null;
|
||||||
this.iv = null;
|
this.iv = null;
|
||||||
|
|
||||||
|
|
||||||
|
function get_hash_len(hash) {
|
||||||
|
if(hash == openpgp.hash.sha1)
|
||||||
|
return 20;
|
||||||
|
else
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_hash_fn(hash) {
|
||||||
|
if(hash == openpgp.hash.sha1)
|
||||||
|
return str_sha1;
|
||||||
|
else
|
||||||
|
return function(c) {
|
||||||
|
return openpgp_packet_number_write(util.calc_checksum(c), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function
|
||||||
|
function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) {
|
||||||
|
var hashlen = get_hash_len(hash_algorithm),
|
||||||
|
hashfn = get_hash_fn(hash_algorithm);
|
||||||
|
|
||||||
|
var hashtext = cleartext.substr(cleartext.length - hashlen);
|
||||||
|
cleartext = cleartext.substr(0, cleartext.length - hashlen);
|
||||||
|
|
||||||
|
var hash = hashfn(cleartext);
|
||||||
|
|
||||||
|
if(hash != hashtext)
|
||||||
|
throw "Hash mismatch!";
|
||||||
|
|
||||||
|
var mpis = openpgp_crypto_getPrivateMpiCount(algorithm);
|
||||||
|
|
||||||
|
var j = 0;
|
||||||
|
var mpi = [];
|
||||||
|
for(var i = 0; i < mpis && j < cleartext.length; i++) {
|
||||||
|
mpi[i] = new openpgp_type_mpi();
|
||||||
|
j += mpi[i].read(cleartext.substr(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
return mpi;
|
||||||
|
}
|
||||||
|
|
||||||
// 5.5.3. Secret-Key Packet Formats
|
// 5.5.3. Secret-Key Packet Formats
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,18 +147,8 @@ function openpgp_packet_secret_key() {
|
||||||
this.encrypted = bytes.substr(i);
|
this.encrypted = bytes.substr(i);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var mpis = openpgp_crypto_getPrivateMpiCount(this.public_key.algorithm);
|
this.mpi = parse_cleartext_mpi(this.hash_algorithm, bytes.substr(i),
|
||||||
this.mpi = [];
|
this.public_key.algorithm);
|
||||||
|
|
||||||
for(var j = 0; j < mpis; j++) {
|
|
||||||
this.mpi[j] = new openpgp_type_mpi();
|
|
||||||
i += this.mpi[j].read(bytes.substr(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// checksum because s2k usage convention is 0
|
|
||||||
this.checksum = [];
|
|
||||||
this.checksum[0] = bytes[i++].charCodeAt();
|
|
||||||
this.checksum[1] = bytes[i++].charCodeAt();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,12 +171,15 @@ function openpgp_packet_secret_key() {
|
||||||
if(this.encrypted == null) {
|
if(this.encrypted == null) {
|
||||||
bytes += String.fromCharCode(0);
|
bytes += String.fromCharCode(0);
|
||||||
|
|
||||||
|
var mpi = '';
|
||||||
for(var i in this.mpi) {
|
for(var i in this.mpi) {
|
||||||
bytes += this.mpi[i].write();
|
mpi += this.mpi[i].write();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytes += mpi;
|
||||||
|
|
||||||
// TODO check the cheksum!
|
// TODO check the cheksum!
|
||||||
bytes += '00'
|
bytes += openpgp_packet_number_write(util.calc_checksum(mpi), 2);
|
||||||
} else if(this.s2k == null) {
|
} else if(this.s2k == null) {
|
||||||
bytes += String.fromCharCode(this.symmetric_algorithm);
|
bytes += String.fromCharCode(this.symmetric_algorithm);
|
||||||
bytes += this.encrypted;
|
bytes += this.encrypted;
|
||||||
|
@ -301,27 +335,9 @@ function openpgp_packet_secret_key() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this.hash_algorithm == openpgp.hash.sha1) {
|
|
||||||
var hash = str_sha1(cleartext.substring(0,cleartext.length - 20));
|
|
||||||
|
|
||||||
if(hash != cleartext.substring(cleartext.length - 20))
|
this.mpi = parse_cleartext_mpi(this.hash_algorithm, cleartext,
|
||||||
throw "Hash mismatch!";
|
this.public_key.algorithm);
|
||||||
cleartext = cleartext.substr(0, cleartext.length - 20);
|
|
||||||
} else {
|
|
||||||
var hash = util.calc_checksum(cleartext.substring(0, cleartext.length - 2));
|
|
||||||
|
|
||||||
if(hash != cleartext.substring(cleartext.length -2))
|
|
||||||
throw "Hash mismatch!";
|
|
||||||
cleartext = cleartext.substr(0, cleartext.length - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
var mpis = openpgp_crypto_getPrivateMpiCount(this.public_key.algorithm);
|
|
||||||
|
|
||||||
var j = 0;
|
|
||||||
for(var i = 0; i < mpis && j < cleartext.length; i++) {
|
|
||||||
this.mpi[i] = new openpgp_type_mpi();
|
|
||||||
j += this.mpi[i].read(cleartext.substr(j));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -26,10 +26,683 @@
|
||||||
*/
|
*/
|
||||||
function openpgp_packet_signature() {
|
function openpgp_packet_signature() {
|
||||||
this.tag = 2;
|
this.tag = 2;
|
||||||
|
this.signatureType = null;
|
||||||
|
this.created = null;
|
||||||
|
this.keyId = null;
|
||||||
|
this.signatureData = null;
|
||||||
|
this.signatureExpirationTime = null;
|
||||||
|
this.signatureNeverExpires = null;
|
||||||
|
this.signedHashValue = null;
|
||||||
|
this.mpi = null;
|
||||||
|
this.publicKeyAlgorithm = null;
|
||||||
|
this.hashAlgorithm = null;
|
||||||
|
this.exportable = null;
|
||||||
|
this.trustLevel = null;
|
||||||
|
this.trustAmount = null;
|
||||||
|
this.regular_expression = null;
|
||||||
|
this.revocable = null;
|
||||||
|
this.keyExpirationTime = null;
|
||||||
|
this.keyNeverExpires = null;
|
||||||
|
this.preferredSymmetricAlgorithms = null;
|
||||||
|
this.revocationKeyClass = null;
|
||||||
|
this.revocationKeyAlgorithm = null;
|
||||||
|
this.revocationKeyFingerprint = null;
|
||||||
|
this.issuerKeyId = null;
|
||||||
|
this.notationFlags = null;
|
||||||
|
this.notationName = null;
|
||||||
|
this.notationValue = null;
|
||||||
|
this.preferredHashAlgorithms = null;
|
||||||
|
this.preferredCompressionAlgorithms = null;
|
||||||
|
this.keyServerPreferences = null;
|
||||||
|
this.preferredKeyServer = null;
|
||||||
|
this.isPrimaryUserID = null;
|
||||||
|
this.policyURI = null;
|
||||||
|
this.keyFlags = null;
|
||||||
|
this.signersUserId = null;
|
||||||
|
this.reasonForRevocationFlag = null;
|
||||||
|
this.reasonForRevocationString = null;
|
||||||
|
this.signatureTargetPublicKeyAlgorithm = null;
|
||||||
|
this.signatureTargetHashAlgorithm = null;
|
||||||
|
this.signatureTargetHash = null;
|
||||||
|
this.embeddedSignature = null;
|
||||||
|
this.verified = false;
|
||||||
|
|
||||||
|
|
||||||
this.write = function() {
|
/**
|
||||||
|
* parsing function for a signature packet (tag 2).
|
||||||
|
* @param {String} bytes payload of a tag 2 packet
|
||||||
|
* @param {Integer} position position to start reading from the bytes string
|
||||||
|
* @param {Integer} len length of the packet or the remaining length of bytes at position
|
||||||
|
* @return {openpgp_packet_encrypteddata} object representation
|
||||||
|
*/
|
||||||
|
this.read = function(bytes) {
|
||||||
|
var mypos = 0;
|
||||||
|
|
||||||
|
this.version = bytes[mypos++].charCodeAt();
|
||||||
|
// switch on version (3 and 4)
|
||||||
|
switch (this.version) {
|
||||||
|
case 3:
|
||||||
|
// One-octet length of following hashed material. MUST be 5.
|
||||||
|
if (bytes[mypos++].charCodeAt() != 5)
|
||||||
|
util.print_debug("openpgp.packet.signature.js\n"+
|
||||||
|
'invalid One-octet length of following hashed material.' +
|
||||||
|
'MUST be 5. @:'+(mypos-1));
|
||||||
|
|
||||||
|
var sigpos = mypos;
|
||||||
|
// One-octet signature type.
|
||||||
|
this.signatureType = bytes[mypos++].charCodeAt();
|
||||||
|
|
||||||
|
// Four-octet creation time.
|
||||||
|
this.created = openpgp_packet_parse_date(bytes.substr(mypos, 4));
|
||||||
|
mypos += 4;
|
||||||
|
|
||||||
|
// storing data appended to data which gets verified
|
||||||
|
this.signatureData = bytes.substring(position, mypos);
|
||||||
|
|
||||||
|
// Eight-octet Key ID of signer.
|
||||||
|
this.keyId = bytes.substring(mypos, mypos +8);
|
||||||
|
mypos += 8;
|
||||||
|
|
||||||
|
// One-octet public-key algorithm.
|
||||||
|
this.publicKeyAlgorithm = bytes[mypos++].charCodeAt();
|
||||||
|
|
||||||
|
// One-octet hash algorithm.
|
||||||
|
this.hashAlgorithm = bytes[mypos++].charCodeAt();
|
||||||
|
|
||||||
|
// Two-octet field holding left 16 bits of signed hash value.
|
||||||
|
this.signedHashValue = openpgp_packet_read_integer(bytes.substr(mypos, 2));
|
||||||
|
mypos += 2;
|
||||||
|
|
||||||
|
var mpicount = 0;
|
||||||
|
// Algorithm-Specific Fields for RSA signatures:
|
||||||
|
// - multiprecision integer (MPI) of RSA signature value m**d mod n.
|
||||||
|
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
||||||
|
mpicount = 1;
|
||||||
|
// Algorithm-Specific Fields for DSA signatures:
|
||||||
|
// - MPI of DSA value r.
|
||||||
|
// - MPI of DSA value s.
|
||||||
|
else if (this.publicKeyAlgorithm == 17)
|
||||||
|
mpicount = 2;
|
||||||
|
|
||||||
|
this.mpi = new Array();
|
||||||
|
for (var i = 0; i < mpicount; i++) {
|
||||||
|
this.mpi[i] = new openpgp_type_mpi();
|
||||||
|
mypos += this.mpi[i].read(bytes.substr(mypos));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
this.signatureType = bytes[mypos++].charCodeAt();
|
||||||
|
this.publicKeyAlgorithm = bytes[mypos++].charCodeAt();
|
||||||
|
this.hashAlgorithm = bytes[mypos++].charCodeAt();
|
||||||
|
|
||||||
|
|
||||||
|
function subpackets(bytes, signed) {
|
||||||
|
// Two-octet scalar octet count for following hashed subpacket
|
||||||
|
// data.
|
||||||
|
var subpacket_length = openpgp_packet_integer_read(
|
||||||
|
bytes.substr(0, 2));
|
||||||
|
|
||||||
|
var i = 2;
|
||||||
|
|
||||||
|
// Hashed subpacket data set (zero or more subpackets)
|
||||||
|
var subpacked_read = 0;
|
||||||
|
while (subpacket_length != subpacked_read) {
|
||||||
|
if (subpacket_length < subpacked_read) {
|
||||||
|
util.print_debug("openpgp.packet.signature.js\n"+
|
||||||
|
"hashed missed something: "+i+" c:"+
|
||||||
|
subpacket_length+" l:"+subpacked_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
var len = openpgp_packet.read_simple_length(bytes.substr(i));
|
||||||
|
i += len.offset;
|
||||||
|
|
||||||
|
// Since it is trivial to add data to the unhashed portion of the packet
|
||||||
|
// we simply ignore all unauthenticated data.
|
||||||
|
if(signed)
|
||||||
|
this.read_sub_packet(bytes.substr(i, len));
|
||||||
|
|
||||||
|
i += len.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += subpacket_length;
|
||||||
|
|
||||||
|
if(signed)
|
||||||
|
this.signatureData = bytes.substring(0, i);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
mypos += subpackets(bytes.substr(mypos), true);
|
||||||
|
mypos += subpackets(bytes.substr(mypos), false);
|
||||||
|
|
||||||
|
// Two-octet field holding the left 16 bits of the signed hash
|
||||||
|
// value.
|
||||||
|
this.signedHashValue = (bytes[mypos++].charCodeAt() << 8) | bytes[mypos++].charCodeAt();
|
||||||
|
|
||||||
|
// One or more multiprecision integers comprising the signature.
|
||||||
|
// This portion is algorithm specific, as described above.
|
||||||
|
var mpicount = 0;
|
||||||
|
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
||||||
|
mpicount = 1;
|
||||||
|
else if (this.publicKeyAlgorithm == 17)
|
||||||
|
mpicount = 2;
|
||||||
|
|
||||||
|
this.mpi = new Array();
|
||||||
|
for (var i = 0; i < mpicount; i++) {
|
||||||
|
this.mpi[i] = new openpgp_type_mpi();
|
||||||
|
if (this.mpi[i].read(bytes, mypos, (mypos-position)) != null &&
|
||||||
|
!this.packetLength < (mypos-position)) {
|
||||||
|
mypos += this.mpi[i].packetLength;
|
||||||
|
} else {
|
||||||
|
util.print_error('signature contains invalid MPI @:'+mypos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
util.print_error("openpgp.packet.signature.js\n"+
|
||||||
|
'unknown signature packet version'+this.version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* creates a string representation of a message signature packet (tag 2).
|
||||||
|
* This can be only used on text data
|
||||||
|
* @param {Integer} signature_type should be 1 (one)
|
||||||
|
* @param {String} data data to be signed
|
||||||
|
* @param {openpgp_msg_privatekey} privatekey private key used to sign the message. (secmpi MUST be unlocked)
|
||||||
|
* @return {String} string representation of a signature packet
|
||||||
|
*/
|
||||||
|
function write_message_signature(signature_type, data, privatekey) {
|
||||||
|
var publickey = privatekey.privateKeyPacket.publicKey;
|
||||||
|
var hash_algo = privatekey.getPreferredSignatureHashAlgorithm();
|
||||||
|
var result = String.fromCharCode(4);
|
||||||
|
result += String.fromCharCode(signature_type);
|
||||||
|
result += String.fromCharCode(publickey.publicKeyAlgorithm);
|
||||||
|
result += String.fromCharCode(hash_algo);
|
||||||
|
var d = Math.round(new Date().getTime() / 1000);
|
||||||
|
var datesubpacket = write_sub_signature_packet(2,""+
|
||||||
|
String.fromCharCode((d >> 24) & 0xFF) +
|
||||||
|
String.fromCharCode((d >> 16) & 0xFF) +
|
||||||
|
String.fromCharCode((d >> 8) & 0xFF) +
|
||||||
|
String.fromCharCode(d & 0xFF));
|
||||||
|
var issuersubpacket = write_sub_signature_packet(16, privatekey.getKeyId());
|
||||||
|
result += String.fromCharCode(((datesubpacket.length + issuersubpacket.length) >> 8) & 0xFF);
|
||||||
|
result += String.fromCharCode ((datesubpacket.length + issuersubpacket.length) & 0xFF);
|
||||||
|
result += datesubpacket;
|
||||||
|
result += issuersubpacket;
|
||||||
|
var trailer = '';
|
||||||
|
|
||||||
|
trailer += String.fromCharCode(4);
|
||||||
|
trailer += String.fromCharCode(0xFF);
|
||||||
|
trailer += String.fromCharCode((result.length) >> 24);
|
||||||
|
trailer += String.fromCharCode(((result.length) >> 16) & 0xFF);
|
||||||
|
trailer += String.fromCharCode(((result.length) >> 8) & 0xFF);
|
||||||
|
trailer += String.fromCharCode((result.length) & 0xFF);
|
||||||
|
var result2 = String.fromCharCode(0);
|
||||||
|
result2 += String.fromCharCode(0);
|
||||||
|
var hash = openpgp_crypto_hashData(hash_algo, data+result+trailer);
|
||||||
|
util.print_debug("DSA Signature is calculated with:|"+data+result+trailer+"|\n"+util.hexstrdump(data+result+trailer)+"\n hash:"+util.hexstrdump(hash));
|
||||||
|
result2 += hash.charAt(0);
|
||||||
|
result2 += hash.charAt(1);
|
||||||
|
result2 += openpgp_crypto_signData(hash_algo,privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm,
|
||||||
|
publickey.mpi,
|
||||||
|
privatekey.privateKeyPacket.secmpi,
|
||||||
|
data+result+trailer);
|
||||||
|
return {openpgp: (openpgp_packet.write_packet_header(2, (result+result2).length)+result + result2),
|
||||||
|
hash: util.get_hashAlgorithmString(hash_algo)};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1)
|
||||||
|
* @param {Integer} type subpacket signature type. Signature types as described in RFC4880 Section 5.2.3.2
|
||||||
|
* @param {String} data data to be included
|
||||||
|
* @return {String} a string-representation of a sub signature packet (See RFC 4880 5.2.3.1)
|
||||||
|
*/
|
||||||
|
function write_sub_signature_packet(type, data) {
|
||||||
|
var result = "";
|
||||||
|
result += openpgp_packet.encode_length(data.length+1);
|
||||||
|
result += String.fromCharCode(type);
|
||||||
|
result += data;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// V4 signature sub packets
|
||||||
|
|
||||||
|
this.read_sub_packet = function(bytes) {
|
||||||
|
var mypos = 0;
|
||||||
|
|
||||||
|
|
||||||
|
var type = bytes[mypos++].charCodeAt() & 0x7F;
|
||||||
|
|
||||||
|
// subpacket type
|
||||||
|
switch (type) {
|
||||||
|
case 2: // Signature Creation Time
|
||||||
|
this.created = openpgp_packet_read_date(bytes.substr(mypos));
|
||||||
|
break;
|
||||||
|
case 3: // Signature Expiration Time
|
||||||
|
this.signatureExpirationTime = (bytes[mypos++].charCodeAt() << 24)
|
||||||
|
| (bytes[mypos++].charCodeAt() << 16) | (bytes[mypos++].charCodeAt() << 8)
|
||||||
|
| bytes[mypos++].charCodeAt();
|
||||||
|
this.signatureNeverExpires = (this.signature_expiration_time == 0);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 4: // Exportable Certification
|
||||||
|
this.exportable = bytes[mypos++].charCodeAt() == 1;
|
||||||
|
break;
|
||||||
|
case 5: // Trust Signature
|
||||||
|
this.trustLevel = bytes[mypos++].charCodeAt();
|
||||||
|
this.trustAmount = bytes[mypos++].charCodeAt();
|
||||||
|
break;
|
||||||
|
case 6: // Regular Expression
|
||||||
|
this.regular_expression = new String();
|
||||||
|
for (var i = 0; i < subplen - 1; i++)
|
||||||
|
this.regular_expression += (bytes[mypos++]);
|
||||||
|
break;
|
||||||
|
case 7: // Revocable
|
||||||
|
this.revocable = bytes[mypos++].charCodeAt() == 1;
|
||||||
|
break;
|
||||||
|
case 9: // Key Expiration Time
|
||||||
|
this.keyExpirationTime = (bytes[mypos++].charCodeAt() << 24)
|
||||||
|
| (bytes[mypos++].charCodeAt() << 16) | (bytes[mypos++].charCodeAt() << 8)
|
||||||
|
| bytes[mypos++].charCodeAt();
|
||||||
|
this.keyNeverExpires = (this.keyExpirationTime == 0);
|
||||||
|
break;
|
||||||
|
case 11: // Preferred Symmetric Algorithms
|
||||||
|
this.preferredSymmetricAlgorithms = new Array();
|
||||||
|
for (var i = 0; i < subplen-1; i++) {
|
||||||
|
this.preferredSymmetricAlgorithms = bytes[mypos++].charCodeAt();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 12: // Revocation Key
|
||||||
|
// (1 octet of class, 1 octet of public-key algorithm ID, 20
|
||||||
|
// octets of
|
||||||
|
// fingerprint)
|
||||||
|
this.revocationKeyClass = bytes[mypos++].charCodeAt();
|
||||||
|
this.revocationKeyAlgorithm = bytes[mypos++].charCodeAt();
|
||||||
|
this.revocationKeyFingerprint = new Array();
|
||||||
|
for ( var i = 0; i < 20; i++) {
|
||||||
|
this.revocationKeyFingerprint = bytes[mypos++].charCodeAt();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 16: // Issuer
|
||||||
|
this.issuerKeyId = bytes.substring(mypos,mypos+8);
|
||||||
|
mypos += 8;
|
||||||
|
break;
|
||||||
|
case 20: // Notation Data
|
||||||
|
this.notationFlags = (bytes[mypos++].charCodeAt() << 24) |
|
||||||
|
(bytes[mypos++].charCodeAt() << 16) |
|
||||||
|
(bytes[mypos++].charCodeAt() << 8) |
|
||||||
|
(bytes[mypos++].charCodeAt());
|
||||||
|
var nameLength = (bytes[mypos++].charCodeAt() << 8) | (bytes[mypos++].charCodeAt());
|
||||||
|
var valueLength = (bytes[mypos++].charCodeAt() << 8) | (bytes[mypos++].charCodeAt());
|
||||||
|
this.notationName = "";
|
||||||
|
for (var i = 0; i < nameLength; i++) {
|
||||||
|
this.notationName += bytes[mypos++];
|
||||||
|
}
|
||||||
|
this.notationValue = "";
|
||||||
|
for (var i = 0; i < valueLength; i++) {
|
||||||
|
this.notationValue += bytes[mypos++];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 21: // Preferred Hash Algorithms
|
||||||
|
this.preferredHashAlgorithms = new Array();
|
||||||
|
for (var i = 0; i < subplen-1; i++) {
|
||||||
|
this.preferredHashAlgorithms = bytes[mypos++].charCodeAt();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 22: // Preferred Compression Algorithms
|
||||||
|
this.preferredCompressionAlgorithms = new Array();
|
||||||
|
for ( var i = 0; i < subplen-1; i++) {
|
||||||
|
this.preferredCompressionAlgorithms = bytes[mypos++].charCodeAt();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 23: // Key Server Preferences
|
||||||
|
this.keyServerPreferences = new Array();
|
||||||
|
for ( var i = 0; i < subplen-1; i++) {
|
||||||
|
this.keyServerPreferences = bytes[mypos++].charCodeAt();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 24: // Preferred Key Server
|
||||||
|
this.preferredKeyServer = new String();
|
||||||
|
for ( var i = 0; i < subplen-1; i++) {
|
||||||
|
this.preferredKeyServer += bytes[mypos++];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 25: // Primary User ID
|
||||||
|
this.isPrimaryUserID = bytes[mypos++] != 0;
|
||||||
|
break;
|
||||||
|
case 26: // Policy URI
|
||||||
|
this.policyURI = new String();
|
||||||
|
for ( var i = 0; i < subplen-1; i++) {
|
||||||
|
this.policyURI += bytes[mypos++];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 27: // Key Flags
|
||||||
|
this.keyFlags = new Array();
|
||||||
|
for ( var i = 0; i < subplen-1; i++) {
|
||||||
|
this.keyFlags = bytes[mypos++].charCodeAt();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 28: // Signer's User ID
|
||||||
|
this.signersUserId += bytes.substr(mypos);
|
||||||
|
break;
|
||||||
|
case 29: // Reason for Revocation
|
||||||
|
this.reasonForRevocationFlag = bytes[mypos++].charCodeAt();
|
||||||
|
this.reasonForRevocationString = new String();
|
||||||
|
for ( var i = 0; i < subplen -2; i++) {
|
||||||
|
this.reasonForRevocationString += bytes[mypos++];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 30: // Features
|
||||||
|
// TODO: to be implemented
|
||||||
|
return subplen+1;
|
||||||
|
case 31: // Signature Target
|
||||||
|
// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
|
||||||
|
this.signatureTargetPublicKeyAlgorithm = bytes[mypos++].charCodeAt();
|
||||||
|
this.signatureTargetHashAlgorithm = bytes[mypos++].charCodeAt();
|
||||||
|
var signatureTargetHashAlgorithmLength = 0;
|
||||||
|
switch(this.signatureTargetHashAlgorithm) {
|
||||||
|
case 1: // - MD5 [HAC] "MD5"
|
||||||
|
case 2: // - SHA-1 [FIPS180] "SHA1"
|
||||||
|
signatureTargetHashAlgorithmLength = 20;
|
||||||
|
break;
|
||||||
|
case 3: // - RIPE-MD/160 [HAC] "RIPEMD160"
|
||||||
|
case 8: // - SHA256 [FIPS180] "SHA256"
|
||||||
|
case 9: // - SHA384 [FIPS180] "SHA384"
|
||||||
|
case 10: // - SHA512 [FIPS180] "SHA512"
|
||||||
|
case 11: // - SHA224 [FIPS180] "SHA224"
|
||||||
|
break;
|
||||||
|
// 100 to 110 - Private/Experimental algorithm
|
||||||
|
default:
|
||||||
|
util.print_error("openpgp.packet.signature.js\n"+"unknown signature target hash algorithm:"+this.signatureTargetHashAlgorithm);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
this.signatureTargetHash = new Array();
|
||||||
|
for (var i = 0; i < signatureTargetHashAlgorithmLength; i++) {
|
||||||
|
this.signatureTargetHash[i] = bytes[mypos++];
|
||||||
|
}
|
||||||
|
case 32: // Embedded Signature
|
||||||
|
this.embeddedSignature = new openpgp_packet_signature();
|
||||||
|
this.embeddedSignature.read_packet(bytes, mypos, len -(mypos-position));
|
||||||
|
return ((mypos+ this.embeddedSignature.packetLength) - position);
|
||||||
|
break;
|
||||||
|
case 100: // Private or experimental
|
||||||
|
case 101: // Private or experimental
|
||||||
|
case 102: // Private or experimental
|
||||||
|
case 103: // Private or experimental
|
||||||
|
case 104: // Private or experimental
|
||||||
|
case 105: // Private or experimental
|
||||||
|
case 106: // Private or experimental
|
||||||
|
case 107: // Private or experimental
|
||||||
|
case 108: // Private or experimental
|
||||||
|
case 109: // Private or experimental
|
||||||
|
case 110: // Private or experimental
|
||||||
|
util.print_error("openpgp.packet.signature.js\n"+'private or experimental signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
|
||||||
|
return subplen+1;
|
||||||
|
break;
|
||||||
|
case 0: // Reserved
|
||||||
|
case 1: // Reserved
|
||||||
|
case 8: // Reserved
|
||||||
|
case 10: // Placeholder for backward compatibility
|
||||||
|
case 13: // Reserved
|
||||||
|
case 14: // Reserved
|
||||||
|
case 15: // Reserved
|
||||||
|
case 17: // Reserved
|
||||||
|
case 18: // Reserved
|
||||||
|
case 19: // Reserved
|
||||||
|
default:
|
||||||
|
util.print_error("openpgp.packet.signature.js\n"+'unknown signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
|
||||||
|
return subplen+1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return mypos -position;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* verifys the signature packet. Note: not signature types are implemented
|
||||||
|
* @param {String} data data which on the signature applies
|
||||||
|
* @param {openpgp_msg_privatekey} key the public key to verify the signature
|
||||||
|
* @return {boolean} True if message is verified, else false.
|
||||||
|
*/
|
||||||
|
function verify(data, key) {
|
||||||
|
// calculating the trailer
|
||||||
|
var trailer = '';
|
||||||
|
trailer += String.fromCharCode(this.version);
|
||||||
|
trailer += String.fromCharCode(0xFF);
|
||||||
|
trailer += String.fromCharCode(this.signatureData.length >> 24);
|
||||||
|
trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
|
||||||
|
trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
|
||||||
|
trailer += String.fromCharCode(this.signatureData.length & 0xFF);
|
||||||
|
switch(this.signatureType) {
|
||||||
|
case 0: // 0x00: Signature of a binary document.
|
||||||
|
if (this.version == 4) {
|
||||||
|
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||||
|
this.mpi, key.obj.publicKeyPacket.mpi, data+this.signatureData+trailer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // 0x01: Signature of a canonical text document.
|
||||||
|
if (this.version == 4) {
|
||||||
|
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||||
|
this.mpi, key.obj.publicKeyPacket.mpi, data+this.signatureData+trailer);
|
||||||
|
return this.verified;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // 0x02: Standalone signature.
|
||||||
|
// This signature is a signature of only its own subpacket contents.
|
||||||
|
// It is calculated identically to a signature over a zero-lengh
|
||||||
|
// binary document. Note that it doesn't make sense to have a V3
|
||||||
|
// standalone signature.
|
||||||
|
if (this.version == 3) {
|
||||||
|
this.verified = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||||
|
this.mpi, key.obj.publicKeyPacket.mpi, this.signatureData+trailer);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
// 0x10: Generic certification of a User ID and Public-Key packet.
|
||||||
|
// The issuer of this certification does not make any particular
|
||||||
|
// assertion as to how well the certifier has checked that the owner
|
||||||
|
// of the key is in fact the person described by the User ID.
|
||||||
|
case 17:
|
||||||
|
// 0x11: Persona certification of a User ID and Public-Key packet.
|
||||||
|
// The issuer of this certification has not done any verification of
|
||||||
|
// the claim that the owner of this key is the User ID specified.
|
||||||
|
case 18:
|
||||||
|
// 0x12: Casual certification of a User ID and Public-Key packet.
|
||||||
|
// The issuer of this certification has done some casual
|
||||||
|
// verification of the claim of identity.
|
||||||
|
case 19:
|
||||||
|
// 0x13: Positive certification of a User ID and Public-Key packet.
|
||||||
|
// The issuer of this certification has done substantial
|
||||||
|
// verification of the claim of identity.
|
||||||
|
//
|
||||||
|
// Most OpenPGP implementations make their "key signatures" as 0x10
|
||||||
|
// certifications. Some implementations can issue 0x11-0x13
|
||||||
|
// certifications, but few differentiate between the types.
|
||||||
|
case 48:
|
||||||
|
// 0x30: Certification revocation signature
|
||||||
|
// This signature revokes an earlier User ID certification signature
|
||||||
|
// (signature class 0x10 through 0x13) or direct-key signature
|
||||||
|
// (0x1F). It should be issued by the same key that issued the
|
||||||
|
// revoked signature or an authorized revocation key. The signature
|
||||||
|
// is computed over the same data as the certificate that it
|
||||||
|
// revokes, and should have a later creation date than that
|
||||||
|
// certificate.
|
||||||
|
|
||||||
|
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||||
|
this.mpi, key.mpi, data+this.signatureData+trailer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 24:
|
||||||
|
// 0x18: Subkey Binding Signature
|
||||||
|
// This signature is a statement by the top-level signing key that
|
||||||
|
// indicates that it owns the subkey. This signature is calculated
|
||||||
|
// directly on the primary key and subkey, and not on any User ID or
|
||||||
|
// other packets. A signature that binds a signing subkey MUST have
|
||||||
|
// an Embedded Signature subpacket in this binding signature that
|
||||||
|
// contains a 0x19 signature made by the signing subkey on the
|
||||||
|
// primary key and subkey.
|
||||||
|
if (this.version == 3) {
|
||||||
|
this.verified = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||||
|
this.mpi, key.mpi, data+this.signatureData+trailer);
|
||||||
|
break;
|
||||||
|
case 25:
|
||||||
|
// 0x19: Primary Key Binding Signature
|
||||||
|
// This signature is a statement by a signing subkey, indicating
|
||||||
|
// that it is owned by the primary key and subkey. This signature
|
||||||
|
// is calculated the same way as a 0x18 signature: directly on the
|
||||||
|
// primary key and subkey, and not on any User ID or other packets.
|
||||||
|
|
||||||
|
// When a signature is made over a key, the hash data starts with the
|
||||||
|
// octet 0x99, followed by a two-octet length of the key, and then body
|
||||||
|
// of the key packet. (Note that this is an old-style packet header for
|
||||||
|
// a key packet with two-octet length.) A subkey binding signature
|
||||||
|
// (type 0x18) or primary key binding signature (type 0x19) then hashes
|
||||||
|
// the subkey using the same format as the main key (also using 0x99 as
|
||||||
|
// the first octet).
|
||||||
|
case 31:
|
||||||
|
// 0x1F: Signature directly on a key
|
||||||
|
// This signature is calculated directly on a key. It binds the
|
||||||
|
// information in the Signature subpackets to the key, and is
|
||||||
|
// appropriate to be used for subpackets that provide information
|
||||||
|
// about the key, such as the Revocation Key subpacket. It is also
|
||||||
|
// appropriate for statements that non-self certifiers want to make
|
||||||
|
// about the key itself, rather than the binding between a key and a
|
||||||
|
// name.
|
||||||
|
case 32:
|
||||||
|
// 0x20: Key revocation signature
|
||||||
|
// The signature is calculated directly on the key being revoked. A
|
||||||
|
// revoked key is not to be used. Only revocation signatures by the
|
||||||
|
// key being revoked, or by an authorized revocation key, should be
|
||||||
|
// considered valid revocation signatures.
|
||||||
|
case 40:
|
||||||
|
// 0x28: Subkey revocation signature
|
||||||
|
// The signature is calculated directly on the subkey being revoked.
|
||||||
|
// A revoked subkey is not to be used. Only revocation signatures
|
||||||
|
// by the top-level signature key that is bound to this subkey, or
|
||||||
|
// by an authorized revocation key, should be considered valid
|
||||||
|
// revocation signatures.
|
||||||
|
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||||
|
this.mpi, key.mpi, data+this.signatureData+trailer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Key revocation signatures (types 0x20 and 0x28)
|
||||||
|
// hash only the key being revoked.
|
||||||
|
case 64:
|
||||||
|
// 0x40: Timestamp signature.
|
||||||
|
// This signature is only meaningful for the timestamp contained in
|
||||||
|
// it.
|
||||||
|
case 80:
|
||||||
|
// 0x50: Third-Party Confirmation signature.
|
||||||
|
// This signature is a signature over some other OpenPGP Signature
|
||||||
|
// packet(s). It is analogous to a notary seal on the signed data.
|
||||||
|
// A third-party signature SHOULD include Signature Target
|
||||||
|
// subpacket(s) to give easy identification. Note that we really do
|
||||||
|
// mean SHOULD. There are plausible uses for this (such as a blind
|
||||||
|
// party that only sees the signature, not the key or source
|
||||||
|
// document) that cannot include a target subpacket.
|
||||||
|
default:
|
||||||
|
util.print_error("openpgp.packet.signature.js\n"+"signature verification for type"+ this.signatureType+" not implemented");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return this.verified;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* generates debug output (pretty print)
|
||||||
|
* @return {String} String which gives some information about the signature packet
|
||||||
|
*/
|
||||||
|
|
||||||
|
function toString () {
|
||||||
|
if (this.version == 3) {
|
||||||
|
var result = '5.2. Signature Packet (Tag 2)\n'+
|
||||||
|
"Packet Length: :"+this.packetLength+'\n'+
|
||||||
|
"Packet version: :"+this.version+'\n'+
|
||||||
|
"One-octet signature type :"+this.signatureType+'\n'+
|
||||||
|
"Four-octet creation time. :"+this.created+'\n'+
|
||||||
|
"Eight-octet Key ID of signer. :"+util.hexidump(this.keyId)+'\n'+
|
||||||
|
"One-octet public-key algorithm. :"+this.publicKeyAlgorithm+'\n'+
|
||||||
|
"One-octet hash algorithm. :"+this.hashAlgorithm+'\n'+
|
||||||
|
"Two-octet field holding left\n" +
|
||||||
|
" 16 bits of signed hash value. :"+this.signedHashValue+'\n';
|
||||||
|
} else {
|
||||||
|
var result = '5.2. Signature Packet (Tag 2)\n'+
|
||||||
|
"Packet Length: :"+this.packetLength+'\n'+
|
||||||
|
"Packet version: :"+this.version+'\n'+
|
||||||
|
"One-octet signature type :"+this.signatureType+'\n'+
|
||||||
|
"One-octet public-key algorithm. :"+this.publicKeyAlgorithm+'\n'+
|
||||||
|
"One-octet hash algorithm. :"+this.hashAlgorithm+'\n'+
|
||||||
|
"Two-octet field holding left\n" +
|
||||||
|
" 16 bits of signed hash value. :"+this.signedHashValue+'\n'+
|
||||||
|
"Signature Creation Time :"+this.created+'\n'+
|
||||||
|
"Signature Expiration Time :"+this.signatureExpirationTime+'\n'+
|
||||||
|
"Signature Never Expires :"+this.signatureNeverExpires+'\n'+
|
||||||
|
"Exportable Certification :"+this.exportable+'\n'+
|
||||||
|
"Trust Signature level: :"+this.trustLevel+' amount'+this.trustAmount+'\n'+
|
||||||
|
"Regular Expression :"+this.regular_expression+'\n'+
|
||||||
|
"Revocable :"+this.revocable+'\n'+
|
||||||
|
"Key Expiration Time :"+this.keyExpirationTime+" "+this.keyNeverExpires+'\n'+
|
||||||
|
"Preferred Symmetric Algorithms :"+this.preferredSymmetricAlgorithms+'\n'+
|
||||||
|
"Revocation Key"+'\n'+
|
||||||
|
" ( 1 octet of class, :"+this.revocationKeyClass +'\n'+
|
||||||
|
" 1 octet of public-key ID, :" +this.revocationKeyAlgorithm+'\n'+
|
||||||
|
" 20 octets of fingerprint) :"+this.revocationKeyFingerprint+'\n'+
|
||||||
|
"Issuer :"+util.hexstrdump(this.issuerKeyId)+'\n'+
|
||||||
|
"Preferred Hash Algorithms :"+this.preferredHashAlgorithms+'\n'+
|
||||||
|
"Preferred Compression Alg. :"+this.preferredCompressionAlgorithms+'\n'+
|
||||||
|
"Key Server Preferences :"+this.keyServerPreferences+'\n'+
|
||||||
|
"Preferred Key Server :"+this.preferredKeyServer+'\n'+
|
||||||
|
"Primary User ID :"+this.isPrimaryUserID+'\n'+
|
||||||
|
"Policy URI :"+this.policyURI+'\n'+
|
||||||
|
"Key Flags :"+this.keyFlags+'\n'+
|
||||||
|
"Signer's User ID :"+this.signersUserId+'\n'+
|
||||||
|
"Notation :"+this.notationName+" = "+this.notationValue+"\n"+
|
||||||
|
"Reason for Revocation\n"+
|
||||||
|
" Flag :"+this.reasonForRevocationFlag+'\n'+
|
||||||
|
" Reason :"+this.reasonForRevocationString+'\nMPI:\n';
|
||||||
|
}
|
||||||
|
for (var i = 0; i < this.mpi.length; i++) {
|
||||||
|
result += this.mpi[i].toString();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the issuer key id of this signature
|
||||||
|
* @return {String} issuer key id as string (8bytes)
|
||||||
|
*/
|
||||||
|
function getIssuer() {
|
||||||
|
if (this.version == 4)
|
||||||
|
return this.issuerKeyId;
|
||||||
|
if (this.verions == 4)
|
||||||
|
return this.keyId;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.read = function() {}
|
/**
|
||||||
|
* Tries to get the corresponding public key out of the public keyring for the issuer created this signature
|
||||||
|
* @return {Object} {obj: [openpgp_msg_publickey], text: [String]} if found the public key will be returned. null otherwise
|
||||||
|
*/
|
||||||
|
function getIssuerKey() {
|
||||||
|
var result = null;
|
||||||
|
if (this.version == 4) {
|
||||||
|
result = openpgp.keyring.getPublicKeysForKeyId(this.issuerKeyId);
|
||||||
|
} else if (this.version == 3) {
|
||||||
|
result = openpgp.keyring.getPublicKeysForKeyId(this.keyId);
|
||||||
|
} else return null;
|
||||||
|
if (result.length == 0)
|
||||||
|
return null;
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
this.getIssuerKey = getIssuerKey;
|
||||||
|
this.getIssuer = getIssuer;
|
||||||
|
this.write_message_signature = write_message_signature;
|
||||||
|
this.verify = verify;
|
||||||
|
this.read_packet = read_packet;
|
||||||
|
this.toString = toString;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user