From 77acb5a59a839999830ec0be40f6ddc0d6335cd7 Mon Sep 17 00:00:00 2001 From: Michal Kolodziej Date: Thu, 9 May 2013 16:51:25 +0200 Subject: [PATCH] Working signature creation. --- resources/openpgp.js | 153 ++++++++++++++++++---------------- resources/openpgp.min.js | 29 +++---- src/ciphers/openpgp.crypto.js | 6 +- src/packet/signature.js | 147 ++++++++++++++++---------------- test/general/packet.js | 47 +++++++++++ 5 files changed, 220 insertions(+), 162 deletions(-) diff --git a/resources/openpgp.js b/resources/openpgp.js index a060ca84..539d4754 100644 --- a/resources/openpgp.js +++ b/resources/openpgp.js @@ -3925,7 +3925,7 @@ function openpgp_crypto_verifySignature(algo, hash_algo, msg_MPIs, publickey_MPI * @param {openpgp_type_mpi[]} secretMPIs Private key multiprecision * integers which is used to sign the data * @param {String} data Data to be signed - * @return {(String|openpgp_type_mpi)} + * @return {openpgp_type_mpi[]} */ function openpgp_crypto_signData(hash_algo, algo, publicMPIs, secretMPIs, data) { @@ -3936,7 +3936,7 @@ function openpgp_crypto_signData(hash_algo, algo, publicMPIs, secretMPIs, data) var rsa = new RSA(); var d = secretMPIs[0].toBigInteger(); var n = publicMPIs[0].toBigInteger(); - var m = openpgp_encoding_emsa_pkcs1_encode(hash_algo, data,publicMPIs[0].mpiByteLength); + var m = openpgp_encoding_emsa_pkcs1_encode(hash_algo, data,publicMPIs[0].byteLength()); util.print_debug("signing using RSA"); return rsa.sign(m, d, n).toMPI(); case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC] @@ -3950,7 +3950,7 @@ function openpgp_crypto_signData(hash_algo, algo, publicMPIs, secretMPIs, data) var m = data; var result = dsa.sign(hash_algo,m, g, p, q, x); util.print_debug("signing using DSA\n result:"+util.hexstrdump(result[0])+"|"+util.hexstrdump(result[1])); - return result[0]+result[1]; + return result[0].toString() + result[1].toString(); case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] util.print_debug("signing with Elgamal is not defined in the OpenPGP standard."); return null; @@ -10917,15 +10917,19 @@ function openpgp_packet_secret_subkey() { */ function openpgp_packet_signature() { this.tag = 2; + this.signatureType = null; - this.created = null; + this.hashAlgorithm = null; + this.publicKeyAlgorithm = null; + this.version = 4; + this.signatureData = null; - this.signatureExpirationTime = null; - this.signatureNeverExpires = null; this.signedHashValue = null; this.mpi = null; - this.publicKeyAlgorithm = null; - this.hashAlgorithm = null; + + this.created = null; + this.signatureExpirationTime = null; + this.signatureNeverExpires = null; this.exportable = null; this.trustLevel = null; this.trustAmount = null; @@ -10953,6 +10957,7 @@ function openpgp_packet_signature() { this.signatureTargetHashAlgorithm = null; this.signatureTargetHash = null; this.embeddedSignature = null; + this.verified = false; @@ -11052,71 +11057,48 @@ function openpgp_packet_signature() { this.signedHashValue = bytes.substr(i, 2); i += 2; - var mpicount = 0; - // Algorithm-Specific Fields for RSA signatures: - // - multiprecision number (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 = []; - for (var j = 0; j < mpicount; j++) { - this.mpi[j] = new openpgp_type_mpi(); - i += this.mpi[j].read(bytes.substr(i)); - } + this.signature = bytes.substr(i); + } + + this.write = function() { + return this.signatureData + + openpgp_packet_number_write(0, 2) + // Number of unsigned subpackets. + this.signedHashValue + + this.signature; } /** - * 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 + * Signs provided data. This needs to be done prior to serialization. + * @param {Object} data Contains packets to be signed. + * @param {openpgp_msg_privatekey} privatekey private key used to sign the message. */ - function write_message_signature(signature_type, data, privatekey) { - var publickey = privatekey.privateKeyPacket.publicKey; - var hash_algo = privatekey.getPreferredSignatureHashAlgorithm(); + this.sign = function(privatekey, data) { + var publickey = privatekey.public_key; + 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 = ''; + result += String.fromCharCode(this.signatureType); + result += String.fromCharCode(this.publicKeyAlgorithm); + result += String.fromCharCode(this.hashAlgorithm); + + + // Add subpackets here + result += openpgp_packet_number_write(0, 2); + + + this.signatureData = result; + + var trailer = this.calculateTrailer(); - 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)}; + var toHash = this.toSign(this.signatureType, data) + this.signatureData + trailer; + var hash = openpgp_crypto_hashData(this.hashAlgorithm, toHash); + + this.signedHashValue = hash.substr(0, 2); + + + this.signature = openpgp_crypto_signData(this.hashAlgorithm, this.publicKeyAlgorithm, + publickey.mpi, privatekey.mpi, toHash); } + /** * 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 @@ -11124,7 +11106,7 @@ function openpgp_packet_signature() { * @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) { + function write_sub_packet(type, data) { var result = ""; result += openpgp_packet.encode_length(data.length+1); result += String.fromCharCode(type); @@ -11341,6 +11323,16 @@ function openpgp_packet_signature() { } } + + this.calculateTrailer = function() { + // calculating the trailer + var trailer = ''; + trailer += String.fromCharCode(this.version); + trailer += String.fromCharCode(0xFF); + trailer += openpgp_packet_number_write(this.signatureData.length, 4); + return trailer + } + /** * verifys the signature packet. Note: not signature types are implemented @@ -11350,16 +11342,29 @@ function openpgp_packet_signature() { */ this.verify = function(key, data) { - var bytes = this.toSign(this.signatureType, data); + var bytes = this.toSign(this.signatureType, data), + trailer = this.calculateTrailer(); - // calculating the trailer - var trailer = ''; - trailer += String.fromCharCode(this.version); - trailer += String.fromCharCode(0xFF); - trailer += openpgp_packet_number_write(this.signatureData.length, 4); + + var mpicount = 0; + // Algorithm-Specific Fields for RSA signatures: + // - multiprecision number (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; + + var mpi = [], i = 0; + for (var j = 0; j < mpicount; j++) { + mpi[j] = new openpgp_type_mpi(); + i += mpi[j].read(this.signature.substr(i)); + } this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, - this.hashAlgorithm, this.mpi, key.mpi, + this.hashAlgorithm, mpi, key.mpi, bytes + this.signatureData + trailer); return this.verified; diff --git a/resources/openpgp.min.js b/resources/openpgp.min.js index 9caa9f70..dd269657 100644 --- a/resources/openpgp.min.js +++ b/resources/openpgp.min.js @@ -114,8 +114,8 @@ function openpgp_crypto_MDCSystemBytes(a,b,c){util.print_debug_hexstr_dump("open "Twofish Algorithm not implemented"))}return null}function openpgp_crypto_generateSessionKey(a){return openpgp_crypto_getRandomBytes(openpgp_crypto_getKeyLength(a))}function openpgp_crypto_getKeyLength(a){switch(a){case 2:case 8:return 24;case 3:case 4:case 7:return 16;case 9:case 10:return 32}return null}function openpgp_crypto_getBlockLength(a){switch(a){case 1:case 2:case 3:return 8;case 4:case 7:case 8:case 9:return 16;case 10:return 32;default:return 0}} function openpgp_crypto_verifySignature(a,b,c,d,e){var f=openpgp_crypto_hashData(b,e);switch(a){case 1:case 2:case 3:e=new RSA;a=d[0].toBigInteger();d=d[1].toBigInteger();c=c[0].toBigInteger();d=e.verify(c,d,a);b=openpgp_encoding_emsa_pkcs1_decode(b,d.toMPI().substring(2));return-1==b?(util.print_error("PKCS1 padding in message or key incorrect. Aborting..."),!1):b==f;case 16:return util.print_error("signing with Elgamal is not defined in the OpenPGP standard."),null;case 17:var a=new DSA,f=c[0].toBigInteger(), c=c[1].toBigInteger(),h=d[0].toBigInteger(),g=d[1].toBigInteger(),j=d[2].toBigInteger(),d=d[3].toBigInteger(),d=a.verify(b,f,c,e,h,g,j,d);return 0==d.compareTo(f);default:return null}} -function openpgp_crypto_signData(a,b,c,d,e){switch(b){case 1:case 2:case 3:var b=new RSA,d=d[0].toBigInteger(),f=c[0].toBigInteger(),a=openpgp_encoding_emsa_pkcs1_encode(a,e,c[0].mpiByteLength);util.print_debug("signing using RSA");return b.sign(a,d,f).toMPI();case 17:b=new DSA;util.print_debug("DSA Sign: q size in Bytes:"+c[1].getByteLength());var f=c[0].toBigInteger(),h=c[1].toBigInteger(),g=c[2].toBigInteger();c[3].toBigInteger();c=d[0].toBigInteger();a=b.sign(a,e,g,f,h,c);util.print_debug("signing using DSA\n result:"+ -util.hexstrdump(a[0])+"|"+util.hexstrdump(a[1]));return a[0]+a[1];case 16:return util.print_debug("signing with Elgamal is not defined in the OpenPGP standard."),null;default:return null}}function openpgp_crypto_hashData(a,b){var c=null;switch(a){case 1:c=MD5(b);break;case 2:c=str_sha1(b);break;case 3:c=RMDstring(b);break;case 8:c=str_sha256(b);break;case 9:c=str_sha384(b);break;case 10:c=str_sha512(b);break;case 11:c=str_sha224(b)}return c} +function openpgp_crypto_signData(a,b,c,d,e){switch(b){case 1:case 2:case 3:var b=new RSA,d=d[0].toBigInteger(),f=c[0].toBigInteger(),a=openpgp_encoding_emsa_pkcs1_encode(a,e,c[0].byteLength());util.print_debug("signing using RSA");return b.sign(a,d,f).toMPI();case 17:b=new DSA;util.print_debug("DSA Sign: q size in Bytes:"+c[1].getByteLength());var f=c[0].toBigInteger(),h=c[1].toBigInteger(),g=c[2].toBigInteger();c[3].toBigInteger();c=d[0].toBigInteger();a=b.sign(a,e,g,f,h,c);util.print_debug("signing using DSA\n result:"+ +util.hexstrdump(a[0])+"|"+util.hexstrdump(a[1]));return a[0].toString()+a[1].toString();case 16:return util.print_debug("signing with Elgamal is not defined in the OpenPGP standard."),null;default:return null}}function openpgp_crypto_hashData(a,b){var c=null;switch(a){case 1:c=MD5(b);break;case 2:c=str_sha1(b);break;case 3:c=RMDstring(b);break;case 8:c=str_sha256(b);break;case 9:c=str_sha384(b);break;case 10:c=str_sha512(b);break;case 11:c=str_sha224(b)}return c} function openpgp_crypto_getHashByteLength(a){switch(a){case 1:return 16;case 2:case 3:return 20;case 8:return 32;case 9:return 48;case 10:return 64;case 11:return 28}return null}function openpgp_crypto_getRandomBytes(a){for(var b="",c=0;cb-a;)window.crypto.getRandomValues(c);return a+Math.abs(c[0]&Math.pow(2,d)-1)}function openpgp_crypto_getSecureRandomOctet(){var a=new Uint32Array(1);window.crypto.getRandomValues(a);return a[0]&255} function openpgp_crypto_getRandomBigInteger(a){if(0>a)return null;var b=openpgp_crypto_getRandomBytes(Math.floor((a+7)/8));0=b.compareTo(a))){for(var c=b.subtract(a),d=openpgp_crypto_getRandomBigInteger(c.bitLength());d>c;)d=openpgp_crypto_getRandomBigInteger(c.bitLength());return a.add(d)}} @@ -383,18 +383,19 @@ switch(f){case 1:throw Error("IDEA is not implemented.");case 2:f=normal_cfb_dec b)},g.length,new keyExpansion(a),c,g);break;case 10:throw Error("Twofish is not implemented.");default:throw Error("Unknown symmetric algorithm.");}this.mpi=b(254==h?openpgp.hash.sha1:"mod",f,this.public_key.algorithm)}};this.getKeyId=function(){if(4==this.version)return this.getFingerprint().substring(12,20);if(3==this.version&&0this.publicKeyAlgorithm){var a=this.MPIs[0].substring(this.MPIs[0].mpiByteLength-8);util.print_debug("openpgp.msg.publickey read_nodes:\nV3 key ID: "+ a);return a}};this.getFingerprint=function(){if(4==this.version)return tohash=String.fromCharCode(153)+String.fromCharCode(this.packetdata.length>>8&255)+String.fromCharCode(this.packetdata.length&255)+this.packetdata,util.print_debug("openpgp.msg.publickey creating subkey fingerprint by hashing:"+util.hexstrdump(tohash)+"\npublickeyalgorithm: "+this.publicKeyAlgorithm),str_sha1(tohash,tohash.length);if(3==this.version&&0this.publicKeyAlgorithm)return MD5(this.MPIs[0].MPI)}} function openpgp_packet_secret_subkey(){openpgp_packet_secret_key.call(this);this.tag=7} -function openpgp_packet_signature(){this.tag=2;this.issuerKeyId=this.revocationKeyFingerprint=this.revocationKeyAlgorithm=this.revocationKeyClass=this.preferredSymmetricAlgorithms=this.keyNeverExpires=this.keyExpirationTime=this.revocable=this.regularExpression=this.trustAmount=this.trustLevel=this.exportable=this.hashAlgorithm=this.publicKeyAlgorithm=this.mpi=this.signedHashValue=this.signatureNeverExpires=this.signatureExpirationTime=this.signatureData=this.created=this.signatureType=null;this.notation= -{};this.embeddedSignature=this.signatureTargetHash=this.signatureTargetHashAlgorithm=this.signatureTargetPublicKeyAlgorithm=this.reasonForRevocationString=this.reasonForRevocationFlag=this.signersUserId=this.keyFlags=this.policyURI=this.isPrimaryUserID=this.preferredKeyServer=this.keyServerPreferences=this.preferredCompressionAlgorithms=this.preferredHashAlgorithms=null;this.verified=!1;this.read=function(a){var b=0;this.version=a[b++].charCodeAt();switch(this.version){case 3:5!=a[b++].charCodeAt()&& -util.print_debug("openpgp.packet.signature.js\ninvalid One-octet length of following hashed material.MUST be 5. @:"+(b-1));this.signatureType=a[b++].charCodeAt();this.created=openpgp_packet_time_read(a.substr(b,4));b+=4;this.signatureData=a.substring(position,b);this.issuerKeyId=a.substring(b,b+8);b+=8;this.publicKeyAlgorithm=a[b++].charCodeAt();this.hashAlgorithm=a[b++].charCodeAt();break;case 4:this.signatureType=a[b++].charCodeAt();this.publicKeyAlgorithm=a[b++].charCodeAt();this.hashAlgorithm= -a[b++].charCodeAt();var c=function(a,b){for(var c=openpgp_packet_number_read(a.substr(0,2)),d=2;d<2+c;){var j=openpgp_packet.read_simple_length(a.substr(d)),d=d+j.offset;b&&this.read_sub_packet(a.substr(d,j.len));d+=j.len}return d},b=b+c.call(this,a.substr(b),!0);this.signatureData=a.substr(0,b);b+=c.call(this,a.substr(b),!1);break;default:util.print_error("openpgp.packet.signature.js\nunknown signature packet version"+this.version)}this.signedHashValue=a.substr(b,2);b+=2;c=0;0this.publicKeyAlgorithm?c=1:17==this.publicKeyAlgorithm&&(c=2);this.mpi=[];for(var d=0;dthis.publicKeyAlgorithm?e=1:17==this.publicKeyAlgorithm&&(e=2);for(var f=[],h=0,g=0;g 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 = []; - for (var j = 0; j < mpicount; j++) { - this.mpi[j] = new openpgp_type_mpi(); - i += this.mpi[j].read(bytes.substr(i)); - } + this.signature = bytes.substr(i); + } + + this.write = function() { + return this.signatureData + + openpgp_packet_number_write(0, 2) + // Number of unsigned subpackets. + this.signedHashValue + + this.signature; } /** - * 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 + * Signs provided data. This needs to be done prior to serialization. + * @param {Object} data Contains packets to be signed. + * @param {openpgp_msg_privatekey} privatekey private key used to sign the message. */ - function write_message_signature(signature_type, data, privatekey) { - var publickey = privatekey.privateKeyPacket.publicKey; - var hash_algo = privatekey.getPreferredSignatureHashAlgorithm(); + this.sign = function(privatekey, data) { + var publickey = privatekey.public_key; + 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 = ''; + result += String.fromCharCode(this.signatureType); + result += String.fromCharCode(this.publicKeyAlgorithm); + result += String.fromCharCode(this.hashAlgorithm); + + + // Add subpackets here + result += openpgp_packet_number_write(0, 2); + + + this.signatureData = result; + + var trailer = this.calculateTrailer(); - 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)}; + var toHash = this.toSign(this.signatureType, data) + this.signatureData + trailer; + var hash = openpgp_crypto_hashData(this.hashAlgorithm, toHash); + + this.signedHashValue = hash.substr(0, 2); + + + this.signature = openpgp_crypto_signData(this.hashAlgorithm, this.publicKeyAlgorithm, + publickey.mpi, privatekey.mpi, toHash); } + /** * 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 @@ -233,7 +215,7 @@ function openpgp_packet_signature() { * @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) { + function write_sub_packet(type, data) { var result = ""; result += openpgp_packet.encode_length(data.length+1); result += String.fromCharCode(type); @@ -450,6 +432,16 @@ function openpgp_packet_signature() { } } + + this.calculateTrailer = function() { + // calculating the trailer + var trailer = ''; + trailer += String.fromCharCode(this.version); + trailer += String.fromCharCode(0xFF); + trailer += openpgp_packet_number_write(this.signatureData.length, 4); + return trailer + } + /** * verifys the signature packet. Note: not signature types are implemented @@ -459,16 +451,29 @@ function openpgp_packet_signature() { */ this.verify = function(key, data) { - var bytes = this.toSign(this.signatureType, data); + var bytes = this.toSign(this.signatureType, data), + trailer = this.calculateTrailer(); - // calculating the trailer - var trailer = ''; - trailer += String.fromCharCode(this.version); - trailer += String.fromCharCode(0xFF); - trailer += openpgp_packet_number_write(this.signatureData.length, 4); + + var mpicount = 0; + // Algorithm-Specific Fields for RSA signatures: + // - multiprecision number (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; + + var mpi = [], i = 0; + for (var j = 0; j < mpicount; j++) { + mpi[j] = new openpgp_type_mpi(); + i += mpi[j].read(this.signature.substr(i)); + } this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, - this.hashAlgorithm, this.mpi, key.mpi, + this.hashAlgorithm, mpi, key.mpi, bytes + this.signatureData + trailer); return this.verified; diff --git a/test/general/packet.js b/test/general/packet.js index ef023f62..12eaf1ac 100644 --- a/test/general/packet.js +++ b/test/general/packet.js @@ -424,6 +424,53 @@ unittests.register("Packet testing", function() { return new test_result('Writing and encryptio of a secret key packet.', key[0].mpi.toString() == key2[0].mpi.toString()); + }, function() { + var key = new openpgp_packet_secret_key; + + var rsa = new RSA(), + mpi = rsa.generate(512, "10001") + + + var mpi = [ + [mpi.d, mpi.p, mpi.q, mpi.u], + [mpi.n, mpi.ee]]; + + mpi = mpi.map(function(k) { + return k.map(function(bn) { + var mpi = new openpgp_type_mpi(); + mpi.fromBigInteger(bn); + return mpi; + }); + }); + + key.public_key.mpi = mpi[1]; + key.mpi = mpi[0]; + + var signed = new openpgp_packetlist(), + literal = new openpgp_packet_literal(), + signature = new openpgp_packet_signature(); + + literal.set_data('Hello world', openpgp_packet_literal.format.utf8); + + signature.hashAlgorithm = openpgp.hash.sha256; + signature.publicKeyAlgorithm = openpgp.publickey.rsa_sign; + signature.signatureType = openpgp_packet_signature.type.binary; + + signature.sign(key, { literal: literal }); + + signed.push(literal); + signed.push(signature); + + var raw = signed.write(); + + var signed2 = new openpgp_packetlist(); + signed2.read(raw); + + var verified = signed2[1].verify(key.public_key, { literal: signed2[0] }); + + + return new test_result('Writing and verification of a signature packet.', + verified == true); }];