/* eslint-disable max-lines */ /* globals tryTests: true */ const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..'); const util = require('../../src/util'); const { isAEADSupported, getPreferredAlgo } = require('../../src/key'); const KeyID = require('../../src/type/keyid'); const chai = require('chai'); chai.use(require('chai-as-promised')); const { expect } = chai; const priv_key_arm2 = ['-----BEGIN PGP PRIVATE KEY BLOCK-----', 'Version: GnuPG v2.0.19 (GNU/Linux)', '', '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', '=lw5e', '-----END PGP PRIVATE KEY BLOCK-----'].join('\n'); const pub_key_arm2 = ['-----BEGIN PGP PUBLIC KEY BLOCK-----', 'Version: GnuPG v2.0.19 (GNU/Linux)', '', 'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+', 'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5', 'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0', 'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS', 'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6', 'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki', 'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf', '9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa', 'JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag', 'Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr', 'woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb', 'LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA', 'SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP', 'GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2', 'bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X', 'W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD', 'AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY', 'hz3tYjKhoFTKEIq3y3Pp', '=h/aX', '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); const pub_key_arm4 = `-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG 2.1.15 (GNU/Linux) mI0EWpoNLAEEAMoO8dfnLvvCze1hjWcr8t1fMdndFQc1fAM7dm6sbqrdlaAz+Dab zF3F9UhIOCcABRm+QHyZlgEsoQpHF/7sWflUK1FpoxdORINtIDilukUkMZ0NnIaD +8pRutdSczPNFvSImSzZNCyLzvDCGMO3+Xeaa6pViSPEeBwhXWJUuHYtABEBAAG0 IkpvZSBVc2VyIDxqb2UudXNlckBwcm90b25tYWlsLmNvbT6ItwQTAQgAIQUCWpoN LAIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRBYtrN4WUnCtoUjBACi6qVb noQJ1aOaOyoBZscDIO5XZHZK4L9V9uJJhD9v1qRF5s0PRiG969EwFlvjqIlLiRej KSxvE/1rcym4GwBUndku1fMM+weTWHNtRn9+BPzN/4eKZbUbY3fHtlk+Lde3N+CZ vrGKS/ICtbtuAfZL0LdzzqnNuBUXlO6EpG5C3riNBFqaDSwBBADDURzGkpTn/FTT xHyheai+zTOUmy7N1ViCRPkErIeD606tZf/sKqAnEChfECeZJReYydN1B3O8QOyI Ly/rH0DS2bt/6juhknPVGHPUAyNxHmiHYXTUgGPEX1QfusjzBcfIk6vHjYBiRm/I u9iwrzCwypA4dWDZSTZuFrVsf4n+twARAQABiJ8EGAEIAAkFAlqaDSwCGwwACgkQ WLazeFlJwrZQEAQAuUrp9Qp76CnKqUsUjcVxq7DJBi/lewyGGYSVAFt6/0Xyg/8Y TEa/c4Dri/HMOtrfbgjp/doIVaZLOXZYfqRcpy3z0M6BierOPB3D+fdaTfd7gIrQ nGHIp2NmbJZnYgl8Ps23qF+LKTa1eE+AmMQYzUHSGuka2lp6OglwWzg/dEw= =/vbH -----END PGP PUBLIC KEY BLOCK-----`; /* const priv_key_arm4 = `-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GnuPG 2.1.15 (GNU/Linux) lQIGBFqaDSwBBADKDvHX5y77ws3tYY1nK/LdXzHZ3RUHNXwDO3ZurG6q3ZWgM/g2 m8xdxfVISDgnAAUZvkB8mZYBLKEKRxf+7Fn5VCtRaaMXTkSDbSA4pbpFJDGdDZyG g/vKUbrXUnMzzRb0iJks2TQsi87wwhjDt/l3mmuqVYkjxHgcIV1iVLh2LQARAQAB /gcDAoZ8RULY7umS4fVGPmTuETCnOOTGancXT5r7chKyfFXlyVU4ULvTdLwdFtqx Vl9tNyED31nIiRP1CTmZLeaVScNGfVLjo8nvpMZUVopw5UdaFADeVTpwVdtp7ru+ IgH4ynrRMgMGh7/dgBzIP8WN4w8uBPK5G4bS34NNiREkVoZ3oh4dA/6aeYfW7lVV cYRl2F7++AGfqS+FpLsE8KjFU2z8POJjWMN1nYKwjNa+beEO0BFYdUFvMzU7eUHA /G0xWAhYvNyuJHE4imgYmCy1OZeawc9h8YGeaQJCh2NTVzaD9HRu0xmz93bNF19q bfUZJC7mC6WzKsRXHX0JmzH+9DShUqGnkRl5fMo2UhQMpSxsMT4dU/Ji4q+t96oy K6g3DMJr5OtZML3XKxGmdy0CgepkG1aikrC9qLfBgxjqi+uTewcbrS9lAOfrZg4N jwt1FLEK8gu7aOeczdW/pFOHOCrX1DnpF81JKJ1a7hz5JRP1m+ffqwm0IkpvZSBV c2VyIDxqb2UudXNlckBwcm90b25tYWlsLmNvbT6ItwQTAQgAIQUCWpoNLAIbAwUL CQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRBYtrN4WUnCtoUjBACi6qVbnoQJ1aOa OyoBZscDIO5XZHZK4L9V9uJJhD9v1qRF5s0PRiG969EwFlvjqIlLiRejKSxvE/1r cym4GwBUndku1fMM+weTWHNtRn9+BPzN/4eKZbUbY3fHtlk+Lde3N+CZvrGKS/IC tbtuAfZL0LdzzqnNuBUXlO6EpG5C3p0CBgRamg0sAQQAw1EcxpKU5/xU08R8oXmo vs0zlJsuzdVYgkT5BKyHg+tOrWX/7CqgJxAoXxAnmSUXmMnTdQdzvEDsiC8v6x9A 0tm7f+o7oZJz1Rhz1AMjcR5oh2F01IBjxF9UH7rI8wXHyJOrx42AYkZvyLvYsK8w sMqQOHVg2Uk2bha1bH+J/rcAEQEAAf4HAwLwNvRIoBFS3OHTIYirkr4sHzSkWFJx xDPozovXgCq7BoCXDMaSIQLwZqEfb+SabYtk7nLSnG2Y2mgwb9swZuBZEWuQjZk7 lX1MvuZ0Ih2QdQSMEJk8sEsMoBGHHdHh/MZO4a27+5B9OceDfnEZZcGSOweUuu1n IlgWcgrM40q4S3Mt39FXFgdJWnpd93hAokKDHklUGMdMLw/02dGVRkJmvUp9qdhe c2njq9HSeYwqbY2rYgcNsF2ZcCLt9UXA2dOG4X2c2mPfjKuTRZUPxNKh6JfL3mlu rBdd/z8gQHoKObyaarVwN3HAbtP0+6Z8a9/wDYj1K9ZCoHuEtKq1qq5J2Ec8+Yzl K0Zlcs760LiYUr69CninMrnbDNnAhrYAcyJS42viUADPv9g+CBbyanB4KyE4UNrZ BCB296lOEW4v1IZVNrNvqrbka3/p0qqBJiFTh7eT3zXpRNArFZDmLCUEEm53qT1a PO/MyYUGTTMRAzTmNTiPiJ8EGAEIAAkFAlqaDSwCGwwACgkQWLazeFlJwrZQEAQA uUrp9Qp76CnKqUsUjcVxq7DJBi/lewyGGYSVAFt6/0Xyg/8YTEa/c4Dri/HMOtrf bgjp/doIVaZLOXZYfqRcpy3z0M6BierOPB3D+fdaTfd7gIrQnGHIp2NmbJZnYgl8 Ps23qF+LKTa1eE+AmMQYzUHSGuka2lp6OglwWzg/dEw= =mr3M -----END PGP PRIVATE KEY BLOCK-----`; */ const revocation_certificate_arm4 = `-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG 2.1.15 (GNU/Linux) Comment: This is a revocation certificate iJ8EIAEIAAkFAlqaDT0CHQAACgkQWLazeFlJwrbOaAP/V38FhBrUy4XYgt8ZX22G ov6IFDNoyRKafSuz7Rg+8K8cf+0MAsSi52ueKfsbPxQ+I1vPeaEuEYbwTjtbvM+M vZcX+VNYdsc1iZeNaT4ayA+2LrCN/xgFj0nrExHqcZAjgBZ9pvKghAqdK4Zb2Ghb 7chPiLLNWJCMtL4bo7a1X84= =HcWg -----END PGP PUBLIC KEY BLOCK-----`; const revoked_key_arm4 = `-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG 2.1.15 (GNU/Linux) mI0EWpoNLAEEAMoO8dfnLvvCze1hjWcr8t1fMdndFQc1fAM7dm6sbqrdlaAz+Dab zF3F9UhIOCcABRm+QHyZlgEsoQpHF/7sWflUK1FpoxdORINtIDilukUkMZ0NnIaD +8pRutdSczPNFvSImSzZNCyLzvDCGMO3+Xeaa6pViSPEeBwhXWJUuHYtABEBAAGI nwQgAQgACQUCWpoNPQIdAAAKCRBYtrN4WUnCts5oA/9XfwWEGtTLhdiC3xlfbYai /ogUM2jJEpp9K7PtGD7wrxx/7QwCxKLna54p+xs/FD4jW895oS4RhvBOO1u8z4y9 lxf5U1h2xzWJl41pPhrID7YusI3/GAWPSesTEepxkCOAFn2m8qCECp0rhlvYaFvt yE+Iss1YkIy0vhujtrVfzrQiSm9lIFVzZXIgPGpvZS51c2VyQHByb3Rvbm1haWwu Y29tPoi3BBMBCAAhBQJamg0sAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJ EFi2s3hZScK2hSMEAKLqpVuehAnVo5o7KgFmxwMg7ldkdkrgv1X24kmEP2/WpEXm zQ9GIb3r0TAWW+OoiUuJF6MpLG8T/WtzKbgbAFSd2S7V8wz7B5NYc21Gf34E/M3/ h4pltRtjd8e2WT4t17c34Jm+sYpL8gK1u24B9kvQt3POqc24FReU7oSkbkLeuI0E WpoNLAEEAMNRHMaSlOf8VNPEfKF5qL7NM5SbLs3VWIJE+QSsh4PrTq1l/+wqoCcQ KF8QJ5klF5jJ03UHc7xA7IgvL+sfQNLZu3/qO6GSc9UYc9QDI3EeaIdhdNSAY8Rf VB+6yPMFx8iTq8eNgGJGb8i72LCvMLDKkDh1YNlJNm4WtWx/if63ABEBAAGInwQY AQgACQUCWpoNLAIbDAAKCRBYtrN4WUnCtlAQBAC5Sun1CnvoKcqpSxSNxXGrsMkG L+V7DIYZhJUAW3r/RfKD/xhMRr9zgOuL8cw62t9uCOn92ghVpks5dlh+pFynLfPQ zoGJ6s48HcP591pN93uAitCcYcinY2ZslmdiCXw+zbeoX4spNrV4T4CYxBjNQdIa 6RraWno6CXBbOD90TA== =8d2d -----END PGP PUBLIC KEY BLOCK-----`; const twoKeys = `-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v2.0.19 (GNU/Linux) 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 PepQmgsu =w6wd -----END PGP PUBLIC KEY BLOCK-----`; const pub_revoked_subkeys = ['-----BEGIN PGP PUBLIC KEY BLOCK-----', 'Version: GnuPG v2.0.19 (GNU/Linux)', '', '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', 'pMiJM+NJAQ==', '=ok+o', '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); const pub_revoked_with_cert = ['-----BEGIN PGP PUBLIC KEY BLOCK-----', 'Comment: GPGTools - https://gpgtools.org', '', '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', 'onCOcv4DKguN2w==', '=OqO3', '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); const pub_sig_test = ['-----BEGIN PGP PUBLIC KEY BLOCK-----', 'Version: GnuPG v2.0.19 (GNU/Linux)', '', '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', 'yeSTTh8ZnzRiwuUH1t90E7w=', '=e8xo', '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); const priv_key_rsa = ['-----BEGIN PGP PRIVATE KEY BLOCK-----', 'Version: GnuPG v2.0.19 (GNU/Linux)', '', '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', '=lw5e', '-----END PGP PRIVATE KEY BLOCK-----'].join('\n'); const user_attr_key = ['-----BEGIN PGP PUBLIC KEY BLOCK-----', 'Version: GnuPG v2.0.22 (GNU/Linux)', '', 'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+', 'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5', 'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0', 'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS', 'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6', 'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki', 'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf', '9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rDRwc7BzAEQAAEBAAAAAAAA', 'AAAAAAAA/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQN', 'DAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/', '2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy', 'MjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAFABQDASIAAhEBAxEB/8QAHwAAAQUB', 'AQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQID', 'AAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0', 'NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKT', 'lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl', '5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL', '/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB', 'CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpj', 'ZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3', 'uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIR', 'AxEAPwD3+iiigAooooA//9mIuQQTAQIAIwUCUzxDqQIbLwcLCQgHAwIBBhUIAgkK', 'CwQWAgMBAh4BAheAAAoJEEpjYTpNbkCU9PEEAKMMaXjhGdgDISBXAAEVXL6MB3x1', 'd/7zBdnUljh1gM34TSKvbeZf7h/1DNgLbJFfSF3KiLViiqRVOumIkjwNIMZPqYtu', 'WoEcElY50mvTETzOKemCt1GYI0GhOY2uZOVRtQLrkX0CB9r5hEQalkrnjNKlbghj', 'LfOYu1uARF16cZUWuI0EUmEvTgEEAOkfz7QRWiWk+I6tdMqgEpOLKsFTLHOh3Inz', 'OZUnccxMRT++J2lDDMhLChz+d0MUxdBq6rrGoEIP2bYE9AjdR1DNedsuwAjnadYI', 'io6TMzk0ApagqHJcr1jhQfi/0sBhCCX+y0ghK8KAbiYnyXPMQFa9F19CbYaFvrj/', 'dXk0N16bABEBAAGJAT0EGAECAAkFAlJhL04CGy4AqAkQSmNhOk1uQJSdIAQZAQIA', 'BgUCUmEvTgAKCRDghPdEbCAsl7qiBADZpokQgEhe2Cuz7xZIniTcM3itFdxdpRl/', 'rrumN0P2cXbcHOMUfpnvwkgZrFEcl0ztvTloTxi7Mzx/c0iVPQXQ4ur9Mjaa5hT1', '/9TYNAG5/7ApMHrb48QtWCL0yxcLVC/+7+jUtm2abFMUU4PfnEqzFlkjY4mPalCm', 'o5tbbszw2VwFBADDZgDd8Vzfyo8r49jitnJNF1u+PLJf7XN6oijzCftAJDBez44Z', 'ofZ8ahPfkAhJe6opxaqgS47s4FIQVOEJcF9RgwLTU6uooSzA+b9XfNmQu7TWrXZQ', 'zBlpyHbxDAr9hmXLiKg0Pa11rOPXu7atTZ3C2Ic97WIyoaBUyhCKt8tz6Q==', '=MVfN', '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); const pgp_desktop_pub = ['-----BEGIN PGP PUBLIC KEY BLOCK-----', 'Version: Encryption Desktop 10.3.0 (Build 9307)', '', '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', '=dVeR', '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); const pgp_desktop_priv = ['-----BEGIN PGP PRIVATE KEY BLOCK-----', 'Version: Encryption Desktop 10.3.0 (Build 9307)', '', 'lQPGBFNjoowBCACeKvpQnv8wN3UdDVrZN//Bh/Dtq60hbZ3ObfTbNVBQ0DLD6jWA', 'lKgwgSa3GLr0a3qrc30CRq0hRIjrFMrg4aPu5sRiZYP90B1cUGf08F2by8f+as2b', 'BOBzRkcxH/ZmBZPU0pkRoOnkMvoT+YVt2MxzaJRBKM1dgcPXTHvZ52j7V0uEJvs8', 's/H8DJq6MtgYqoS1zt/+eqUSDCcsVJBsEl7o7qU2d9i074hiBouM2B2mimvBKFIn', 'W2kmG6fSryNSLaUMwvOTEC/esVNlgvSBfhu82Gic8Rwc+g0cHUnAESChxz/jE0P6', 'INt2IpBZKeuXCY97tQmce3R4GOc/r3FNBBa3ABEBAAH+CQMCnq0oXlNfXhuothLb', '7AD3fAc7cpnuondcU2+OdOmnkrB73Qf7iVztLXRcMdIZloSqTlAna8w2ZhmDAdId', 'EkEO0Uj+Gf7jjC7bLPob/fOj1TMZB3EPX8xs4DhD2oBI5hPNcFrZdHY+qUh1MvMm', 'zdKgBsnbU6nJK4MrhrJ7InPIopqbNcw3ILrJZkD7U6fhiROx0+7CQ9DSVEscTj/K', 'u3FeGchNwY2ZmTEDrXy2ZGcQRSuw04GPUcXsBqgD3vivhJtq88K5a4SFPx28uaDO', 'VXvbUhQ6BpfMaAvpjfJZHzelU4LyQQP+cR/lmR+E7CNuxGa4sT6+NgJ4mQjdWNTc', 'XBaFUU8DgrOX2pAjYgszbETlATK1LRVM2eV/bXBURpEY8DL+OtwE1eAb/m4dAJXE', 'cFx8CyaZfI64m27X6av/9GTATXVLHuQUbQHiqhxpaOJSj3ykUvfnQGQedKkT6m7/', 'Od1B1dQuO0NwRQaM9SOfpNoM9pLU4z2cyOJJBtNydigTyqH7S9WK77BMrsWyHNCG', 'yXo8qrCLv8oBGLM8m0WfT8twF/VyFo3iVUHIkzy7NbDu9QqiXnGzg7aBeo1L8mwk', 'Fa5vI44Y1kI2XyjPtpOWtxHaq0YGCtSXuQtr3fSQW/AxQzqJW6lzTjdVSCXXxY/G', '2DHWbRbbB2bdk1ehJUzSYHRMvgdsvFkZrdLy5Ibz5bTR80RRHn2Z8vYr/bSTOXdF', 'Xo2F5CvhTME+1BJRhObgqJax8vRnArhu+JVml2cjigHnpH05WzEWv7ezqwsQlUz9', 'EUN0dZ8Bg4UH7khdcl1Xcepb3+kzFFrGAQG02n1HhZ1Lc1pUTzHKrIQ57x4LUuP8', 'ZOrysjcAC9TdqySvWEilEGsn/mu6/tnmZNaViDWlzah6mRgaz3Z+m2NkfcJbn/ZH', 'VHWfOZEku5mNtB1QR1AgRGVza3RvcCAxMC4zIDxwZ3BAc3ltLmRlPp0DxgRTY6KN', 'AQgA6tnPjznr7HHcoEFXNRC+LEkDOLAm5kTU9MY+2joJyHG7XmEAhPRt4Cp5Fq79', 'sXPvGZ6tQnD8NVvqc3+91ThTLLKCIRdLOunIGIEJdCr7gN49kgDYisWxt7QQIsv7', 'Q0SqbGJa7F/jPj5EDf36XJlACJy1yfP6KI6NunffLa23BUU0t0S/TWqq4185nQcz', 'J1JnZItyyBIyIWXrNtz56B/mIDvIU56SxxpsrcYctAT68vW0njyQ7XRNIzsmvn4o', '+H9YHnSz3VdXeJaXd7TdU+WLT2lbgzF5BvDN3AlJI8jiONfu0rW9oBmHsQdjDcOl', 'WdExsCx5Lz7+La7EK/mX0rUVeQARAQAB/gkDAm8zCrvNFCfycCMEudU+3gQFw9Vw', 'YP5SEAiCwegbNw/RsPXxIy6nzFbKMP9qN8SApFwhuz9qf6SeeSafNtXLDz1dZEQd', 'yYF4BQ0GLZpeE0kF6XvdefVpTiYJaSc2Px+Ae+fw+s+jF/STvLMI8xjWBmUugs/o', 'Xto58R6ILKC7n4Fl0YrZcB2hRyIkFu2fq9KhcdAj15rXxxL0Fpzn4wwynCGQW+EO', 'Ix3QfDmuFweoHrU15Q7ItmpFlX+QfvTzL7uBS8WUwx2Fd/LkbA7K7yivCBDy6LxB', 'rPnffE1EibAVdOHKIkIaSw+zBAOnkieaJou/BEH/NUerAk1uvzZZwi3tKoYy8rxU', 'EGPcyblYyBHYRKgGwLsjN1VFvnutBDq7f1uRo5ElCSiVfMsST9VNHIft4V0l6Lsb', 'VK/2U5+gT6GUeSXW9Rm4fSZwyslSeB2d0Cq6gbkEUAsIaI8JDtnkBPf/boHb0/S7', 'yFeode6LIUrGqrc9ti4Zky+QFsGchJtc191pNsuvYXgeocEz2UjEBra+Tf/Z6Ysv', 'zMU8+fVeubWvRpSDhlLc8/+z9FD0hqKJzuJUT5sLfBIvPOkpjDP9k48k5wABzW6S', 'Mevw/X2M2vGRdHit/Pzn25Ei1H5O4dUMUkneym0qZxQmi8l/4cl8Yr1yYOKk+dsk', '1dOOGYnyNkoPtrIjLSzctkWZPhVjM7thasBeI77eVdAP4qhf4lCTcnqvnO6eNFLw', 'ZylzWyYPZrHGIut6Ltasvz2syeAGEDG2RBLNO+z8Mw4RM9jWmNGESiA8RjcBbSfa', 'l5iBJgRBfVwB9v3/3Jh6V5BA1t9LY1nGbodpM6xQVQRHpzMYYO241bB+dtbW3a3y', 'XvVs3DJafcAgdGv/TF39h1OP518mNzDG9tYYeAMbJrjby/L0OfS0lEC1gE2Nh1va', '5g==', '=63Nq', '-----END PGP PRIVATE KEY BLOCK-----'].join('\n'); const rsa_ecc_pub = ['pub rsa4096/C9DEDC77 2015-10-17 [expires: 2018-10-16]', 'uid Google Security Team ', 'sub nistp384/70C16E3C 2015-10-17 [expires: 2018-10-16]', 'sub rsa4096/50CB43FB 2015-10-17 [expires: 2018-10-16]', 'sub nistp384/102D9086 2015-10-17 [expires: 2018-10-16]', 'sub rsa4096/DFC40367 2015-10-17 [expires: 2018-10-16]', '', '-----BEGIN PGP PUBLIC KEY BLOCK-----', 'Version: GnuPG v2', '', 'mQINBFYiIB8BEACxs55+7GG6ONQV3UFYf36UDSVFbuvNB5V1NaEnkY0t+RVMigLR', 'Zdl0HHsiaTKfKs4jqjLQAoR6Fcre9jlEhatotRg3AvHV1XYebxRlzdfXxyD0d6i9', 'Quc1zbca0T8F1C5c7xfYP5g9iKWn5yFtHC3S7mLeOg7Ltx84bTo8AF7bHGA3uIQf', 'uCtE8l6Z57HTeaf2IR/893jLOir8lvmTef83m/+e1j6ZwmKxxZO2s+aGKre6Fqsz', 'Oo89CpWKNrdZ3IN8+Y4udZNlr7u0os7ffY0shfbLrqt+eVEu4EHfbpQTJxvalZJK', 'tEnGtV8S7Z3dcPcimxvO7HZu7Wz8VnRzY/AZtee4fC+i2yBu1rWKgY3V1tFKdxVr', 'KDnmS5MBgBAxv69mM3bf8QPinL4mtIQ65/Dt4ksJuysRmGwQ8LkjSLQCMMepnjBs', '/63wJ3e4wN1LCwnJonA2f8gZQHNeGPUhVVd/dWFDtmQaLwKFcI0GS/DiUPBIJir5', 'DWnrEedtlcSLlwwcUglFsG4Sds/tLr+z5yE88ZrDrIlX9fb9cCAsDq7c8/NCzgvw', 'kFez14sXgGhMz6ZfFzM49o0XwlvAeuSJRWBvnKonxM7/laqv4gK0zur3a6+D6qCN', 'vt9iWO/YG+0Fvhmyxe34/Q71nXWc9t5aLcokmYLGY1Dpzf9oB8hDRdMCAQARAQAB', 'tCpHb29nbGUgU2VjdXJpdHkgVGVhbSA8c2VjdXJpdHlAZ29vZ2xlLmNvbT6JAjwE', 'EwEIACYFAlYiIB8CGwEFCQWjmoAFCwkIBwIGFQgJCgsCAxYCAQIeAQIXgAAKCRC4', '5BBcyd7cd8MzD/9YdMVZniQH4qBKxLFIoYGfLzCEI0S9IVUA37wrZ4YiRODSJRMf', 'El6oVfTO/g8xpeQlDgHj1w2IDoSkeQrY+7rf9H41sGGOBDGXSQT+7Z7XFH2mPPvC', 'cqYqR32BDNDkO/LL1BzzRlQvNmnGHxo098sqTgb7hoVsP+qFoem7JUMpcAV1KrUo', 'P81haV8a/25ouWFZu5P68WFh861TyIjIYLQCns2fG+zlKFGN9Uynv6E5+Qk7dmni', 'XnHRaiYZP9+wux6zm5a5wD/h6Iv4hyg/0Vnx5SyH8QOm3Qm6pkUciQkSmZQvf0r7', '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', '=Q/kB', '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); const valid_binding_sig_among_many_expired_sigs_pub = [ '-----BEGIN PGP PUBLIC KEY BLOCK-----', '', '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', '4z6aN5G1sT5159GF', '=yzZh', '-----END PGP PUBLIC KEY BLOCK-----' ].join('\n'); const key_without_subkey = [ '-----BEGIN PGP PRIVATE KEY BLOCK-----', 'Version: OpenPGP.js v2.6.2', 'Comment: https://openpgpjs.org', '', 'xcLYBFp9nCsBCACXTmLI9bJzaAanrD7r6j7gNDS7PsebJr0e182hgHVnGkr3', '8XCsCdWSllUNfBRln4MI8GfWVO5Bhhx5en6ntCptJVeSsohAHfBzmdoauSGW', 'y+M+3dlSGeVqgqmDukQSxuNgKBC/ELDhKvAb8uKWnS/MUOapk/6aF8mf9Vqm', 'eG/1RHrIvxfeOsRCEFH0OqB2tOeCWPXohxpzv2AvFxWviwzpedwNGDhN/XjZ', 'JzI4LyBKlorHJvwe4KLKtaLuOq0jmNkT6AcsniyhvqN8QRP4OK7084Uc/7Yd', '6Qrcnw/6plqMB5J2PyYkB6eTptp28bwIxUGzfGQ6qfDyHHQBIbAVt3m5ABEB', 'AAEAB/9uDdjynSvon5C/oxy9Ukvbnn2AeOCNLLdA2O07/Ijoroo7IIW4zQpo', 'rio9PbREWqrf9KVCk9IdHORXQ88eQoDdlNzG2k8ae+xq2Ux4RZJ18eVf09P/', '0NA7EcElDHX5RmsahOnxX72YejfdzGQd80VSEsJENF5rTMQeMkN2dIHS3pFM', '9ar2nJe9dc/L9ND0P79X8twZvvfh287Tm23fs384nRedcUwELm43kNV7Us3t', 'ub1ORmAzHhVCa8dWev7Zca7FqiZxa0u3X/QHvVMMpr0ewTBulr/mEjaglfYf', 'dNp1PxduWYPWU54/XLG3G4nqLUS++qjd3O46VhMMCIigGf01BACgrkPwdrTJ', 'EGCfgIq48IGoMU//wS1P0g7EIzplwGAzGAJQw6LhGqKrDONcyKGqHzRgn8oz', 'dF8iezGjlVq7oiyrrB4ez1gDG4RRDC+6+PTn/TXBTZ21krUgPUrB0jcqV7SQ', 'IIWZost7zNcbEqiPI91SPAMwYJZbJrSL4pTnDVLfewQA8RB1y3IzuK/rT+gs', 'JfcSHqZ12G+sUIgpK6yv4pN7hQDhWC3+qe8ULnLLXYv+FQslnRW7tTkAbCRl', 'kJvbibRqrYj+fQS2d3Hau5HYcGKcv9KPgOhB49yRkQpWCT+fqsQwJByyeZ47', 'iiJRR8t0X92nr0zbf0f+LalmK4cQnQ6LS1sEAN2R8RiamrNcbsdmre0v6QVL', 'WUOIwRWABRWFOm9QbSr80ji1q9pHlS5WbIw4LVeiO8V6H21QTL2fqDA9yWOK', 'mNsOgIi+1PMkC4lwPu60VR7yBtLFWFF2SuuqPuDG8TFA2PBQFisrxcq63E38', 'kroxpqxNCXXuB3E0uNL2fO6dqWbaRPzNF2dpYm9saW5AcHJvdG9ubWFpbC5i', 'bHVlwsBcBBABAgAGBQJafZwrAAoJEFu1JX+Hv3FrMWEH/jE6HN5MayB6RHe7', 'FTrfMlMEh54BqsiugmAIgtKYcxUcNsPw/hC53lJ6tDzo3/zk/2shvfItafh5', 'ldUsERj1y5e7OMR+2GgfgMdddLddBuV8sXv2HwQgMtykeXOIPuH+7CZDwV7F', 'lUyrykwpIjGGPkK+fG64fVt0cfWprdEsqcGZmHf/lHtoGprG8syfF+Ao3beI', 'g6HJ61NHIBy4ewueKMBZ58/9VF2MQ7YgBQCtQNAnQKKrDFmxjZw3J4zBl83i', '3LrYpnYepvMUitQ/Y2pBAYygUExZ0dPC2uGFdPISbDGLg3DhGcyy1MvbLuNh', 'EyjB8RncAfSIwK4dSGVh+PD5dkc=', '=w6Dj', '-----END PGP PRIVATE KEY BLOCK-----' ].join('\n'); const multi_uid_key = ['-----BEGIN PGP PUBLIC KEY BLOCK-----', 'Version: GnuPG v1', '', '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', 'ljIYQms3pCv1ja6bLlNKpPII', '=qxBI', '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); const wrong_key = ['-----BEGIN PGP PUBLIC KEY BLOCK-----', 'Version: OpenPGP.js v0.9.0', '', 'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5', 'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg', 'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM', 'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq', 'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1', '=6XMW', '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); const expiredKey = `-----BEGIN PGP PRIVATE KEY BLOCK----- xcA4BAAAAAEBAgCgONc0J8rfO6cJw5YTP38x1ze2tAYIO7EcmRCNYwMkXngb 0Qdzg34Q5RW0rNiR56VB6KElPUhePRPVklLFiIvHABEBAAEAAf9qabYMzsz/ /LeRVZSsTgTljmJTdzd2ambUbpi+vt8MXJsbaWh71vjoLMWSXajaKSPDjVU5 waFNt9kLqwGGGLqpAQD5ZdMH2XzTq6GU9Ka69iZs6Pbnzwdz59Vc3i8hXlUj zQEApHargCTsrtvSrm+hK/pN51/BHAy9lxCAw9f2etx+AeMA/RGrijkFZtYt jeWdv/usXL3mgHvEcJv63N5zcEvDX5X4W1bND3Rlc3QxIDxhQGIuY29tPsJ7 BBABCAAvBQIAAAABBQMAAAU5BgsJBwgDAgkQzcF99nGrkAkEFQgKAgMWAgEC GQECGwMCHgEAABAlAfwPehmLZs+gOhOTTaSslqQ50bl/REjmv42Nyr1ZBlQS DECl1Qu4QyeXin29uEXWiekMpNlZVsEuc8icCw6ABhIZ =/7PI -----END PGP PRIVATE KEY BLOCK-----`; const multipleBindingSignatures = `-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v2 mQINBFQNRrkBEAChLrYuYjiy1jq7smQtYPln6XGJjMiJ1PbZwGK2CKQaIW6u4EUJ Dhy6j/vbApZUJbH0krnY3KY0wWjGkAjPa32J5uIU3ldKqcZEg4mavJlsnFqwGJtB txsDVl+2qr6BNLXSHuv/xyDHOOwWv2Hij6uPup4demscvQzNkwL08KnjJyJj/uw4 QQgXwhYBsNeHfqJN+qLuSN1hJyzGRCXCsw/QjjCjtTqns25pFFYI5viNl5bRogDx 3/FiMKJEcs3U3Gzn4XECjolRiETmGB61VZuwFatvUqEnWsz6NjsvHYkILplpOoE0 Ittk9P9/RIoBaKpvArN0NzkPPY+/HIx6h7pEyx2/IaH7IknDNAhc3jX+dgF33+tl h4CsiUg5ra1Jg20+FXcu8F67ie21lRWXZJ+St16o4cXlQ5JCmy4qiekpN03zGW92 Gpk6tpMdAMZIH6LQPea+Cjfbu2OMkSxokQ+7MSj7CXa/vu64qq3O1/34IC1fcnek QxoI4ses4fnyoMWDFR6v+zsyptA4v8gZGU3OliLrgRokEJYbavtU54yDVyu5peM5 iJlriNun5YnHCm7AclmrhOuKv12VfDLO6pIsb/gDpGemjcEIVj7/WhlTxr5YglXT LikCbEiIm2YJxw5j4Z2Tj11dXK4RpBpTqvY/MEmSLRjxsr3mlP5KFBDZBwARAQAB tB1UaG9tYXMgR3JpZXMgPG1haWxAdGdyaWVzLmRlPohGBBMRAgAGBQJUO/8GAAoJ ECuuPPba/7AAkpIAnjC4ApIaLN2cBV2phfqOMsjFNvrTAJ9+KDMEAGkgU2fPm5Dz xKYsNY87g4hrBBARAgArBQJUSRZuBYMB4oUAHhpodHRwOi8vd3d3LmNhY2VydC5v cmcvY3BzLnBocAAKCRDSuw0BZdD9WBqPAJ9RqDJ2ANbegApkOWMQaS+XpY8McgCg jPuffq5cUqBBJljqyguekUfktsKJARwEEAEIAAYFAlRJI1kACgkQPDI5e2lh0zCg Ywf+OUUuk0mgcZYv8uieAPcfWulG6oq6wGKbtDNfRH+JnwPF/lyaLUBRyLUlVbgG diQNJoTotqJyCqWoGHU/1ssI46pnt7bVb0lUa4kkrFRzqTsN6QcwXI9QRLXp1Hje bk5x2+E1uQ8FUVppjznSI8GbQofYEoIesxlRee54UD+8iAlyH5JNckLHPVeOr7Cc JTmBqic9B3RK9yZm9TfiGCyRoB3/jV/FBwzQ1QZrBbdRyEU5ai1x3Q4MxRL74nJp OSFW3oSY+P1jSlFB0v3HZW00z4xwDzrlCKbn79wHhNAvh10chF9LwreMBedKnuw6 qI1pC40VPktPN/4cmGyHC6pgl4kCHAQQAQgABgUCVQSWmQAKCRAodzh7/xuV5oLY D/sGwQe1LpVOoEcudTsVqpC6T08cNSZWLRCeokxtxa1Yk/r8MIq8t/fijk0Dh/dE j9QcvQ9NfypAwOVelse1MXlbL/J/gNAgG92/NbXu3+Oqy/bCOSSPJzWrnYhC1GeX Khu8xOE+mYkxwcPEiMcfwo0NBSLVJL981Z3pRw7PFj+eSE+4JM+DxJaBP//pMiFa Aac0Y42NXCJRRcmNPED55HnDDhUZ+sbbl2mWsHq9NkStul1qtWx1JgVLdHsFHgPo dcx2G611/WYUOvsNl16QIuxiW+xv3HhxkPij5Dv8XpCPOM/LeGWjL7hPdbWIIXGh eKASEeS89aKDZSQsj7LhE/ds2GSEifj0VscxLZRq/UiFChDMImydTuAxeAGsRtb2 u1Po0ww2s6sZcNzz3zISHNtO8hewV/vDhCav3gDw1f5LFA58waiVihIkYWa5JJ40 FMdnWLeODTzciCdRbx5KZtHKebKI77AWr+fXH9M7sRDVuN5XKCHRZOO76qkymmen jSrS8j7dtrWP37spJ8/T68pVb3LLsYsVxp5U6DV4Av+hPToBy0/ux0iICQa3QsbY iZvsx7JzZhsKdt2S+ItEY+cqdsFrLxS4jE8xoUDXIZvOOlEyxQOQ2O6nsHRjSVSQ 7imZ88U9/Yl686GIpiDpP4+/AKn7qdgWmZBqcBI7QTww1IkCPQQTAQgAJwUCVA1G uQIbAwUJB4TOAAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRCCk/uBsYKD9ap6 D/9tDUpaulHdyJoT4LjdmR5Twlen6D/WRxIAK63Avad0gZa3y7chj3eED9HH6gw4 UmqQvpR8kfgnaJJVVPtPZBKUU0+UvnP6SH2i+thwAoGUjxWFa+cIaH41GAc3Buo2 WUOqYF+o6W0o+2ly6gICqP8FTNZllIlIsMn65ksN0290zUHUt2QDydzGVIA5OiOS nkBr/0Cwe6ZF7VAUlF5MGsZdLMgAHbKmyQTX1FAn45xEigtOb8tmDobryW/Ga+sM kYGC91ttTR/AYtNvb57x2aepm3vePfMtZ0YCHiyZexcLv5lqmjspRgHtRn/+/Fs/ OGHL70mHfPH1zp3k8zHbaEVMVHwBzLT+Du96Eom+jL4PiBNXOnGyQuPeRrP18QHk kANqufLEB16ZeeHFa0/zKCILarxwV8G8zM8dbQbwNv8e5fAUbNP7LkMKbvDm2woB LJqOGu8mF8js5JEUIgtYMI4FAuhB4DtX3yH98af7TZyEGHIJUxcasbg829qmYnrU NoPL8qBV8trirU3D7iYvf1NTe15+9agtsdUkoBIUrzgzLQkkHVbbvydbZrwNebe8 WFLfOrAb8CN6WeC0sI+Tahqn10V15kF2quZU5jVu5gd+XXNzuuQCV8VLF8Q3S6O+ zJPHZGpjExxgFwMm25hBQ7CrtVlKVH/crP6KuKi4iI16D4hrBBARAgArBQJWIsfE BYMB4oUAHhpodHRwOi8vd3d3LmNhY2VydC5vcmcvY3BzLnBocAAKCRDSuw0BZdD9 WHZQAJ9v6PgK/zwn1+ZHCnTU7z+10rMsUgCaA9+Pa31VBCsdqtAca8pZJP35YFaI awQQEQIAKwUCWAO/3QWDAeKFAB4aaHR0cDovL3d3dy5jYWNlcnQub3JnL2Nwcy5w aHAACgkQ0rsNAWXQ/Vir0wCeMYJjvyYTq+X2z26Gw9YYA0qM5GMAn2KFAJcap4Vp 3umZUAsRWq7KaFzFuQINBFQNRrkBEADFYg1yIZ4p2ncZdphG0bnTm/6Ng4RlgiZl DRSGNM1gqckn30wKcNteqUUyEQMkw97fCfqYJads3/j+BpMHW8h7AVsbezSHuv+c DljMaeGjYHZc3uRa0lxXTfi+8aEAKRqka0w1wyEkiO0YVXyuz7/o3vDd9pGoCIX3 g6l/z1doSzVKGrQQr384/hhLpBgZN4uxtrbVypx+Aq8yN+l4n5ELuOmCh69tI6h4 jnIwfKgnebpjB0OOnyZ/Taq219wZ4Mmjfn3WI+PxnUe0Sswp0KvXHyOoN6X8rgcK NpTPzxkJ02VA4m9laZpDOHnysBcafM4uHwpzQ4izKq31bUPDm2hBHzSgMtLNfG7C OmMEf01mwPkbuOKMVid85TVrmJeQEMPd0Fad5Zr81deRUHuUZD+1xsRY1SUtL4u3 OrVaVV6DkbjIPeaWiSqng0dyxdydzZwkUSHEmf8fMtCawVB13RR4sUdOwK0IIn0n bBcYFnyE3KwUsekfDe2ejP2AF6XbFoSHJKBKaUMl5qqfEoPMRefdfjJikfPzrGXa vOBVLiEuWmR1pif0r4OCfssHF6dJsR5lnO9p0owxDuKE5gqYwaRC9VbM4FEGM80l ORTsdhIlm7R/oATfAhYPyj49ResvOifgQ2UfTR3hCxEYlme8SRBmb187kFQHEfS7 g85R/DGA3QARAQABiQIlBBgBCAAPBQJUDUa5AhsMBQkHhM4AAAoJEIKT+4GxgoP1 pUoP/1dhADAsm8vOdu5bSqs2O25g3Ib67FaKdgZxbsApy++1sXScy7BodnfOIvhc el6EYYqtNmCfdxI87X2nNcJcsYWtxU5DKSKlDIG40RJL2aGG2pJ8QT3MgWgibCLW uAdkfx8RNlSnpb9L3bUULwsbCd+muYk6en2TpiqxCRgI5Ypea+sfJf2ho327F9eQ iW9QB+4ZhSQv/FdbZYWoVhPVo2PkJaIWbK1txMA5xCKjL/F4jcNiNHYU0uLAdgmQ 4IiUXNEygqJK14Nr/8O6nsJlVgQ9u0y7TO37KkBd0LWJRTuepcgaCawyzWV0tfXq +64QQ1GSRMPNbaVeqi+LU/Hc3bBWX1m9Ox7Zs6ocL6ScPGIUHapp45IAEMLfCu5H gJQN5ZanJAf2RDYn3owpZWYCmxV97y2HMfQotqPWvzlPJtLXmpgDnRS7JOwZn8CE DJXudGK27xbAvNyRuVzK8XEVnc5+H6zFWiPtzAN8NepiJy56hNuu52/y8Eh35oVt 3OpOb6aGkUYzY45uQvhCtvG6X2CvJiy+31+pkfXTzRk2FhTeyWbVm+2M1ft7cHv+ fW8WQmmDD/cs3sdVpGstDbKVwCALGO6RUKjJDSXiZQUuB/ufjA5FRNzT2vfO7bX7 LDz4ZOY+PHS76ihek7a8HdMrSidBetiCG6to4OQ3PySjQYdkiQIlBBgBCAAPAhsM BQJWIfuxBQkCFgZxAAoJEIKT+4GxgoP1V/cQAJCQEqMi1URwd7ODEgIpJ4/LQg+E R3nDRiYzG9yVzKw9c7TfMJgpjoDqom+wxW4jt8doNCTl0UOer3WQkazKB75hrbCM mzRVyUpyG6yQYErg7MAsl60x5Y+odxrN+idY45erlNbLoIIXokEb7VZoE3YFxs89 Ez6YuXwVGkTmr30HkMMlpX+psd1N46vcaeDJhcZpUmdxgi1kBBpinAZFhsSY1fhA g3hVZI91EzsCeFwNfGVVNK0+Ph5erwB1kF3JSXTp+4pCGD0pQwj79O4USKLbaU9m MnyLsg5HSDx6YLKD9vjQYWNbnJkmVSqBjXlaOI4ttj+8Z+7sMj4PXbSq6gMIB0Ba 4szEqd4EVxJhYATQl0KYu/YzDeHSEXfkguhIazDVXrWszXmcVpYQbvA1ADalpxdV tvexJgnNYv+wkUauosSjkMhLG2WVLGQ5fg+AdBPeMhEb/aTTtn4aZ7Tkc/vXFWV9 Mb0n/Fo96mcCEOK28+w6z/HkBIG8KgX6+GTCTTI+5ix1HL8Jjs4qM/cZupHIxBQJ SzFRPrm/JzbYNzus0qnpcUoLQPbAPwywOQfZnN4+1/piy1t0lRPrJh6NL0YvEtuM 5bIxEtmu4V4Mm+j1i/oieeAuJyj4lIWMZgh5uesS8yBBNu4c1BiSGBe5xb6x0uyd b1+K7XlqT1/U+WFbuQINBFRJJmoBEADqbDxtQTD3TWQqZQzPqhGiCLxOONjNG7RS hMR3LDn0DBMTtw8rUG6qSGefxv6xqkiYNFi6WX2nJ6JATqMrIkXDCkhzLKU4JSMg 4VYqIej0+1ETymjJBo+9Cp/YjjWBfCnXW1Xy1Bkiovx16XiFz9zI+L4Y89ziYuWk GdzJQpM9pezZNlwVJ6fxYBFt0Xmi3cDywzVi3TuZ1kzRBQbkKyzlWJPlzrXHTW3x fGZkw1R4A2oBvyRoTnSeNYMYJrgFKcWunTrgN4MUKZzWsw2imZJWRvBIUCAxm+wf tMPIAEi9XhQEXSOKVOsyRDypTv9Q+b98TqabCIFpFjOCCsCZVyqJbVlD8tebCTzB KW7y9GcKsUg/8NwgWZeOO/uWwear+2dahFO/rrHEooyjP5J8TfF0rsU6uZ0vjSMq OJ6Qi/PYE+dSQl7dwZMdj0JhToNq64M3KX7H1mlLSoGJNMpsdT5s2+0HAkaQirVH zmqk2PiG9ofNZHSQwlwn3bxfO7WMenTmtqRJ8f5ZsezvMLAm6NfCZ2UgfoLIUfCS 65Fq7jFdUntO6TmWocnBslAwczMbTNQ7+c5YtAP6yAihpScORuV9G2aHpg3pG3vy yD1jYFVno1GYsDbT26DY8eGAWXMioFxNx31HVJh1hwq/tIaKk9skWIZyAUjmTKEJ HTis7ixMXwARAQABiQQ+BBgBCAAJBQJUSSZqAhsCAikJEIKT+4GxgoP1wV0gBBkB CAAGBQJUSSZqAAoJEOAAT9SU7ImVBS4P/0OSwomCkw2aZROmJS9CPu9jfjwgqMdY 33VcHs1SqdXdCJBdRVIu3zs4/AB/bksPeRn4UfQoJ6xQXMoG6vRisZxPexpsIOw4 cvZF7tYofOzUUnm7qF1HS0lC94KUrvJK52FLfFZu+BQB8zgBrR4p7Y5Gs/jvLUIC OEUkXowijLJ7BPO76i7FG9ibynrei7c9RFp8DL5kEYmfSARoTb0hR875zi0a8/uh YMWmXcRvUtq6SC6q+bhMD5CmS9s8UfnNjVhOYR501M8expCQJsbyM+r49xCUxMLz OYkJOWgKnbyIxFFj6SFdV9oABh7r6Oqgnz8On8kEg2Qosdz87tlr0ZhG6PasMHet L1hGSy8VBMWAHLPwtScVLr5KOuZ6S7ao+lhe2lcGEdzBkRw75lqhaCaRkJXLlBbK ecEL4QWcoAATwFasiioBkrZhJEFay+tAZx7SrUKdxrh936XYOj4yXvwNRQshIDRG rMyunG3fsR9DraR8/tzNdu+2HLzaWwZl2AnegcSmj0y6K5RvTQy4qO74afFBrHml uhoTRpXt3YYoja7ql7bfZGBg5cdzoMEpJiEVXpmiKnd92JHeiiXNygSCVpBLFZl9 z/6U4m051fd/+nnC7Y1rs0AwmHzEFHwyMMHf98MjJxk9L6wH0BvcJL3yBMPOHUat idDV4/pGzi5VFzoP/0GyypLfaj5xgfIbjSyyK+LLueZXyNpA8Qpn9jHUrI03R/AC Rx0C5k/vlGR9ac1BqQjafhgQlmRNI/JK6lz41VPyomWE4atBeluq9KP8ijBcxY8M nMyyxtt8kKm51pKyseXzFiUEaH9De71Gz9CcmLYyYAlsGPE2gV7AEnzG09cSya3t sIA+sKZ6qQT8A7gspy3Kigv2IaoOpWyQFzHYDAmKkV0u77+Nf9K86GNFcS9rP2/y aes09MwIQ3j1PEh2/EK3kf1ViJU/DvIdPSTxWS02/YcXDDSExai6HqTsxnS7OUMo Sug754F1BFdN1D9vROaMxZBJHM+OoLtRXoIGy+3YLSScLW6xOrZ2zfD3dJD0H4jm IbGlMjq8llftLx7gLcVL1khlFKHjHuRqcTnDtvDBJTg0fIlpi+5PXNfm33dINuOH cWnqmxGcPY6ES0wurgz13NCYZL/G0x//LPoPSneJPb7G5ZtPN2jseGHA5zBV/kb6 3YU84twmEnbZ0gZbCm89uvmulMUIaX8Z2iy7Tig6tEC/LqT26RwuWihGpXv3HlId 2FFAZ5HOtKWR7PQDgf8nOma/en5g3n3VOa5w7JgXdK0GaKRuo8EL5C2ocVknJ7/o o5s4nJb0841kHuAmY1Vv4AkwChTCFP77z5OOzSrlTMAQXsootYGV/Uw/Qa9wuQIN BFRJJugBEADJSsQfPqDSle4AS/jx9R5494mL7aRQ78WrRYNADyofHw1I7Ty4EXZ+ DloSZzNM0nJkWKycgalnBa67kTOg9FhD2y+8aISUpFIiWeeBV2IDlf8bLzqi73/u +oI6x7LNmKRl9Ei+cbyU68b6exjMIuwl6R2pxN14bgAQAzGYOnYxke8Ub9G5ANs4 9VxFlpE0AajckjW7dZu3404SJhYAUNkurK9xg5MlvTLMr55k+8hsUZaXdUQeUsiW +qadSe4qfy7g8tzf31yAKICr8udXgdHa3zLBhRu1gUOo3pRDIcMcBID/iCVXexPD VYqljiny8AZKvMWRhT9NzDLhJntGq4bo3z+HaOlFWysbzYl/6AzxHed4iQ/7vHkl e5MQlx7WtWNJVjJRw3fc5SOtYds2Xmc02g+NSmJM9Ve7M3JAp5Lv4LeGvLAu7q5M UbFhkZ/31uSCwS8cXhdMz91DvNZ5KNAwmS9y4ojUorjcpsMQcs0uHbOHgtmLIJbB xbjJmUmVfMn+ZsSt/Hx4Y3DGUU01zjnj6prq5RaCKYEJwxhMvXJiYJ4L94rQJGvY clb2JuH7E7q2H5g+fMJHiQj9KoY/fMhuc0lY0W6Af+M8snCovLwgTR7bpIv98vxA +FpZS2NINA2nEcF0KpjqQ2zVUBOa9iUx3GLnqXvbGnsi1ayRhTzG9QARAQABiQIf BBgBCAAJBQJUSSboAhsMAAoJEIKT+4GxgoP1qSUQAJCqBGEp3HRfG3f2B1WELShA vyT5rn/Nu8OvQ+OnubYlkKl9rBpP0evxEJjfrmK9PRhfPM+Ep7QUARXwMavAbH/g bSxg6XwPPrimMDrluVoD4o3YE6OBjzpynhxRBHYAW+//VZCzJQoY+0Q6iNcWEfuH daTsTWwIUUOfXuPimCpXbNP5RLxbnX1gs0MuDuUuBrLudZ2nqR89WVSubWdLNN64 nF6KqANK1HXr5iSRFG7eRPp4hiVDdELo3cJgR6ohFGARctwst39C95URouyCwTRj fKYwJ50Ha/xeHlMNV8Ddnd+nOvgapxDqCKcBTUC03WRxQSfvu6nMh3KUzUfX9xPM kCAF0pNT+JE0hdJophU0lSgvFCSHor7bigol31cavlvkswEcI7Kyufvt2W3FAma+ bJaLcqfGCCoIOdf7n4VNCfFArzXsPx2chrPRf7akO4/cumVxqcKrDZf1Gdy3cXEx Bl7cynwaatNDnspvpJWNxJQ20vJ5ibbfPrZetowAnGV0qhKM2emQIVl4q3+UDUEb yeHL7FBsg5GXafOTcoZ8F8qhWTjICvG1aXaI4ORO1ljA/fB0wl18ypjhaCtrI6VB qkxuzU0slqdngdLUr1iA+A8oOIZlXkcFfHTnW36O8hZVj2vK3CU9WVsEa/gJI1p1 p92yZgB3r2+f6/GIe2+7 =jZgG -----END PGP PUBLIC KEY BLOCK-----`; const mergeKey1 = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + '\n' + 'mQENBFtDaAIBCACX5Y/YO7CuP6PMBIJWUMXFb50cGgzzowCbhdzpYU589iz1npjR\n' + 'yBmZPmnKK4KfEMz0buY+763/LFwihbfBh5jsh3oV14rqg+P6VNLeCATuGWO/5JKy\n' + 'jRNzjmQZFLcmbStF1W3+vIvJJDibMqvjHLE33z7t17BLU/fVu4F2BuuKVsM5xm/J\n' + 'HIYFzCeWR5O8+0s6Kd1SKZwzy7ySBV0w3Pk0go076RnyKyv8vneogTubA0qSAKJx\n' + 'jm6k94wJSSt3CyH5ogcLd4wjsylA65wOPIy7ROvcg05hdWO83qto4tE8o2mpB+Wc\n' + 'MZ6gkyLZnQEvKBKlh1H2BBrnI2w4iDRVSCOVABEBAAG0JVN1YktleU1lcmdlIFRl\n' + 'c3QgPG5vc3VjaEBleGFtcGxlLm9yZz6JAVQEEwEIAD4WIQSJdpCFeXsnZzf+xlKb\n' + 'N/Be0N878AUCW0NoAgIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAK\n' + 'CRCbN/Be0N878MfWB/4wEIXGoYc8sYcFIjeRsIniQN+TaOhKY4kOdbk/MJh5hDcc\n' + 'OwXpahc6C14pzSh7C5bkwRzWrm0hsONR5uhrx09154GU5ie88yIKTYC58ef4TwB+\n' + 'Kq4UvOV0xbkFGmyGhlDWgA9nSCotHzt//9fLqY26m7pZ1JVczDWVHIqwTv4lAF5G\n' + 'fBuDEV9w6fcbvIiqSrTx/lekNQjCE4+JhBahindko4jeP4bj/699Q0f+j2pHJ5xU\n' + 'zHoWAI8RowX7EDzwydnTG0Rrx9QoN2QcUjw6Lsg9//i7fk5PochYa7kGYcHGLvXP\n' + '8fwk7K1be8ZnRwUx8dqzoQVtYRxdHP19P796PD5guQENBFtDaAIBCAC3FKAMPRU/\n' + 't03vbsVibHkpCI6KVaInTu7+HWksYQ8gp89w2nzQZLvAfIMKJBVdZa+nRoTTjZ6B\n' + 'zwmvtiCjv202/9L8BcBmsNFnKapgi8bD4L8r/9lSMngD1ebSdVuopNQXzDXLYsKl\n' + '8OLup1AFPQPEwDnn72pHF7fIJBOJkuXnS9syCViLlFeziBGsY/RD0hWE7YgIK+m0\n' + '0M+57EzDntjsVTI5d3V8EwEUJU1nADtnbkjQoyCXBfqxYe4+SmiWkyFKFVfIQeX/\n' + 'muoq79b9/NVM7G+vTcSzTCPKKKdw1Zefb1i/S/O1HWwA3KJCFYOMPtqLLf2hIF/5\n' + '3LC1SRVCJ7bHABEBAAGJATwEGAEIACYWIQSJdpCFeXsnZzf+xlKbN/Be0N878AUC\n' + 'W0NoAgIbDAUJA8JnAAAKCRCbN/Be0N878Hf6B/4nun5NklDp/X5EvhHKdTgOMlIC\n' + 'f0RsrqRGvQTOMmoxeQ8w88GkTuGIUSHWPxXPracNfqxETOY+D91dQDKpgIMSPqDk\n' + 'tAEnXhX2S36Eb/68hkkwOF2I5Ngcv39n6BLvREGf8JiUR7O/MRgfcjebfH4Trc/K\n' + 'XorBDo4y3g2wg68ueuEQHfi8HprWec2QjiSgTTaNfG0oS+UKLJB9ZsPhVB59lE4B\n' + 'giI/4DD0FYR9pUfo9SG2sQKWlD5jIWob5S8x2QYZKFXYDEGX7V9/yjReGAfqjhQY\n' + 'EPmHvKuRRWbzEP0ckFPVsyc6E07OzZyfnHOPIGXH/IFO0OF7Zj8Cvh8BaPYW\n' + '=hJLN\n' + '-----END PGP PUBLIC KEY BLOCK-----\n'; const mergeKey2 = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + '\n' + 'mQENBFtDaAIBCACX5Y/YO7CuP6PMBIJWUMXFb50cGgzzowCbhdzpYU589iz1npjR\n' + 'yBmZPmnKK4KfEMz0buY+763/LFwihbfBh5jsh3oV14rqg+P6VNLeCATuGWO/5JKy\n' + 'jRNzjmQZFLcmbStF1W3+vIvJJDibMqvjHLE33z7t17BLU/fVu4F2BuuKVsM5xm/J\n' + 'HIYFzCeWR5O8+0s6Kd1SKZwzy7ySBV0w3Pk0go076RnyKyv8vneogTubA0qSAKJx\n' + 'jm6k94wJSSt3CyH5ogcLd4wjsylA65wOPIy7ROvcg05hdWO83qto4tE8o2mpB+Wc\n' + 'MZ6gkyLZnQEvKBKlh1H2BBrnI2w4iDRVSCOVABEBAAG0JVN1YktleU1lcmdlIFRl\n' + 'c3QgPG5vc3VjaEBleGFtcGxlLm9yZz6JAVQEEwEIAD4WIQSJdpCFeXsnZzf+xlKb\n' + 'N/Be0N878AUCW0NoAgIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAK\n' + 'CRCbN/Be0N878MfWB/4wEIXGoYc8sYcFIjeRsIniQN+TaOhKY4kOdbk/MJh5hDcc\n' + 'OwXpahc6C14pzSh7C5bkwRzWrm0hsONR5uhrx09154GU5ie88yIKTYC58ef4TwB+\n' + 'Kq4UvOV0xbkFGmyGhlDWgA9nSCotHzt//9fLqY26m7pZ1JVczDWVHIqwTv4lAF5G\n' + 'fBuDEV9w6fcbvIiqSrTx/lekNQjCE4+JhBahindko4jeP4bj/699Q0f+j2pHJ5xU\n' + 'zHoWAI8RowX7EDzwydnTG0Rrx9QoN2QcUjw6Lsg9//i7fk5PochYa7kGYcHGLvXP\n' + '8fwk7K1be8ZnRwUx8dqzoQVtYRxdHP19P796PD5g0dFT0VEBEAABAQAAAAAAAAAA\n' + 'AAAAAP/Y/+AAEEpGSUYAAQEBASwBLAAA/+EN2kV4aWYAAElJKgAIAAAABQAaAQUA\n' + 'AQAAAEoAAAAbAQUAAQAAAFIAAAAoAQMAAQAAAAIAAAAxAQIADAAAAFoAAAAyAQIA\n' + 'FAAAAGYAAAB6AAAALAEAAAEAAAAsAQAAAQAAAEdJTVAgMi4xMC40ADIwMTg6MDc6\n' + 'MDkgMTU6NTY6NDAACAAAAQQAAQAAAAABAAABAQQAAQAAAAABAAACAQMAAwAAAOAA\n' + 'AAADAQMAAQAAAAYAAAAGAQMAAQAAAAYAAAAVAQMAAQAAAAMAAAABAgQAAQAAAOYA\n' + 'AAACAgQAAQAAAOsMAAAAAAAACAAIAAgA/9j/4AAQSkZJRgABAQAAAQABAAD/2wBD\n' + 'AAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcp\n' + 'LDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIy\n' + 'MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAEAAQAD\n' + 'ASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAA\n' + 'AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAk\n' + 'M2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlq\n' + 'c3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG\n' + 'x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEB\n' + 'AQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx\n' + 'BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5\n' + 'OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaX\n' + 'mJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq\n' + '8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigAooooAKKKKACiiigAooooAKKKKA\n' + 'CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\n' + 'CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\n' + 'CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\n' + 'CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKK+QPib8Tf8AhY39l/8A\n' + 'Eo/s/wCweb/y8+bv37P9hcY2e/WgDv8A/hpr/qUf/Kl/9qo/4aa/6lH/AMqX/wBq\n' + 'rwCigD6/+GXxN/4WN/an/Eo/s/7B5X/Lz5u/fv8A9hcY2e/WvQK+AK+v/hl8Tf8A\n' + 'hY39qf8AEo/s/wCweV/y8+bv37/9hcY2e/WgD0CiiigAooooAKKKKACiiigAoooo\n' + 'AKKKKACiivkD4m/E3/hY39l/8Sj+z/sHm/8ALz5u/fs/2FxjZ79aAO//AOGmv+pR\n' + '/wDKl/8AaqP+Gmv+pR/8qX/2qvAKKAPr/wCGXxN/4WN/an/Eo/s/7B5X/Lz5u/fv\n' + '/wBhcY2e/WvQK+AK+v8A4ZfE3/hY39qf8Sj+z/sHlf8ALz5u/fv/ANhcY2e/WgD0\n' + 'CiiigAooooAKKKKACiiigAr4Ar7/AK+AKACiiigAr3/9mX/maf8At0/9rV4BXv8A\n' + '+zL/AMzT/wBun/tagD6AooooAKKKKACiiigAooooAKKKKACiiigAr4Ar7/r4AoAK\n' + 'KKKACvf/ANmX/maf+3T/ANrV4BXv/wCzL/zNP/bp/wC1qAPoCiiigAooooAKKKKA\n' + 'CiiigArz/wCJvwy/4WN/Zf8AxN/7P+web/y7ebv37P8AbXGNnv1r0CigD4Aor7/o\n' + 'oA+QPhl8Mv8AhY39qf8AE3/s/wCweV/y7ebv37/9tcY2e/Wvr+iigAooooAKKKKA\n' + 'CiiigAooooAKKKKACiiigArz/wCJvwy/4WN/Zf8AxN/7P+web/y7ebv37P8AbXGN\n' + 'nv1r0CigD4Aor7/ooA+QPhl8Mv8AhY39qf8AE3/s/wCweV/y7ebv37/9tcY2e/Wv\n' + 'r+iigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\n' + '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\n' + 'v+Xbytmzf/ttnO/26V6BQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA\n' + 'BRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA\n' + 'BRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA\n' + 'BRRRQAUUUUAFFFFABRRRQB//2QD/2wBDABsSFBcUERsXFhceHBsgKEIrKCUlKFE6\n' + 'PTBCYFVlZF9VXVtqeJmBanGQc1tdhbWGkJ6jq62rZ4C8ybqmx5moq6T/2wBDARwe\n' + 'HigjKE4rK06kbl1upKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSk\n' + 'pKSkpKSkpKSkpKSkpKT/wgARCABAAEADAREAAhEBAxEB/8QAGQABAQEBAQEAAAAA\n' + 'AAAAAAAAAAQFAwEC/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB\n' + '0wAAACY6nQHyTFYMsrKQcTONcAAAAiPSwAGSWk5mGkVHhARm4UEJmnEHc1ygAAAA\n' + '/8QAHhAAAwACAgMBAAAAAAAAAAAAAQIDAAQQEhETMCD/2gAIAQEAAQUC+NLpMo4d\n' + 'eCQoTYR24vF2pBDOfFV7zlrv7PjexmYW9n5tsN3g5pPan5wEqZ7QwWmcN5jLbHcK\n' + 'pYxn60yuuHwyoOVjRjKQkPj/AP/EABQRAQAAAAAAAAAAAAAAAAAAAGD/2gAIAQMB\n' + 'AT8BAf/EABQRAQAAAAAAAAAAAAAAAAAAAGD/2gAIAQIBAT8BAf/EACMQAAIBAwQB\n' + 'BQAAAAAAAAAAAAERAAIQIRIwMTKBIEFRYXH/2gAIAQEABj8C2UefqMXZ4iyP2+qn\n' + 'LiPNzTASEBtAAZiPb0qg4jPM1j2jHMVY8ztO0004EQDis6cGdDdaT5nydr//xAAi\n' + 'EAEBAAEDBAIDAAAAAAAAAAABEQAhMUEQMGGBUXEgkbH/2gAIAQEAAT8h7OoZ+HDA\n' + 'z6fzq5eDnABo7dTgI9JnOE366qUxcDVS73tGmUXXNWEGumyfjoiBzvc4wmfeMSyi\n' + 'J4wy8HOQCr8MfgfemJRPouLBU3eXKZLxm5arXowtX9OOx9BcRGJEwFYFXIAXkTGI\n' + 'NN3tf//aAAwDAQACAAMAAAAQAAAAAgAAEAEAAAAAEAAggAgkAkgAAAAA/8QAFBEB\n' + 'AAAAAAAAAAAAAAAAAAAAYP/aAAgBAwEBPxAB/8QAFBEBAAAAAAAAAAAAAAAAAAAA\n' + 'YP/aAAgBAgEBPxAB/8QAJBABAAEDAwQCAwAAAAAAAAAAAREAITFBUWEQMIGRIPBx\n' + 'scH/2gAIAQEAAT8Q7JCzpQHylqYMsjlbPPUgJZVWvEAALtZz1NOQkkSANW+KnASm\n' + 'G4COcdTDBIXEiP8AKDEA1EoZiz2pSwLiFzRzaiI5ZAeQbZ+6fACsziEuuTFRgJTT\n' + 'YDPGat0gRi5nxP2KYC2QVCgMCMjymniaUDoTan2xT9pNwewik+Sw2NuD90JedBjl\n' + '2OaiVfmYmDHFuhhnCj5nh+6zQxVScX2TSJyIRIRoE5EAEq0J3CgB+WnEplyJjBGm\n' + 'e1//2YkBVAQTAQgAPhYhBIl2kIV5eydnN/7GUps38F7Q3zvwBQJbQ2nuAhsDBQkD\n' + 'wmcABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEJs38F7Q3zvwjvsH/jrxLY5X\n' + '7qTHTBzsAt8yGRpFB0RBo4CI184t6KA7NpSmjeBiy2J5kz0RjdvEdj4bs5JKQkDk\n' + 'ikUr+3r79w/W04+KDrue1fXCKK9KfWmi/b3qcNBPkpgAhyROtCHHC7OaX6LHnm8w\n' + 'IPO4oMoyqW4wbwPdOyBLde3FkzOx8XPmvgzzBwyC3Wve3CC/PvEnmiT0EjYqAU1j\n' + 'piz7cVLsawElBi7rtA6Ryiz1/xY/LYPprGsLhvG3/wtD+dWVPPSd7xS2sl6C5KJB\n' + 'ZhKI1uIwdTCGO/Th6FKqO/9djRzOgRaPwxe5uR+HTcgWRAUXlzU9AKzWikIBo8Iu\n' + 'eQc3Ss7SlRnwn365AQ0EW0NoAgEIALcUoAw9FT+3Te9uxWJseSkIjopVoidO7v4d\n' + 'aSxhDyCnz3DafNBku8B8gwokFV1lr6dGhNONnoHPCa+2IKO/bTb/0vwFwGaw0Wcp\n' + 'qmCLxsPgvyv/2VIyeAPV5tJ1W6ik1BfMNctiwqXw4u6nUAU9A8TAOefvakcXt8gk\n' + 'E4mS5edL2zIJWIuUV7OIEaxj9EPSFYTtiAgr6bTQz7nsTMOe2OxVMjl3dXwTARQl\n' + 'TWcAO2duSNCjIJcF+rFh7j5KaJaTIUoVV8hB5f+a6irv1v381Uzsb69NxLNMI8oo\n' + 'p3DVl59vWL9L87UdbADcokIVg4w+2ost/aEgX/ncsLVJFUIntscAEQEAAYkBPAQY\n' + 'AQgAJhYhBIl2kIV5eydnN/7GUps38F7Q3zvwBQJbQ2gCAhsMBQkDwmcAAAoJEJs3\n' + '8F7Q3zvwd/oH/ie6fk2SUOn9fkS+Ecp1OA4yUgJ/RGyupEa9BM4yajF5DzDzwaRO\n' + '4YhRIdY/Fc+tpw1+rERM5j4P3V1AMqmAgxI+oOS0ASdeFfZLfoRv/ryGSTA4XYjk\n' + '2By/f2foEu9EQZ/wmJRHs78xGB9yN5t8fhOtz8peisEOjjLeDbCDry564RAd+Lwe\n' + 'mtZ5zZCOJKBNNo18bShL5QoskH1mw+FUHn2UTgGCIj/gMPQVhH2lR+j1IbaxApaU\n' + 'PmMhahvlLzHZBhkoVdgMQZftX3/KNF4YB+qOFBgQ+Ye8q5FFZvMQ/RyQU9WzJzoT\n' + 'Ts7NnJ+cc48gZcf8gU7Q4XtmPwK+HwFo9hY=\n' + '=REGo\n' + '-----END PGP PUBLIC KEY BLOCK-----\n'; const priv_key_2000_2008 = `-----BEGIN PGP PRIVATE KEY BLOCK----- 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 t/ia1kMpSEiOVLlX5dfHZzhR3WNtBqU= =C0fJ -----END PGP PRIVATE KEY BLOCK-----`; const key_with_authorized_revocation_key = `-----BEGIN PGP PUBLIC KEY BLOCK----- Version: OpenPGP.js VERSION Comment: https://openpgpjs.org xsBNBFujnwwBCADK1xX03tSCmktPDS9Ncij3O5wG+F5/5Zm7QJDc39Wt1t/K szCSobWtm/UObQVZjsTGwg0ZUPgepgWGGDBL0dlc1NObwUiOhGYnJnd4V25P iU5Mg3+DhRq+LzNK+oGlpVPDpwQ48S8HOphbswKUpuaDcEQ2f+NKIc0eXe5m ut5x9uoVj8jneUNsHYq6FIlxh4knzpJWFj5+LNi7plMCwKip6srVNf8He/q0 0xA/4vjSIOfGIE7TCBH33CbHEr98p81Cf4g0E+kswEz5iWE2SDCyYgQkMrkz H9mtVqk3nFT8NR0USxKqH9bGhaTx1AWq/HDgsphayPEWQ0usjQDrbQUnABEB AAHNDnRlc3QgPGFAYi5jb20+wsCNBBABCABBBQJbo58MBgsJBwgDAhcMgAH0 cOUNyxrV8eZOCGRKY2E6TW5AlAkQWICi/ReDcrkEFQgKAgMWAgECGQECGwMC HgEAADgHB/0WIHh6maX2LZ0u5ujk1tZxWMrCycccopdQNKN0RGD98X4fyY6J wfmKb107gcidJBFct0sVWFW8GU42w9pVMU5qWD6kyFkgcmov319UL+7aZ19b HOWVKUTb6rFG8/qAbq3BF7YB/cZIBWMFKAS3BRJ4Kz23GheAB2A9oVLmuq5o gW5c2R1YC0T0XyXEFiw9uZ+AS6kEZymFPRQfPUIbJs1ct/lAN+mC9Qp0Y6CL 60Hd6jlKUb6TgljaQ6CtLfT9v72GeKznapKr9IEtsgYv69j0c/MRM2nmu50c g+fICiiHrTbNS6jkUz0pZLe7hdhWHeEiqcA9+GC1DxOQCRCS/YNfzsBNBFuj nwwBCADK1xX03tSCmktPDS9Ncij3O5wG+F5/5Zm7QJDc39Wt1t/KszCSobWt m/UObQVZjsTGwg0ZUPgepgWGGDBL0dlc1NObwUiOhGYnJnd4V25PiU5Mg3+D hRq+LzNK+oGlpVPDpwQ48S8HOphbswKUpuaDcEQ2f+NKIc0eXe5mut5x9uoV j8jneUNsHYq6FIlxh4knzpJWFj5+LNi7plMCwKip6srVNf8He/q00xA/4vjS IOfGIE7TCBH33CbHEr98p81Cf4g0E+kswEz5iWE2SDCyYgQkMrkzH9mtVqk3 nFT8NR0USxKqH9bGhaTx1AWq/HDgsphayPEWQ0usjQDrbQUnABEBAAHCwF8E GAEIABMFAlujnwwJEFiAov0Xg3K5AhsMAACI/QgArvTcutod+7n1D8wCwM50 jo3x4KPuQw+NwbOnMbFwv0R8i8NqtSFf2bYkkZ7RLViTmphvSon4h2WgfczL SBulZ1QZF7zCKXmXDg8/HZgRUflC1XMixpB8Hqouin5AVgMbsbHg30V2uPco V3DeFQ8HWxQC9symaMW/20MkqNXgCjM0us7kVwTEJQqZ6KYrFVjKyprSQRyP rfckEBuZnj91OS+kAHlZ+ScZIuV4QVF0e2U6oEuB+qFXppR030PJoO6WDOzm 67hkzfrc3VpKw/I+vVJnZb4GOhNTSpa+p8i4gTyWmrOZ0G85QoldHWlWaRBg lbjwPj3QUTbLFvHisYzXEQ== =aT8U -----END PGP PUBLIC KEY BLOCK----- `; const key_with_authorized_revocation_key_in_separate_sig = `-----BEGIN PGP PUBLIC KEY BLOCK----- Version: CounterMailEngine v1.4 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 =KtVw -----END PGP PUBLIC KEY BLOCK----- `; const key_with_revoked_third_party_cert = `-----BEGIN PGP PUBLIC KEY BLOCK----- Comment: GPGTools - https://gpgtools.org mQENBFS2KSEBCACzz8KtwE5ualmgF+rKo8aPQ9inTQWCNzCuTs3HaSe0D5heGoSh mJWl9B5zvXN78L3yzmtWQV92CXOkCRWezIY8y+aN+aJZ6PzPE5Yy74404v3yG9ZK jGlAWC7Wgkx+YR2vbzj7hDqi5e6TpDGsFkH3OsI3nY7FIvXWbz9Ih4/s/nBPuF0v sBZ0n97ItszhnrXvvrF1fQvEviB0+xF5DfUURWP45EA+NWnBl7HFzY4FeN5ImYZK Nt6A88i9SIB3MiwRSUy1UwJjL2L8l+rLbr20JbnIUuJN3h/dY10igxyOh5gsXtr1 fabsm6s2AacrCjQqLkXSnB8Ucu+Enz5R1s0dABEBAAG0KVBhc3N3b3J0ICDDpMOE Pz9eXjEyIDIgwrUgIDxwd2RAdGVzdC5jb20+iFoEMBEKABoFAlYvilYTHSBJY2gg d2VpcyBlcyBuaWNodAAKCRDheQpvjBNXTQ5jAKC0AMb5Ivoy0DKNI8Hjus72ob3u TACg32AGuCernx1Wt7/5oi4KdjxjjxeJATIEEAEIACYFAlS2KSIGCwkIBwMCCRBj ZJ9T2gveXAQVCAIKAxYCAQIbAwIeAQAA/c4H/i/NgI36q/2lwcRkt5rsVBUlx+Ho +iKIEh1+XKfDq4A8DTjeYCCOg/k3hDm2LpmmclwRc2X9CMwraSoFTEN6Em78Kd5a DFaNPbWGP0RCW5zqPGAoZSvOlZYsLMaswFMBD93wf3XwHK8HxTJhTmQC1kGSplO1 GMWkTh6B3tqiy/Jk7Hp5mPASQBid+E9rjr8CgOPF26hjTw+UUBs2ZWO9U9PyhBYH xLIwtUDoZvqhTdXD0aV7vhRQw6p3UEzxa8t/1iGogHe2CfcMgq5jYmHLTZN3VGE3 djwLQIikRRig7dTBD9BgeG6a+22XRbvpOsHBzsAH4UC97nS+wzkgkyvqfOKIRgQQ EQoABgUCVi+JYAAKCRDheQpvjBNXTTNIAJwJacb4mKUPrRnnNcGXC6hjizuJOACg zVFVnWA/A+GrHBogUD780vcJwMG5AQ0EVLYpIQEIANNCJ5sUKv6YDWRToF/tG6ik LjTAcNelr5LCXLT3Y7CAmk7y88vzCaTLZZUWgwyK8lYGZ3x2icoc4fJeo5BhHNJz TSL239cTsAugNoVMJFG2xm1TEzBsBCNPOOVpS5cArt6mmhxozwkafawtgA+5z0zB vQm0AHPudSAJp3Gx69meRzAJgdFVgljZVyCUmQizJqJ1dQPPgarpJKJy3f0+g0ec yx+gTA4nj+zfqjrXM4O1Ok/Di+8mneA3bhadiYU1VjkqY+1UqkQOU0UFdDlBppRj xr6h00xECoayyPXr/U+gFSgZHO1mKk3meCyNVKLGAajQxWVWfBwoPixfqOXlBh0A EQEAAYkBHwQYAQgAEwUCVLYpIwkQY2SfU9oL3lwCGwwAAMkDB/9QeLRyEOX2LWdZ UkxSldMklAvMBjqY27cC1Qn8wiWzHNJKVEnQ9MiKn0mVRohkRKgsiWfSugDVyVov eTM7PSjDlAYALCSxSYStykordUSf/5WYb9Mmea4J/WXBQCvwJKFU47ZDl2Tg+HdS SVznLTt/ASxd2Nap2mUveC4ivGdSo1KOq3+t95xGC7dh4U3JwPanBZ6cfBJbnSEs QWLUAPnlfn37Ff14haRETX3ND82bkXKEGEk6O5HJ0PWuUtl+TFIkYUGh4zFOZZWq VHwaffAHDrmTZt/pOXg9l/VFnzfxrId33Tog3Zvejm2+8d2LhSCtfdrdJ/Dx2CZM Yzxp9Mp9 =uVX6 -----END PGP PUBLIC KEY BLOCK----- `; const certifying_key = `-----BEGIN PGP PUBLIC KEY BLOCK----- Comment: GPGTools - https://gpgtools.org mQGiBEOd+/gRBACfqCfgQCmUzOr7iA1CerGVmFm8HcN+NVGSpkwF6pmPJh1XVGEA Nz9Aok6Vx4MQ+QCKo9dTXMZWDE4W/vzaKaEmsirsxGgn7JhK0t/9VeXXieWiJirA 5iTQMsRjfnS6MLLUr56E7HmDZftiOcpJu81S943r+oeINhq37SlJM7Q47wCg8miR egss26IZfW3RvBuNW1KEDh0D/195DH6sl+/qmgUAj3M7ai1iKOqkILdNuIkYRc18 bsBYIAOjY81guhlEabYEqv8FUKPh2A7dAe/4og89HrUsVxOKJ9EGyrcqyJj676gK BL383t1dQvyJyWfV5z4umUMaF/xE46go3Trdyu86aJDe57B74RYbWL2aaGLtkPJ2 rHOnBACG5PmLM6EXWJQSfbRqJHlRysc3MOAXMnxu8DVz+Tm0nPcArUG+Mf3GmxT+ 537nHqF2xEgVvwfkvGB51ideRRQMhHUzy583zkuPYV1cJ6ykfeA6EHzVbT4vRzO8 AW9ELBKTK9F4N4gGTOdAATcaMC0gwzCz+fofJEJqC/9CS2pYvrQlVGhvbWFzIE9i ZXJuZMO2cmZlciA8dG9iZXJuZG9AZ214LmRlPohdBBMRAgAdBQJDnfv4BgsJCAcD AgQVAggDBBYCAwECHgECF4AACgkQ4XkKb4wTV02nkACfWvWnRawPI9AmgXpg6jg1 /22exKkAoMJ+yFhjtuGobOrIAPcEYrwlTQXBiGsEEBECACsFAksJKNQFgwHihQAe Gmh0dHA6Ly93d3cuY2FjZXJ0Lm9yZy9jcHMucGhwAAoJENK7DQFl0P1Y4VoAmgMc 2qWuBtOBb6Uj6DskTtXORlPgAKCB3Hqp8dJ3dbQh5m0Ebf8F3P71WrkCDQRDnfw1 EAgAkp+0jMpfKKF6Gxy63fP3tCFzn9vq3GBtbNnvp8b0dx6nf+ZxELt/q9K4Yz9g +sXq0RFQGV+YwS2BGoogzRcT4PHmUBcEAbjZIs9lZdZDEF0/68d+32mHSkLZJxGI ezXJK3+MpGPnCMbQ63UYpcY1BvL7Vbj6P4X75dJJReGIHQMBA0FEYB5AVm6HrWU5 eDvOZ2w8QAAUluFnD9/xNRqBpcwm5uoox7zq60W5coK6p6WX8t5+WMMrRKF2A1Ru aTxYQKo3f8XQA4e6tEcdGFlk1K9W8Ov1xVRQa6EqQYZFesbuoo8HHuSNsJ7PQrP+ vyYcafohlO/q4QtJXoUimsrEywADBQf7BQWrEx9YlNNsUD2yuov8pYCymxfUVTzK huxGHmNj1htXfWWScA2uqD97HOdFu5nvoL2tdaO1RQR/OXKRBcUg6FhOQqqxQSxi Vcsoy3aofGi3CWVXgn7KlSopkhlb4ELjzt5H+BMneXdgowO4MimXAfivI7OZl2fN ut7emyN9qaeY/e25UKmCYhmhE5hM2+lV8wEmmu/qTCPiZ2u0zH/PE9AAwRz/6X+p gsW0WIQpI6iQSSq4KyJxebtJFmCSTFawuXB6rCGovDXo/BkRsDEj1rpZnkwKJPa0 dEhKK4EzNrUzpWHeE3gKPjFXVmcjIPWVAC3BJoJRHOHg8wqLKcX5MYhGBBgRAgAG BQJDnfw1AAoJEOF5Cm+ME1dNChoAoMKa/qx/RKlu3iQPtN6p4NlhRA9IAJ94F/7l cKFQz1DDfFCfVpSIJRGozQ== =EYzO -----END PGP PUBLIC KEY BLOCK----- `; /* const revoked_primary_user = `-----BEGIN PGP PUBLIC KEY BLOCK----- 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 =qfwW -----END PGP PUBLIC KEY BLOCK----- `; */ const key_created_2030 = `-----BEGIN PGP PUBLIC KEY BLOCK----- xsBNBHEtJEoBCAC5eMNNia6oZJI7llva4L9/O9/TXd5HZt95hbXCBHr5BTmD VDHNYXCpi7L+1qTDJqaAHY/GyeSgiAeFOEKOiyFXhdSgiLmru4DLtp+6cg8C AiJR/V/GzN5vtSL7JuQu8LOzYZnPzoNtM9i5P1c0MqTguP9HMSuF+kqId+q5 siZK+YqZPH0VHNDHOe31ulNeC9jRTaiafg5m0zkI3Go4wRoCt6CzO+hQJ6u+ knHBQ2YfDBX2PtXn77CAGLgh2heX2Abd1LvvweMlDzqYFhwk+dHEUT8DA0rl vJwuOiNAkfRhC4nwtLhikvlOs6Uh8hrblxuab2kTwYsPFawQR5wPEPsJABEB AAHNIkNyZWF0ZWQgaW4gMjAzMCA8Y3JlYXRlZEAyMDMwLm9yZz7CwHUEEAEI AB8FAnEtJEoGCwkHCAMCBBUICgIDFgIBAhkBAhsDAh4BAAoJEFuE0AYFWFcL K8MIAJAowJs1PY10ChPvcoVNDtgO23eXLi1C1x3IBeV2l2JtwvJ8ZTTCiKF/ IdPIsxKhV39pebFip3hIsjSYCF3SlkGht8XiJBVamsNtXhfY0JB6mkKntVBA 4OiQ7Aa94mq7nvEwFtwS3W7Wdf8R5BlWTADPwKkXFj3/G7pHy1HiQ/+6xL0U RkH57QUsl73IgAH5XaoXbhgvuCD66kQBoSkG6NFh/EUuwHkv6PEAcczGhsr5 ewDH4+XxhGKY9X71CrVAR5V0UoC3MJM1MNgvkSycciZsz/1oRiWSl7XWChGe tlOn21ImIkRmHC4ev3BbbGWiI4WNWmQ9Tm/2Qt/hkAQbOZ3OwE0EcS0kSgEI ALSV5Z3NSBV/nftJzYJ7VVWzlzxAMQODj+iWpD28XqchslF0+xS4LVMDvoG7 Sa6RoHq6muMG+pcP0ho7kpPvXc5LEjhYvOdbdaRWqxBoywAzvMZga+u1vKsy 087xgmffASkFPqwPDkuOMQ7LSG16NGMDKZGubfdKy+FY+AcL1Cnc76LgEixR DPuLZyPRVUOmPWPoEebbHfQRYQpZmEbDY6D3XECm6yM1BlbvL0+SAksP2Ib+ g9f4NFbXGWVaKYflifbUcnXi5+xZdt4D0k56eySl26Rz0ojt7hzY7d+V/zEm KxoHT5OvXV5BV0B/e/nSrOIyQkhTGejON14lOtFV5WsAEQEAAcLAXwQYAQgA CQUCcS0kSgIbDAAKCRBbhNAGBVhXC2SqCACJovJpZJTKDBXfRvNMRO2LdTpC lAkm9RyBjQ4BGxoqEaXtxJAOyKjDzvD6+zwlJwAWSM4j2oYsaZsSosASfXHj kcy5HTRP6MN6pcBnNPlJIlOqVdzqMCStLnFrYpsvl7xD3VrfOOz9gTuZl/n9 GbziMjGUES8PK63IR/JKI4iNKD9M3xLkHOFjyxHG17AlHPHBdtb7DvKg780H Sh4BCGqNrB0ikvMCZwZBpIAck4BGXPeuykFQ93BxCsbVdXIKqK44g5+hG2Bg iCzXvu4VCEMxMYOkOV4857v958DC7Z7W6BYEYpa9DP0O2zAwDmhu/kRFfKVQ 3GOWvBNGqRPrEJ49 =JOnb -----END PGP PUBLIC KEY BLOCK----- `; const v5_sample_key = `-----BEGIN PGP PRIVATE KEY BLOCK----- lGEFXJH05BYAAAAtCSsGAQQB2kcPAQEHQFhZlVcVVtwf+21xNQPX+ecMJJBL0MPd fj75iux+my8QAAAAAAAiAQCHZ1SnSUmWqxEsoI6facIVZQu6mph3cBFzzTvcm5lA Ng5ctBhlbW1hLmdvbGRtYW5AZXhhbXBsZS5uZXSIlgUTFggASCIhBRk0e8mHJGQC X5nfPsLgAA7ZiEiS4fez6kyUAJFZVptUBQJckfTkAhsDBQsJCAcCAyICAQYVCgkI CwIEFgIDAQIeBwIXgAAA9cAA/jiR3yMsZMeEQ40u6uzEoXa6UXeV/S3wwJAXRJy9 M8s0AP9vuL/7AyTfFXwwzSjDnYmzS0qAhbLDQ643N+MXGBJ2BZxmBVyR9OQSAAAA MgorBgEEAZdVAQUBAQdA+nysrzml2UCweAqtpDuncSPlvrcBWKU0yfU0YvYWWAoD AQgHAAAAAAAiAP9OdAPppjU1WwpqjIItkxr+VPQRT8Zm/Riw7U3F6v3OiBFHiHoF GBYIACwiIQUZNHvJhyRkAl+Z3z7C4AAO2YhIkuH3s+pMlACRWVabVAUCXJH05AIb DAAAOSQBAP4BOOIR/sGLNMOfeb5fPs/02QMieoiSjIBnijhob2U5AQC+RtOHCHx7 TcIYl5/Uyoi+FOvPLcNw4hOv2nwUzSSVAw== =IiS2 -----END PGP PRIVATE KEY BLOCK----- `; const mismatchingKeyParams = `-----BEGIN PGP PRIVATE KEY BLOCK----- Version: OpenPGP.js v4.7.0 Comment: https://openpgpjs.org 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 0NubenKyljKtyHyoU+S+TqUyx7gf5A== =Lj9k -----END PGP PRIVATE KEY BLOCK----- `; const gnuDummyKeySigningSubkey = ` -----BEGIN PGP PRIVATE KEY BLOCK----- Version: OpenPGP.js VERSION Comment: https://openpgpjs.org xZUEWCC+hwEEALu8GwefswqZLoiKJk1Nd1yKmVWBL1ypV35FN0gCjI1NyyJX UfQZDdC2h0494OVAM2iqKepqht3tH2DebeFLnc2ivvIFmQJZDnH2/0nFG2gC rSySWHUjVfbMSpmTaXpit8EX/rjNauGOdbePbezOSsAhW7R9pBdtDjPnq2Zm vDXXABEBAAH+B2UAR05VAc0JR05VIER1bW15wrgEEwECACIFAlggvocCGwMG CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEJ3XHFanUJgCeMYD/2zKefpl clQoBdDPJKCYJm8IhuWuoF8SnHAsbhD+U42Gbm+2EATTPj0jyGPkZzl7a0th S2rSjQ4JF0Ktgdr9585haknpGwr31t486KxXOY4AEsiBmRyvTbaQegwKaQ+C /0JQYo/XKpsaX7PMDBB9SNFSa8NkhxYseLaB7gbM8w+Lx8EYBFggvpwBBADF YeeJwp6MAVwVwXX/eBRKBIft6LC4E9czu8N2AbOW97WjWNtXi3OuM32OwKXq vSck8Mx8FLOAuvVq41NEboeknhptw7HzoQMB35q8NxA9lvvPd0+Ef+BvaVB6 NmweHttt45LxYxLMdXdGoIt3wn/HBY81HnMqfV/KnggZ+imJ0wARAQABAAP7 BA56WdHzb53HIzYgWZl04H3BJdB4JU6/FJo0yHpjeWRQ46Q7w2WJzjHS6eBB G+OhGzjAGYK7AUr8wgjqMq6LQHt2f80N/nWLusZ00a4lcMd7rvoHLWwRj80a RzviOvvhP7kZY1TrhbS+Sl+BWaNIDOxS2maEkxexztt4GEl2dWUCAMoJvyFm qPVqVx2Yug29vuJsDcr9XwnjrYI8PtszJI8Fr+5rKgWE3GJumheaXaug60dr mLMXdvT/0lj3sXquqR0CAPoZ1Mn7GaUKjPVJ7CiJ/UjqSurrGhruA5ikhehQ vUB+v4uIl7ICcX8zfiP+SMhWY9qdkmOvLSSSMcTkguMfe68B/j/qf2en5OHy 6NJgMIjMrBHvrf34f6pxw5p10J6nxjooZQxV0P+9MoTHWsy0r6Er8IOSSTGc WyWJ8wmSqiq/dZSoJcLAfQQYAQIACQUCWCC+nAIbAgCoCRCd1xxWp1CYAp0g BBkBAgAGBQJYIL6cAAoJEOYZSGiVA/C9CT4D/2Vq2dKxHmzn/UD1MWSLXUbN ISd8tvHjoVg52RafdgHFmg9AbE0DW8ifwaai7FkifD0IXiN04nER3MuVhAn1 gtMu03m1AQyX/X39tHz+otpwBn0g57NhFbHFmzKfr/+N+XsDRj4VXn13hhqM qQR8i1wgiWBUFJbpP5M1BPdH4Qfkcn8D/j8A3QKYGGETa8bNOdVTRU+sThXr imOfWu58V1yWCmLE1kK66qkqmgRVUefqacF/ieMqNmsAY+zmR9D4fg2wzu/d nPjJXp1670Vlzg7oT5XVYnfys7x4GLHsbaOSjXToILq+3GwI9UjNjtpobcfm mNG2ibD6lftLOtDsVSDY8a6a =KjxQ -----END PGP PRIVATE KEY BLOCK----- `; const gnuDummyKey = ` -----BEGIN PGP PRIVATE KEY BLOCK----- Version: OpenPGP.js VERSION Comment: https://openpgpjs.org xZUEWCC+hwEEALu8GwefswqZLoiKJk1Nd1yKmVWBL1ypV35FN0gCjI1NyyJX UfQZDdC2h0494OVAM2iqKepqht3tH2DebeFLnc2ivvIFmQJZDnH2/0nFG2gC rSySWHUjVfbMSpmTaXpit8EX/rjNauGOdbePbezOSsAhW7R9pBdtDjPnq2Zm vDXXABEBAAH+B2UAR05VAc0JR05VIER1bW15wrgEEwECACIFAlggvocCGwMG CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEJ3XHFanUJgCeMYD/2zKefpl clQoBdDPJKCYJm8IhuWuoF8SnHAsbhD+U42Gbm+2EATTPj0jyGPkZzl7a0th S2rSjQ4JF0Ktgdr9585haknpGwr31t486KxXOY4AEsiBmRyvTbaQegwKaQ+C /0JQYo/XKpsaX7PMDBB9SNFSa8NkhxYseLaB7gbM8w+L =yGSn -----END PGP PRIVATE KEY BLOCK----- `; const eddsaKeyAsEcdsa = ` -----BEGIN PGP PRIVATE KEY BLOCK----- Version: OpenPGP.js VERSION Comment: https://openpgpjs.org xVgEXseu0BMJKwYBBAHaRw8BAQdA7MOW/AQa3aDGJJw9upY2Qv4cxv4MQHr5 81xmFwvyf+EAAQC0bOQsFDKCdAQ4cACKqbSDO2st+V9s3bEmSZV+fVR6ww44 zRFib2IgPGJvYkBib2IuY29tPsJ3BBATCgAgBQJex69xBgsJBwgDAgQVCAoC BBYCAQACGQECGwMCHgEACgkQInpzQil4KrkPrQD7BkYxgDzyrfynM8mUSEdr 4iOivzbGo9zmn7cwluO2LI4A9iCJG4Xao9VFlyOAizVzNWlhfptwWVH5awh4 YFDlUSbHXQRex67QEgorBgEEAZdVAQUBAQdAI5fo7gn4y8IybTJ1m+xn90Xs uqlIEDirKMx7WVJ/2QcDAQgHAAD/cPduuCXzoLkEI6Po4kTfoWXC6w6AEyGg LA+BABNTPIAPp8JhBBgTCAAJBQJex69xAhsMAAoJECJ6c0IpeCq5D7EA/Ajk xCrUtYPsmEDcr+1TFQCoOFGEKiYG6wNeuTaLqvPjAPsH8p3BnYBqlELdHU2I 9RFfjwPHLd+fZMQC6+mEaRJ4AA== =2b6I -----END PGP PRIVATE KEY BLOCK----- `; const dsaGnuDummyKeyWithElGamalSubkey = `-----BEGIN PGP PRIVATE KEY BLOCK----- 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 vqBGKJzmO5q3cECw =X9kJ -----END PGP PRIVATE KEY BLOCK-----`; const dsaPrivateKey = `-----BEGIN PGP PRIVATE KEY BLOCK----- lQNTBF69PO8RCACHP4KLQcYOPGsGV9owTZvxnvHvvrY8W0v8xDUL3y6CLc05srF1 kQp/81iUfP5g57BEiDpJV95kMh+ulBthIOGnuMCkodJjuBICB4K6BtFTV4Fw1Q5S S7aLC9beCaMvvGHXsK6MbknYl+IVJY7Zmml1qUSrBIQFGp5kqdhIX4o+OrzZ1zYj ALicqzD7Zx2VRjGNQv7UKv4CkBOC8ncdnq/4/OQeOYFzVbCOf+sJhTgz6yxjHJVC fLk7w8l2v1zV11VJuc8cQiQ9g8tjbKgLMsbyzy7gl4m9MSCdinG36XZuPibZrSm0 H8gKAdd1FT84a3/qU2rtLLR0y8tCxBj89Xx/AQCv7CDmwoU+/yGpBVVl1mh0ZUkA /VJUhnJfv5MIOIi3AQf8CS9HrEmYJg/A3z0DcvcwIu/9gqpRLTqH1iT5o4BCg2j+ Cog2ExYkQl1OEPkEQ1lKJSnD8MDwO3BlkJ4cD0VSKxlnwd9dsu9m2+F8T+K1hoA7 PfH89TjD5HrEaGAYIdivLYSwoTNOO+fY8FoVC0RR9pFNOmjiTU5PZZedOxAql5Os Hp2bYhky0G9trjo8Mt6CGhvgA3dAKyONftLQr9HSM0GKacFV+nRd9TGCPNZidKU8 MDa/SB/08y1bBGX5FK5wwiZ6H5qD8VAUobH3kwKlrg0nL00/EqtYHJqvJ2gkT5/v h8+z4R4TuYiy4kKF2FLPd5OjdA31IVDoVgCwF0WHLgf/X9AiTr/DPs/5dIYN1+hf UJwqjzr3dlokRwx3CVDcOVsdkWRwb8cvxubbsIorvUrF02IhYjHJMjIHT/zFt2zA +VPzO4zabUlawWVepPEwrCtXgvn9aXqjhAYbilG3UZamhfstGUmbmvWVDadALwby EO8u2pfLhI2lep63V/+KtUOLhfk8jKRSvxvxlYAvMi7sK8kB+lYy17XKN+IMYgf8 gMFV6XGKpdmMSV3jOvat8cI6vnRO0i+g3jANP3PfrFEivat/rVgxo67r4rxezfFn J29qwB9rgbRgMBGsbDvIlQNV/NWFvHy2uQAEKn5eX4CoLsCZoR2VfK3BwBCxhYDp /wAA/0GSmI9MlMnLadFNlcX2Bm4i15quZAGF8JxwHbj1dhdUEYq0E1Rlc3QgPHRl c3RAdGVzdC5pbz6IlAQTEQgAPBYhBAq6lCI5EfrbHP1qZCxnOy/rlEGVBQJevTzv AhsDBQsJCAcCAyICAQYVCgkICwIEFgIDAQIeBwIXgAAKCRAsZzsv65RBlUPoAP9Q aTCWpHWZkvZzC8VU64O76fHp31rLWlcZFttuDNLyeAEAhOxkQHk6GR88R+EF5mrn clr63t9Q4wreqOlO0NR5/9k= =UW2O -----END PGP PRIVATE KEY BLOCK----- `; const uidlessKey = `-----BEGIN PGP PRIVATE KEY BLOCK----- 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 CciXuhqnLwoVF5/uXMYffVtfl/OU+w== =EqcV -----END PGP PRIVATE KEY BLOCK-----`; const rsaSignOnly = `-----BEGIN PGP PRIVATE KEY BLOCK----- xcLYBF9Gl+MBCACc09O3gjyO0B1ledGxGFSUpPmhhJzkxKoY1WDX8VlASCHz bAA/BytgYBXHTe7N+N3yJ6uiN3DIQ2j5uGWk/h5jyIOsRuzQxJ40n8AdK/71 SGDCG1X5l1h9vmVTJxkQ3pcOxqRg55EEuJWKN1v7B1hIPxhaM5hgH/7s+PNn lQddckQJqYkpm9Hy6EI7f9oHrOtWJWZoCHkWZVld7+9ZVPi34ex5ofYOuvNL AIKZCc7lAiUiDJYQ+hIJRoYwLYhjIshpYoHgNeG4snlupNO32BiwDbHFDjeu eoBLQ0rxZV7B664ceCmIl+VRht9G20hfGoTjAiop5tyrN1ZeL4EaI+aTABEB AAEAB/oCKTQnftvHwrkBVlyzSN6tfXylF2551Q3n4CZGg3efI/9PCa9wF58+ WApqmgsUqcNbVnDfl2T58ow05FLMxnFFNnHJq8ltfnXl+gG6c7iy94p79SQE AGCOL7xNassXrDAQZhqWkCdiLK3b6r9F8Y3URb/AYbWH2BkFkS0oWQDav+Tw lABt5vG2L5QtnShdqi8CCitcHGEKHocPHp0yAQlp3oAMq09YubgrzESDJ7Pe l93cT35NlyimAZ6IYk/gumX0/6spqcw7205KfG6P84WlMp3WmE0IUWtiOp+7 rjMjDki0WeVKtuLbHBhOwKvxcILWz+0vQf3uu6aXOKQ3JlsVBADHoXa6QjrT RmKD9ch65Pkd+EZiKhe+pqqIArVj4QsVBEnaggR59SD8uXhtpyBnvOp3xpof Vut3SKWl/jmH7vKansFbHOo8xLUyVctu7lCL2/v85FcRJxfPK00MBic+z/vf mWOAY1VBoi5I9qi6o8vVHA5BJ/xw2uV9VpxfiLG0vwQAyRxHmoZl/OxaZUsm J9eDYV9xyYumkTCYvHPk9X+ehS+XeYh24z1q9a/1jEnSR3A5XE67UCLaspiA +Px7nSU1+ftJ9bC2bnRR0Upop+3UkPeCBVp4tYAhsNnPXhSWC0gCgeGU7EmW DechFg29LId35LXKgmXls9u5yDy2w978Hy0D/jbKZaxNMMwlx/XCFCoBEcXS DBzg7GHNXdillJqy215j46lfVqOCB3IiffNKjHua2l6fQc0BoiWIZnElMnIa faEBBSpOVqKhktDFacHa5xChjqXZVyw68qc0I36xkCfcwvYCpNKKkXv90r8A tRI6gpBLeMJvkL3VkmKd6AZymxFxRGjNEkJvYiA8aW5mb0Bib2IuY29tPsLA jQQQAQgAIAUCX0aX4wYLCQcIAwIEFQgKAgQWAgEAAhkBAhsDAh4BACEJEAr9 x5ZY6oZmFiEEm+B7p+lshgEOwGGZCv3HlljqhmaUWgf/efmGSpOKIGQ3Kh32 HUqn/4ARvUmqMtZz4xUA9P3GAPY8XwJf00jSQlAo4//3aA1eEOJFHCr2qzCk /4gIoZEScTTZp4itfL/Fer3UX+bV/VeTNgZGi+MRylSDQxLRQNpRgu+FmRAi E6fr8D8GMvEcGb0jTRgWGj1EVtfOHfDg+EyPrtw+Z8u/bErUJ+Fnxz+KOGSN SBQVAOflUYFoQhUNgZiq1s8WFD55sfes3UdBwsmHquDtYGo9dvWLJXxTEF8q QCyKHYdk25ShIlNpRUqOH3CHqY/38z7QeV7INwtZaQvoES08RlD6ZMtczYLj BZou86lozq7ISvRg1RSIWZ0ZRA== =A9Ts -----END PGP PRIVATE KEY BLOCK----- `; const encryptedRsaSignOnly = `-----BEGIN PGP MESSAGE----- wcBMAwr9x5ZY6oZmAQf+Lxghg4keIFpEq8a65gFkIfW+chHTDPlfI8xnx6U9 HdsICX3Oye5V0ToCVKkEWDxfN1yCfXiYalSNo7ScRZKR7C+j02/pC+FfR6AJ 2cvdFoGIrLaXdjXXc/oXbsCCZA4C1DhQqpdORo2qGF0Q6Sm8659B0CfOgYSL fBfKQ5VJngUT5JG8Uek3YuXBufPNhzdmXLHyB2Y2CwKkldi2vo4YNAukDhrR 2TojxdNoouhnMm+gloCE1n8huY1vw5F78/uiHen0tmHQ0dxtfk8cc1burgl/ zUdJ3Sg6Eu+OC2ae5II63iB5fG+lCwZtfuepWnePDv8RDKNHCVP/LoBNpGOZ U9I6AUkZWdcsueib9ghKDDy+HbUbf2kCJWUnuyeOCKqQifDb8bsLmdQY4Wb6 EBeLgD8oZHVsH3NLjPakPw== =STqy -----END PGP MESSAGE-----`; const shortP521Key = `-----BEGIN PGP PRIVATE KEY BLOCK----- xcAiBV/Pa+4TAAAAjQUrgQQAIwQjBADY+IGvRpeUzbT0+YRUe0KCMxAZmDY1 KjDzULlmOJOS0bfZfqd4HsUF2hRoU/rg1gu1ju/Nt/18db0SJExOqVB9CgA0 ZYiYyJhGYDOVg/bD54E7a3txWuDPB1DzkGWJH8PkqGNzU0BJpZcUVA6Th09s YeO7rx5jSoyWNXjUYKwc24trFAAAAAAARQIItVgIiTWNT+QEVnZqDKKTIOUU XEetkjCjPed1RiSchiZpwq+Bvx5hWGsbV5Pjj0S6EuH/ca5w+2ZyITLWZjr1 LP8eP80UVGVzdCA8dGVzdEB0ZXN0LmNvbT7CwBUFEBMKACEFAl/Pa+4ECwkH CAMVCAoEFgIBAAIZAQIbAwIeBwMiAQIAIyIhBbDerrGG7kdy9vbLYvb/j6TC 53fuQgK9Gtt1xng5MgpSUX0CCJZB+Ppt8yG5hBzwiGz5ZRpPVBFihEftaTOO tKUuYRpWlvgA/XV11DgL6KZWRwu4C2venydBW987CVXCbRp4r18FAgkBjTR1 AXHEstTVwJYj8mWkOZrz+Bfqvu6pWPmVYclgHJK2sSWizakvX/DtX/LFgTJL UoASOVvu1hYHDsCO7vWWC/bHwCYFX89r7hIAAACRBSuBBAAjBCMEAULqNQ3L CcdVlpIHiq4Xb+elTEdu2oDDA+FCbwroX3wvMatrH6GodxCcrjQKUrfVNiiI cvj+r6SE/pRDnxsvW/JSAWUz3XKfVXccb0PYf0ikkTmb8UW33AaNYX6Srk0W iamEmEzUpCMiiyXiYe+fp9JD63rKLXBbvLCT2mHuYO/hOikKAwEKCQAAAAAA RQIDBONtE8bb3Yr2otNhdR67lg529mm3rSRsyWwMBVUPwX0RTTZ/bejq7XP5 fuXV8QSEjWdOdPBARGw9jhw51D1XWl8gFsK9BRgTCgAJBQJfz2vuAhsMACMi IQWw3q6xhu5Hcvb2y2L2/4+kwud37kICvRrbdcZ4OTIKUiWwAgkBdH+OZHBt D2Yx2xKVPqDGJgMa5Ta8GmQZOFnoC2SpB6i9hIOfwiNjNLs+bv+kTxZ09nzf 3ZUGYi5Ei70hLrDAy7UCCNQNObtPmUYaUTtRzj3S9jUohbIpQxcfyoCMh6aP usLw5q4tc+I5gdq57aiulJ8r4Jj9rdzsZFA7PzNJ9WPGVYJ3 =GSXO -----END PGP PRIVATE KEY BLOCK-----`; const expiredPublicKeyThroughDirectSignature = `-----BEGIN PGP PUBLIC KEY BLOCK----- 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 Be4ubVrj5KjhX2PVNEJd3XZRzaXZE2aAMQ== =ZeAz -----END PGP PUBLIC KEY BLOCK-----`; function versionSpecificTests() { it('Preferences of generated key', function() { const testPref = function(key) { // key flags const keyFlags = openpgp.enums.keyFlags; expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.certifyKeys).to.equal(keyFlags.certifyKeys); expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.signData).to.equal(keyFlags.signData); expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptCommunication).to.equal(keyFlags.encryptCommunication); expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptStorage).to.equal(keyFlags.encryptStorage); const sym = openpgp.enums.symmetric; expect(key.users[0].selfCertifications[0].preferredSymmetricAlgorithms).to.eql([sym.aes256, sym.aes128, sym.aes192]); if (openpgp.config.aeadProtect) { const aead = openpgp.enums.aead; expect(key.users[0].selfCertifications[0].preferredAEADAlgorithms).to.eql([aead.eax, aead.ocb]); } const hash = openpgp.enums.hash; expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha256, hash.sha512]); const compr = openpgp.enums.compression; expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.uncompressed, compr.zlib, compr.zip]); let expectedFeatures; if (openpgp.config.v5Keys) { expectedFeatures = [7]; // v5 + aead + mdc } else if (openpgp.config.aeadProtect) { expectedFeatures = [3]; // aead + mdc } else { expectedFeatures = [1]; // mdc } expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures); }; const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello', format: 'object' }; return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) { testPref(privateKey); testPref(publicKey); }); }); it('Preferences of generated key - with config values', async function() { const preferredSymmetricAlgorithmVal = openpgp.config.preferredSymmetricAlgorithm; const preferredHashAlgorithmVal = openpgp.config.preferredHashAlgorithm; const preferredCompressionAlgorithmVal = openpgp.config.preferredCompressionAlgorithm; const preferredAEADAlgorithmVal = openpgp.config.preferredAEADAlgorithm; openpgp.config.preferredSymmetricAlgorithm = openpgp.enums.symmetric.aes192; openpgp.config.preferredHashAlgorithm = openpgp.enums.hash.sha224; openpgp.config.preferredCompressionAlgorithm = openpgp.enums.compression.zip; openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.experimentalGCM; const testPref = function(key) { // key flags const keyFlags = openpgp.enums.keyFlags; expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.certifyKeys).to.equal(keyFlags.certifyKeys); expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.signData).to.equal(keyFlags.signData); expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptCommunication).to.equal(keyFlags.encryptCommunication); expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptStorage).to.equal(keyFlags.encryptStorage); const sym = openpgp.enums.symmetric; expect(key.users[0].selfCertifications[0].preferredSymmetricAlgorithms).to.eql([sym.aes192, sym.aes256, sym.aes128]); if (openpgp.config.aeadProtect) { const aead = openpgp.enums.aead; expect(key.users[0].selfCertifications[0].preferredAEADAlgorithms).to.eql([aead.experimentalGCM, aead.eax, aead.ocb]); } const hash = openpgp.enums.hash; expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha224, hash.sha256, hash.sha512]); const compr = openpgp.enums.compression; expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.zip, compr.zlib, compr.uncompressed]); let expectedFeatures; if (openpgp.config.v5Keys) { expectedFeatures = [7]; // v5 + aead + mdc } else if (openpgp.config.aeadProtect) { expectedFeatures = [3]; // aead + mdc } else { expectedFeatures = [1]; // mdc } expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures); }; const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello', format: 'object' }; try { const { privateKey, publicKey } = await openpgp.generateKey(opt); testPref(privateKey); testPref(publicKey); } finally { openpgp.config.preferredSymmetricAlgorithm = preferredSymmetricAlgorithmVal; openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal; openpgp.config.preferredCompressionAlgorithm = preferredCompressionAlgorithmVal; openpgp.config.preferredAEADAlgorithm = preferredAEADAlgorithmVal; } }); it('Generated key is not unlocked by default', async function() { const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '123', format: 'object' }; const { privateKey: key } = await openpgp.generateKey(opt); return openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: key }).then(async armoredMessage => openpgp.decrypt({ message: await openpgp.readMessage({ armoredMessage }), decryptionKeys: key })).catch(function(err) { expect(err.message).to.match(/Decryption key is not decrypted./); }); }); it('Generate key - single userID', function() { const userID = { name: 'test', email: 'a@b.com', comment: 'test comment' }; const opt = { userIDs: userID, passphrase: '123', format: 'object' }; return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test (test comment) '); expect(key.users[0].userID.name).to.equal(userID.name); expect(key.users[0].userID.email).to.equal(userID.email); expect(key.users[0].userID.comment).to.equal(userID.comment); }); }); it('Generate key - single userID (all empty)', function() { const userID = { name: '', email: '', comment: '' }; const opt = { userIDs: userID, passphrase: '123', format: 'object' }; return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal(''); expect(key.users[0].userID.name).to.equal(userID.name); expect(key.users[0].userID.email).to.equal(userID.email); expect(key.users[0].userID.comment).to.equal(userID.comment); }); }); it('Generate key - single userID (empty email)', function() { const userID = { name: 'test', email: '', comment: 'test comment' }; const opt = { userIDs: userID, passphrase: '123', format: 'object' }; return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test (test comment)'); expect(key.users[0].userID.name).to.equal(userID.name); expect(key.users[0].userID.email).to.equal(userID.email); expect(key.users[0].userID.comment).to.equal(userID.comment); }); }); it('Generate key - single userID (empty comment)', function() { const userID = { name: 'test', email: 'a@b.com', comment: '' }; const opt = { userIDs: userID, passphrase: '123', format: 'object' }; return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].userID.name).to.equal(userID.name); expect(key.users[0].userID.email).to.equal(userID.email); expect(key.users[0].userID.comment).to.equal(userID.comment); }); }); it('Generate key - setting date to the past', function() { const past = new Date(0); const opt = { userIDs: { name: 'Test User', email: 'text@example.com' }, passphrase: 'secret', date: past, format: 'object' }; return openpgp.generateKey(opt).then(function({ privateKey }) { expect(privateKey).to.exist; expect(+privateKey.getCreationTime()).to.equal(+past); expect(+privateKey.subkeys[0].getCreationTime()).to.equal(+past); expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.equal(+past); }); }); it('Generate key - setting date to the future', function() { const future = new Date(Math.ceil(Date.now() / 1000) * 1000 + 1000); const opt = { userIDs: { name: 'Test User', email: 'text@example.com' }, passphrase: 'secret', date: future, format: 'object' }; return openpgp.generateKey(opt).then(function({ privateKey }) { expect(privateKey).to.exist; expect(+privateKey.getCreationTime()).to.equal(+future); expect(+privateKey.subkeys[0].getCreationTime()).to.equal(+future); expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.equal(+future); }); }); it('Generate key - multi userID', function() { const userID1 = { name: 'test', email: 'a@b.com' }; const userID2 = { name: 'test', email: 'b@c.com' }; const opt = { userIDs: [userID1, userID2], passphrase: '123', format: 'object' }; return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(2); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[1].userID.userID).to.equal('test '); expect(key.users[1].selfCertifications[0].isPrimaryUserID).to.be.null; }); }); it('Generate key - default values', function() { const userID = { name: 'test', email: 'a@b.com' }; const opt = { userIDs: [userID], format: 'object' }; return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.isDecrypted()).to.be.true; expect(key.getAlgorithmInfo().algorithm).to.equal('eddsa'); expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.subkeys).to.have.length(1); expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); }); }); it('Generate key - two subkeys with default values', function() { const userID = { name: 'test', email: 'a@b.com' }; const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{},{}] }; return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.subkeys).to.have.length(2); expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('ecdh'); }); }); it('Generate RSA key - two subkeys with default values', async function() { const rsaBits = 512; const minRSABits = openpgp.config.minRSABits; openpgp.config.minRSABits = rsaBits; const userID = { name: 'test', email: 'a@b.com' }; const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{},{}] }; try { const { privateKey: key } = await openpgp.generateKey(opt); expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.subkeys).to.have.length(2); expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign'); expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign'); } finally { openpgp.config.minRSABits = minRSABits; } }); it('Generate key - one signing subkey', function() { const userID = { name: 'test', email: 'a@b.com' }; const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{}, { sign: true }] }; return openpgp.generateKey(opt).then(async function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.subkeys).to.have.length(2); expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); expect(await key.getEncryptionKey()).to.equal(key.subkeys[0]); expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('eddsa'); expect(await key.getSigningKey()).to.equal(key.subkeys[1]); }); }); it('Reformat key - one signing subkey', async function() { const userID = { name: 'test', email: 'a@b.com' }; const opt = { userIDs: [userID], format: 'object', subkeys:[{}, { sign: true }] }; const { privateKey } = await openpgp.generateKey(opt); return openpgp.reformatKey({ privateKey, userIDs: [userID] }).then(async function({ privateKey: armoredKey }) { const key = await openpgp.readKey({ armoredKey }); expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.subkeys).to.have.length(2); expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); expect(await key.getEncryptionKey()).to.equal(key.subkeys[0]); expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('eddsa'); expect(await key.getSigningKey()).to.equal(key.subkeys[1]); }); }); it('Generate key - override main RSA key options for subkey', async function() { const rsaBits = 512; const minRSABits = openpgp.config.minRSABits; openpgp.config.minRSABits = rsaBits; const userID = { name: 'test', email: 'a@b.com' }; const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ type: 'ecc', curve: 'curve25519' }] }; try { const { privateKey: key } = await openpgp.generateKey(opt); expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign'); expect(key.getAlgorithmInfo().bits).to.equal(opt.rsaBits); expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); } finally { openpgp.config.minRSABits = minRSABits; } }); it('Generate key - ensure keyExpirationTime works', function() { const expect_delta = 365 * 24 * 60 * 60; const userID = { name: 'test', email: 'a@b.com' }; const opt = { userIDs: userID, passphrase: '123', format: 'object', keyExpirationTime: expect_delta }; return openpgp.generateKey(opt).then(async function({ privateKey: key }) { const expiration = await key.getExpirationTime(); expect(expiration).to.exist; const actual_delta = (new Date(expiration) - new Date()) / 1000; expect(Math.abs(actual_delta - expect_delta)).to.be.below(60); const subkeyExpiration = await key.subkeys[0].getExpirationTime(); expect(subkeyExpiration).to.exist; const actual_subkeyDelta = (new Date(subkeyExpiration) - new Date()) / 1000; expect(Math.abs(actual_subkeyDelta - expect_delta)).to.be.below(60); }); }); it('Sign and verify key - primary user', async function() { let publicKey = await openpgp.readKey({ armoredKey: pub_sig_test }); const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const { minRSABits } = openpgp.config; openpgp.config.minRSABits = 1024; try { publicKey = await publicKey.signPrimaryUser([privateKey]); const signatures = await publicKey.verifyPrimaryUser([privateKey]); const publicSigningKey = await publicKey.getSigningKey(); const privateSigningKey = await privateKey.getSigningKey(); expect(signatures.length).to.equal(2); expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex()); expect(signatures[0].valid).to.be.null; expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex()); expect(signatures[1].valid).to.be.true; } finally { openpgp.config.minRSABits = minRSABits; } }); it('Sign key and verify with wrong key - primary user', async function() { let publicKey = await openpgp.readKey({ armoredKey: pub_sig_test }); const wrongKey = await openpgp.readKey({ armoredKey: wrong_key }); const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const { minRSABits } = openpgp.config; openpgp.config.minRSABits = 1024; try { publicKey = await publicKey.signPrimaryUser([privateKey]); const signatures = await publicKey.verifyPrimaryUser([wrongKey]); const publicSigningKey = await publicKey.getSigningKey(); const privateSigningKey = await privateKey.getSigningKey(); expect(signatures.length).to.equal(2); expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex()); expect(signatures[0].valid).to.be.null; expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex()); expect(signatures[1].valid).to.be.null; } finally { openpgp.config.minRSABits = minRSABits; } }); it('Sign and verify key - all users', async function() { let publicKey = await openpgp.readKey({ armoredKey: multi_uid_key }); const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const { minRSABits } = openpgp.config; openpgp.config.minRSABits = 1024; try { publicKey = await publicKey.signAllUsers([privateKey]); const signatures = await publicKey.verifyAllUsers([privateKey]); const publicSigningKey = await publicKey.getSigningKey(); const privateSigningKey = await privateKey.getSigningKey(); expect(signatures.length).to.equal(4); expect(signatures[0].userID).to.equal(publicKey.users[0].userID.userID); expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex()); expect(signatures[0].valid).to.be.null; expect(signatures[1].userID).to.equal(publicKey.users[0].userID.userID); expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex()); expect(signatures[1].valid).to.be.true; expect(signatures[2].userID).to.equal(publicKey.users[1].userID.userID); expect(signatures[2].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex()); expect(signatures[2].valid).to.be.null; expect(signatures[3].userID).to.equal(publicKey.users[1].userID.userID); expect(signatures[3].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex()); expect(signatures[3].valid).to.be.true; } finally { openpgp.config.minRSABits = minRSABits; } }); it('Sign key and verify with wrong key - all users', async function() { let publicKey = await openpgp.readKey({ armoredKey: multi_uid_key }); const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const wrongKey = await openpgp.readKey({ armoredKey: wrong_key }); const { minRSABits } = openpgp.config; openpgp.config.minRSABits = 1024; try { publicKey = await publicKey.signAllUsers([privateKey]); const signatures = await publicKey.verifyAllUsers([wrongKey]); const publicSigningKey = await publicKey.getSigningKey(); const privateSigningKey = await privateKey.getSigningKey(); expect(signatures.length).to.equal(4); expect(signatures[0].userID).to.equal(publicKey.users[0].userID.userID); expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex()); expect(signatures[0].valid).to.be.null; expect(signatures[1].userID).to.equal(publicKey.users[0].userID.userID); expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex()); expect(signatures[1].valid).to.be.null; expect(signatures[2].userID).to.equal(publicKey.users[1].userID.userID); expect(signatures[2].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex()); expect(signatures[2].valid).to.be.null; expect(signatures[3].userID).to.equal(publicKey.users[1].userID.userID); expect(signatures[3].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex()); expect(signatures[3].valid).to.be.null; } finally { openpgp.config.minRSABits = minRSABits; } }); it('Reformat and encrypt key with no subkey', async function() { const userID = { name: 'test', email: 'a@b.com' }; const key = await openpgp.readKey({ armoredKey: key_without_subkey }); const opt = { privateKey: key, userIDs: [userID], passphrase: 'test', format: 'object' }; return openpgp.reformatKey(opt).then(function({ privateKey: newKey }) { expect(newKey.users.length).to.equal(1); expect(newKey.users[0].userID.userID).to.equal('test '); expect(newKey.isDecrypted()).to.be.false; }); }); it('Reformat key with one subkey', async function() { const original = await openpgp.readKey({ armoredKey: priv_key_rsa }); const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' }); const userID = { name: 'test', email: 'b@c.com' }; const before = new Date(0); expect(+privateKey.getCreationTime()).to.not.equal(+before); expect(+privateKey.subkeys[0].getCreationTime()).to.not.equal(+before); expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.not.equal(+before); const opt = { privateKey, userIDs: userID, date: before, format: 'object' }; return openpgp.reformatKey(opt).then(function({ privateKey: refKey }) { expect(refKey.users.length).to.equal(1); expect(refKey.users[0].userID.userID).to.equal('test '); expect(+refKey.subkeys[0].bindingSignatures[0].created).to.equal(+before); }); }); it('Reformat key with no subkey', async function() { const userID = { name: 'test', email: 'a@b.com' }; const key = await openpgp.readKey({ armoredKey: key_without_subkey }); const opt = { privateKey: key, userIDs: [userID], format: 'object' }; return openpgp.reformatKey(opt).then(async function({ privateKey: newKey, publicKey: newKeyPublic }) { expect(newKey.users.length).to.equal(1); expect(newKey.users[0].userID.userID).to.equal('test '); expect(newKey.isDecrypted()).to.be.true; return openpgp.sign({ message: await openpgp.createCleartextMessage({ text: 'hello' }), signingKeys: newKey, armor: true }).then(async function(signed) { return openpgp.verify( { message: await openpgp.readCleartextMessage({ cleartextMessage: signed }), verificationKeys: newKeyPublic } ).then(async function(verified) { expect(verified.signatures[0].valid).to.be.true; const newSigningKey = await newKey.getSigningKey(); expect(verified.signatures[0].keyID.toHex()).to.equal(newSigningKey.getKeyID().toHex()); expect(verified.signatures[0].signature.packets.length).to.equal(1); }); }); }); }); it('Reformat and encrypt key', async function() { const original = await openpgp.readKey({ armoredKey: priv_key_rsa }); const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' }); const userID1 = { name: 'test2', email: 'b@c.com' }; const userID2 = { name: 'test3', email: 'c@d.com' }; const passphrase = '123'; const reformatOpt = { privateKey, userIDs: [userID1, userID2], passphrase, format: 'object' }; return openpgp.reformatKey(reformatOpt).then(async ({ privateKey: refKey }) => { expect(refKey.users.length).to.equal(2); expect(refKey.users[0].userID.userID).to.equal('test2 '); expect(refKey.isDecrypted()).to.be.false; const decryptedKey = await openpgp.decryptKey({ privateKey: refKey, passphrase }); expect(decryptedKey.isDecrypted()).to.be.true; }); }); it('Sign and encrypt with reformatted key', async function() { const userID1 = { name: 'test1', email: 'a@b.com' }; const userID2 = { name: 'test2', email: 'b@c.com' }; const { privateKey } = await openpgp.generateKey({ userIDs: userID1, format: 'object' }); const opt2 = { privateKey, userIDs: userID2, format: 'object' }; return openpgp.reformatKey(opt2).then(async function({ privateKey: newKey, publicKey: newKeyPublic }) { const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: newKey.toPublic(), signingKeys: newKey, armor: true, config: { minRSABits: 1024 } }); const decrypted = await openpgp.decrypt({ message: await openpgp.readMessage({ armoredMessage: encrypted }), decryptionKeys: newKey, verificationKeys: newKeyPublic, config: { minRSABits: 1024 } }); expect(decrypted.data).to.equal('hello'); expect(decrypted.signatures[0].valid).to.be.true; }); }); it('Reject with user-friendly error when reformatting encrypted key', async function() { const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa }); await expect( openpgp.reformatKey({ privateKey, userIDs: { name: 'test2', email: 'a@b.com' }, passphrase: '1234' }) ).to.be.rejectedWith('Error reformatting keypair: Key is not decrypted'); }); it('Revoke generated key with revocation certificate', async function() { const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '1234', format: 'object' }; const { publicKey, revocationCertificate } = await openpgp.generateKey(opt); return openpgp.revokeKey({ key: publicKey, revocationCertificate, format: 'object' }).then(async function({ publicKey: revKey }) { expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason); expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal(''); await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); }); }); it('Revoke generated key with private key', async function() { const opt = { userIDs: { name: 'test', email: 'a@b.com' }, format: 'object' }; const { privateKey: key } = await openpgp.generateKey(opt); return openpgp.revokeKey({ key, reasonForRevocation: { string: 'Testing key revocation' }, format: 'object' }).then(async function({ publicKey: revKey }) { expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason); expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('Testing key revocation'); await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); }); }); it('Revoke reformatted key with revocation certificate', async function() { const original = await openpgp.readKey({ armoredKey: priv_key_rsa }); const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' }); const opt = { privateKey, userIDs: { name: 'test', email: 'a@b.com' }, format: 'object' }; const { publicKey: refKey, revocationCertificate } = await openpgp.reformatKey(opt); return openpgp.revokeKey({ key: refKey, revocationCertificate, format: 'object' }).then(async function({ publicKey: revKey }) { expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason); expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal(''); await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); await expect(privateKey.verifyPrimaryKey()).to.be.fulfilled; }); }); it('Parses V5 sample key', async function() { // sec ed25519 2019-03-20 [SC] // 19347BC9872464025F99DF3EC2E0000ED9884892E1F7B3EA4C94009159569B54 // uid emma.goldman@example.net // ssb cv25519 2019-03-20 [E] // E4557C2B02FFBF4B04F87401EC336AF7133D0F85BE7FD09BAEFD9CAEB8C93965 const key = await openpgp.readKey({ armoredKey: v5_sample_key }); expect(await key.keyPacket.getFingerprint()).to.equal('19347bc9872464025f99df3ec2e0000ed9884892e1f7b3ea4c94009159569b54'); expect(await key.subkeys[0].getFingerprint()).to.equal('e4557c2b02ffbf4b04f87401ec336af7133d0f85be7fd09baefd9caeb8c93965'); await key.verifyPrimaryKey(); }); } module.exports = () => describe('Key', function() { let v5KeysVal; let aeadProtectVal; tryTests('V4', versionSpecificTests, { if: !openpgp.config.ci, beforeEach: function() { v5KeysVal = openpgp.config.v5Keys; openpgp.config.v5Keys = false; }, afterEach: function() { openpgp.config.v5Keys = v5KeysVal; } }); tryTests('V5', versionSpecificTests, { if: !openpgp.config.ci, beforeEach: function() { v5KeysVal = openpgp.config.v5Keys; aeadProtectVal = openpgp.config.aeadProtect; openpgp.config.v5Keys = true; openpgp.config.aeadProtect = true; }, afterEach: function() { openpgp.config.v5Keys = v5KeysVal; openpgp.config.aeadProtect = aeadProtectVal; } }); it('Parsing armored text with RSA key and ECC subkey', async function() { const pubKeys = await openpgp.readKeys({ armoredKeys: rsa_ecc_pub }); expect(pubKeys).to.exist; expect(pubKeys).to.have.length(1); expect(pubKeys[0].getKeyID().toHex()).to.equal('b8e4105cc9dedc77'); }); it('Parsing armored text with two keys', async function() { const pubKeys = await openpgp.readKeys({ armoredKeys: twoKeys }); expect(pubKeys).to.exist; expect(pubKeys).to.have.length(2); expect(pubKeys[0].getKeyID().toHex()).to.equal('4a63613a4d6e4094'); expect(pubKeys[1].getKeyID().toHex()).to.equal('dbf223e870534df4'); }); it('Parsing armored key with an authorized revocation key in a User ID self-signature', async function() { const pubKey = await openpgp.readKey({ armoredKey: key_with_authorized_revocation_key }); await expect(pubKey.getPrimaryUser()).to.be.rejectedWith('This key is intended to be revoked with an authorized key, which OpenPGP.js does not support.'); }); it('Parsing armored key with an authorized revocation key in a direct-key signature', async function() { const pubKey = await openpgp.readKey({ armoredKey: key_with_authorized_revocation_key_in_separate_sig }); const primaryUser = await pubKey.getPrimaryUser(); expect(primaryUser).to.exist; }); it('Parsing V5 public key packet', async function() { // Manually modified from https://gitlab.com/openpgp-wg/rfc4880bis/blob/00b2092/back.mkd#sample-eddsa-key const packetBytes = util.hexToUint8Array(` 98 37 05 53 f3 5f 0b 16 00 00 00 2d 09 2b 06 01 04 01 da 47 0f 01 01 07 40 3f 09 89 94 bd d9 16 ed 40 53 19 79 34 e4 a8 7c 80 73 3a 12 80 d6 2f 80 10 99 2e 43 ee 3b 24 06 `.replace(/\s+/g, '')); const packetlist = await openpgp.PacketList.fromBinary(packetBytes, util.constructAllowedPackets([openpgp.PublicKeyPacket]), openpgp.config); const key = packetlist[0]; expect(key).to.exist; }); it('Testing key ID and fingerprint for V4 keys', async function() { const pubKeysV4 = await openpgp.readKeys({ armoredKeys: twoKeys }); expect(pubKeysV4).to.exist; expect(pubKeysV4).to.have.length(2); const pubKeyV4 = pubKeysV4[0]; expect(pubKeyV4).to.exist; expect(pubKeyV4.getKeyID().toHex()).to.equal('4a63613a4d6e4094'); expect(await pubKeyV4.getFingerprint()).to.equal('f470e50dcb1ad5f1e64e08644a63613a4d6e4094'); }); it('Create new key ID with fromID()', async function() { const [pubKeyV4] = await openpgp.readKeys({ armoredKeys: twoKeys }); const keyID = pubKeyV4.getKeyID(); const newKeyID = KeyID.fromID(keyID.toHex()); expect(newKeyID.equals(keyID)).to.be.true; }); it('Testing key method getSubkeys', async function() { const pubKey = await openpgp.readKey({ armoredKey: pub_sig_test }); expect(pubKey).to.exist; const packetlist = await openpgp.PacketList.fromBinary( (await openpgp.unarmor(pub_sig_test)).data, util.constructAllowedPackets([...Object.values(openpgp).filter(packetClass => !!packetClass.tag)]), openpgp.config ); const subkeyPackets = [packetlist[8], packetlist[11]]; const subkeys = await pubKey.getSubkeys(); expect(subkeys).to.exist; expect(subkeys).to.have.length(2); expect(subkeys[0].getKeyID().equals(subkeyPackets[0].getKeyID())).to.be.true; expect(subkeys[1].getKeyID().equals(subkeyPackets[1].getKeyID())).to.be.true; }); it('Verify status of revoked primary key', async function() { const pubKey = await openpgp.readKey({ armoredKey: pub_revoked_subkeys }); await expect(pubKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); }); it('Verify status of revoked subkey', async function() { const pubKey = await openpgp.readKey({ armoredKey: pub_sig_test }); expect(pubKey).to.exist; expect(pubKey.subkeys).to.exist; expect(pubKey.subkeys).to.have.length(2); await expect(pubKey.subkeys[0].verify()).to.be.rejectedWith('Subkey is revoked'); }); it('Verify status of key with non-self revocation signature', async function() { const { rejectPublicKeyAlgorithms } = openpgp.config; openpgp.config.rejectPublicKeyAlgorithms = new Set(); try { const pubKey = await openpgp.readKey({ armoredKey: key_with_revoked_third_party_cert }); const [selfCertification] = await pubKey.verifyPrimaryUser(); const publicSigningKey = await pubKey.getSigningKey(); expect(selfCertification.keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex()); expect(selfCertification.valid).to.be.true; const certifyingKey = await openpgp.readKey({ armoredKey: certifying_key }); const certifyingSigningKey = await certifyingKey.getSigningKey(); const signatures = await pubKey.verifyPrimaryUser([certifyingKey]); expect(signatures.length).to.equal(2); expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex()); expect(signatures[0].valid).to.be.null; expect(signatures[1].keyID.toHex()).to.equal(certifyingSigningKey.getKeyID().toHex()); expect(signatures[1].valid).to.be.false; const { user } = await pubKey.getPrimaryUser(); await expect(user.verifyCertificate(user.otherCertifications[0], [certifyingKey], undefined, openpgp.config)).to.be.rejectedWith('User certificate is revoked'); } finally { openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms; } }); it('Verify primary key with authorized revocation key in a direct-key signature', async function() { const pubKey = await openpgp.readKey({ armoredKey: key_with_authorized_revocation_key_in_separate_sig }); await pubKey.verifyPrimaryKey(); }); it('Verify certificate of key with future creation date', async function() { const pubKey = await openpgp.readKey({ armoredKey: key_created_2030 }); const user = pubKey.users[0]; await user.verifyCertificate(user.selfCertifications[0], [pubKey], pubKey.keyPacket.created, openpgp.config); const verifyAllResult = await user.verifyAllCertifications([pubKey], pubKey.keyPacket.created, openpgp.config); expect(verifyAllResult[0].valid).to.be.true; await user.verify(pubKey.keyPacket.created, openpgp.config); }); it('Evaluate key flags to find valid encryption key packet', async function() { const pubKey = await openpgp.readKey({ armoredKey: pub_sig_test }); // remove subkeys pubKey.subkeys = []; // primary key has only key flags for signing await expect(pubKey.getEncryptionKey()).to.be.rejectedWith('Could not find valid encryption key packet in key c076e634d32b498d'); }); it('should pad an ECDSA P-521 key with shorter secret key', async function() { const key = await openpgp.readKey({ armoredKey: shortP521Key }); // secret key should be padded expect(key.keyPacket.privateParams.d.length === 66); // sanity check await expect(key.validate()).to.be.fulfilled; }); it('should not decrypt using a sign-only RSA key, unless explicitly configured', async function () { const key = await openpgp.readKey({ armoredKey: rsaSignOnly }); await expect(openpgp.decrypt({ message: await openpgp.readMessage({ armoredMessage: encryptedRsaSignOnly }), decryptionKeys: key })).to.be.rejectedWith(/Session key decryption failed/); await expect(openpgp.decrypt({ message: await openpgp.readMessage({ armoredMessage: encryptedRsaSignOnly }), decryptionKeys: key, config: { allowInsecureDecryptionWithSigningKeys: true } })).to.be.fulfilled; }); it('Key.getExpirationTime()', async function() { const [, pubKey] = await openpgp.readKeys({ armoredKeys: twoKeys }); expect(pubKey).to.exist; expect(pubKey).to.be.an.instanceof(openpgp.PublicKey); const expirationTime = await pubKey.getExpirationTime(); expect(expirationTime.toISOString()).to.be.equal('2018-11-26T10:58:29.000Z'); }); it('Key.getExpirationTime() - expired key', async function() { const pubKey = await openpgp.readKey({ armoredKey: expiredKey }); expect(pubKey).to.exist; expect(pubKey).to.be.an.instanceof(openpgp.PublicKey); const expirationTime = await pubKey.getExpirationTime(); expect(expirationTime.toISOString()).to.be.equal('1970-01-01T00:22:18.000Z'); }); it('SubKey.getExpirationTime()', async function() { const [, pubKey] = await openpgp.readKeys({ armoredKeys: twoKeys }); expect(pubKey).to.exist; expect(pubKey).to.be.an.instanceof(openpgp.PublicKey); const expirationTime = await pubKey.subkeys[0].getExpirationTime(); expect(expirationTime.toISOString()).to.be.equal('2018-11-26T10:58:29.000Z'); }); it('Key.getExpirationTime() - never expiring key', async function() { const { minRSABits } = openpgp.config; try { openpgp.config.minRSABits = 1024; const privKey = await openpgp.readKey({ armoredKey: priv_key_2000_2008 }); const expirationTime = await privKey.getExpirationTime(); expect(expirationTime).to.equal(Infinity); } finally { openpgp.config.minRSABits = minRSABits; } }); it('Key.getExpirationTime() - key expiration in direct-key signature', async function() { const privKey = await openpgp.readKey({ armoredKey: expiredPublicKeyThroughDirectSignature }); const expirationTime = await privKey.getExpirationTime(); expect(expirationTime.toISOString()).to.equal('2020-06-13T14:57:14.000Z'); }); it("decryptKey() - throw if key parameters don't correspond", async function() { const privateKey = await openpgp.readKey({ armoredKey: mismatchingKeyParams }); await expect(openpgp.decryptKey({ privateKey, passphrase: 'userpass' })).to.be.rejectedWith('Key is invalid'); }); it("validate() - don't throw if key parameters correspond", async function() { const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519', format: 'object' }); await expect(key.validate()).to.not.be.rejected; }); it('validate() - throw if all-gnu-dummy key', async function() { const key = await openpgp.readKey({ armoredKey: gnuDummyKey }); await expect(key.validate()).to.be.rejectedWith('Cannot validate an all-gnu-dummy key'); }); it('validate() - gnu-dummy primary key with signing subkey', async function() { const key = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey }); await expect(key.validate()).to.not.be.rejected; }); it('validate() - gnu-dummy primary key with encryption subkey', async function() { const key = await openpgp.readKey({ armoredKey: dsaGnuDummyKeyWithElGamalSubkey }); await expect(key.validate()).to.not.be.rejected; }); it('validate() - curve ed25519 (eddsa) cannot be used for ecdsa', async function() { const key = await openpgp.readKey({ armoredKey: eddsaKeyAsEcdsa }); await expect(key.validate()).to.be.rejectedWith('Key is invalid'); }); it('isDecrypted() - should reflect whether all (sub)keys are encrypted', async function() { const passphrase = '12345678'; const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519', passphrase, format: 'object' }); expect(key.isDecrypted()).to.be.false; await key.subkeys[0].keyPacket.decrypt(passphrase); expect(key.isDecrypted()).to.be.true; }); it('isDecrypted() - gnu-dummy primary key', async function() { const key = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey }); expect(key.isDecrypted()).to.be.true; const encryptedKey = await openpgp.encryptKey({ privateKey: key, passphrase: '12345678' }); expect(encryptedKey.isDecrypted()).to.be.false; }); it('isDecrypted() - all-gnu-dummy key', async function() { const key = await openpgp.readKey({ armoredKey: gnuDummyKey }); expect(key.isDecrypted()).to.be.false; }); it('makeDummy() - the converted key can be parsed', async function() { const { privateKey: key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' }, format: 'object' }); key.keyPacket.makeDummy(); const parsedKeys = await openpgp.readKey({ armoredKey: key.armor() }); expect(parsedKeys).to.not.be.empty; }); it('makeDummy() - the converted key can be encrypted and decrypted', async function() { const { privateKey: key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' }, format: 'object' }); const passphrase = 'passphrase'; key.keyPacket.makeDummy(); expect(key.isDecrypted()).to.be.true; const encryptedKey = await openpgp.encryptKey({ privateKey: key, passphrase }); expect(encryptedKey.isDecrypted()).to.be.false; const decryptedKey = await openpgp.decryptKey({ privateKey: encryptedKey, passphrase }); expect(decryptedKey.isDecrypted()).to.be.true; }); it('makeDummy() - the converted key is valid but can no longer sign', async function() { const key = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); expect(key.keyPacket.isDummy()).to.be.false; key.keyPacket.makeDummy(); expect(key.keyPacket.isDummy()).to.be.true; await key.validate(); await expect(openpgp.reformatKey({ privateKey: key, userIDs: { name: 'test', email: 'a@b.com' } })).to.be.rejectedWith(/Cannot reformat a gnu-dummy primary key/); }); it('makeDummy() - subkeys of the converted key can still sign', async function() { const key = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); expect(key.keyPacket.isDummy()).to.be.false; key.keyPacket.makeDummy(); expect(key.keyPacket.isDummy()).to.be.true; await expect(openpgp.sign({ message: await openpgp.createMessage({ text: 'test' }), signingKeys: [key], config: { minRSABits: 1024 } })).to.be.fulfilled; }); it('makeDummy() - should work for encrypted keys', async function() { const passphrase = 'hello world'; const key = await openpgp.readKey({ armoredKey: priv_key_rsa }); expect(key.keyPacket.isDummy()).to.be.false; expect(key.keyPacket.makeDummy()).to.not.throw; expect(key.keyPacket.isDummy()).to.be.true; // dummy primary key should always be marked as not decrypted const decryptedKey = await openpgp.decryptKey({ privateKey: key, passphrase }); expect(decryptedKey.keyPacket.isDummy()).to.be.true; expect(decryptedKey.keyPacket.isEncrypted === null); expect(decryptedKey.keyPacket.isDecrypted()).to.be.false; const encryptedKey = await openpgp.encryptKey({ privateKey: decryptedKey, passphrase }); expect(encryptedKey.keyPacket.isDummy()).to.be.true; expect(encryptedKey.keyPacket.isEncrypted === null); expect(encryptedKey.keyPacket.isDecrypted()).to.be.false; // confirm that the converted keys can be parsed await openpgp.readKey({ armoredKey: encryptedKey.armor() }); await openpgp.readKey({ armoredKey: decryptedKey.armor() }); }); it('clearPrivateParams() - check that private key can no longer be used', async function() { const key = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); await key.clearPrivateParams(); await expect(key.validate()).to.be.rejectedWith('Key is not decrypted'); }); it('clearPrivateParams() - detect that private key parameters were removed', async function() { const key = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const signingKeyPacket = key.subkeys[0].keyPacket; const privateParams = signingKeyPacket.privateParams; await key.clearPrivateParams(); key.keyPacket.isEncrypted = false; key.keyPacket.privateParams = privateParams; key.subkeys[0].keyPacket.isEncrypted = false; key.subkeys[0].keyPacket.privateParams = privateParams; await expect(key.validate()).to.be.rejectedWith('Key is invalid'); }); it('clearPrivateParams() - detect that private key parameters were zeroed out', async function() { const key = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const signingKeyPacket = key.subkeys[0].keyPacket; const privateParams = {}; Object.entries(signingKeyPacket.privateParams).forEach(([name, value]) => { privateParams[name] = value; }); await key.clearPrivateParams(); key.keyPacket.isEncrypted = false; key.keyPacket.privateParams = privateParams; key.subkeys[0].keyPacket.isEncrypted = false; key.subkeys[0].keyPacket.privateParams = privateParams; await expect(key.validate()).to.be.rejectedWith('Key is invalid'); }); it('update() - throw error if fingerprints not equal', async function() { const keys = await openpgp.readKeys({ armoredKeys: twoKeys }); await expect(keys[0].update(keys[1])).to.be.rejectedWith(/Primary key fingerprints must be equal/); }); it('update() - merge revocation signatures', async function() { const source = await openpgp.readKey({ armoredKey: pub_revoked_subkeys }); const dest = await openpgp.readKey({ armoredKey: pub_revoked_subkeys }); expect(source.revocationSignatures).to.exist; dest.revocationSignatures = []; return dest.update(source).then(updated => { expect(updated.revocationSignatures[0]).to.exist.and.be.an.instanceof(openpgp.SignaturePacket); }); }); it('update() - merge user', async function() { const source = await openpgp.readKey({ armoredKey: pub_sig_test }); const dest = await openpgp.readKey({ armoredKey: pub_sig_test }); expect(source.users[1]).to.exist; dest.users.pop(); const updated = await dest.update(source); expect(updated.users[1]).to.exist; expect(updated.users[1].userID).to.equal(source.users[1].userID); expect(updated.users[1].selfCertifications.length).to.equal(source.users[1].selfCertifications.length); // check that the added users stores certifications separately updated.users[1].selfCertifications.pop(); expect(updated.users[1].selfCertifications.length).to.not.equal(source.users[1].selfCertifications.length); // merge self-signatures const updatedAgain = await updated.update(source); expect(updatedAgain.users[1].selfCertifications.length).to.equal(source.users[1].selfCertifications.length); }); it('update() - merge user - other and certification revocation signatures', async function() { const source = await openpgp.readKey({ armoredKey: pub_sig_test }); const dest = await openpgp.readKey({ armoredKey: pub_sig_test }); expect(source.users[1].otherCertifications).to.exist; expect(source.users[1].revocationSignatures).to.exist; dest.users[1].otherCertifications = []; dest.users[1].revocationSignatures.pop(); return dest.update(source).then(updated => { expect(updated.users[1].otherCertifications).to.exist.and.to.have.length(1); expect(updated.users[1].otherCertifications[0].signature).to.equal(source.users[1].otherCertifications[0].signature); expect(updated.users[1].revocationSignatures).to.exist.and.to.have.length(2); expect(updated.users[1].revocationSignatures[1].signature).to.equal(source.users[1].revocationSignatures[1].signature); }); }); it('update() - merge subkey', async function() { const source = await openpgp.readKey({ armoredKey: pub_sig_test }); const dest = await openpgp.readKey({ armoredKey: pub_sig_test }); expect(source.subkeys[1]).to.exist; dest.subkeys.pop(); const updated = await dest.update(source); expect(updated.subkeys[1]).to.exist; expect( updated.subkeys[1].getKeyID().toHex() ).to.equal( source.subkeys[1].getKeyID().toHex() ); expect(updated.subkeys[1].bindingSignatures.length).to.equal(source.subkeys[1].bindingSignatures.length); // check that the added subkey stores binding signatures separately updated.subkeys[1].bindingSignatures.pop(); expect(updated.subkeys[1].bindingSignatures.length).to.not.equal(source.subkeys[1].bindingSignatures.length); // merge binding signature const updatedAgain = await updated.update(source); expect(updatedAgain.subkeys[1].bindingSignatures.length).to.equal(source.subkeys[1].bindingSignatures.length); }); it('update() - merge subkey - revocation signature', async function() { const source = await openpgp.readKey({ armoredKey: pub_sig_test }); const dest = await openpgp.readKey({ armoredKey: pub_sig_test }); expect(source.subkeys[0].revocationSignatures).to.exist; dest.subkeys[0].revocationSignatures = []; return dest.update(source).then(updated => { expect(updated.subkeys[0].revocationSignatures).to.exist; expect(updated.subkeys[0].revocationSignatures[0].signature).to.equal(updated.subkeys[0].revocationSignatures[0].signature); }); }); it('update() - merge private key into public key', async function() { const source = await openpgp.readKey({ armoredKey: priv_key_rsa }); const [dest] = await openpgp.readKeys({ armoredKeys: twoKeys }); expect(dest.isPrivate()).to.be.false; return dest.update(source).then(async updated => { expect(updated.isPrivate()).to.be.true; return Promise.all([ updated.verifyPrimaryKey().then(async result => { await expect(source.verifyPrimaryKey()).to.eventually.equal(result); }), updated.users[0].verify(updated.keyPacket).then(async result => { await expect(source.users[0].verify(source.keyPacket)).to.eventually.equal(result); }), updated.subkeys[0].verify().then(async result => { await expect(source.subkeys[0].verify()).to.eventually.deep.equal(result); }) ]); }); }); it('update() - merge private key into public key - no subkeys', async function() { const source = await openpgp.readKey({ armoredKey: priv_key_rsa }); const [dest] = await openpgp.readKeys({ armoredKeys: twoKeys }); source.subkeys = []; dest.subkeys = []; expect(dest.isPrivate()).to.be.false; const updated = await dest.update(source); expect(updated.isPrivate()).to.be.true; await updated.verifyPrimaryKey(); await source.verifyPrimaryKey(); await updated.users[0].verify(updated.keyPacket); await source.users[0].verify(source.keyPacket); }); it('update() - merge private key into public key - mismatch throws error', async function() { const source = await openpgp.readKey({ armoredKey: priv_key_rsa }); const [dest] = await openpgp.readKeys({ armoredKeys: twoKeys }); source.subkeys = []; expect(dest.subkeys).to.exist; expect(dest.isPrivate()).to.be.false; await expect(dest.update(source)) .to.be.rejectedWith('Cannot update public key with private key if subkeys mismatch'); }); it('update() - merge subkey binding signatures', async function() { const source = await openpgp.readKey({ armoredKey: pgp_desktop_pub }); const dest = await openpgp.readKey({ armoredKey: pgp_desktop_priv }); expect(source.subkeys[0].bindingSignatures[0]).to.exist; await source.subkeys[0].verify(); expect(dest.subkeys[0].bindingSignatures[0]).to.not.exist; const updated = await dest.update(source); expect(updated.subkeys[0].bindingSignatures[0]).to.exist; // the source primary key should still verify the subkey updated.subkeys[0].mainKey = source; await updated.subkeys[0].verify(); updated.subkeys[0].mainKey = updated; }); it('update() - merge multiple subkey binding signatures', async function() { const source = await openpgp.readKey({ armoredKey: multipleBindingSignatures }); const dest = await openpgp.readKey({ armoredKey: multipleBindingSignatures }); // remove last subkey binding signature of destination subkey dest.subkeys[0].bindingSignatures.length = 1; expect((await source.subkeys[0].getExpirationTime()).toISOString()).to.equal('2015-10-18T07:41:30.000Z'); expect((await dest.subkeys[0].getExpirationTime()).toISOString()).to.equal('2018-09-07T06:03:37.000Z'); return dest.update(source).then(async updated => { expect(updated.subkeys[0].bindingSignatures.length).to.equal(1); // destination key gets new expiration date from source key which has newer subkey binding signature expect((await updated.subkeys[0].getExpirationTime()).toISOString()).to.equal('2015-10-18T07:41:30.000Z'); }); }); it('revoke() - primary key', async function() { const privKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), passphrase: 'hello world' }); await privKey.revoke({ flag: openpgp.enums.reasonForRevocation.keyRetired, string: 'Testing key revocation' }).then(async revKey => { expect(revKey.revocationSignatures).to.exist.and.have.length(1); expect(revKey.revocationSignatures[0].signatureType).to.equal(openpgp.enums.signature.keyRevocation); expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.keyRetired); expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('Testing key revocation'); await privKey.verifyPrimaryKey(); await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); }); }); it('revoke() - subkey', async function() { const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const privKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), passphrase: 'hello world' }); const subkey = pubKey.subkeys[0]; await subkey.revoke(privKey.keyPacket, { flag: openpgp.enums.reasonForRevocation.keySuperseded }).then(async revKey => { expect(revKey.revocationSignatures).to.exist.and.have.length(1); expect(revKey.revocationSignatures[0].signatureType).to.equal(openpgp.enums.signature.subkeyRevocation); expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.keySuperseded); expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal(''); await subkey.verify(); await expect(revKey.verify()).to.be.rejectedWith('Subkey is revoked'); }); }); it('applyRevocationCertificate() should produce the same revoked key as GnuPG', async function() { const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm4 }); return pubKey.applyRevocationCertificate(revocation_certificate_arm4).then(async revKey => { expect(revKey.armor()).to.equal((await openpgp.readKey({ armoredKey: revoked_key_arm4 })).armor()); }); }); it('getRevocationCertificate() should produce the same revocation certificate as GnuPG', async function() { const revKey = await openpgp.readKey({ armoredKey: revoked_key_arm4 }); const revocationCertificate = await revKey.getRevocationCertificate(); const input = await openpgp.unarmor(revocation_certificate_arm4); const packetlist = await openpgp.PacketList.fromBinary(input.data, util.constructAllowedPackets([openpgp.SignaturePacket]), openpgp.config); const armored = openpgp.armor(openpgp.enums.armor.publicKey, packetlist.write()); expect(revocationCertificate.replace(/^Comment: .*$\n/mg, '')).to.equal(armored.replace(/^Comment: .*$\n/mg, '')); }); it('getRevocationCertificate() should have an appropriate comment', async function() { const revKey = await openpgp.readKey({ armoredKey: revoked_key_arm4 }); const revocationCertificate = await revKey.getRevocationCertificate(); expect(revocationCertificate).to.match(/Comment: This is a revocation certificate/); expect(revKey.armor()).not.to.match(/Comment: This is a revocation certificate/); }); it("getPreferredAlgo('symmetric') - one key", async function() { const [key1] = await openpgp.readKeys({ armoredKeys: twoKeys }); const prefAlgo = await getPreferredAlgo('symmetric', [key1], undefined, undefined, { ...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes256 }); expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256); }); it("getPreferredAlgo('symmetric') - two key", async function() { const { aes128, aes192, cast5 } = openpgp.enums.symmetric; const [key1, key2] = await openpgp.readKeys({ armoredKeys: twoKeys }); const primaryUser = await key2.getPrimaryUser(); primaryUser.selfCertification.preferredSymmetricAlgorithms = [6, aes192, cast5]; const prefAlgo = await getPreferredAlgo('symmetric', [key1, key2], undefined, undefined, { ...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes192 }); expect(prefAlgo).to.equal(aes192); const prefAlgo2 = await getPreferredAlgo('symmetric', [key1, key2], undefined, undefined, { ...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes256 }); expect(prefAlgo2).to.equal(aes128); }); it("getPreferredAlgo('symmetric') - two key - one without pref", async function() { const [key1, key2] = await openpgp.readKeys({ armoredKeys: twoKeys }); const primaryUser = await key2.getPrimaryUser(); primaryUser.selfCertification.preferredSymmetricAlgorithms = null; const prefAlgo = await getPreferredAlgo('symmetric', [key1, key2]); expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128); }); it("getPreferredAlgo('aead') - one key - OCB", async function() { const [key1] = await openpgp.readKeys({ armoredKeys: twoKeys }); const primaryUser = await key1.getPrimaryUser(); primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag primaryUser.selfCertification.preferredAEADAlgorithms = [2,1]; const prefAlgo = await getPreferredAlgo('aead', [key1], undefined, undefined, { ...openpgp.config, preferredAEADAlgorithm: openpgp.enums.aead.ocb }); expect(prefAlgo).to.equal(openpgp.enums.aead.ocb); const supported = await isAEADSupported([key1]); expect(supported).to.be.true; }); it("getPreferredAlgo('aead') - two key - one without pref", async function() { const keys = await openpgp.readKeys({ armoredKeys: twoKeys }); const key1 = keys[0]; const key2 = keys[1]; const primaryUser = await key1.getPrimaryUser(); primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag primaryUser.selfCertification.preferredAEADAlgorithms = [2,1]; const primaryUser2 = await key2.getPrimaryUser(); primaryUser2.selfCertification.features = [7]; // Monkey-patch AEAD feature flag const prefAlgo = await getPreferredAlgo('aead', [key1, key2]); expect(prefAlgo).to.equal(openpgp.enums.aead.eax); const supported = await isAEADSupported([key1, key2]); expect(supported).to.be.true; }); it("getPreferredAlgo('aead') - two key - one with no support", async function() { const keys = await openpgp.readKeys({ armoredKeys: twoKeys }); const key1 = keys[0]; const key2 = keys[1]; const primaryUser = await key1.getPrimaryUser(); primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag primaryUser.selfCertification.preferredAEADAlgorithms = [2,1]; const prefAlgo = await getPreferredAlgo('aead', [key1, key2]); expect(prefAlgo).to.equal(openpgp.enums.aead.eax); const supported = await isAEADSupported([key1, key2]); expect(supported).to.be.false; }); it('User attribute packet read & write', async function() { const key = await openpgp.readKey({ armoredKey: user_attr_key }); const key2 = await openpgp.readKey({ armoredKey: key.armor() }); expect(key.users[1].userAttribute).eql(key2.users[1].userAttribute); }); it('getPrimaryUser()', async function() { const key = await openpgp.readKey({ armoredKey: pub_sig_test }); const primUser = await key.getPrimaryUser(); expect(primUser).to.exist; expect(primUser.user.userID.userID).to.equal('Signature Test '); expect(primUser.user.userID.name).to.equal('Signature Test'); expect(primUser.user.userID.email).to.equal('signature@test.com'); expect(primUser.user.userID.comment).to.equal(''); expect(primUser.selfCertification).to.be.an.instanceof(openpgp.SignaturePacket); }); it('getPrimaryUser() should throw if no UserIDs are bound', async function() { const keyWithoutUserID = `-----BEGIN PGP PRIVATE KEY BLOCK----- xVgEWxpFkRYJKwYBBAHaRw8BAQdAYjjZLkp4qG7KAqJeVQlxQT6uCPq6rylV02nC c6D/a8YAAP0YtS4UeLzeJGSgjGTlvSd3TWEsjxdGyzwfHCOejXMRbg2+zSFVbmJv dW5kIFVJRCA8dW5ib3VuZEBleGFtcGxlLm9yZz7HXQRbGkWREgorBgEEAZdVAQUB AQdAfxbFuoNlm5KfoqaWICETfMljzVTDAtiSM0TYSHzGAz8DAQoJAAD/cuu7bxUE goBAhIyVH+pmvWpuDJbfu1Vaj5KiQxsKxJgP/MJ+BBgWCgAwApsMBYJbGkWRBYkB 3+IAFqEE30YL4fxJBMTm8ONLPOiTkVxEIS8JkDzok5FcRCEvAABb+gEAnQb/rMLO Vz/bMCJoAShgybW1r6kRWejybzIjFSLnx/YA/iLZeo5UNdlXRJco+15RbFiNSAbw VYGdb3eNlV8CfoEC =FYbP -----END PGP PRIVATE KEY BLOCK-----`; const key = await openpgp.readKey({ armoredKey: keyWithoutUserID }); await expect(key.getPrimaryUser()).to.be.rejectedWith('Could not find valid self-signature in key 3ce893915c44212f'); }); it('Generate session key - latest created user', async function() { const publicKey = await openpgp.readKey({ armoredKey: multi_uid_key }); // Set second user to prefer aes128. We should select this user by default, since it was created later. publicKey.users[1].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128]; const sessionKey = await openpgp.generateSessionKey({ encryptionKeys: publicKey }); expect(sessionKey.algorithm).to.equal('aes128'); }); it('Generate session key - primary user', async function() { const publicKey = await openpgp.readKey({ armoredKey: multi_uid_key }); // Set first user to primary. We should select this user by default. publicKey.users[0].selfCertifications[0].isPrimaryUserID = true; // Set first user to prefer aes128. publicKey.users[0].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128]; const sessionKey = await openpgp.generateSessionKey({ encryptionKeys: publicKey }); expect(sessionKey.algorithm).to.equal('aes128'); }); it('Generate session key - specific user', async function() { const publicKey = await openpgp.readKey({ armoredKey: multi_uid_key }); const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); // Set first user to primary. We won't select this user, this is to test that. publicKey.users[0].selfCertifications[0].isPrimaryUserID = true; // Set second user to prefer aes128. We will select this user. publicKey.users[1].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128]; const sessionKey = await openpgp.generateSessionKey({ encryptionKeys: publicKey, encryptionUserIDs: { name: 'Test User', email: 'b@c.com' } }); expect(sessionKey.algorithm).to.equal('aes128'); const config = { minRSABits: 1024 }; await openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, encryptionUserIDs: { name: 'Test User', email: 'b@c.com' }, armor: false, config }); await expect(openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, encryptionUserIDs: { name: 'Test User', email: 'c@c.com' }, armor: false, config })).to.be.rejectedWith('Could not find user that matches that user ID'); }); it('Fails to encrypt to User ID-less key', async function() { const publicKey = await openpgp.readKey({ armoredKey: uidlessKey }); expect(publicKey.users.length).to.equal(0); const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: uidlessKey }), passphrase: 'correct horse battery staple' }); await expect(openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, armor: false })).to.be.rejectedWith('Could not find primary user'); }); it('Sign - specific user', async function() { const publicKey = await openpgp.readKey({ armoredKey: multi_uid_key }); const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const privateKeyClone = await openpgp.readKey({ armoredKey: priv_key_rsa }); // Duplicate user privateKey.users.push(privateKeyClone.users[0]); // Set first user to primary. We won't select this user, this is to test that. privateKey.users[0].selfCertifications[0].isPrimaryUserID = true; // Change userID of the first user so that we don't select it. This also makes this user invalid. privateKey.users[0].userID = openpgp.UserIDPacket.fromObject({ name: 'Test User', email: 'b@c.com' }); // Set second user to prefer aes128. We will select this user. privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512]; const config = { minRSABits: 1024 }; const signed = await openpgp.sign({ message: await openpgp.createMessage({ text: 'hello' }), signingKeys: privateKey, signingUserIDs: { name: 'Test McTestington', email: 'test@example.com' }, armor: false, config }); const signature = await openpgp.readMessage({ binaryMessage: signed }); expect(signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512); const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), passwords: 'test', signingKeys: privateKey, signingUserIDs: { name: 'Test McTestington', email: 'test@example.com' }, armor: false, config }); const { signatures } = await openpgp.decrypt({ message: await openpgp.readMessage({ binaryMessage: encrypted }), passwords: 'test' }); expect(signatures[0].signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512); await expect(openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, signingUserIDs: { name: 'Not Test McTestington', email: 'test@example.com' }, armor: false, config })).to.be.rejectedWith('Could not find user that matches that user ID'); }); it('Find a valid subkey binding signature among many invalid ones', async function() { const key = await openpgp.readKey({ armoredKey: valid_binding_sig_among_many_expired_sigs_pub }); expect(await key.getEncryptionKey(undefined, undefined, undefined, { ...openpgp.config, minRSABits: 1024 })).to.not.be.null; }); it('Selects the most recent subkey binding signature', async function() { const key = await openpgp.readKey({ armoredKey: multipleBindingSignatures }); expect((await key.subkeys[0].getExpirationTime()).toISOString()).to.equal('2015-10-18T07:41:30.000Z'); }); it('Selects the most recent non-expired subkey binding signature', async function() { const key = await openpgp.readKey({ armoredKey: multipleBindingSignatures }); key.subkeys[0].bindingSignatures[1].signatureNeverExpires = false; key.subkeys[0].bindingSignatures[1].signatureExpirationTime = 0; expect((await key.subkeys[0].getExpirationTime()).toISOString()).to.equal('2018-09-07T06:03:37.000Z'); }); it('Selects the most recent valid subkey binding signature', async function() { const key = await openpgp.readKey({ armoredKey: multipleBindingSignatures }); key.subkeys[0].bindingSignatures[1].signatureData[0]++; expect((await key.subkeys[0].getExpirationTime()).toISOString()).to.equal('2018-09-07T06:03:37.000Z'); }); it('Handles a key with no valid subkey binding signatures gracefully', async function() { const key = await openpgp.readKey({ armoredKey: multipleBindingSignatures }); key.subkeys[0].bindingSignatures[0].signatureData[0]++; key.subkeys[0].bindingSignatures[1].signatureData[0]++; expect(await key.subkeys[0].getExpirationTime()).to.be.null; }); it('Reject encryption with revoked primary user', async function() { const key = await openpgp.readKey({ armoredKey: pub_revoked_subkeys }); return openpgp.encrypt({ encryptionKeys: [key], message: await openpgp.createMessage({ text: 'random data' }) }).then(() => { throw new Error('encryptSessionKey should not encrypt with revoked public key'); }).catch(function(error) { expect(error.message).to.equal('Error encrypting message: Primary user is revoked'); }); }); it('Reject encryption with revoked subkey', async function() { const key = await openpgp.readKey({ armoredKey: pub_revoked_subkeys }); key.revocationSignatures = []; key.users[0].revocationSignatures = []; return openpgp.encrypt({ encryptionKeys: [key], message: await openpgp.createMessage({ text: 'random data' }), date: new Date(1386842743000) }).then(() => { throw new Error('encryptSessionKey should not encrypt with revoked public key'); }).catch(error => { expect(error.message).to.equal('Error encrypting message: Could not find valid encryption key packet in key ' + key.getKeyID().toHex() + ': Subkey is revoked'); }); }); it('Reject encryption with key revoked with appended revocation cert', async function() { const key = await openpgp.readKey({ armoredKey: pub_revoked_with_cert }); return openpgp.encrypt({ encryptionKeys: [key], message: await openpgp.createMessage({ text: 'random data' }) }).then(() => { throw new Error('encryptSessionKey should not encrypt with revoked public key'); }).catch(function(error) { expect(error.message).to.equal('Error encrypting message: Primary key is revoked'); }); }); it('Merge key with another key with non-ID user attributes', async function() { const key = await openpgp.readKey({ armoredKey: mergeKey1 }); const updateKey = await openpgp.readKey({ armoredKey: mergeKey2 }); expect(key).to.exist; expect(updateKey).to.exist; expect(key.users).to.have.length(1); return key.update(updateKey).then(updated => { expect(updated.getFingerprint()).to.equal(updateKey.getFingerprint()); expect(updated.users).to.have.length(2); expect(updated.users[1].userID).to.be.null; }); }); it("Should throw when trying to encrypt a key that's already encrypted", async function() { const passphrase = 'hello world'; const key = await openpgp.readKey({ armoredKey: priv_key_rsa }); const decryptedKey = await openpgp.decryptKey({ privateKey: key, passphrase }); const encryptedKey = await openpgp.encryptKey({ privateKey: decryptedKey, passphrase }); await expect(openpgp.encryptKey({ privateKey: encryptedKey, passphrase })).to.be.eventually.rejectedWith(/Key packet is already encrypted/); }); describe('addSubkey functionality testing', function() { const rsaBits = 1024; let minRSABits; beforeEach(function() { minRSABits = openpgp.config.minRSABits; openpgp.config.minRSABits = rsaBits; }); afterEach(function() { openpgp.config.minRSABits = minRSABits; }); it('create and add a new rsa subkey to stored rsa key', async function() { const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const total = privateKey.subkeys.length; let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' }); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); const subkey = newPrivateKey.subkeys[total]; expect(subkey).to.exist; expect(newPrivateKey.subkeys.length).to.be.equal(total + 1); const subkeyN = subkey.keyPacket.publicParams.n; const pkN = privateKey.keyPacket.publicParams.n; expect(subkeyN.length).to.be.equal(pkN.length); expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign'); expect(subkey.getAlgorithmInfo().bits).to.be.equal(privateKey.getAlgorithmInfo().bits); await subkey.verify(); }); it('Add a new default subkey to an rsaSign key', async function() { const userID = { name: 'test', email: 'a@b.com' }; const opt = { type: 'rsa', rsaBits, userIDs: [userID], format: 'object', subkeys: [] }; const { privateKey: key } = await openpgp.generateKey(opt); expect(key.subkeys).to.have.length(0); key.getAlgorithmInfo().algorithm = 'rsaSign'; const newKey = await key.addSubkey(); expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign'); }); it('Add a new default subkey to an ecc key', async function() { const userID = { name: 'test', email: 'a@b.com' }; const opt = { type: 'ecc', userIDs: [userID], format: 'object', subkeys: [] }; const { privateKey: key } = await openpgp.generateKey(opt); expect(key.subkeys).to.have.length(0); const newKey = await key.addSubkey(); expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519'); }); it('Add a new default subkey to a dsa key', async function() { const key = await openpgp.readKey({ armoredKey: dsaPrivateKey }); const total = key.subkeys.length; const newKey = await key.addSubkey(); expect(newKey.subkeys[total].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign'); expect(newKey.subkeys[total].getAlgorithmInfo().bits).to.equal(Math.max(key.getAlgorithmInfo().bits, openpgp.config.minRSABits)); }); it('should throw when trying to encrypt a subkey separately from key', async function() { const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const opt = { rsaBits: rsaBits, passphrase: 'subkey passphrase' }; await expect(privateKey.addSubkey(opt)).to.be.rejectedWith('Subkey could not be encrypted here, please encrypt whole key'); }); it('encrypt and decrypt key with added subkey', async function() { const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const total = privateKey.subkeys.length; const passphrase = '12345678'; const newPrivateKey = await privateKey.addSubkey({ type: 'rsa' }); const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase }); expect(encNewPrivateKey.subkeys.length).to.be.equal(total + 1); const armoredKey = encNewPrivateKey.armor(); const importedPrivateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey }), passphrase }); const subkey = importedPrivateKey.subkeys[total]; expect(subkey).to.exist; expect(importedPrivateKey.subkeys.length).to.be.equal(total + 1); await subkey.verify(); }); it('create and add a new eddsa subkey to a eddsa key', async function() { const passphrase = '12345678'; const userID = { name: 'test', email: 'a@b.com' }; const { privateKey } = await openpgp.generateKey({ curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] }); const total = privateKey.subkeys.length; let newPrivateKey = await privateKey.addSubkey({ curve: 'curve25519', userIDs: [userID], sign: true }); const subkey1 = newPrivateKey.subkeys[total]; const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase }); newPrivateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: encNewPrivateKey.armor() }), passphrase }); const subkey2 = newPrivateKey.subkeys[total]; expect(subkey2.isDecrypted()).to.be.true; expect(subkey1.getKeyID().toHex()).to.be.equal(subkey2.getKeyID().toHex()); expect(subkey2).to.exist; expect(newPrivateKey.subkeys.length).to.be.equal(total + 1); const subkeyOid = subkey2.keyPacket.publicParams.oid; const pkOid = privateKey.keyPacket.publicParams.oid; expect(subkeyOid.getName()).to.be.equal(pkOid.getName()); expect(subkey2.getAlgorithmInfo().algorithm).to.be.equal('eddsa'); await subkey2.verify(); }); it('create and add a new ecdsa subkey to a eddsa key', async function() { const userID = { name: 'test', email: 'a@b.com' }; const { privateKey } = await openpgp.generateKey({ curve: 'ed25519', userIDs: [userID], format: 'object', subkeys:[] }); const total = privateKey.subkeys.length; let newPrivateKey = await privateKey.addSubkey({ curve: 'p256', sign: true }); newPrivateKey = await openpgp.readKey({ armoredKey: newPrivateKey.armor() }); const subkey = newPrivateKey.subkeys[total]; expect(subkey).to.exist; expect(newPrivateKey.subkeys.length).to.be.equal(total + 1); expect(newPrivateKey.getAlgorithmInfo().curve).to.be.equal('ed25519'); expect(subkey.getAlgorithmInfo().curve).to.be.equal('p256'); expect(newPrivateKey.getAlgorithmInfo().algorithm).to.be.equal('eddsa'); expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('ecdsa'); await subkey.verify(); }); it('create and add a new ecc subkey to a rsa key', async function() { const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const total = privateKey.subkeys.length; const opt2 = { type: 'ecc', curve: 'curve25519' }; let newPrivateKey = await privateKey.addSubkey(opt2); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); expect(newPrivateKey.subkeys.length).to.be.equal(total + 1); const subkey = newPrivateKey.subkeys[total]; expect(subkey).to.exist; expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('ecdh'); expect(subkey.getAlgorithmInfo().curve).to.be.equal(openpgp.enums.curve.curve25519); await subkey.verify(); }); it('create and add a new rsa subkey to a ecc key', async function() { const userID = { name: 'test', email: 'a@b.com' }; const opt = { curve: 'ed25519', userIDs: [userID], format: 'object', subkeys:[] }; const { privateKey } = await openpgp.generateKey(opt); const total = privateKey.subkeys.length; let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' }); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey }); const subkey = newPrivateKey.subkeys[total]; expect(subkey).to.exist; expect(newPrivateKey.subkeys.length).to.be.equal(total + 1); expect(subkey.getAlgorithmInfo().bits).to.be.equal(4096); expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign'); await subkey.verify(); }); it('create and add a new rsa subkey to a dsa key', async function() { const privateKey = await openpgp.readKey({ armoredKey: dsaPrivateKey }); const total = privateKey.subkeys.length; let newPrivateKey = await privateKey.addSubkey({ type: 'rsa', rsaBits: 2048 }); newPrivateKey = await openpgp.readKey({ armoredKey: newPrivateKey.armor() }); expect(newPrivateKey.subkeys.length).to.be.equal(total + 1); const subkey = newPrivateKey.subkeys[total]; expect(subkey).to.exist; expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign'); expect(subkey.getAlgorithmInfo().bits).to.be.equal(2048); await subkey.verify(); }); it('sign/verify data with the new subkey correctly using curve25519', async function() { const userID = { name: 'test', email: 'a@b.com' }; const opt = { curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] }; const { privateKey } = await openpgp.generateKey(opt); const total = privateKey.subkeys.length; const opt2 = { sign: true }; let newPrivateKey = await privateKey.addSubkey(opt2); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); const subkey = newPrivateKey.subkeys[total]; const subkeyOid = subkey.keyPacket.publicParams.oid; const pkOid = newPrivateKey.keyPacket.publicParams.oid; expect(subkeyOid.getName()).to.be.equal(pkOid.getName()); expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('eddsa'); await subkey.verify(); expect(await newPrivateKey.getSigningKey()).to.be.equal(subkey); const signed = await openpgp.sign({ message: await openpgp.createMessage({ text: 'the data to signed' }), signingKeys: newPrivateKey, armor:false }); const message = await openpgp.readMessage({ binaryMessage: signed }); const { signatures } = await openpgp.verify({ message, verificationKeys: [newPrivateKey.toPublic()] }); expect(signatures).to.exist; expect(signatures.length).to.be.equal(1); expect(signatures[0].keyID.toHex()).to.be.equal(subkey.getKeyID().toHex()); expect(await signatures[0].verified).to.be.true; }); it('encrypt/decrypt data with the new subkey correctly using curve25519', async function() { const userID = { name: 'test', email: 'a@b.com' }; const vData = 'the data to encrypted!'; const opt = { curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] }; const { privateKey } = await openpgp.generateKey(opt); const total = privateKey.subkeys.length; let newPrivateKey = await privateKey.addSubkey(); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); const subkey = newPrivateKey.subkeys[total]; const publicKey = newPrivateKey.toPublic(); await subkey.verify(); expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey); const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: vData }), encryptionKeys: publicKey, armor:false }); expect(encrypted).to.be.exist; const message = await openpgp.readMessage({ binaryMessage: encrypted }); const pkSessionKeys = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey); expect(pkSessionKeys).to.exist; expect(pkSessionKeys.length).to.be.equal(1); expect(pkSessionKeys[0].publicKeyID.toHex()).to.be.equals(subkey.keyPacket.getKeyID().toHex()); const decrypted = await openpgp.decrypt({ message, decryptionKeys: newPrivateKey }); expect(decrypted).to.exist; expect(decrypted.data).to.be.equal(vData); }); it('sign/verify data with the new subkey correctly using rsa', async function() { const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const total = privateKey.subkeys.length; const opt2 = { sign: true, rsaBits: rsaBits }; let newPrivateKey = await privateKey.addSubkey(opt2); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); const subkey = newPrivateKey.subkeys[total]; expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign'); await subkey.verify(); expect(await newPrivateKey.getSigningKey()).to.be.equal(subkey); const signed = await openpgp.sign({ message: await openpgp.createMessage({ text: 'the data to signed' }), signingKeys: newPrivateKey, armor:false }); const message = await openpgp.readMessage({ binaryMessage: signed }); const { signatures } = await openpgp.verify({ message, verificationKeys: [newPrivateKey.toPublic()] }); expect(signatures).to.exist; expect(signatures.length).to.be.equal(1); expect(signatures[0].keyID.toHex()).to.be.equal(subkey.getKeyID().toHex()); expect(await signatures[0].verified).to.be.true; }); it('encrypt/decrypt data with the new subkey correctly using rsa', async function() { const privateKey = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); const total = privateKey.subkeys.length; let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' }); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); const subkey = newPrivateKey.subkeys[total]; const publicKey = newPrivateKey.toPublic(); const vData = 'the data to encrypted!'; expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey); const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: vData }), encryptionKeys: publicKey, armor:false }); expect(encrypted).to.be.exist; const message = await openpgp.readMessage({ binaryMessage: encrypted }); const pkSessionKeys = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey); expect(pkSessionKeys).to.exist; expect(pkSessionKeys.length).to.be.equal(1); expect(pkSessionKeys[0].publicKeyID.toHex()).to.be.equals(subkey.keyPacket.getKeyID().toHex()); const decrypted = await openpgp.decrypt({ message, decryptionKeys: newPrivateKey }); expect(decrypted).to.exist; expect(decrypted.data).to.be.equal(vData); }); }); it('Subkey.verify returns the latest valid signature', async function () { const { privateKey: encryptionKey } = await openpgp.generateKey({ userIDs: { name: 'purple' }, format: 'object' }); const encryptionKeySignature = await encryptionKey.getSubkeys()[0].verify(); expect(encryptionKeySignature instanceof openpgp.SignaturePacket).to.be.true; expect(encryptionKeySignature.keyFlags[0] & openpgp.enums.keyFlags.encryptCommunication).to.be.equals(openpgp.enums.keyFlags.encryptCommunication); expect(encryptionKeySignature.keyFlags[0] & openpgp.enums.keyFlags.encryptStorage).to.be.equals(openpgp.enums.keyFlags.encryptStorage); const { privateKey: signingKey } = await openpgp.generateKey({ userIDs: { name: 'purple' }, format: 'object', subkeys: [{ sign: true }] }); const signingKeySignature = await signingKey.getSubkeys()[0].verify(); expect(signingKeySignature instanceof openpgp.SignaturePacket).to.be.true; expect(signingKeySignature.keyFlags[0] & openpgp.enums.keyFlags.signData).to.be.equals(openpgp.enums.keyFlags.signData); }); });