mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-06-09 07:36:42 +00:00

RFC9580 says that: Argon2 is only used with AEAD (S2K usage octet 253). An implementation MUST NOT create and MUST reject as malformed any secret key packet where the S2K usage octet is not AEAD (253) and the S2K specifier type is Argon2. Therefore, we disallow reading and writing Argon2 keys without AEAD. And: [The Simple and Salted S2K methods] are used only for reading in backwards compatibility mode. Since v6 keys don't need backwards compatibility, we also disallow reading Simple S2K there. We still allow reading Salted S2K since the spec says it may be used "when [the password] is high entropy".
5071 lines
242 KiB
JavaScript
5071 lines
242 KiB
JavaScript
/* eslint-disable max-lines */
|
||
/* globals tryTests, loadStreamsPolyfill */
|
||
import sinon from 'sinon';
|
||
import * as stream from '@openpgp/web-stream-tools';
|
||
import { use as chaiUse, expect } from 'chai';
|
||
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
|
||
chaiUse(chaiAsPromised);
|
||
|
||
import openpgp from '../initOpenpgp.js';
|
||
import crypto from '../../src/crypto';
|
||
import * as random from '../../src/crypto/random.js';
|
||
import util from '../../src/util.js';
|
||
import keyIDType from '../../src/type/keyid.js';
|
||
import { getPreferredCipherSuite } from '../../src/key';
|
||
|
||
import * as input from './testInputs.js';
|
||
|
||
const detectBrowser = () => typeof navigator === 'object';
|
||
|
||
const pub_key = [
|
||
'-----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 priv_key = [
|
||
'-----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_de = [
|
||
'-----BEGIN PGP PUBLIC KEY BLOCK-----',
|
||
'Version: GnuPG v2.0.22 (GNU/Linux)',
|
||
'',
|
||
'mQMuBFLVgdQRCACOlpq0cd1IazNjOEpWPZvx/O3JMbdDs3B3iCG0Mo5OUZ8lpKU5',
|
||
'EslVgTd8IcUU14ZMOO7y91dw0KP4q61b4OIy7oVxzfFfKCC1s0Dc7GTay+qo5afJ',
|
||
'wbWcgTyCIahTRmi5UepU7xdRHRMlqAclOwY2no8fw0JRQfFwRFCjbMdmvzC/k+Wo',
|
||
'A42nn8YaSAG2v7OqF3rkYjkv/7iak48PO/l0Q13USAJLIWdHvRTir78mQUsEY0qR',
|
||
'VoNqz5sMqakzhTvTav07EVy/1xC6GKoWXA9sdB/4r7+blVuu9M4yD40GkE69oAXO',
|
||
'mz6tG3lRq41S0OSzNyDWtUQgMVF6wYqVxUGrAQDJM5A1rF1RKzFiHdkyy57E8LC1',
|
||
'SIJyIXWJ0c5b8/olWQf9G5a17fMjkRTC3FO+ZHwFE1jIM6znYOF2GltDToLuJPq9',
|
||
'lWrI7zVP9AJPwrUt7FK2MBNAvd1jKyIhdU98PBQ2pr+jmyqIycl9iDGXLDO7D7E/',
|
||
'TBnxwQzoL/5b7UnPImuXOwv5JhVmyV2t003xjzb1EGggOnpKugUtVLps8JiLl9n+',
|
||
'Nkj5wpU7NXbuHj2XGkkGmKkCIz4l0dJQR9V6svJV9By0RPgfGPXlN1VR6f2ounNy',
|
||
'6REnDCQP9S3Li5eNcxlSGDIxIZL22j63sU/68GVlzqhVdGXxofv5jGtajiNSpPot',
|
||
'ElZU0dusna4PzYmiBCsyN8jENWSzHLJ37N4ScN4b/gf6Axf9FU0PjzPBN1o9W6zj',
|
||
'kpfhlSWDjE3BK8jJ7KvzecM2QE/iJsbuyKEsklw1v0MsRDsox5QlQJcKOoUHC+OT',
|
||
'iKm8cnPckLQNPOw/kb+5Auz7TXBQ63dogDuqO8QGGOpjh8SIYbblYQI5ueo1Tix3',
|
||
'PlSU36SzOQfxSOCeIomEmaFQcU57O1CLsRl//+5lezMFDovJyQHQZfiTxSGfPHij',
|
||
'oQzEUyEWYHKQhIRV6s5VGvF3hN0t8fo0o57bzhV6E7IaSz2Cnm0O0S2PZt8DBN9l',
|
||
'LYNw3cFgzMb/qdFJGR0JXz+moyAYh/fYMiryb6d8ghhvrRy0CrRlC3U5K6qiYfKu',
|
||
'lLQURFNBL0VMRyA8ZHNhQGVsZy5qcz6IewQTEQgAIwUCUtWB1AIbAwcLCQgHAwIB',
|
||
'BhUIAgkKCwQWAgMBAh4BAheAAAoJELqZP8Ku4Yo6Aa0A/1Kz5S8d9czLiDbrhSa/',
|
||
'C1rQ5qiWpFq9UNTFg2P/gASvAP92TzUMLK2my8ew1xXShtrfXked5fkSuFrPlZBs',
|
||
'b4Ta67kCDQRS1YHUEAgAxOKx4y5QD78uPLlgNBHXrcncUNBIt4IXBGjQTxpFcn5j',
|
||
'rSuj+ztvXJQ8wCkx+TTb2yuL5M+nXd7sx4s+M4KZ/MZfI6ZX4lhcoUdAbB9FWiV7',
|
||
'uNntyeFo8qgGM5at/Q0EsyzMSqbeBxk4bpd5MfYGThn0Ae2xaw3X94KaZ3LjtHo2',
|
||
'V27FD+jvmmoAj9b1+zcO/pJ8SuojQmcnS4VDVV+Ba5WPTav0LzDdQXyGMZI9PDxC',
|
||
'jAI2f1HjTuxIt8X8rAQSQdoMIcQRYEjolsXS6iob1eVigyL86hLJjI3VPn6kBCv3',
|
||
'Tb+WXX+9LgSAt9yvv4HMwBLK33k6IH7M72SqQulZywADBQgAt2xVTMjdVyMniMLj',
|
||
'Ed4HbUgwyCPkVkcA4zTXqfKu+dAe4dK5tre0clkXZVtR1V8RDAD0zaVyM030e2zb',
|
||
'zn4cGKDL2dmwk2ZBeXWZDgGKoKvGKYf8PRpTAYweFzol3OUdfXH5SngOylCD4OCL',
|
||
's4RSVkSsllIWqLpnS5IJFgt6PDVcQgGXo2ZhVYkoLNhWTIEBuJWIyc4Vj20YpTms',
|
||
'lgHnjeq5rP6781MwAJQnViyJ2SziGK4/+3CoDiQLO1zId42otXBvsbUuLSL5peX4',
|
||
'v2XNVMLJMY5iSfzbBWczecyapiQ3fbVtWgucgrqlrqM3546v+GdATBhGOu8ppf5j',
|
||
'7d1A7ohhBBgRCAAJBQJS1YHUAhsMAAoJELqZP8Ku4Yo6SgoBAIVcZstwz4lyA2et',
|
||
'y61IhKbJCOlQxyem+kepjNapkhKDAQDIDL38bZWU4Rm0nq82Xb4yaI0BCWDcFkHV',
|
||
'og2umGfGng==',
|
||
'=v3+L',
|
||
'-----END PGP PUBLIC KEY BLOCK-----'
|
||
].join('\n');
|
||
|
||
const priv_key_de = [
|
||
'-----BEGIN PGP PRIVATE KEY BLOCK-----',
|
||
'Version: GnuPG v2.0.22 (GNU/Linux)',
|
||
'',
|
||
'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',
|
||
'DHTORVqAOdoOcu5Qh7AQg1GdSmfFAsx2',
|
||
'=kyeP',
|
||
'-----END PGP PRIVATE KEY BLOCK-----'
|
||
].join('\n');
|
||
|
||
const priv_key_2000_2008 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
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
|
||
t/ia1kMpSEiOVLlX5dfHZzhR3WNtBqU=
|
||
=C0fJ
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
|
||
const priv_key_2038_2045 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
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
|
||
0uyeibPdgJTjARMuQzDFA8bdbM540vBf5Q==
|
||
=WLIN
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
|
||
const priv_key_expires_1337 = `-----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 priv_key_sha3 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xUsGZN8edBsAAAAgdUMlFMFCVKNo7sdUd6FVBos6NNjpUpSdrodk6BfPb/kA+3bu
|
||
A2+WY2LwyxlX5o07WR2VSn+wuegC3v28yO0tClHCtwYfGw4AAABIBYJk3x50BAsJ
|
||
CAcHFQ4MCgkICwIWAAIXgAKbAwIeCSIhBpbSe0QWuaCNSSLaePhXEP3BxQ2VHX3W
|
||
pW1U6svHvCUiBScJAgcCAAAAACMZIP8aHixoyC9wS3q/TNV/IfOQa81f+U5Ucz6H
|
||
4I+c5bWRYUzH/piBB4n5FoYlld+/SViCQIBCQ+fynLmaj5wlf22+mISTt/9je1Zf
|
||
YWlJ+WSJyi5gY5EH9DubfuIU3VaqCM0aQmVybmFkZXR0ZSA8YkBleGFtcGxlLm9y
|
||
Zz7CugYTGw4AAABLBYJk3x50BAsJCAcHFQ4MCgkICwIWAAIXgAIZAQKbAwIeCSIh
|
||
BpbSe0QWuaCNSSLaePhXEP3BxQ2VHX3WpW1U6svHvCUiBScJAgcCAAAAAMMGIJEi
|
||
9+yqkFKsNwX1H5II0riPudFpwBx2ypVjNk4aNb7Exl56Aac4tXEhz4fH41q0dAzF
|
||
ww2erZaiUqmohQ4AFSw1jN/WOiDfb1DkjT/HJ8vXMGpwWdgFPoqsWzTNhd5VCcdL
|
||
BmTfHnQZAAAAIAGMcsqVCXLclRhVamWciSxmnYF1FFs80W7dNUH07HUOAHh/S601
|
||
If+/eZKDIj3jq7oOe2PzHSYEK+mpQD1hBpF2wpsGGBsOAAAALAWCZN8edAKbDCIh
|
||
BpbSe0QWuaCNSSLaePhXEP3BxQ2VHX3WpW1U6svHvCUiAAAAANj3IBknZTPsMpWA
|
||
we0Jl5gw/Dj4lWAGoJfWfk+6s3Q86Hag3Hu8VBsapzmul+vzy0KJa+ZRcZz2n8aj
|
||
0vTl4sOZ0EcCdFDfkh/tR//gKkT6BiSBG86WoFq3f6U/RC+z0Ym7Dw==
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
|
||
const passphrase = 'hello world';
|
||
const plaintext = input.createSomeMessage();
|
||
const password1 = 'I am a password';
|
||
const password2 = 'I am another password';
|
||
|
||
const twoPasswordGPGFail = [
|
||
'-----BEGIN PGP MESSAGE-----',
|
||
'Version: OpenPGP.js v3.0.0',
|
||
'Comment: https://openpgpjs.org',
|
||
'',
|
||
'wy4ECQMIWjj3WEfWxGpgrfb3vXu0TS9L8UNTBvNZFIjltGjMVkLFD+/afgs5',
|
||
'aXt0wy4ECQMIrFo3TFN5xqtgtB+AaAjBcWJrA4bvIPBpJ38PbMWeF0JQgrqg',
|
||
'j3uehxXy0mUB5i7B61g0ho+YplyFGM0s9XayJCnu40tWmr5LqqsRxuwrhJKR',
|
||
'migslOF/l6Y9F0F9xGIZWGhxp3ugQPjVKjj8fOH7ap14mLm60C8q8AOxiSmL',
|
||
'ubsd/hL7FPZatUYAAZVA0a6hmQ==',
|
||
'=cHCV',
|
||
'-----END PGP MESSAGE-----'
|
||
].join('\n');
|
||
|
||
const ecdh_msg_bad = `-----BEGIN PGP MESSAGE-----
|
||
Version: ProtonMail
|
||
Comment: https://protonmail.com
|
||
|
||
wV4DlF328rtCW+wSAQdA9FsAz4rCdoxY/oZaa68WMPMXbO+wtHs4ZXtAOJOs
|
||
SlwwDaABXYC2dt0hUS2zRAL3gBGf4udH/CKJ1vPE58sNeh0ERYLxPHgwrpqI
|
||
oNVWOWH50kUBIdqd7by8RwLOk9GyV6008iFOlOG90mfjvt2g5DsnSB4wEeMg
|
||
pVu3fXj8iAKvFxvihwv1M7gNtP14StP6CngvyGVVEHQ=
|
||
=mvcB
|
||
-----END PGP MESSAGE-----`;
|
||
|
||
const ecdh_dec_key = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
Version: OpenPGP.js v4.4.6
|
||
Comment: https://openpgpjs.org
|
||
|
||
xYYEXEBTPxYJKwYBBAHaRw8BAQdAbXBY+2lpOatB+ZLokS/JIWqrVOseja9S
|
||
ewQxMKN6ueT+CQMIuUXr0XofC6VgJvFLyLwDlyyvT4I1HWGKZ6W9HUaslKvS
|
||
rw362rbMZKKfUtfjRJvpqiIU3Dr7iDkHB5vT7Tp5S7AZ2tNKoh/bwfTKdHsT
|
||
1803InFhX3Rlc3RlcjJAcHJvdG9ubWFpbC5jb20iIDxxYV90ZXN0ZXIyQHBy
|
||
b3Rvbm1haWwuY29tPsJ3BBAWCgAfBQJcQFM/BgsJBwgDAgQVCAoCAxYCAQIZ
|
||
AQIbAwIeAQAKCRClzcrGJTMHyTpjAQCJZ7p0TJBZyPQ8m64N24glaM6oM78q
|
||
2Ogpc0e9LcrPowD6AssY2YfUwJNzVFVzR+Lulzu6XVPjn0pXGMhOl03SrQ3H
|
||
iwRcQFM/EgorBgEEAZdVAQUBAQdAAgJJUhKvjGWMq1sDhrJgvqbHK1t1W5RF
|
||
Xoet5noIlAADAQgH/gkDCOFdJ7Yv2cTZYETRT5+ak/ntmslcAqtk3ebd7Ok3
|
||
tQIjO3TYUbkV1eqrpA4I42kGCUkU4Dy26wxuaLRSsO1u/RgXjExZLP9FlWFI
|
||
h6lLS1bCYQQYFggACQUCXEBTPwIbDAAKCRClzcrGJTMHyfNBAP9sdyU3GHNR
|
||
7+QdwYvQp7wN+2VUd8vIf7iwAHOK1Cj4ywD+NhzjFfGYESJ68nnkrYlYdf+u
|
||
OBqYz6mzZAWQZqsjbg4=
|
||
=zrks
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
|
||
const ecdh_msg_bad_2 = `-----BEGIN PGP MESSAGE-----
|
||
Version: ProtonMail
|
||
Comment: https://protonmail.com
|
||
|
||
wV4DtM+8giJEGNISAQhA2rYu8+B41rJi6Gsr4TVeKyDtI0KjhhlLZs891rCG
|
||
6X4wxNkxCuTJZax7gQZbDKh2kETK/RH75s9g7H/WV9kZ192NTGmMFiKiautH
|
||
c5BGRGxM0sDfAQZb3ZsAUORHKPP7FczMv5aMU2Ko7O2FHc06bMdnZ/ag7GMF
|
||
Bdl4EizttNTQ5sNCAdIXUoA8BJLHPgPiglnfTqqx3ynkBNMzfH46oKf08oJ+
|
||
6CAQhJdif67/iDX8BRtaKDICBpv3b5anJht7irOBqf9XX13SGkmqKYF3T8eB
|
||
W7ZV5EdCTC9KU+1BBPfPEi93F4OHsG/Jo80e5MDN24/wNxC67h7kUQiy3H4s
|
||
al+5mSAKcIfZJA4NfPJg9zSoHgfRNGI8Q7ao+c8CLPiefGcMsakNsWUdRyBT
|
||
SSLH3z/7AH4GxBvhDEEG3cZwmXzZAJMZmzTa+SrsxZzRpGB/aawyRntOWm8w
|
||
6Lq9ntq4S8suj/YK62dJpJxFl8xs+COngpMDvCexX9lYlh/r/y4JRQl06oUK
|
||
wv7trvi89TkK3821qHxr7XwI1Ncr2qDJVNlN4W+b6WFyLXnXaJAUMyZ/6inm
|
||
RR8BoR2KkEAku3Ne/G5QI51ktNJ7cCodeVOkZj8+iip1/AGyjxZCybq/N8rc
|
||
bpOWdMhJ6Hy+JzGNY1qNXcHJPw==
|
||
=99Fs
|
||
-----END PGP MESSAGE-----`;
|
||
|
||
const ecdh_dec_key2 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
Version: OpenPGP.js v4.4.9
|
||
Comment: https://openpgpjs.org
|
||
|
||
xYYEXEg93hYJKwYBBAHaRw8BAQdAeoA+T4vr3P0hFFsbzJpgy7/ZnKCrlehr
|
||
Myk5QAsBYgf+CQMIQ76YL5sEx+Zgr7DLZ5fhQn1U9+8aLIQaIbaT51nEjEMD
|
||
7h6mrJmp7oIr4PyijsIU+0LasXh/qlNeVQVWSygDq9L4nXDEGQhlMq3oH1FN
|
||
NM07InBha292c2thdGVzdEBwcm90b25tYWlsLmNvbSIgPHBha292c2thdGVz
|
||
dEBwcm90b25tYWlsLmNvbT7CdwQQFgoAHwUCXEg93gYLCQcIAwIEFQgKAgMW
|
||
AgECGQECGwMCHgEACgkQp7+eOYEhwd6x5AD9E0LA62odFFDH76wjEYrPCvOH
|
||
cYM56/5ZqZoGPPmbE98BAKCz/SQ90tiCMmlLEDXGX+a1bi6ttozqrnSQigic
|
||
DI4Ix4sEXEg93hIKKwYBBAGXVQEFAQEHQPDXy2mDfbMKOpCBZB2Ic5bfoWGV
|
||
iXvCFMnTLRWfGHUkAwEIB/4JAwhxMnjHjyALomBWSsoYxxB6rj6JKnWeikyj
|
||
yjXZdZqdK5F+0rk4M0l7lF0wt5PhT2uMCLB7aH/mSFN1cz7sBeJl3w2soJsT
|
||
ve/fP/8NfzP0wmEEGBYIAAkFAlxIPd4CGwwACgkQp7+eOYEhwd5MWQEAp0E4
|
||
QTnEnG8lYXhOqnOw676oV2kEU6tcTj3DdM+cW/sA/jH3FQQjPf+mA/7xqKIv
|
||
EQr2Mx42THr260IFYp5E/rIA
|
||
=oA0b
|
||
-----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 rsaPrivateKeyPKCS1 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
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
|
||
=dSNv
|
||
-----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 multipleEncryptionAndSigningSubkeys = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
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
|
||
=PUAJ
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
|
||
const twoPublicKeys = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||
Version: GnuPG v2.0.19 (GNU/Linux)
|
||
|
||
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
|
||
PepQmgsu
|
||
=w6wd
|
||
-----END PGP PUBLIC KEY BLOCK-----`;
|
||
|
||
const twoPrivateKeys = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xVgEYJQe2xYJKwYBBAHaRw8BAQdAjTDKUXTWruoPIdDA5tpTEax/nCIKgmeS
|
||
jabWRyMTWoEAAQCM8rs15ex7sQ7T4sBf8jHeKvHiUBoTkhKJVAzsnorHdhGn
|
||
zRB0ZXN0IDx0ZXN0QGEuaXQ+wowEEBYKAB0FAmCUHtsECwkHCAMVCAoEFgAC
|
||
AQIZAQIbAwIeAQAhCRAQIA5NLDEFChYhBAWs5LsefVu3mjXXaBAgDk0sMQUK
|
||
BYcBAMxy3zEZhNtw2nnB9jAlIOSeCUJq/GuarTWQkhAZLFIeAP9400rWrELS
|
||
zvNgdct9fctoM21ZByUlkmNdPgYf7fjaAMddBGCUHtsSCisGAQQBl1UBBQEB
|
||
B0DdGhv0sVHFzGvDPzTYhNKnUxd68oocIEkt5Ku6ZAD0VAMBCAcAAP9rRNBE
|
||
OumQKygox59KL7FjEYXSR8TqI4t3CFlfWW/D8A+gwngEGBYIAAkFAmCUHtsC
|
||
GwwAIQkQECAOTSwxBQoWIQQFrOS7Hn1bt5o112gQIA5NLDEFCoPdAQCTy2kg
|
||
z3F/iZApy2Sf5SIThnQMsgEr296Fgfvm8YMFCAEA82+TF79snlPbVHSIrdDg
|
||
lPMSDEkIcxzIQN0EEo1qlwzFWARglB7iFgkrBgEEAdpHDwEBB0D/kNASbsOD
|
||
S9RePgrsUDdY3plKDRLIIvpAIkbr1PoDoAABANEBtAiU2YjVOfHzDgbblSCd
|
||
+tPSDaYbAyHmCNMDqsRQD8rNEHRlc3QgPHRlc3RAYS5pdD7CjAQQFgoAHQUC
|
||
YJQe4gQLCQcIAxUICgQWAAIBAhkBAhsDAh4BACEJEIrXtvI38e+rFiEERNKb
|
||
HKnqdF8HwqMZite28jfx76trWAEA6YFR+4gMFr3xM/HReS+pYE1SSHIQjHgz
|
||
SsU0N93pk5EA/ijuLZfsRf7uD6Yb0rEDIJa3NT7KwIUIUtDpbQLtIrcFx10E
|
||
YJQe4hIKKwYBBAGXVQEFAQEHQLfK3MpbSeRa1Ko1NtNDNXOc/sqvEeIjAAKg
|
||
V0OWVpsJAwEIBwAA/3Nr3/t32OJi9GFEVEN2/VWes5825aFBPEU6UcBaSgCw
|
||
EU/CeAQYFggACQUCYJQe4gIbDAAhCRCK17byN/HvqxYhBETSmxyp6nRfB8Kj
|
||
GYrXtvI38e+rSKMBAJaIk9bLz+AN0Ho8pHGP3gEddvLwvioNhdkCJ7CfwWmI
|
||
AP9fcXZg/Eo55YB/B5XKLkuzDFwJaTlncrD5jcUgtVXFCg==
|
||
=q2yi
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
|
||
const armoredDummyPrivateKey1 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
Version: GnuPG v1.4.11 (GNU/Linux)
|
||
|
||
lQGqBFERnrMRBADmM0hIfkI3yosjgbWo9v0Lnr3CCE+8KsMszgVS+hBu0XfGraKm
|
||
ivcA2aaJimHqVYOP7gEnwFAxHBBpeTJcu5wzCFyJwEYqVeS3nnaIhBPplSF14Duf
|
||
i6bB9RV7KxVAg6aunmM2tAutqC+a0y2rDaf7jkJoZ9gWJe2zI+vraD6fiwCgxvHo
|
||
3IgULB9RqIqpLoMgXfcjC+cD/1jeJlKRm+n71ryYwT/ECKsspFz7S36z6q3XyS8Q
|
||
QfrsUz2p1fbFicvJwIOJ8B20J/N2/nit4P0gBUTUxv3QEa7XCM/56/xrGkyBzscW
|
||
AzBoy/AK9K7GN6z13RozuAS60F1xO7MQc6Yi2VU3eASDQEKiyL/Ubf/s/rkZ+sGj
|
||
yJizBACtwCbQzA+z9XBZNUat5NPgcZz5Qeh1nwF9Nxnr6pyBv7tkrLh/3gxRGHqG
|
||
063dMbUk8pmUcJzBUyRsNiIPDoEUsLjY5zmZZmp/waAhpREsnK29WLCbqLdpUors
|
||
c1JJBsObkA1IM8TZY8YUmvsMEvBLCCanuKpclZZXqeRAeOHJ0v4DZQJHTlUBtBZU
|
||
ZXN0MiA8dGVzdDJAdGVzdC5jb20+iGIEExECACIFAlERnrMCGwMGCwkIBwMCBhUI
|
||
AgkKCwQWAgMBAh4BAheAAAoJEBEnlAPLFp74xc0AoLNZINHe0ytOsNtMCuLvc3Vd
|
||
vePUAJ9KX3L5IBqHarsa+aJHX7r796SokZ0BWARREZ6zEAQA2WkxmNbfeMzGUocN
|
||
3JEVe0o6rxGt5eGrTSmWisduDP3MURabhUXnf4T8oaeYcbJjkLLxMrJmNq55ln1e
|
||
4bSG5mDkh/ryKsV81m3F0DbqO/z/891nRSP5fondFVral4wsMOzBNgs4vVk7V/F2
|
||
0MPjR90CIhnVDKPAQbQA+3PjUR8AAwUEALn922AEE+0d7xSMMFpR7ic3Me5QEGnp
|
||
cT4ft6oc0UK5kAnvKoksZUc0hpBHjX1w3LTz847/5hRDuuDvwvGMWK8IfsjOF9T7
|
||
rK8QtJuBEyJxjoScA/YZP5vX4y0U1reUEa0EdwmVrnZzatMAe2FhlaR9PlHkOcm5
|
||
DZwkcExL0dbI/gMDArxZ+5N7kH4zYLtr9glJS/pJ7F0YJqJpNwCbqD8+8DqHD8Uv
|
||
MgQ/rtBxBJJOaF+1AjCd123hLgzIkkfdTh8loV9hDXMKeJgmiEkEGBECAAkFAlER
|
||
nrMCGwwACgkQESeUA8sWnvhBswCfdXjznvHCc73/6/MhWcv3dbeTT/wAoLyiZg8+
|
||
iY3UT9QkV9d0sMgyLkug
|
||
=GQsY
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
|
||
const armoredPublicKey1 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||
Version: GnuPG v1.4.11 (GNU/Linux)
|
||
|
||
mQGiBFERlw4RBAD6Bmcf2w1dtUmtCLkdxeqZLArk3vYoQAjdibxA3gXVyur7fsWb
|
||
ro0jVbBHqOCtC6jDxE2l52NP9+tTlWeVMaqqNvUE47LSaPq2DGI8Wx1Rj6bF3mTs
|
||
obYEwhGbGh/MhJnME9AHODarvk8AZbzo0+k1EwrBWF6dTUBPfqO7rGU2ewCg80WV
|
||
x5pt3evj8rRK3jQ8SMKTNRsD/1PhTdxdZTdXARAFzcW1VaaruWW0Rr1+XHKKwDCz
|
||
i7HE76SO9qjnQfZCZG75CdQxI0h8GFeN3zsDqmhob2iSz2aJ1krtjM+iZ1FBFd57
|
||
OqCV6wmk5IT0RBN12ZzMS19YvzN/ONXHrmTZlKExd9Mh9RKLeVNw+bf6JsKQEzcY
|
||
JzFkBACX9X+hDYchO/2hiTwx4iOO9Fhsuh7eIWumB3gt+aUpm1jrSbas/QLTymmk
|
||
uZuQVXI4NtnlvzlNgWv4L5s5RU5WqNGG7WSaKNdcrvJZRC2dgbUJt04J5CKrWp6R
|
||
aIYal/81Ut1778lU01PEt563TcQnUBlnjU5OR25KhfSeN5CZY7QUVGVzdCA8dGVz
|
||
dEB0ZXN0LmNvbT6IYgQTEQIAIgUCURGXDgIbAwYLCQgHAwIGFQgCCQoLBBYCAwEC
|
||
HgECF4AACgkQikDlZK/UvLSspgCfcNaOpTg1W2ucR1JwBbBGvaERfuMAnRgt3/rs
|
||
EplqEakMckCtikEnpxYe
|
||
=b2Ln
|
||
-----END PGP PUBLIC KEY BLOCK-----`;
|
||
|
||
const expiredPublicKeyThroughDirectSignature = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||
|
||
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
|
||
Be4ubVrj5KjhX2PVNEJd3XZRzaXZE2aAMQ==
|
||
=ZeAz
|
||
-----END PGP PUBLIC KEY BLOCK-----`;
|
||
|
||
const eccPrivateKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xVgEYaYskRYJKwYBBAHaRw8BAQdAlHT6jzgvcng/qDvb+LH+nA4+AWrMLUYf
|
||
aNJIuJRUjXMAAP9llTr5+fNSY78FNnpx53muMtyeDINkeUGGwgqAfxj9lhEV
|
||
zRN0ZXN0IDx0ZXN0QHRlc3QuaXQ+wowEEBYKAB0FAmGmLJEECwkHCAMVCAoE
|
||
FgACAQIZAQIbAwIeAQAhCRBvJAzR+vGyExYhBCaNeWwMzRW97WhAq28kDNH6
|
||
8bITWWkA/0R3zADs94dVo+iSNzrtZaDkbHOMb/yjketYmI0XS8UpAP4hUmKN
|
||
QcohP6007t0gaQUcgdwum7PKUoM6BeBG8GaTAsddBGGmLJESCisGAQQBl1UB
|
||
BQEBB0CibQAv6tvWCWoe6xlkkZGbLpVWvHwgIPzRVdz4e79DdQMBCAcAAP9T
|
||
4SntnkgSUnM39dFoTPIoitrsOcHZbvXPCcvclKgZKBJTwngEGBYIAAkFAmGm
|
||
LJECGwwAIQkQbyQM0frxshMWIQQmjXlsDM0Vve1oQKtvJAzR+vGyE5ORAQD+
|
||
lfFvJjue+tnuIR+ZubxtpKaJpCOWkAcrkx41NtsLwgD/TAkWh1KDWg0IOcUE
|
||
MbVkSnU2Z+vhSmYubDCldNOSVwE=
|
||
=bTUQ
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
|
||
const rsaKeyWithNoFeaturesFromRNP = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
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
|
||
8wENR68u88WrKOGN359vq/DKwd3A
|
||
=c2mQ
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
|
||
function withCompression(tests) {
|
||
const compressionTypes = Object.values(openpgp.enums.compression);
|
||
|
||
compressionTypes.forEach(function (compression) {
|
||
const compressionName = openpgp.enums.read(openpgp.enums.compression, compression);
|
||
if (compressionName === 'bzip2') {
|
||
return; // bzip2 compression is not supported.
|
||
}
|
||
const group = `compression - ${compressionName}`;
|
||
|
||
describe(group, function() {
|
||
let compressSpy;
|
||
let decompressSpy;
|
||
|
||
beforeEach(function () {
|
||
compressSpy = sinon.spy(openpgp.CompressedDataPacket.prototype, 'compress');
|
||
decompressSpy = sinon.spy(openpgp.CompressedDataPacket.prototype, 'decompress');
|
||
});
|
||
|
||
afterEach(function () {
|
||
compressSpy.restore();
|
||
decompressSpy.restore();
|
||
});
|
||
|
||
tests(
|
||
function(options) {
|
||
options.config = { preferredCompressionAlgorithm: compression };
|
||
return options;
|
||
},
|
||
function() {
|
||
if (compression === openpgp.enums.compression.uncompressed) {
|
||
expect(compressSpy.called).to.be.false;
|
||
expect(decompressSpy.called).to.be.false;
|
||
return;
|
||
}
|
||
|
||
expect(compressSpy.called).to.be.true;
|
||
expect(compressSpy.thisValues[0].algorithm).to.equal(compression);
|
||
expect(decompressSpy.called).to.be.true;
|
||
expect(decompressSpy.thisValues[0].algorithm).to.equal(compression);
|
||
}
|
||
);
|
||
});
|
||
});
|
||
}
|
||
|
||
export default () => describe('OpenPGP.js public api tests', function() {
|
||
describe('readKey(s) and readPrivateKey(s) - unit tests', function() {
|
||
it('readKey and readPrivateKey should create equal private keys', async function() {
|
||
const key = await openpgp.readKey({ armoredKey: priv_key });
|
||
const privateKey = await openpgp.readPrivateKey({ armoredKey: priv_key });
|
||
expect(key.isPrivate()).to.be.true;
|
||
expect(privateKey.isPrivate()).to.be.true;
|
||
expect(key.isDecrypted()).to.be.false;
|
||
expect(privateKey.isDecrypted()).to.be.false;
|
||
expect(key.getKeyID().equals(privateKey.getKeyID())).to.be.true;
|
||
});
|
||
|
||
it('readPrivateKeys and readKeys should create equal private keys', async function() {
|
||
const keys = await openpgp.readKeys({ armoredKeys: twoPrivateKeys });
|
||
const privateKeys = await openpgp.readPrivateKeys({ armoredKeys: twoPrivateKeys });
|
||
// pairwise comparison
|
||
const zip = (arr1, arr2) => arr1.map((el, i) => [el, arr2[i]]);
|
||
zip(keys, privateKeys).forEach(([key, privateKey]) => {
|
||
expect(key.isPrivate()).to.be.true;
|
||
expect(privateKey.isPrivate()).to.be.true;
|
||
expect(key.isDecrypted()).to.be.true;
|
||
expect(privateKey.isDecrypted()).to.be.true;
|
||
expect(key.getKeyID().equals(privateKey.getKeyID())).to.be.true;
|
||
});
|
||
});
|
||
|
||
it('readPrivateKey and readPrivateKeys should have consistent results', async function() {
|
||
const privateAndPublicKeyBlock = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xVgEZkI3VBYJKwYBBAHaRw8BAQdA7nW1t5qRdtIYzEVEEhRSDgTgbk2JHofY
|
||
Ph8FuGsDqgwAAQDYVpZt1w6a+vxgb4M351aCpA2sCfx8kbFg23h8Irtm1xFY
|
||
zQ88dGVzdEB0ZXN0LmNvbT7CwBMEEBYKAIUFgmZCN1QDCwkHCZDuyoEpQ/KE
|
||
H0UUAAAAAAAcACBzYWx0QG5vdGF0aW9ucy5vcGVucGdwanMub3JnzKJ8mXOC
|
||
wnEp6lVJ/5+rRzR4UcwlL8EjhOS+rV0T8pAFFQgKDA4EFgACAQIZAQKbAwIe
|
||
ARYhBECs3D9sMFn6oOxAqu7KgSlD8oQfAAAPbwD+NjyEHt1CRI+0XmgHdiwZ
|
||
JN115IO+M37bOxgBnTbVoF0BAMGECXVQoSRVNy0TYf+AUUPQ6tSZ1zLXszwe
|
||
FK3w+CoGxjMEZkI3VBYJKwYBBAHaRw8BAQdA7nW1t5qRdtIYzEVEEhRSDgTg
|
||
bk2JHofYPh8FuGsDqgzNDzx0ZXN0QHRlc3QuY29tPsLAEwQQFgoAhQWCZkI3
|
||
VAMLCQcJkO7KgSlD8oQfRRQAAAAAABwAIHNhbHRAbm90YXRpb25zLm9wZW5w
|
||
Z3Bqcy5vcmfMonyZc4LCcSnqVUn/n6tHNHhRzCUvwSOE5L6tXRPykAUVCAoM
|
||
DgQWAAIBAhkBApsDAh4BFiEEQKzcP2wwWfqg7ECq7sqBKUPyhB8AAA9vAP42
|
||
PIQe3UJEj7ReaAd2LBkk3XXkg74zfts7GAGdNtWgXQEAwYQJdVChJFU3LRNh
|
||
/4BRQ9Dq1JnXMtezPB4UrfD4KgY=
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
// readPrivateKey should read the first private key encountered in a key block
|
||
const key = await openpgp.readPrivateKey({ armoredKey: privateAndPublicKeyBlock });
|
||
const privateKeys = await openpgp.readPrivateKeys({ armoredKeys: privateAndPublicKeyBlock });
|
||
expect(privateKeys.length).to.equal(1);
|
||
expect(key.isPrivate()).to.be.true;
|
||
expect(privateKeys[0].isPrivate()).to.be.true;
|
||
expect(key.isDecrypted()).to.be.true;
|
||
expect(privateKeys[0].isDecrypted()).to.be.true;
|
||
expect(key.getKeyID().equals(privateKeys[0].getKeyID())).to.be.true;
|
||
});
|
||
|
||
it('readKey and readKeys should have consistent results', async function() {
|
||
const publicAndPrivateKeyBlock = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xjMEZkI3VBYJKwYBBAHaRw8BAQdA7nW1t5qRdtIYzEVEEhRSDgTgbk2JHofY
|
||
Ph8FuGsDqgzNDzx0ZXN0QHRlc3QuY29tPsLAEwQQFgoAhQWCZkI3VAMLCQcJ
|
||
kO7KgSlD8oQfRRQAAAAAABwAIHNhbHRAbm90YXRpb25zLm9wZW5wZ3Bqcy5v
|
||
cmfMonyZc4LCcSnqVUn/n6tHNHhRzCUvwSOE5L6tXRPykAUVCAoMDgQWAAIB
|
||
AhkBApsDAh4BFiEEQKzcP2wwWfqg7ECq7sqBKUPyhB8AAA9vAP42PIQe3UJE
|
||
j7ReaAd2LBkk3XXkg74zfts7GAGdNtWgXQEAwYQJdVChJFU3LRNh/4BRQ9Dq
|
||
1JnXMtezPB4UrfD4KgbFWARmQjdUFgkrBgEEAdpHDwEBB0DudbW3mpF20hjM
|
||
RUQSFFIOBOBuTYkeh9g+HwW4awOqDAABANhWlm3XDpr6/GBvgzfnVoKkDawJ
|
||
/HyRsWDbeHwiu2bXEVjNDzx0ZXN0QHRlc3QuY29tPsLAEwQQFgoAhQWCZkI3
|
||
VAMLCQcJkO7KgSlD8oQfRRQAAAAAABwAIHNhbHRAbm90YXRpb25zLm9wZW5w
|
||
Z3Bqcy5vcmfMonyZc4LCcSnqVUn/n6tHNHhRzCUvwSOE5L6tXRPykAUVCAoM
|
||
DgQWAAIBAhkBApsDAh4BFiEEQKzcP2wwWfqg7ECq7sqBKUPyhB8AAA9vAP42
|
||
PIQe3UJEj7ReaAd2LBkk3XXkg74zfts7GAGdNtWgXQEAwYQJdVChJFU3LRNh
|
||
/4BRQ9Dq1JnXMtezPB4UrfD4KgY=
|
||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||
// readKey should read the first key encountered in a key block
|
||
const key = await openpgp.readKey({ armoredKey: publicAndPrivateKeyBlock });
|
||
const keys = await openpgp.readKeys({ armoredKeys: publicAndPrivateKeyBlock });
|
||
expect(keys.length).to.equal(2);
|
||
expect(key.isPrivate()).to.be.false;
|
||
expect(keys[0].isPrivate()).to.be.false;
|
||
expect(keys[1].isPrivate()).to.be.true;
|
||
});
|
||
|
||
it('readPrivateKey should throw on armored public key', async function() {
|
||
await expect(openpgp.readPrivateKey({ armoredKey: pub_key })).to.be.rejectedWith(/Armored text not of type private key/);
|
||
});
|
||
|
||
it('readPrivateKeys should throw on armored public keys', async function() {
|
||
await expect(openpgp.readPrivateKeys({ armoredKeys: twoPublicKeys })).to.be.rejectedWith(/Armored text not of type private key/);
|
||
});
|
||
});
|
||
|
||
describe('generateKey - validate user ids', function() {
|
||
it('should fail for invalid user name', async function() {
|
||
const opt = {
|
||
userIDs: [{ name: {}, email: 'text@example.com' }]
|
||
};
|
||
const test = openpgp.generateKey(opt);
|
||
await expect(test).to.eventually.be.rejectedWith(/Invalid user ID format/);
|
||
});
|
||
|
||
it('should fail for invalid user email address (missing @)', async function() {
|
||
const opt = {
|
||
userIDs: [{ name: 'Test User', email: 'textexample.com' }]
|
||
};
|
||
const test = openpgp.generateKey(opt);
|
||
await expect(test).to.eventually.be.rejectedWith(/Invalid user ID format/);
|
||
});
|
||
|
||
it('should fail for string user ID', async function() {
|
||
const opt = {
|
||
userIDs: 'Test User <text@example.com>'
|
||
};
|
||
const test = openpgp.generateKey(opt);
|
||
await expect(test).to.eventually.be.rejectedWith(/Invalid user ID format/);
|
||
});
|
||
|
||
it('should work for valid single user ID object', function() {
|
||
const opt = {
|
||
userIDs: { name: 'Test User', email: 'text@example.com' }
|
||
};
|
||
return openpgp.generateKey(opt);
|
||
});
|
||
|
||
it('should work for array of user ID objects', function() {
|
||
const opt = {
|
||
userIDs: [{ name: 'Test User', email: 'text@example.com' }]
|
||
};
|
||
return openpgp.generateKey(opt);
|
||
});
|
||
|
||
it('should work for undefined name', function() {
|
||
const opt = {
|
||
userIDs: { email: 'text@example.com' }
|
||
};
|
||
return openpgp.generateKey(opt);
|
||
});
|
||
|
||
it('should work for an undefined email address', function() {
|
||
const opt = {
|
||
userIDs: { name: 'Test User' }
|
||
};
|
||
return openpgp.generateKey(opt);
|
||
});
|
||
});
|
||
|
||
describe('generateKey - unit tests', function() {
|
||
it('should still support curve="curve25519" for ECC key type (v4 key)', function() {
|
||
const opt = {
|
||
userIDs: { name: 'Test User', email: 'text@example.com' },
|
||
type: 'ecc',
|
||
curve: 'curve25519',
|
||
format: 'object'
|
||
};
|
||
return openpgp.generateKey(opt).then(async function({ privateKey: key }) {
|
||
expect(key).to.exist;
|
||
expect(key.getAlgorithmInfo().rsaBits).to.equal(undefined);
|
||
expect(key.getAlgorithmInfo().algorithm).to.equal('eddsaLegacy');
|
||
expect(key.getAlgorithmInfo().curve).to.equal('ed25519Legacy');
|
||
expect(key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined);
|
||
expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
|
||
expect(key.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519Legacy');
|
||
});
|
||
});
|
||
|
||
it('should have default params set (v4 key)', function() {
|
||
const now = util.normalizeDate(new Date());
|
||
const opt = {
|
||
userIDs: { name: 'Test User', email: 'text@example.com' },
|
||
passphrase: 'secret',
|
||
date: now,
|
||
format: 'object'
|
||
};
|
||
return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) {
|
||
for (const key of [publicKey, privateKey]) {
|
||
expect(key).to.exist;
|
||
expect(key.keyPacket.version).to.equal(4);
|
||
expect(key.users.length).to.equal(1);
|
||
expect(key.users[0].userID.name).to.equal('Test User');
|
||
expect(key.users[0].userID.email).to.equal('text@example.com');
|
||
expect(key.getAlgorithmInfo().rsaBits).to.equal(undefined);
|
||
expect(key.getAlgorithmInfo().curve).to.equal('ed25519Legacy');
|
||
expect(+key.getCreationTime()).to.equal(+now);
|
||
expect(await key.getExpirationTime()).to.equal(Infinity);
|
||
expect(key.subkeys.length).to.equal(1);
|
||
expect(key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined);
|
||
expect(key.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519Legacy');
|
||
expect(+key.subkeys[0].getCreationTime()).to.equal(+now);
|
||
expect(await key.subkeys[0].getExpirationTime()).to.equal(Infinity);
|
||
}
|
||
});
|
||
});
|
||
|
||
it('should have default params set (v6 key)', function() {
|
||
const now = util.normalizeDate(new Date());
|
||
const opt = {
|
||
userIDs: { name: 'Test User', email: 'text@example.com' },
|
||
passphrase: 'secret',
|
||
date: now,
|
||
format: 'object',
|
||
config: { v6Keys: true }
|
||
};
|
||
return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) {
|
||
for (const key of [publicKey, privateKey]) {
|
||
expect(key).to.exist;
|
||
expect(key.keyPacket.version).to.equal(6);
|
||
expect(key.users.length).to.equal(1);
|
||
expect(key.users[0].userID.name).to.equal('Test User');
|
||
expect(key.users[0].userID.email).to.equal('text@example.com');
|
||
expect(key.getAlgorithmInfo().algorithm).to.equal('ed25519');
|
||
expect(key.getAlgorithmInfo().rsaBits).to.equal(undefined);
|
||
expect(key.getAlgorithmInfo().curve).to.equal(undefined);
|
||
expect(+key.getCreationTime()).to.equal(+now);
|
||
expect(await key.getExpirationTime()).to.equal(Infinity);
|
||
expect(key.subkeys.length).to.equal(1);
|
||
expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x25519');
|
||
expect(key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined);
|
||
expect(key.subkeys[0].getAlgorithmInfo().curve).to.equal(undefined);
|
||
expect(+key.subkeys[0].getCreationTime()).to.equal(+now);
|
||
expect(await key.subkeys[0].getExpirationTime()).to.equal(Infinity);
|
||
}
|
||
});
|
||
});
|
||
|
||
it('should output keypair with expected format', async function() {
|
||
const opt = {
|
||
userIDs: { name: 'Test User', email: 'text@example.com' }
|
||
};
|
||
const armored = await openpgp.generateKey({ ...opt, format: 'armored' });
|
||
expect((await openpgp.readKey({ armoredKey: armored.privateKey })).isPrivate()).to.be.true;
|
||
expect((await openpgp.readKey({ armoredKey: armored.publicKey })).isPrivate()).to.be.false;
|
||
|
||
const binary = await openpgp.generateKey({ ...opt, format: 'binary' });
|
||
expect((await openpgp.readKey({ binaryKey: binary.privateKey })).isPrivate()).to.be.true;
|
||
expect((await openpgp.readKey({ binaryKey: binary.publicKey })).isPrivate()).to.be.false;
|
||
|
||
const { privateKey, publicKey } = await openpgp.generateKey({ ...opt, format: 'object' });
|
||
expect(privateKey.isPrivate()).to.be.true;
|
||
expect(publicKey.isPrivate()).to.be.false;
|
||
});
|
||
});
|
||
|
||
describe('reformatKey - unit tests', function() {
|
||
it('should output keypair with expected format', async function() {
|
||
const encryptedKey = await openpgp.readKey({ armoredKey: priv_key });
|
||
const original = await openpgp.decryptKey({
|
||
privateKey: encryptedKey,
|
||
passphrase: passphrase
|
||
});
|
||
|
||
const opt = {
|
||
privateKey: original,
|
||
userIDs: { name: 'Test User', email: 'text@example.com' }
|
||
};
|
||
const armored = await openpgp.reformatKey({ ...opt, format: 'armored' });
|
||
expect((await openpgp.readKey({ armoredKey: armored.privateKey })).isPrivate()).to.be.true;
|
||
expect((await openpgp.readKey({ armoredKey: armored.publicKey })).isPrivate()).to.be.false;
|
||
|
||
const binary = await openpgp.reformatKey({ ...opt, format: 'binary' });
|
||
expect((await openpgp.readKey({ binaryKey: binary.privateKey })).isPrivate()).to.be.true;
|
||
expect((await openpgp.readKey({ binaryKey: binary.publicKey })).isPrivate()).to.be.false;
|
||
|
||
const { privateKey, publicKey } = await openpgp.reformatKey({ ...opt, format: 'object' });
|
||
expect(privateKey.isPrivate()).to.be.true;
|
||
expect(publicKey.isPrivate()).to.be.false;
|
||
});
|
||
});
|
||
|
||
describe('revokeKey - unit tests', function() {
|
||
it('should output key with expected format', async function() {
|
||
const encryptedKey = await openpgp.readKey({ armoredKey: priv_key });
|
||
const key = await openpgp.decryptKey({
|
||
privateKey: encryptedKey,
|
||
passphrase: passphrase
|
||
});
|
||
|
||
const armored = await openpgp.revokeKey({ key, format: 'armored' });
|
||
expect((await openpgp.readKey({ armoredKey: armored.privateKey })).isPrivate()).to.be.true;
|
||
expect((await openpgp.readKey({ armoredKey: armored.publicKey })).isPrivate()).to.be.false;
|
||
|
||
const binary = await openpgp.revokeKey({ key, format: 'binary' });
|
||
expect((await openpgp.readKey({ binaryKey: binary.privateKey })).isPrivate()).to.be.true;
|
||
expect((await openpgp.readKey({ binaryKey: binary.publicKey })).isPrivate()).to.be.false;
|
||
|
||
const { privateKey, publicKey } = await openpgp.revokeKey({ key, format: 'object' });
|
||
expect(privateKey.isPrivate()).to.be.true;
|
||
expect(publicKey.isPrivate()).to.be.false;
|
||
});
|
||
});
|
||
|
||
describe('decryptKey - unit tests', function() {
|
||
it('should work for correct passphrase', async function() {
|
||
const privateKey = await openpgp.readKey({ armoredKey: priv_key });
|
||
const originalKey = await openpgp.readKey({ armoredKey: privateKey.armor() });
|
||
return openpgp.decryptKey({
|
||
privateKey: privateKey,
|
||
passphrase: passphrase
|
||
}).then(unlocked => {
|
||
expect(unlocked.getKeyID().toHex()).to.equal(privateKey.getKeyID().toHex());
|
||
expect(unlocked.subkeys[0].getKeyID().toHex()).to.equal(privateKey.subkeys[0].getKeyID().toHex());
|
||
expect(unlocked.isDecrypted()).to.be.true;
|
||
expect(unlocked.keyPacket.privateParams).to.not.be.null;
|
||
// original key should be unchanged
|
||
expect(privateKey.isDecrypted()).to.be.false;
|
||
expect(privateKey.keyPacket.privateParams).to.be.null;
|
||
expect(privateKey).to.deep.equal(originalKey);
|
||
});
|
||
});
|
||
|
||
it('should work with multiple passphrases', async function() {
|
||
const privateKey = await openpgp.readKey({ armoredKey: priv_key });
|
||
const originalKey = await openpgp.readKey({ armoredKey: privateKey.armor() });
|
||
return openpgp.decryptKey({
|
||
privateKey: privateKey,
|
||
passphrase: ['rubbish', passphrase]
|
||
}).then(unlocked => {
|
||
expect(unlocked.getKeyID().toHex()).to.equal(privateKey.getKeyID().toHex());
|
||
expect(unlocked.subkeys[0].getKeyID().toHex()).to.equal(privateKey.subkeys[0].getKeyID().toHex());
|
||
expect(unlocked.isDecrypted()).to.be.true;
|
||
expect(unlocked.keyPacket.privateParams).to.not.be.null;
|
||
// original key should be unchanged
|
||
expect(privateKey.isDecrypted()).to.be.false;
|
||
expect(privateKey.keyPacket.privateParams).to.be.null;
|
||
expect(privateKey).to.deep.equal(originalKey);
|
||
});
|
||
});
|
||
|
||
it('should fail for incorrect passphrase', async function() {
|
||
const privateKey = await openpgp.readKey({ armoredKey: priv_key });
|
||
const originalKey = await openpgp.readKey({ armoredKey: privateKey.armor() });
|
||
return openpgp.decryptKey({
|
||
privateKey: privateKey,
|
||
passphrase: 'incorrect'
|
||
}).then(function() {
|
||
throw new Error('Should not decrypt with incorrect passphrase');
|
||
}).catch(function(error) {
|
||
expect(error.message).to.match(/Incorrect key passphrase/);
|
||
// original key should be unchanged
|
||
expect(privateKey.isDecrypted()).to.be.false;
|
||
expect(privateKey.keyPacket.privateParams).to.be.null;
|
||
expect(privateKey).to.deep.equal(originalKey);
|
||
});
|
||
});
|
||
|
||
it('should fail for corrupted key', async function() {
|
||
const privateKeyMismatchingParams = await openpgp.readKey({ armoredKey: mismatchingKeyParams });
|
||
const originalKey = await openpgp.readKey({ armoredKey: privateKeyMismatchingParams.armor() });
|
||
return openpgp.decryptKey({
|
||
privateKey: privateKeyMismatchingParams,
|
||
passphrase: 'userpass'
|
||
}).then(function() {
|
||
throw new Error('Should not decrypt corrupted key');
|
||
}).catch(function(error) {
|
||
expect(error.message).to.match(/Key is invalid/);
|
||
expect(privateKeyMismatchingParams.isDecrypted()).to.be.false;
|
||
expect(privateKeyMismatchingParams.keyPacket.privateParams).to.be.null;
|
||
expect(privateKeyMismatchingParams).to.deep.equal(originalKey);
|
||
});
|
||
});
|
||
|
||
it('should fail for encrypted key with unknown s2k (unparseableKeyMaterial)', async function() {
|
||
// key encrypted with invalid s2kType = 23, to test that it can still be used for encryption/verification
|
||
const encryptedKeyUnknownS2K = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xYYEZJ2H3RYJKwYBBAHaRw8BAQdA3V39Xv0+436Rpn/2UlcnOC1BGprmAlWY
|
||
RBKjAq0hAtD+CRcIdHzwqoLa54cAbBOEIgBh7Xa1Qh5wCGAmEVWnAldaqvk+
|
||
NcvUL2bR6AQsGIT6YEihOS3xLKobMOd2XlO5ItQoWnONzkWgzjFvctgnlhmq
|
||
I80AwowEEBYKAD4FgmSdh90ECwkHCAmQaBT7gxSTsXwDFQgKBBYAAgECGQEC
|
||
mwMCHgEWIQSvRnJTQT6TtdZFk0NoFPuDFJOxfAAAT7kBALmmUEJt5HMAOWiW
|
||
7/8y4wllm8zNQ9vbl5Q0cWbeWj/8AP9HDa2rRxHY/37g5zXdmL9f/qNWr9Fk
|
||
EBRhLLwusumuDMeLBGSdh90SCisGAQQBl1UBBQEBB0Am2yjjialeIVXHJJ2P
|
||
b7KiapCC0mD95F0EFz6zz0l4DgMBCAf+CRcISMdt0OUFCNUABB/OD0UW7MPK
|
||
Y3t8RrUTYoiCuhuPRDLOJ5NnMNagVQLt3jQsI8JRjzmYbiTrA/V3iJIEDu5C
|
||
NWbnvCM7Hs7+OqPzJPJ2w8J4BBgWCAAqBYJknYfdCZBoFPuDFJOxfAKbDBYh
|
||
BK9GclNBPpO11kWTQ2gU+4MUk7F8AADwfwD8CsOVw/3zm1UwUbGUi+fuf6Pr
|
||
VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
|
||
0pYO
|
||
=rWL8
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
await expect(openpgp.decryptKey({
|
||
privateKey: encryptedKeyUnknownS2K,
|
||
passphrase: 'test'
|
||
})).to.be.rejectedWith(/Key packet cannot be decrypted: unsupported S2K or cipher algo/);
|
||
});
|
||
});
|
||
|
||
describe('encryptKey - unit tests', function() {
|
||
it('should not change original key', async function() {
|
||
const { privateKey: armoredKey } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }] });
|
||
// read both keys from armored data to make sure all fields are exactly the same
|
||
const key = await openpgp.readKey({ armoredKey });
|
||
const originalKey = await openpgp.readKey({ armoredKey });
|
||
return openpgp.encryptKey({
|
||
privateKey: key,
|
||
passphrase: passphrase
|
||
}).then(locked => {
|
||
expect(locked.getKeyID().toHex()).to.equal(key.getKeyID().toHex());
|
||
expect(locked.subkeys[0].getKeyID().toHex()).to.equal(key.subkeys[0].getKeyID().toHex());
|
||
expect(locked.isDecrypted()).to.be.false;
|
||
expect(locked.keyPacket.privateParams).to.be.null;
|
||
// original key should be unchanged
|
||
expect(key.isDecrypted()).to.be.true;
|
||
expect(key.keyPacket.privateParams).to.not.be.null;
|
||
expect(key).to.deep.equal(originalKey);
|
||
});
|
||
});
|
||
|
||
it('encrypted key can be decrypted', async function() {
|
||
const { privateKey } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }], format: 'object' });
|
||
const locked = await openpgp.encryptKey({
|
||
privateKey,
|
||
passphrase: passphrase
|
||
});
|
||
expect(locked.isDecrypted()).to.be.false;
|
||
const unlocked = await openpgp.decryptKey({
|
||
privateKey: locked,
|
||
passphrase: passphrase
|
||
});
|
||
expect(unlocked.isDecrypted()).to.be.true;
|
||
});
|
||
|
||
it('should throw on empty passphrase', async function() {
|
||
const { privateKey } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }], format: 'object' });
|
||
await expect(openpgp.encryptKey({
|
||
privateKey,
|
||
passphrase: ''
|
||
})).to.be.rejectedWith(/passphrase is required for key encryption/);
|
||
});
|
||
|
||
it('should support multiple passphrases', async function() {
|
||
const { privateKey } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }], format: 'object' });
|
||
const passphrases = ['123', '456'];
|
||
const locked = await openpgp.encryptKey({
|
||
privateKey,
|
||
passphrase: passphrases
|
||
});
|
||
expect(locked.isDecrypted()).to.be.false;
|
||
await expect(openpgp.decryptKey({
|
||
privateKey: locked,
|
||
passphrase: passphrases[0]
|
||
})).to.eventually.be.rejectedWith(/Incorrect key passphrase/);
|
||
const unlocked = await openpgp.decryptKey({
|
||
privateKey: locked,
|
||
passphrase: passphrases
|
||
});
|
||
expect(unlocked.isDecrypted()).to.be.true;
|
||
});
|
||
|
||
it('should support encrypting with argon2 s2k', async function() {
|
||
const key = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey });
|
||
const locked = await openpgp.encryptKey({
|
||
privateKey: key,
|
||
passphrase: passphrase,
|
||
config: {
|
||
s2kType: openpgp.enums.s2k.argon2,
|
||
aeadProtect: true
|
||
}
|
||
});
|
||
expect(key.isDecrypted()).to.be.true;
|
||
expect(locked.isDecrypted()).to.be.false;
|
||
expect(locked.keyPacket.isDummy()).to.be.true;
|
||
const unlocked = await openpgp.decryptKey({
|
||
privateKey: locked,
|
||
passphrase: passphrase
|
||
});
|
||
expect(key.isDecrypted()).to.be.true;
|
||
expect(unlocked.isDecrypted()).to.be.true;
|
||
expect(unlocked.keyPacket.isDummy()).to.be.true;
|
||
});
|
||
|
||
it('should encrypt gnu-dummy key', async function() {
|
||
const key = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey });
|
||
const locked = await openpgp.encryptKey({
|
||
privateKey: key,
|
||
passphrase: passphrase
|
||
});
|
||
expect(key.isDecrypted()).to.be.true;
|
||
expect(locked.isDecrypted()).to.be.false;
|
||
expect(locked.keyPacket.isDummy()).to.be.true;
|
||
const unlocked = await openpgp.decryptKey({
|
||
privateKey: locked,
|
||
passphrase: passphrase
|
||
});
|
||
expect(key.isDecrypted()).to.be.true;
|
||
expect(unlocked.isDecrypted()).to.be.true;
|
||
expect(unlocked.keyPacket.isDummy()).to.be.true;
|
||
});
|
||
});
|
||
|
||
describe('decrypt - unit tests', function() {
|
||
let minRSABitsVal;
|
||
|
||
beforeEach(async function() {
|
||
minRSABitsVal = openpgp.config.minRSABits;
|
||
openpgp.config.minRSABits = 512;
|
||
});
|
||
|
||
afterEach(function() {
|
||
openpgp.config.minRSABits = minRSABitsVal;
|
||
});
|
||
|
||
it('Calling decrypt with encrypted key leads to exception', async function() {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const privateKey = await openpgp.readKey({ armoredKey: priv_key });
|
||
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: privateKey
|
||
};
|
||
const encrypted = await openpgp.encrypt(encOpt);
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
await expect(openpgp.decrypt(decOpt)).to.be.rejectedWith('Error decrypting message: Decryption key is not decrypted.');
|
||
});
|
||
|
||
it('decrypt/verify should succeed with valid signature (expectSigned=true)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey,
|
||
encryptionKeys: publicKey
|
||
});
|
||
const { data, signatures } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: publicKey,
|
||
expectSigned: true
|
||
});
|
||
expect(data).to.equal(plaintext);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
});
|
||
|
||
it('decrypt/verify should throw on missing public keys (expectSigned=true)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
});
|
||
await expect(openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: privateKey,
|
||
expectSigned: true
|
||
})).to.be.eventually.rejectedWith(/Verification keys are required/);
|
||
});
|
||
|
||
it('decrypt/verify should throw on missing signature (expectSigned=true)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey
|
||
});
|
||
await expect(openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: publicKey,
|
||
expectSigned: true
|
||
})).to.be.eventually.rejectedWith(/Message is not signed/);
|
||
});
|
||
|
||
it('decrypt/verify should throw on invalid signature (expectSigned=true)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const wrongPublicKey = (await openpgp.readKey({ armoredKey: priv_key_2000_2008 })).toPublic();
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
});
|
||
await expect(openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: wrongPublicKey,
|
||
expectSigned: true
|
||
})).to.be.eventually.rejectedWith(/Could not find signing key/);
|
||
});
|
||
|
||
it('decrypt/verify should succeed with valid signature (expectSigned=true, with streaming)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey,
|
||
encryptionKeys: publicKey
|
||
});
|
||
const { data: streamedData, signatures } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: stream.toStream(encrypted) }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: publicKey,
|
||
expectSigned: true
|
||
});
|
||
const data = await stream.readToEnd(streamedData);
|
||
expect(data).to.equal(plaintext);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
});
|
||
|
||
it('decrypt/verify should throw on missing public keys (expectSigned=true, with streaming)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
});
|
||
await expect(openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: stream.toStream(encrypted) }),
|
||
decryptionKeys: privateKey,
|
||
expectSigned: true
|
||
})).to.be.eventually.rejectedWith(/Verification keys are required/);
|
||
});
|
||
|
||
it('decrypt/verify should throw on missing signature (expectSigned=true, with streaming)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey
|
||
});
|
||
await expect(openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: stream.toStream(encrypted) }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: publicKey,
|
||
expectSigned: true
|
||
})).to.be.eventually.rejectedWith(/Message is not signed/);
|
||
});
|
||
|
||
it('decrypt/verify should throw on invalid signature (expectSigned=true, with streaming)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const wrongPublicKey = (await openpgp.readKey({ armoredKey: priv_key_2000_2008 })).toPublic();
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
});
|
||
const { data: streamedData } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: stream.toStream(encrypted) }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: wrongPublicKey,
|
||
expectSigned: true
|
||
});
|
||
await expect(
|
||
stream.readToEnd(streamedData)
|
||
).to.be.eventually.rejectedWith(/Could not find signing key/);
|
||
});
|
||
|
||
it('Supports decrypting with GnuPG dummy key', async function() {
|
||
const { rejectMessageHashAlgorithms } = openpgp.config;
|
||
Object.assign(openpgp.config, { rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.md5, openpgp.enums.hash.ripemd]) });
|
||
try {
|
||
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
||
Version: GnuPG v1.4.11 (GNU/Linux)
|
||
|
||
hQEOA1N4OCSSjECBEAP/diDJCQn4e88193PgqhbfAkohk9RQ0v0MPnXpJbCRTHKO
|
||
8r9nxiAr/TQv4ZOingXdAp2JZEoE9pXxZ3r1UWew04czxmgJ8FP1ztZYWVFAWFVi
|
||
Tj930TBD7L1fY/MD4fK6xjEG7z5GT8k4tn4mLm/PpWMbarIglfMopTy1M/py2cID
|
||
/2Sj7Ikh3UFiG+zm4sViYc5roNbMy8ixeoKixxi99Mx8INa2cxNfqbabjblFyc0Z
|
||
BwmbIc+ZiY2meRNI5y/tk0gRD7hT84IXGGl6/mH00bsX/kkWdKGeTvz8s5G8RDHa
|
||
Za4HgLbXItkX/QarvRS9kvkD01ujHfj+1ZvgmOBttNfP0p8BQLIICqvg1eYD9aPB
|
||
+GtOZ2F3+k5VyBL5yIn/s65SBjNO8Fqs3aL0x+p7s1cfUzx8J8a8nWpqq/qIQIqg
|
||
ZJH6MZRKuQwscwH6NWgsSVwcnVCAXnYOpbHxFQ+j7RbF/+uiuqU+DFH/Rd5pik8b
|
||
0Dqnp0yfefrkjQ0nuvubgB6Rv89mHpnvuJfFJRInpg4lrHwLvRwdpN2HDozFHcKK
|
||
aOU=
|
||
=4iGt
|
||
-----END PGP MESSAGE-----`;
|
||
const passphrase = 'abcd';
|
||
// exercises the GnuPG s2k type 1001 extension:
|
||
// the secrets on the primary key have been stripped.
|
||
const dummyKey = await openpgp.readKey({ armoredKey: armoredDummyPrivateKey1 });
|
||
const publicKey = await openpgp.readKey({ armoredKey: armoredPublicKey1 });
|
||
const message = await openpgp.readMessage({ armoredMessage });
|
||
const primaryKeyPacket = dummyKey.keyPacket.write();
|
||
expect(dummyKey.isDecrypted()).to.be.false;
|
||
const decryptedDummyKey = await openpgp.decryptKey({ privateKey: dummyKey, passphrase });
|
||
expect(decryptedDummyKey.isDecrypted()).to.be.true;
|
||
// decrypting with a secret subkey works
|
||
const msg = await openpgp.decrypt({
|
||
message, decryptionKeys: decryptedDummyKey, verificationKeys: publicKey, config: { rejectPublicKeyAlgorithms: new Set() }
|
||
});
|
||
expect(msg.signatures).to.exist;
|
||
expect(msg.signatures).to.have.length(1);
|
||
expect(await msg.signatures[0].verified).to.be.true;
|
||
expect((await msg.signatures[0].signature).packets.length).to.equal(1);
|
||
// secret key operations involving the primary key should fail
|
||
await expect(openpgp.sign({
|
||
message: await openpgp.createMessage({ text: 'test' }), signingKeys: decryptedDummyKey, config: { rejectPublicKeyAlgorithms: new Set() }
|
||
})).to.eventually.be.rejectedWith(/Cannot sign with a gnu-dummy key/);
|
||
await expect(
|
||
openpgp.reformatKey({ userIDs: { name: 'test' }, privateKey: decryptedDummyKey })
|
||
).to.eventually.be.rejectedWith(/Cannot reformat a gnu-dummy primary key/);
|
||
|
||
const encryptedDummyKey = await openpgp.encryptKey({ privateKey: decryptedDummyKey, passphrase });
|
||
expect(encryptedDummyKey.isDecrypted()).to.be.false;
|
||
const primaryKeyPacket2 = encryptedDummyKey.keyPacket.write();
|
||
expect(primaryKeyPacket).to.deep.equal(primaryKeyPacket2);
|
||
} finally {
|
||
Object.assign(openpgp.config, { rejectMessageHashAlgorithms });
|
||
}
|
||
});
|
||
|
||
it('decrypt with `config.constantTimePKCS1Decryption` option should succeed', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const publicKey2 = await openpgp.readKey({ armoredKey: eccPrivateKey });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey,
|
||
encryptionKeys: [publicKey, publicKey2]
|
||
});
|
||
const { data } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: privateKey,
|
||
config: { constantTimePKCS1Decryption: true }
|
||
});
|
||
expect(data).to.equal(plaintext);
|
||
});
|
||
|
||
it('decrypt with `config.constantTimePKCS1Decryption` option should succeed (with streaming)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const publicKey2 = await openpgp.readKey({ armoredKey: eccPrivateKey });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey,
|
||
encryptionKeys: [publicKey, publicKey2]
|
||
});
|
||
const { data: streamedData } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: stream.toStream(encrypted) }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: publicKey,
|
||
expectSigned: true,
|
||
config: { constantTimePKCS1Decryption: true }
|
||
});
|
||
const data = await stream.readToEnd(streamedData);
|
||
expect(data).to.equal(plaintext);
|
||
});
|
||
|
||
it('decrypt with `config.constantTimePKCS1Decryption` option should fail if session key algo support is disabled', async function () {
|
||
const publicKeyRSA = await openpgp.readKey({ armoredKey: pub_key });
|
||
const privateKeyRSA = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
const privateKeyECC = await openpgp.readPrivateKey({ armoredKey: eccPrivateKey });
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKeyRSA,
|
||
encryptionKeys: [publicKeyRSA, privateKeyECC]
|
||
});
|
||
|
||
const config = {
|
||
constantTimePKCS1Decryption: true,
|
||
constantTimePKCS1DecryptionSupportedSymmetricAlgorithms: new Set()
|
||
};
|
||
// decryption using RSA key should fail
|
||
await expect(openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: privateKeyRSA,
|
||
config
|
||
})).to.be.rejectedWith(/Session key decryption failed/);
|
||
// decryption using ECC key should succeed (PKCS1 is not used, so constant time countermeasures are not applied)
|
||
const { data } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: privateKeyECC,
|
||
config
|
||
});
|
||
expect(data).to.equal(plaintext);
|
||
});
|
||
|
||
});
|
||
|
||
describe('verify - unit tests', function() {
|
||
let minRSABitsVal;
|
||
|
||
beforeEach(async function() {
|
||
minRSABitsVal = openpgp.config.minRSABits;
|
||
openpgp.config.minRSABits = 512;
|
||
});
|
||
|
||
afterEach(function() {
|
||
openpgp.config.minRSABits = minRSABitsVal;
|
||
});
|
||
|
||
describe('message', function() {
|
||
verifyTests(false);
|
||
|
||
it('verify should succeed with valid signature (expectSigned=true, with streaming)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const signed = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey
|
||
});
|
||
const { data: streamedData, signatures } = await openpgp.verify({
|
||
message: await openpgp.readMessage({ armoredMessage: stream.toStream(signed) }),
|
||
verificationKeys: publicKey,
|
||
expectSigned: true
|
||
});
|
||
const data = await stream.readToEnd(streamedData);
|
||
expect(data).to.equal(plaintext);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
});
|
||
|
||
it('verify should throw on missing signature (expectSigned=true, with streaming)', async function () {
|
||
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
|
||
await expect(openpgp.verify({
|
||
message: await openpgp.createMessage({ text: stream.toStream(plaintext) }),
|
||
verificationKeys: publicKey,
|
||
expectSigned: true
|
||
})).to.be.eventually.rejectedWith(/Message is not signed/);
|
||
});
|
||
|
||
it('verify should throw on invalid signature (expectSigned=true, with streaming)', async function () {
|
||
const wrongPublicKey = (await openpgp.readKey({ armoredKey: priv_key_2000_2008 })).toPublic();
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const signed = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey
|
||
});
|
||
const { data: streamedData } = await openpgp.verify({
|
||
message: await openpgp.readMessage({ armoredMessage: stream.toStream(signed) }),
|
||
verificationKeys: wrongPublicKey,
|
||
expectSigned: true
|
||
});
|
||
await expect(
|
||
stream.readToEnd(streamedData)
|
||
).to.be.eventually.rejectedWith(/Could not find signing key/);
|
||
});
|
||
|
||
it('verify should fail if the signature is re-used with a different message', async function () {
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const message = await openpgp.createMessage({ text: 'a message' });
|
||
const armoredSignature = await openpgp.sign({
|
||
message,
|
||
signingKeys: privateKey,
|
||
detached: true
|
||
});
|
||
const { signatures } = await openpgp.verify({
|
||
message,
|
||
signature: await openpgp.readSignature({ armoredSignature }),
|
||
verificationKeys: privateKey.toPublic()
|
||
});
|
||
expect(await signatures[0].verified).to.be.true;
|
||
// pass a different message
|
||
await expect(openpgp.verify({
|
||
message: await openpgp.createMessage({ text: 'a different message' }),
|
||
signature: await openpgp.readSignature({ armoredSignature }),
|
||
verificationKeys: privateKey.toPublic(),
|
||
expectSigned: true
|
||
})).to.be.rejectedWith(/digest did not match/);
|
||
});
|
||
});
|
||
|
||
describe('cleartext message', function() {
|
||
verifyTests(true);
|
||
});
|
||
|
||
function verifyTests(useCleartext) {
|
||
const createMessage = useCleartext ? openpgp.createCleartextMessage : openpgp.createMessage;
|
||
const readMessage = ({ armoredMessage }) => (
|
||
useCleartext ?
|
||
openpgp.readCleartextMessage({ cleartextMessage: armoredMessage }) :
|
||
openpgp.readMessage({ armoredMessage })
|
||
);
|
||
const text = useCleartext ? util.removeTrailingSpaces(plaintext) : plaintext;
|
||
|
||
it('verify should succeed with valid signature (expectSigned=true)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const signed = await openpgp.sign({
|
||
message: await createMessage({ text }),
|
||
signingKeys: privateKey
|
||
});
|
||
const { data, signatures } = await openpgp.verify({
|
||
message: await readMessage({ armoredMessage: signed }),
|
||
verificationKeys: publicKey,
|
||
expectSigned: true
|
||
});
|
||
expect(data).to.equal(text);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
});
|
||
|
||
it('verify should throw on missing signature (expectSigned=true)', async function () {
|
||
const publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
|
||
await expect(openpgp.verify({
|
||
message: await createMessage({ text }),
|
||
verificationKeys: publicKey,
|
||
expectSigned: true
|
||
})).to.be.eventually.rejectedWith(/Message is not signed/);
|
||
});
|
||
|
||
it('verify should throw on invalid signature (expectSigned=true)', async function () {
|
||
const wrongPublicKey = (await openpgp.readKey({ armoredKey: priv_key_2000_2008 })).toPublic();
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const signed = await openpgp.sign({
|
||
message: await createMessage({ text }),
|
||
signingKeys: privateKey
|
||
});
|
||
await expect(openpgp.verify({
|
||
message: await readMessage({ armoredMessage: signed }),
|
||
verificationKeys: wrongPublicKey,
|
||
expectSigned: true
|
||
})).to.be.eventually.rejectedWith(/Could not find signing key/);
|
||
});
|
||
}
|
||
});
|
||
|
||
describe('sign - unit tests', function() {
|
||
it('Supports signing with GnuPG dummy key', async function() {
|
||
const dummyKey = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey });
|
||
const sig = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: 'test' }),
|
||
signingKeys: dummyKey,
|
||
date: new Date('2018-12-17T03:24:00'),
|
||
config: { minRSABits: 1024 }
|
||
});
|
||
expect(sig).to.match(/-----END PGP MESSAGE-----\n$/);
|
||
});
|
||
|
||
it('Calling sign with no signing key leads to exception', async function() {
|
||
await expect(openpgp.sign({
|
||
message: await openpgp.createMessage({ text: plaintext })
|
||
})).to.be.rejectedWith(/No signing keys provided/);
|
||
});
|
||
|
||
it('Signing with key which uses sha3 should generate a valid sha3 signature', async function() {
|
||
const privKey = await openpgp.readKey({ armoredKey: priv_key_sha3 });
|
||
const pubKey = privKey.toPublic();
|
||
const text = 'Hello, world.';
|
||
const message = await openpgp.createCleartextMessage({ text });
|
||
|
||
const cleartextMessage = await openpgp.sign({ message, signingKeys: privKey, format: 'armored' });
|
||
const parsedArmored = await openpgp.readCleartextMessage({ cleartextMessage });
|
||
expect(parsedArmored.signature.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
|
||
expect(
|
||
parsedArmored.signature.packets.filterByTag(openpgp.enums.packet.signature)[0].hashAlgorithm
|
||
).to.equal(openpgp.enums.hash.sha3_512);
|
||
|
||
const verified = await openpgp.verify({ message: parsedArmored, verificationKeys: pubKey, expectSigned: true });
|
||
expect(verified.data).to.equal(text);
|
||
});
|
||
|
||
it('should output cleartext message of expected format', async function() {
|
||
const text = 'test';
|
||
const message = await openpgp.createCleartextMessage({ text });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
const config = { minRSABits: 1024 };
|
||
|
||
const cleartextMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'armored' });
|
||
const parsedArmored = await openpgp.readCleartextMessage({ cleartextMessage });
|
||
expect(parsedArmored.text).to.equal(text);
|
||
expect(parsedArmored.signature.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
|
||
|
||
await expect(openpgp.sign({ message, signingKeys: privateKey, config, format: 'binary' })).to.be.rejectedWith('');
|
||
|
||
const objectMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'object' });
|
||
expect(objectMessage.signature.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
|
||
const verified = await openpgp.verify({ message: objectMessage, verificationKeys: privateKey, expectSigned: true, config });
|
||
expect(verified.data).to.equal(text);
|
||
});
|
||
|
||
it('should output message of expected format', async function() {
|
||
const text = 'test';
|
||
const message = await openpgp.createMessage({ text });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
const config = { minRSABits: 1024 };
|
||
|
||
const armoredMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'armored' });
|
||
const parsedArmored = await openpgp.readMessage({ armoredMessage });
|
||
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
|
||
|
||
const binaryMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'binary' });
|
||
const parsedBinary = await openpgp.readMessage({ binaryMessage });
|
||
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
|
||
|
||
const objectMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'object' });
|
||
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
|
||
const verified = await openpgp.verify({ message: objectMessage, verificationKeys: privateKey, expectSigned: true, config });
|
||
expect(verified.data).to.equal(text);
|
||
});
|
||
|
||
it('should output message of expected format', async function() {
|
||
const text = 'test';
|
||
const message = await openpgp.createMessage({ text });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
const config = { minRSABits: 1024 };
|
||
|
||
const armoredMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'armored' });
|
||
const parsedArmored = await openpgp.readMessage({ armoredMessage });
|
||
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
|
||
|
||
const binaryMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'binary' });
|
||
const parsedBinary = await openpgp.readMessage({ binaryMessage });
|
||
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
|
||
|
||
const objectMessage = await openpgp.sign({ message, signingKeys: privateKey, config, format: 'object' });
|
||
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
|
||
const verified = await openpgp.verify({ message: objectMessage, verificationKeys: privateKey, expectSigned: true, config });
|
||
expect(verified.data).to.equal(text);
|
||
});
|
||
|
||
it('should output message of expected format (with streaming)', async function() {
|
||
const text = 'test';
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
const config = { minRSABits: 1024 };
|
||
|
||
const armoredMessage = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: stream.toStream(text) }),
|
||
signingKeys: privateKey,
|
||
format: 'armored',
|
||
config
|
||
});
|
||
const parsedArmored = await openpgp.readMessage({ armoredMessage });
|
||
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
|
||
|
||
const binaryMessage = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: stream.toStream(text) }),
|
||
signingKeys: privateKey,
|
||
format: 'binary',
|
||
config
|
||
});
|
||
const parsedBinary = await openpgp.readMessage({ binaryMessage });
|
||
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
|
||
|
||
const objectMessage = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: stream.toStream(text) }),
|
||
signingKeys: privateKey,
|
||
format: 'object',
|
||
config
|
||
});
|
||
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.onePassSignature)).to.have.length(1);
|
||
objectMessage.packets[1].data = await stream.readToEnd(objectMessage.packets[1].data);
|
||
objectMessage.packets[2].signedHashValue = await stream.readToEnd(objectMessage.packets[2].signedHashValue);
|
||
const { data: streamedData } = await openpgp.verify({ message: objectMessage, verificationKeys: privateKey, expectSigned: true, config });
|
||
expect(await stream.readToEnd(streamedData)).to.equal(text);
|
||
expect(streamedData).to.equal(text);
|
||
});
|
||
|
||
it('should output message of expected format (detached)', async function() {
|
||
const text = 'test';
|
||
const message = await openpgp.createMessage({ text });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
const config = { minRSABits: 1024 };
|
||
|
||
const armoredSignature = await openpgp.sign({ message, signingKeys: privateKey, detached: true, config, format: 'armored' });
|
||
const parsedArmored = await openpgp.readSignature({ armoredSignature });
|
||
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
|
||
|
||
const binarySignature = await openpgp.sign({ message, signingKeys: privateKey, detached: true, config, format: 'binary' });
|
||
const parsedBinary = await openpgp.readSignature({ binarySignature });
|
||
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
|
||
|
||
const objectSignature = await openpgp.sign({ message, signingKeys: privateKey, detached: true, config, format: 'object' });
|
||
expect(objectSignature.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
|
||
const verified = await openpgp.verify({ message, signature: objectSignature, verificationKeys: privateKey, expectSigned: true, config });
|
||
expect(verified.data).to.equal(text);
|
||
});
|
||
|
||
it('should output message of expected format (detached, with streaming)', async function() {
|
||
const text = 'test';
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
const config = { minRSABits: 1024 };
|
||
|
||
const armoredSignature = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: stream.toStream(text) }),
|
||
signingKeys: privateKey,
|
||
detached: true,
|
||
format: 'armored',
|
||
config
|
||
});
|
||
const parsedArmored = await openpgp.readSignature({ armoredSignature: await stream.readToEnd(armoredSignature) });
|
||
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
|
||
|
||
const binarySignature = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: stream.toStream(text) }),
|
||
signingKeys: privateKey,
|
||
detached: true,
|
||
format: 'binary',
|
||
config
|
||
});
|
||
const parsedBinary = await openpgp.readSignature({ binarySignature: await stream.readToEnd(binarySignature) });
|
||
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
|
||
|
||
const streamedMessage = await openpgp.createMessage({ text: stream.toStream(text) });
|
||
const objectSignature = await openpgp.sign({
|
||
message: streamedMessage,
|
||
signingKeys: privateKey,
|
||
detached: true,
|
||
format: 'object',
|
||
config
|
||
});
|
||
expect(objectSignature.packets.filterByTag(openpgp.enums.packet.signature)).to.have.length(1);
|
||
|
||
const armoredStreamedMessage = streamedMessage.armor(); // consume input message stream, to allow to read the signed hash
|
||
objectSignature.packets[0].signedHashValue = await stream.readToEnd(objectSignature.packets[0].signedHashValue);
|
||
const { data: streamedData } = await openpgp.verify({
|
||
message: await openpgp.readMessage({ armoredMessage: armoredStreamedMessage }),
|
||
signature: objectSignature,
|
||
verificationKeys: privateKey,
|
||
expectSigned: true,
|
||
config
|
||
});
|
||
expect(await stream.readToEnd(streamedData)).to.equal(text);
|
||
});
|
||
});
|
||
|
||
describe('encrypt - unit tests', function() {
|
||
it('should output message of expected format', async function() {
|
||
const passwords = 'password';
|
||
const text = 'test';
|
||
const message = await openpgp.createMessage({ text });
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const armoredMessage = await openpgp.encrypt({ message, passwords, format: 'armored' });
|
||
const parsedArmored = await openpgp.readMessage({ armoredMessage });
|
||
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
|
||
|
||
const binaryMessage = await openpgp.encrypt({ message, passwords, format: 'binary' });
|
||
const parsedBinary = await openpgp.readMessage({ binaryMessage });
|
||
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
|
||
|
||
const config = { minRSABits: 1024 };
|
||
const objectMessage = await openpgp.encrypt({ message, passwords, signingKeys: privateKey, config, format: 'object' });
|
||
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
|
||
const decrypted = await openpgp.decrypt({ message: objectMessage, passwords, verificationKeys: privateKey, expectSigned: true, config });
|
||
expect(decrypted.data).to.equal(text);
|
||
});
|
||
|
||
it('should output message of expected format (with streaming)', async function() {
|
||
const passwords = 'password';
|
||
const text = 'test';
|
||
const privateKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase
|
||
});
|
||
|
||
const armoredMessage = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: stream.toStream(text) }),
|
||
passwords,
|
||
format: 'armored'
|
||
});
|
||
const parsedArmored = await openpgp.readMessage({ armoredMessage });
|
||
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
|
||
|
||
const binaryMessage = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: stream.toStream(text) }),
|
||
passwords,
|
||
format: 'binary'
|
||
});
|
||
const parsedBinary = await openpgp.readMessage({ binaryMessage });
|
||
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
|
||
|
||
const config = { minRSABits: 1024 };
|
||
const objectMessage = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: stream.toStream(text) }),
|
||
passwords,
|
||
signingKeys: privateKey,
|
||
format: 'object',
|
||
config
|
||
});
|
||
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
|
||
const { data: streamedData } = await openpgp.decrypt({ message: objectMessage, passwords, verificationKeys: privateKey, expectSigned: true, config });
|
||
expect(await stream.readToEnd(streamedData)).to.equal(text);
|
||
});
|
||
|
||
it('should support encrypting with encrypted key with unknown s2k (unparseableKeyMaterial)', async function() {
|
||
const originalDecryptedKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xVgEZJ2H3RYJKwYBBAHaRw8BAQdA3V39Xv0+436Rpn/2UlcnOC1BGprmAlWY
|
||
RBKjAq0hAtAAAQCykslk/kEP7+O9sOsuvgX2Xfz4peQuNo2vD/w4dMZpchKj
|
||
zQDCjAQQFgoAPgWCZJ2H3QQLCQcICZBoFPuDFJOxfAMVCAoEFgACAQIZAQKb
|
||
AwIeARYhBK9GclNBPpO11kWTQ2gU+4MUk7F8AABPuQEAuaZQQm3kcwA5aJbv
|
||
/zLjCWWbzM1D29uXlDRxZt5aP/wA/0cNratHEdj/fuDnNd2Yv1/+o1av0WQQ
|
||
FGEsvC6y6a4Mx10EZJ2H3RIKKwYBBAGXVQEFAQEHQCbbKOOJqV4hVccknY9v
|
||
sqJqkILSYP3kXQQXPrPPSXgOAwEIBwAA/34s+u8hyLdzdLxjrEEN9zNb+C8d
|
||
EyBNxMpyZ/NJsUxoEIPCeAQYFggAKgWCZJ2H3QmQaBT7gxSTsXwCmwwWIQSv
|
||
RnJTQT6TtdZFk0NoFPuDFJOxfAAA8H8A/ArDlcP985tVMFGxlIvn7n+j61RQ
|
||
SxvLnPSImimp5/w2AQCXGTWR0Un6Q6FdqVAORABItjHY8ZEcrBUJ2D0QLtKW
|
||
Dg==
|
||
=wiwz
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
// `originalDecryptedKey` encrypted with invalid s2kType = 23, to test that it can still be used for encryption/verification
|
||
const encryptedKeyUnknownS2K = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xYYEZJ2H3RYJKwYBBAHaRw8BAQdA3V39Xv0+436Rpn/2UlcnOC1BGprmAlWY
|
||
RBKjAq0hAtD+CRcIdHzwqoLa54cAbBOEIgBh7Xa1Qh5wCGAmEVWnAldaqvk+
|
||
NcvUL2bR6AQsGIT6YEihOS3xLKobMOd2XlO5ItQoWnONzkWgzjFvctgnlhmq
|
||
I80AwowEEBYKAD4FgmSdh90ECwkHCAmQaBT7gxSTsXwDFQgKBBYAAgECGQEC
|
||
mwMCHgEWIQSvRnJTQT6TtdZFk0NoFPuDFJOxfAAAT7kBALmmUEJt5HMAOWiW
|
||
7/8y4wllm8zNQ9vbl5Q0cWbeWj/8AP9HDa2rRxHY/37g5zXdmL9f/qNWr9Fk
|
||
EBRhLLwusumuDMeLBGSdh90SCisGAQQBl1UBBQEBB0Am2yjjialeIVXHJJ2P
|
||
b7KiapCC0mD95F0EFz6zz0l4DgMBCAf+CRcISMdt0OUFCNUABB/OD0UW7MPK
|
||
Y3t8RrUTYoiCuhuPRDLOJ5NnMNagVQLt3jQsI8JRjzmYbiTrA/V3iJIEDu5C
|
||
NWbnvCM7Hs7+OqPzJPJ2w8J4BBgWCAAqBYJknYfdCZBoFPuDFJOxfAKbDBYh
|
||
BK9GclNBPpO11kWTQ2gU+4MUk7F8AADwfwD8CsOVw/3zm1UwUbGUi+fuf6Pr
|
||
VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
|
||
0pYO
|
||
=rWL8
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: 'test' }),
|
||
encryptionKeys: encryptedKeyUnknownS2K
|
||
});
|
||
|
||
// decrypt with original key
|
||
const decrypted = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: originalDecryptedKey
|
||
});
|
||
expect(decrypted.data).to.equal('test');
|
||
});
|
||
|
||
it('does not encrypt to expired key (expiration time subpacket on a direct-key signature)', async function() {
|
||
const expiredKey = await openpgp.readKey({ armoredKey: expiredPublicKeyThroughDirectSignature });
|
||
await expect(
|
||
openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: expiredKey })
|
||
).to.be.rejectedWith(/Primary key is expired/);
|
||
});
|
||
|
||
it('uses AEAD when the encryption key prefs support it (SEIPDv2', async function() {
|
||
const v4PrivateKeyWithOCBPref = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
|
||
exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
|
||
BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||
2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
|
||
RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
|
||
7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
|
||
LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
|
||
GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||
2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
|
||
M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
|
||
k0mXubZvyl4GBg==
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
const v6PrivateKeyWithOCBPref = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
|
||
exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
|
||
BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||
2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
|
||
RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
|
||
7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
|
||
LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
|
||
GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||
2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
|
||
M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
|
||
k0mXubZvyl4GBg==
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: 'test' }),
|
||
encryptionKeys: [v4PrivateKeyWithOCBPref, v6PrivateKeyWithOCBPref],
|
||
format: 'object'
|
||
});
|
||
|
||
const seipd = encrypted.packets[2];
|
||
expect(seipd).to.be.instanceOf(openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||
expect(seipd.version).to.equal(2);
|
||
expect(seipd.aeadAlgorithm).to.equal(openpgp.enums.aead.ocb);
|
||
});
|
||
|
||
it('should support encrypting to a key without features (missing SEIPDv1 feature)', async function () {
|
||
const key = await openpgp.readKey({ armoredKey: rsaKeyWithNoFeaturesFromRNP });
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: 'test' }),
|
||
encryptionKeys: key
|
||
});
|
||
const decrypted = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: key
|
||
});
|
||
expect(decrypted.data).to.equal('test');
|
||
});
|
||
});
|
||
|
||
describe('encryptSessionKey - unit tests', function() {
|
||
it('should output message of expected format', async function() {
|
||
const passwords = 'password';
|
||
const sessionKey = { data: new Uint8Array(16).fill(1), algorithm: 'aes128' };
|
||
|
||
const armoredMessage = await openpgp.encryptSessionKey({ ...sessionKey, passwords, format: 'armored' });
|
||
const parsedArmored = await openpgp.readMessage({ armoredMessage });
|
||
expect(parsedArmored.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
|
||
|
||
const binaryMessage = await openpgp.encryptSessionKey({ ...sessionKey, passwords, format: 'binary' });
|
||
const parsedBinary = await openpgp.readMessage({ binaryMessage });
|
||
expect(parsedBinary.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
|
||
|
||
const objectMessage = await openpgp.encryptSessionKey({ ...sessionKey, passwords, format: 'object' });
|
||
expect(objectMessage.packets.filterByTag(openpgp.enums.packet.symEncryptedSessionKey)).to.have.length(1);
|
||
const [decryptedSessionKey] = await openpgp.decryptSessionKeys({ message: objectMessage, passwords });
|
||
expect(decryptedSessionKey).to.deep.equal(sessionKey);
|
||
});
|
||
|
||
it('passing no encryption keys or passwords leads to exception', async function() {
|
||
await expect(openpgp.encryptSessionKey({
|
||
algorithm: 'aes256',
|
||
data: util.hexToUint8Array('3e99c1bb485e70a1fcef09a7ad8d38d171015243bbdd853e1a2b0e334d122ff3')
|
||
})).to.be.rejectedWith(/No encryption keys or passwords provided/);
|
||
});
|
||
|
||
// keep this after the 'memory-heavy' test to confirm that the Wasm module was successfully reloaded
|
||
it('supports encrypting with argon2 s2k', async function() {
|
||
const config = { s2kType: openpgp.enums.s2k.argon2 };
|
||
const passwords = 'password';
|
||
const sessionKey = {
|
||
algorithm: 'aes128',
|
||
data: util.hexToUint8Array('01FE16BBACFD1E7B78EF3B865187374F')
|
||
};
|
||
const encrypted = await openpgp.encryptSessionKey({ ...sessionKey, passwords, config, format: 'object' });
|
||
expect(encrypted.packets).to.have.length(1);
|
||
const skesk = encrypted.packets[0];
|
||
expect(skesk.s2k.type).to.equal('argon2');
|
||
const [decryptedSessionKey] = await openpgp.decryptSessionKeys({ message: encrypted, passwords });
|
||
expect(decryptedSessionKey).to.deep.equal(sessionKey);
|
||
});
|
||
});
|
||
|
||
describe('decryptSessionKeys - unit tests', function() {
|
||
it('should decrypt message with two SKESKs where the wrong password returns a symmetric algo equal to 0', async function () {
|
||
// SKESK packets do not have an intrisic integrity check, and the session key must be used to check its validity.
|
||
// This message is such that when the password is used to try and decrypt the first (mismatching) SKESK, the result returns a '0' byte for
|
||
// the session key algo. This corresponds to the 'plaintext' algo identifier (https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-12.2.1),
|
||
// now removed from OpenPGP.js .
|
||
// This test guards against regressions caused by mishandling this value on SKESK decryption.
|
||
const message = await openpgp.readMessage({ armoredMessage:`-----BEGIN PGP MESSAGE-----
|
||
|
||
wy4ECQMIf6HA/a6XkOAAlaU1z+uVfU5kmHmqNqahQH859nAMresQ6w1uIjsL
|
||
ZE5bwy4ECQMIKVfCf+GWBesA5KFPuIDa6kLLn/AvEgbCi5DOg2xdIf73SNSN
|
||
Tqy7nfex0sANAVtHHRkHVTRVTVa3MFjjiWeBEDtnfyVMntWJ21ihrIU9eb9p
|
||
qS7UljZZ0u++xSWclU2IGBXCIdO0wLuS6hYk3q5OFexWj8OIoYJX88nkA2iW
|
||
5xyGd9EFRWVsR4CREt8lwrIE2t/h8XpRlhJmY6Iefg8+2DeN8vDdhNs/B02o
|
||
0zAE0hF+3xvwZTLi4hDrhBZEgBedPaeX4jlmDc3qzh2wlgV/Mq/FUakYfSLl
|
||
bc1PCpfqkLZSuCfv4eoTrWohWi9lS/pRXY9hzzHtlnjo6w==
|
||
-----END PGP MESSAGE-----` });
|
||
const sessionKeys = await openpgp.decryptSessionKeys({ message, passwords: 'I am another password' });
|
||
expect(sessionKeys).to.have.length(1); // first SKESK dropped due to '0' being treated as invalid algo identifier
|
||
expect(sessionKeys[0].algorithm).to.equal('aes256');
|
||
|
||
// decrypt() used to fail on this type of input
|
||
const decrypted = await openpgp.decrypt({ message, passwords: 'I am another password', format: 'binary' });
|
||
expect(decrypted.data).to.deep.equal(
|
||
util.hexToUint8Array('e280872009d699e0b5bae18ba1e28c86d280d184e1b888e1a8b3e28ab7e0afa8e0b98be283bde28db5e1b1afd48de1b5b2e280a7e199b0e1a487e185afd3a1e18ca5e0bfb4e28892e19e98e29bb8e29594e0baaae0b681e1929af09f9882f09f9897f09f9882f09f98abf09f988ff09f98b6f09f98bcf09f98bcf09f9981f09f9982e2808720090d0aed959ceab5adec96b42feca1b0ec84a0eba790')
|
||
);
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
|
||
it('should decrypt PKESK v6 and return a null symmetric algorithm', async function() {
|
||
// test vector https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#appendix-A.8
|
||
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
||
|
||
wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO
|
||
WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS
|
||
aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l
|
||
yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo
|
||
bhF30A+IitsxxA==
|
||
-----END PGP MESSAGE-----`;
|
||
|
||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
|
||
exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
|
||
BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||
2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
|
||
RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
|
||
7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
|
||
LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
|
||
GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||
2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
|
||
M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
|
||
k0mXubZvyl4GBg==
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
|
||
const sessionKeys = await openpgp.decryptSessionKeys({
|
||
message: await openpgp.readMessage({ armoredMessage }),
|
||
decryptionKeys: privateKey
|
||
});
|
||
|
||
expect(sessionKeys).to.have.length(1);
|
||
expect(sessionKeys[0].algorithm).to.equal(null); // PKESK v6 does not include the algo info
|
||
});
|
||
|
||
it('supports decrypting with argon2 s2k (memory-heavy params)', async function() {
|
||
const passwords = 'password';
|
||
// Test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#appendix-A.8.1
|
||
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
||
Comment: Encrypted using AES with 128-bit key
|
||
Comment: Session key: 01FE16BBACFD1E7B78EF3B865187374F
|
||
|
||
wycEBwScUvg8J/leUNU1RA7N/zE2AQQVnlL8rSLPP5VlQsunlO+ECxHSPgGYGKY+
|
||
YJz4u6F+DDlDBOr5NRQXt/KJIf4m4mOlKyC/uqLbpnLJZMnTq3o79GxBTdIdOzhH
|
||
XfA3pqV4mTzF
|
||
-----END PGP MESSAGE-----`;
|
||
const expectedSessionKey = util.hexToUint8Array('01FE16BBACFD1E7B78EF3B865187374F');
|
||
|
||
try {
|
||
const [decryptedSessionKey] = await openpgp.decryptSessionKeys({
|
||
message: await openpgp.readMessage({ armoredMessage }),
|
||
passwords
|
||
});
|
||
expect(decryptedSessionKey.data).to.deep.equal(expectedSessionKey);
|
||
expect(decryptedSessionKey.algorithm).to.equal('aes128');
|
||
} catch (err) {
|
||
if (detectBrowser()) { // Expected to fail in the CI, especially in Browserstack
|
||
expect(err.message).to.match(/Could not allocate required memory/);
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
describe('encrypt, decrypt, sign, verify - integration tests', function() {
|
||
let privateKey_2000_2008;
|
||
let publicKey_2000_2008;
|
||
let privateKey_2038_2045;
|
||
let publicKey_2038_2045;
|
||
let privateKey_1337;
|
||
let publicKey_1337;
|
||
let privateKey;
|
||
let publicKey;
|
||
let publicKeyNoAEAD;
|
||
|
||
let aeadProtectVal;
|
||
let preferredAEADAlgorithmVal;
|
||
let aeadChunkSizeByteVal;
|
||
let v6KeysVal;
|
||
let minRSABitsVal;
|
||
|
||
beforeEach(async function() {
|
||
publicKey = await openpgp.readKey({ armoredKey: pub_key });
|
||
publicKeyNoAEAD = await openpgp.readKey({ armoredKey: pub_key });
|
||
privateKey = await openpgp.readKey({ armoredKey: priv_key });
|
||
privateKey_2000_2008 = await openpgp.readKey({ armoredKey: priv_key_2000_2008 });
|
||
publicKey_2000_2008 = privateKey_2000_2008.toPublic();
|
||
privateKey_2038_2045 = await openpgp.readKey({ armoredKey: priv_key_2038_2045 });
|
||
publicKey_2038_2045 = privateKey_2038_2045.toPublic();
|
||
privateKey_1337 = await openpgp.readKey({ armoredKey: priv_key_expires_1337 });
|
||
publicKey_1337 = privateKey_1337.toPublic();
|
||
|
||
aeadProtectVal = openpgp.config.aeadProtect;
|
||
preferredAEADAlgorithmVal = openpgp.config.preferredAEADAlgorithm;
|
||
aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
|
||
v6KeysVal = openpgp.config.v6Keys;
|
||
minRSABitsVal = openpgp.config.minRSABits;
|
||
|
||
openpgp.config.minRSABits = 512;
|
||
});
|
||
|
||
afterEach(function() {
|
||
openpgp.config.aeadProtect = aeadProtectVal;
|
||
openpgp.config.preferredAEADAlgorithm = preferredAEADAlgorithmVal;
|
||
openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
|
||
openpgp.config.v6Keys = v6KeysVal;
|
||
openpgp.config.minRSABits = minRSABitsVal;
|
||
});
|
||
|
||
it('Configuration', async function() {
|
||
const showCommentVal = openpgp.config.showComment;
|
||
const showVersionVal = openpgp.config.showVersion;
|
||
const commentStringVal = openpgp.config.commentString;
|
||
|
||
try {
|
||
const encryptedDefault = await openpgp.encrypt({ encryptionKeys:publicKey, message:await openpgp.createMessage({ text: plaintext }) });
|
||
expect(encryptedDefault).to.exist;
|
||
expect(encryptedDefault).not.to.match(/^Version:/);
|
||
expect(encryptedDefault).not.to.match(/^Comment:/);
|
||
|
||
openpgp.config.showComment = true;
|
||
openpgp.config.commentString = 'different';
|
||
const encryptedWithComment = await openpgp.encrypt({ encryptionKeys:publicKey, message:await openpgp.createMessage({ text: plaintext }) });
|
||
expect(encryptedWithComment).to.exist;
|
||
expect(encryptedWithComment).not.to.match(/^Version:/);
|
||
expect(encryptedWithComment).to.match(/Comment: different/);
|
||
} finally {
|
||
openpgp.config.showComment = showCommentVal;
|
||
openpgp.config.showVersion = showVersionVal;
|
||
openpgp.config.commentString = commentStringVal;
|
||
}
|
||
});
|
||
|
||
tryTests('CFB mode (asm.js)', tests, {
|
||
if: true,
|
||
beforeEach: function() {
|
||
openpgp.config.aeadProtect = false;
|
||
}
|
||
});
|
||
|
||
tryTests('GCM mode (V6 keys)', tests, {
|
||
if: true,
|
||
beforeEach: function() {
|
||
openpgp.config.aeadProtect = true;
|
||
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.gcm;
|
||
openpgp.config.v6Keys = true;
|
||
|
||
// Monkey-patch SEIPD V2 feature flag
|
||
publicKey.users[0].selfCertifications[0].features = [9];
|
||
publicKey_2000_2008.users[0].selfCertifications[0].features = [9];
|
||
publicKey_2038_2045.users[0].selfCertifications[0].features = [9];
|
||
}
|
||
});
|
||
|
||
tryTests('EAX mode (small chunk size)', tests, {
|
||
if: true,
|
||
beforeEach: function() {
|
||
openpgp.config.aeadProtect = true;
|
||
openpgp.config.aeadChunkSizeByte = 0;
|
||
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.eax;
|
||
|
||
// Monkey-patch SEIPD V2 feature flag
|
||
publicKey.users[0].selfCertifications[0].features = [9];
|
||
publicKey_2000_2008.users[0].selfCertifications[0].features = [9];
|
||
publicKey_2038_2045.users[0].selfCertifications[0].features = [9];
|
||
}
|
||
});
|
||
|
||
tryTests('OCB mode', tests, {
|
||
if: true,
|
||
beforeEach: function() {
|
||
openpgp.config.aeadProtect = true;
|
||
openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.ocb;
|
||
|
||
// Monkey-patch SEIPD V2 feature flag
|
||
publicKey.users[0].selfCertifications[0].features = [9];
|
||
publicKey_2000_2008.users[0].selfCertifications[0].features = [9];
|
||
publicKey_2038_2045.users[0].selfCertifications[0].features = [9];
|
||
}
|
||
});
|
||
|
||
function tests() {
|
||
describe('encryptSessionKey, decryptSessionKeys', function() {
|
||
const sk = new Uint8Array([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]);
|
||
|
||
let decryptedPrivateKey; // to avoid decrypting key before each test
|
||
beforeEach(async function() {
|
||
if (!decryptedPrivateKey) {
|
||
decryptedPrivateKey = await openpgp.decryptKey({ privateKey, passphrase });
|
||
}
|
||
privateKey = decryptedPrivateKey;
|
||
});
|
||
|
||
it('should encrypt with public key', function() {
|
||
return openpgp.encryptSessionKey({
|
||
data: sk,
|
||
algorithm: 'aes128',
|
||
encryptionKeys: publicKey,
|
||
format: 'binary'
|
||
}).then(async function(encrypted) {
|
||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||
return openpgp.decryptSessionKeys({
|
||
message,
|
||
decryptionKeys: privateKey
|
||
});
|
||
}).then(function(decrypted) {
|
||
expect(decrypted[0].data).to.deep.equal(sk);
|
||
});
|
||
});
|
||
|
||
it('should encrypt with password', function() {
|
||
return openpgp.encryptSessionKey({
|
||
data: sk,
|
||
algorithm: 'aes128',
|
||
passwords: password1,
|
||
format: 'binary'
|
||
}).then(async function(encrypted) {
|
||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||
return openpgp.decryptSessionKeys({
|
||
message,
|
||
passwords: password1
|
||
});
|
||
}).then(function(decrypted) {
|
||
expect(decrypted[0].data).to.deep.equal(sk);
|
||
});
|
||
});
|
||
|
||
it('should not decrypt with a key without binding signatures', function() {
|
||
return openpgp.encryptSessionKey({
|
||
data: sk,
|
||
algorithm: 'aes128',
|
||
encryptionKeys: publicKey,
|
||
format: 'binary'
|
||
}).then(async function(encrypted) {
|
||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||
const invalidPrivateKey = await openpgp.readKey({ armoredKey: priv_key });
|
||
invalidPrivateKey.subkeys[0].bindingSignatures = [];
|
||
return openpgp.decryptSessionKeys({
|
||
message,
|
||
decryptionKeys: invalidPrivateKey
|
||
}).then(() => {
|
||
throw new Error('Should not decrypt with invalid key');
|
||
}).catch(error => {
|
||
expect(error.message).to.match(/Error decrypting session keys: Session key decryption failed./);
|
||
});
|
||
});
|
||
});
|
||
|
||
it('roundtrip workflow: encrypt, decryptSessionKeys, decrypt with pgp key pair', async function () {
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey
|
||
});
|
||
const decryptedSessionKeys = await openpgp.decryptSessionKeys({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: privateKey
|
||
});
|
||
const decrypted = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
sessionKeys: decryptedSessionKeys[0]
|
||
});
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
});
|
||
|
||
it('roundtrip workflow: encrypt, decryptSessionKeys, decrypt with pgp key pair -- trailing spaces', async function () {
|
||
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey
|
||
});
|
||
const decryptedSessionKeys = await openpgp.decryptSessionKeys({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: privateKey
|
||
});
|
||
const decrypted = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
sessionKeys: decryptedSessionKeys[0]
|
||
});
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
});
|
||
|
||
it('roundtrip workflow: encrypt, decryptSessionKeys, decrypt with password', async function () {
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
passwords: password1
|
||
});
|
||
const decryptedSessionKeys = await openpgp.decryptSessionKeys({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
passwords: password1
|
||
});
|
||
const decrypted = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
sessionKeys: decryptedSessionKeys[0]
|
||
});
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
});
|
||
|
||
it('roundtrip workflow: encrypt with multiple passwords, decryptSessionKeys, decrypt with multiple passwords', async function () {
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
passwords: [password1, password2]
|
||
});
|
||
const decryptedSessionKeys = await openpgp.decryptSessionKeys({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
passwords: [password1, password2]
|
||
});
|
||
const decrypted = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
sessionKeys: decryptedSessionKeys[0]
|
||
});
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
});
|
||
|
||
it('roundtrip workflow: encrypt twice with one password, decryptSessionKeys, only one session key', async function () {
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
passwords: [password1, password1]
|
||
});
|
||
const decryptedSessionKeys = await openpgp.decryptSessionKeys({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
passwords: password1
|
||
});
|
||
expect(decryptedSessionKeys.length).to.equal(1);
|
||
const decrypted = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
sessionKeys: decryptedSessionKeys[0]
|
||
});
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
});
|
||
});
|
||
|
||
describe('AES / RSA encrypt, decrypt, sign, verify', function() {
|
||
const wrong_pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n' +
|
||
'Version: OpenPGP.js v0.9.0\r\n' +
|
||
'Comment: Hoodiecrow - https://hoodiecrow.com\r\n' +
|
||
'\r\n' +
|
||
'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\r\n' +
|
||
'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\r\n' +
|
||
'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\r\n' +
|
||
'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\r\n' +
|
||
'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' +
|
||
'=6XMW\r\n' +
|
||
'-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n';
|
||
|
||
let decryptedPrivateKey; // to avoid decrypting key before each test
|
||
beforeEach(async function() {
|
||
if (!decryptedPrivateKey) {
|
||
decryptedPrivateKey = await openpgp.decryptKey({ privateKey, passphrase });
|
||
}
|
||
privateKey = decryptedPrivateKey;
|
||
});
|
||
|
||
it('should encrypt then decrypt', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: privateKey
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(decrypted.signatures).to.exist;
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
});
|
||
|
||
it('should encrypt then decrypt with multiple private keys', async function () {
|
||
const privKeyDE = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key_de }),
|
||
passphrase
|
||
});
|
||
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: [privKeyDE, privateKey]
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(decrypted.signatures).to.exist;
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
});
|
||
|
||
it('should encrypt then decrypt with wildcard (anonymous recipient)', async function () {
|
||
const { privateKey: privateKeyV4orV6 } = await openpgp.generateKey({ userIDs: { email: 'test@test.it' }, format: 'object' });
|
||
const plaintext = 'hello world';
|
||
|
||
const encryptedMessage = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: privateKeyV4orV6,
|
||
wildcard: true,
|
||
format: 'object'
|
||
});
|
||
|
||
expect(encryptedMessage.getEncryptionKeyIDs().every(keyID => keyID.isWildcard())).to.be.true;
|
||
const armoredMessage = encryptedMessage.armor();
|
||
|
||
const parsedEncryptedMessage = await openpgp.readMessage({ armoredMessage });
|
||
expect(parsedEncryptedMessage.getEncryptionKeyIDs().every(keyID => keyID.isWildcard())).to.be.true;
|
||
|
||
const decrypted = await openpgp.decrypt({ message: parsedEncryptedMessage, decryptionKeys: privateKeyV4orV6 });
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(decrypted.signatures).to.exist;
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
|
||
it('should encrypt then decrypt with wildcard with multiple private keys (anonymous recipient)', async function () {
|
||
const privKeyDE = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key_de }),
|
||
passphrase
|
||
});
|
||
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
wildcard: true
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: [privKeyDE, privateKey]
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(decrypted.signatures).to.exist;
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
});
|
||
|
||
it('should encrypt then decrypt using returned session key', async function () {
|
||
const sessionKey = await openpgp.generateSessionKey({
|
||
encryptionKeys: publicKey
|
||
});
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
sessionKey
|
||
});
|
||
expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
|
||
const decrypted = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
sessionKeys: sessionKey
|
||
});
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(decrypted.signatures).to.exist;
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
|
||
it('should encrypt using custom session key and decrypt using session key', async function () {
|
||
const sessionKey = {
|
||
data: crypto.generateSessionKey(openpgp.enums.symmetric.aes256),
|
||
algorithm: 'aes256'
|
||
};
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
sessionKey: sessionKey,
|
||
encryptionKeys: publicKey
|
||
};
|
||
const decOpt = {
|
||
sessionKeys: sessionKey
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(false);
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
});
|
||
});
|
||
|
||
it('should encrypt using custom session key and decrypt using private key', async function () {
|
||
const sessionKey = {
|
||
data: crypto.generateSessionKey(openpgp.enums.symmetric.aes128),
|
||
algorithm: 'aes128'
|
||
};
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
sessionKey: sessionKey,
|
||
encryptionKeys: publicKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: privateKey
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
expect(encrypted).to.match(/^-----BEGIN PGP MESSAGE/);
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version === 2).to.equal(false);
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
});
|
||
});
|
||
|
||
it('should encrypt/sign and decrypt/verify', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: publicKey
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
const supportsSEIPDv2 = !!(publicKey.users[0].selfCertifications[0].features?.[0] & openpgp.enums.features.seipdv2);
|
||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version).to.equal(supportsSEIPDv2 ? 2 : 1);
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(await decrypted.signatures[0].verified).to.be.true;
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(decrypted.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should encrypt/sign and decrypt/verify (expectSigned=true)', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: publicKey,
|
||
expectSigned: true
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
const supportsSEIPDv2 = !!(publicKey.users[0].selfCertifications[0].features?.[0] & openpgp.enums.features.seipdv2);
|
||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version).to.equal(supportsSEIPDv2 ? 2 : 1);
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(await decrypted.signatures[0].verified).to.be.true;
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(decrypted.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should encrypt/sign and decrypt/verify (no AEAD support)', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKeyNoAEAD,
|
||
signingKeys: privateKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: publicKeyNoAEAD
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version).to.equal(1);
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(await decrypted.signatures[0].verified).to.be.true;
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(decrypted.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should encrypt/sign and decrypt/verify with generated key', function () {
|
||
const genOpt = {
|
||
userIDs: [{ name: 'Test User', email: 'text@example.com' }]
|
||
};
|
||
|
||
return openpgp.generateKey(genOpt).then(async function(newKey) {
|
||
const supportsSEIPDv2 = openpgp.config.aeadProtect;
|
||
const newPublicKey = await openpgp.readKey({ armoredKey: newKey.publicKey });
|
||
const newPrivateKey = await openpgp.readKey({ armoredKey: newKey.privateKey });
|
||
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: newPublicKey,
|
||
signingKeys: newPrivateKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: newPrivateKey,
|
||
verificationKeys: newPublicKey
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
expect(decOpt.message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version).to.equal(supportsSEIPDv2 ? 2 : 1);
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(await decrypted.signatures[0].verified).to.be.true;
|
||
const signingKey = await newPrivateKey.getSigningKey();
|
||
expect(decrypted.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
});
|
||
|
||
it('should encrypt/sign and decrypt/verify with generated key and detached signatures', async function () {
|
||
const newKey = await openpgp.generateKey({
|
||
userIDs: [{ name: 'Test User', email: 'text@example.com' }]
|
||
});
|
||
const supportsSEIPDv2 = openpgp.config.aeadProtect;
|
||
const newPublicKey = await openpgp.readKey({ armoredKey: newKey.publicKey });
|
||
const newPrivateKey = await openpgp.readKey({ armoredKey: newKey.privateKey });
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: newPublicKey
|
||
});
|
||
const signed = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: newPrivateKey,
|
||
detached: true
|
||
});
|
||
const message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
expect(message.packets.findPacket(openpgp.enums.packet.symEncryptedIntegrityProtectedData).version).to.equal(supportsSEIPDv2 ? 2 : 1);
|
||
const decrypted = await openpgp.decrypt({
|
||
message,
|
||
signature: await openpgp.readSignature({ armoredSignature: signed }),
|
||
decryptionKeys: newPrivateKey,
|
||
verificationKeys: newPublicKey
|
||
});
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(await decrypted.signatures[0].verified).to.be.true;
|
||
const signingKey = await newPrivateKey.getSigningKey();
|
||
expect(decrypted.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
|
||
it('should encrypt/sign and decrypt/verify with null string input', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: '' }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: publicKey
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function (decrypted) {
|
||
expect(decrypted.data).to.equal('');
|
||
expect(await decrypted.signatures[0].verified).to.be.true;
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(decrypted.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should encrypt/sign and decrypt/verify with detached signatures', async function () {
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey
|
||
});
|
||
const signed = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey,
|
||
detached: true
|
||
});
|
||
const decrypted = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
signature: await openpgp.readSignature({ armoredSignature: signed }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: publicKey
|
||
});
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(await decrypted.signatures[0].verified).to.be.true;
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(decrypted.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
|
||
it('should encrypt and decrypt/verify with detached signature as input for encryption', async function () {
|
||
const { rejectPublicKeyAlgorithms } = openpgp.config;
|
||
try {
|
||
openpgp.config.rejectPublicKeyAlgorithms = new Set();
|
||
|
||
const plaintext = ' \t┍ͤ၂༫◧˘˻ᙑ⏴ំந⛑nٓኵΉⅶ⋋ŵ⋲ͽᣏ₅ᄶɼ┋⌔û᬴Ƚᔡᧅ≃ṱἆ݂૿ӌٹჵ⛇⛌ \t\n한국어/조선말';
|
||
|
||
const privKeyDE = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key_de }),
|
||
passphrase
|
||
});
|
||
|
||
const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de });
|
||
|
||
const signOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privKeyDE,
|
||
detached: true
|
||
};
|
||
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
};
|
||
|
||
const decOpt = {
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: [publicKey, pubKeyDE]
|
||
};
|
||
|
||
await openpgp.sign(signOpt).then(async function (armoredSignature) {
|
||
encOpt.signature = await openpgp.readSignature({ armoredSignature });
|
||
return openpgp.encrypt(encOpt);
|
||
}).then(async function (armoredMessage) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function (decrypted) {
|
||
let signingKey;
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(await decrypted.signatures[0].verified).to.be.true;
|
||
signingKey = await privateKey.getSigningKey();
|
||
expect(decrypted.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[0].signature).packets.length).to.equal(1);
|
||
expect(await decrypted.signatures[1].verified).to.be.true;
|
||
signingKey = await privKeyDE.getSigningKey();
|
||
expect(decrypted.signatures[1].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[1].signature).packets.length).to.equal(1);
|
||
});
|
||
} finally {
|
||
openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
|
||
}
|
||
});
|
||
|
||
it('should fail to encrypt and decrypt/verify with detached signature as input for encryption with wrong public key', async function () {
|
||
const signOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey,
|
||
detached: true
|
||
};
|
||
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey
|
||
};
|
||
|
||
const decOpt = {
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: await openpgp.readKey({ armoredKey: wrong_pubkey })
|
||
};
|
||
|
||
return openpgp.sign(signOpt).then(async function (armoredSignature) {
|
||
encOpt.signature = await openpgp.readSignature({ armoredSignature });
|
||
return openpgp.encrypt(encOpt);
|
||
}).then(async function (armoredMessage) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function ({ signatures, data }) {
|
||
expect(data).to.equal(plaintext);
|
||
await expect(signatures[0].verified).to.be.rejectedWith(/Could not find signing key/);
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should fail to verify decrypted data with wrong public pgp key', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: await openpgp.readKey({ armoredKey: wrong_pubkey })
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function ({ signatures, data }) {
|
||
expect(data).to.equal(plaintext);
|
||
await expect(signatures[0].verified).to.be.rejectedWith(/Could not find signing key/);
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should fail to verify decrypted null string with wrong public pgp key', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: '' }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: await openpgp.readKey({ armoredKey: wrong_pubkey })
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function ({ signatures, data }) {
|
||
expect(data).to.equal('');
|
||
await expect(signatures[0].verified).to.be.rejectedWith(/Could not find signing key/);
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should successfully decrypt signed message without public keys to verify', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: privateKey
|
||
};
|
||
const decOpt = {
|
||
decryptionKeys: privateKey
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function ({ signatures, data }) {
|
||
expect(data).to.equal(plaintext);
|
||
await expect(signatures[0].verified).to.be.rejectedWith(/Could not find signing key/);
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should fail to verify decrypted data with wrong public pgp key with detached signatures', async function () {
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey
|
||
});
|
||
const signed = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey,
|
||
detached: true
|
||
});
|
||
const { signatures, data } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
signature: await openpgp.readSignature({ armoredSignature: signed }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: await openpgp.readKey({ armoredKey: wrong_pubkey })
|
||
});
|
||
expect(data).to.equal(plaintext);
|
||
await expect(signatures[0].verified).to.be.rejectedWith(/Could not find signing key/);
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
|
||
it('should encrypt and decrypt/verify both signatures when signed with two private keys', async function () {
|
||
const { rejectPublicKeyAlgorithms } = openpgp.config;
|
||
try {
|
||
openpgp.config.rejectPublicKeyAlgorithms = new Set();
|
||
|
||
const privKeyDE = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key_de }),
|
||
passphrase
|
||
});
|
||
|
||
const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de });
|
||
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: publicKey,
|
||
signingKeys: [privateKey, privKeyDE]
|
||
};
|
||
|
||
const decOpt = {
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: [publicKey, pubKeyDE]
|
||
};
|
||
|
||
await openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(async function (decrypted) {
|
||
let signingKey;
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(await decrypted.signatures[0].verified).to.be.true;
|
||
signingKey = await privateKey.getSigningKey();
|
||
expect(decrypted.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[0].signature).packets.length).to.equal(1);
|
||
expect(await decrypted.signatures[1].verified).to.be.true;
|
||
signingKey = await privKeyDE.getSigningKey();
|
||
expect(decrypted.signatures[1].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[1].signature).packets.length).to.equal(1);
|
||
});
|
||
} finally {
|
||
openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
|
||
}
|
||
});
|
||
|
||
it('should fail to decrypt modified message', async function() {
|
||
await loadStreamsPolyfill();
|
||
// need to generate new key with AEAD support
|
||
const { privateKey } = await openpgp.generateKey({ userIDs: [{ email: 'test@email.com' }], type: 'rsa', format: 'object' });
|
||
const { aeadAlgo } = await getPreferredCipherSuite([privateKey], undefined, undefined, openpgp.config);
|
||
// sanity check
|
||
expect(aeadAlgo).to.equal(openpgp.config.aeadProtect ? openpgp.config.preferredAEADAlgorithm : undefined);
|
||
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ binary: new Uint8Array(500) }),
|
||
encryptionKeys: privateKey
|
||
});
|
||
// corrupt the SEIPD packet
|
||
const encryptedCorrupted = encrypted.substr(0, 1000) + (encrypted[1000] === 'a' ? 'b' : 'a') + encrypted.substr(1001);
|
||
|
||
const generateSingleChunkStream = () => (
|
||
new ReadableStream({
|
||
start(controller) {
|
||
controller.enqueue(encryptedCorrupted);
|
||
controller.close();
|
||
}
|
||
})
|
||
);
|
||
const generateMultiChunkStream = () => (
|
||
new ReadableStream({
|
||
start() {
|
||
this.remaining = encryptedCorrupted.split('\n');
|
||
},
|
||
async pull(controller) {
|
||
if (this.remaining.length) {
|
||
// sleep to slow down enqeueing
|
||
await new Promise(resolve => { setTimeout(resolve); });
|
||
controller.enqueue(this.remaining.shift() + '\n');
|
||
} else {
|
||
controller.close();
|
||
}
|
||
}
|
||
})
|
||
);
|
||
|
||
if (openpgp.config.aeadProtect) {
|
||
const expectedError = /Authentication tag mismatch|Unsupported state or unable to authenticate data/;
|
||
// AEAD fails either on AEAD chunk decryption or when reading the decrypted stream:
|
||
// if the corruption is in the first AEAD chunk, then `openpgp.decrypt` will throw
|
||
// when reading the decrypted stream to parse the packet list.
|
||
await Promise.all([
|
||
testStreamingDecryption(encryptedCorrupted, true, expectedError, true),
|
||
testStreamingDecryption(encryptedCorrupted, false, expectedError, true),
|
||
// `config.allowUnauthenticatedStream` does not apply to AEAD
|
||
testStreamingDecryption(generateSingleChunkStream(), true, expectedError, openpgp.config.aeadChunkSizeByte > 0),
|
||
testStreamingDecryption(generateSingleChunkStream(), false, expectedError, openpgp.config.aeadChunkSizeByte > 0),
|
||
// Increasing number of streaming chunks should not affect the result
|
||
testStreamingDecryption(generateMultiChunkStream(), true, expectedError, openpgp.config.aeadChunkSizeByte > 0),
|
||
testStreamingDecryption(generateMultiChunkStream(), false, expectedError, openpgp.config.aeadChunkSizeByte > 0)
|
||
]);
|
||
} else {
|
||
const expectedError = /Modification detected/;
|
||
await Promise.all([
|
||
testStreamingDecryption(encryptedCorrupted, true, expectedError, true),
|
||
testStreamingDecryption(encryptedCorrupted, false, expectedError, true),
|
||
testStreamingDecryption(generateSingleChunkStream(), true, expectedError, false),
|
||
testStreamingDecryption(generateSingleChunkStream(), false, expectedError, true),
|
||
// Increasing number of streaming chunks should not affect the result
|
||
testStreamingDecryption(generateMultiChunkStream(), true, expectedError, false),
|
||
testStreamingDecryption(generateMultiChunkStream(), false, expectedError, true)
|
||
]);
|
||
}
|
||
|
||
async function testStreamingDecryption(encryptedDataOrStream, allowUnauthenticatedStream, expectedErrorMessage, expectedFailureOnDecrypt = null) {
|
||
// parsing the message won't fail since armor checksum is ignored
|
||
const message = await openpgp.readMessage({ armoredMessage: encryptedDataOrStream });
|
||
let didFailOnDecrypt = true;
|
||
|
||
try {
|
||
const { data: decrypted } = await openpgp.decrypt({
|
||
message,
|
||
decryptionKeys: [privateKey],
|
||
config: { allowUnauthenticatedStream }
|
||
});
|
||
didFailOnDecrypt = false;
|
||
await stream.readToEnd(decrypted);
|
||
// expected to have thrown
|
||
throw new Error(`Expected decryption to fail with error ${expectedErrorMessage}`);
|
||
} catch (e) {
|
||
expect(e.message).to.match(expectedErrorMessage);
|
||
expect(didFailOnDecrypt).to.equal(expectedFailureOnDecrypt);
|
||
}
|
||
}
|
||
});
|
||
|
||
it('should fail to decrypt unarmored message with garbage data appended', async function() {
|
||
const key = privateKey;
|
||
const message = await openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: key, signingKeys: key, format: 'binary' });
|
||
const encrypted = util.concat([message, new Uint8Array([11])]);
|
||
await expect((async () => {
|
||
await openpgp.decrypt({ message: await openpgp.readMessage({ binaryMessage: encrypted }), decryptionKeys: key, verificationKeys: key });
|
||
})()).to.be.rejectedWith('Error during parsing. This message / key probably does not conform to a valid OpenPGP format.');
|
||
});
|
||
});
|
||
|
||
describe('ELG / DSA encrypt, decrypt, sign, verify', function() {
|
||
|
||
it('round trip test', async function () {
|
||
const { rejectPublicKeyAlgorithms } = openpgp.config;
|
||
try {
|
||
openpgp.config.rejectPublicKeyAlgorithms = new Set();
|
||
|
||
const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de });
|
||
const privKeyDE = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key_de }),
|
||
passphrase
|
||
});
|
||
pubKeyDE.users[0].selfCertifications[0].features = [7]; // Monkey-patch AEAD feature flag
|
||
await openpgp.encrypt({
|
||
encryptionKeys: pubKeyDE,
|
||
signingKeys: privKeyDE,
|
||
message: await openpgp.createMessage({ text: plaintext })
|
||
}).then(async function (encrypted) {
|
||
return openpgp.decrypt({
|
||
decryptionKeys: privKeyDE,
|
||
verificationKeys: pubKeyDE,
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted })
|
||
});
|
||
}).then(async function (decrypted) {
|
||
expect(decrypted.data).to.exist;
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(await decrypted.signatures[0].verified).to.be.true;
|
||
const signingKey = await privKeyDE.getSigningKey();
|
||
expect(decrypted.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await decrypted.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
} finally {
|
||
openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
|
||
}
|
||
});
|
||
});
|
||
|
||
describe('3DES decrypt', function() {
|
||
const pgp_msg = [
|
||
'-----BEGIN PGP MESSAGE-----',
|
||
'Version: GnuPG/MacGPG2 v2.0.19 (Darwin)',
|
||
'Comment: GPGTools - https://gpgtools.org',
|
||
'',
|
||
'hIwDBU4Dycfvp2EBA/9tuhQgOrcATcm2PRmIOcs6q947YhlsBTZZdVJDfVjkKlyM',
|
||
'M0yE+lnNplWb041Cpfkkl6IvorKQd2iPbAkOL0IXwmVN41l+PvVgMcuFvvzetehG',
|
||
'Ca0/VEYOaTZRNqyr9FIzcnVy1I/PaWT3iqVAYa+G8TEA5Dh9RLfsx8ZA9UNIaNI+',
|
||
'ASm9aZ3H6FerNhm8RezDY5vRn6xw3o/wH5YEBvV2BEmmFKZ2BlqFQxqChr8UNwd1',
|
||
'Ieebnq0HtBPE8YU/L0U=',
|
||
'=JyIa',
|
||
'-----END PGP MESSAGE-----'
|
||
].join('\n');
|
||
|
||
const priv_key = [
|
||
'-----BEGIN PGP PRIVATE KEY BLOCK-----',
|
||
'Version: GnuPG/MacGPG2 v2.0.19 (Darwin)',
|
||
'Comment: GPGTools - https://gpgtools.org',
|
||
'',
|
||
'lQH+BFLqLegBBAC/rN3g30Jrcpx5lTb7Kxe+ZfS7ppOIoBjjN+qcOh81cJJVS5dT',
|
||
'UGcDsm2tCLVS3P2dGaYhfU9fsoSq/wK/tXsdoWXvXdjHbbueyi1kTZqlnyT190UE',
|
||
'vmDxH0yqquvUaf7+CNXC0T6l9gGS9p0x7xNydWRb7zeK1wIsYI+dRGQmzQARAQAB',
|
||
'/gMDArgQHMknurQXy0Pho3Nsdu6zCUNXuplvaSXruefKsQn6eexGPnecNTT2iy5N',
|
||
'70EK371D7GcNhhLsn8roUcj1Hi3kR14wXW7lcQBy9RRbbglIJXIqKJ8ywBEO8BaQ',
|
||
'b0plL+w5A9EvX0BQc4d53MTqySh6POsEDOxPzH4D/JWbaozfmc4LfGDqH1gl7ebY',
|
||
'iu81vnBuuskjpz8rxRI81MldJEIObrTE2x46DF7AmS6L6u/Qz3AAmZd89p5INCdx',
|
||
'DemxzuMKpC3wSgdgSSKHHTKiNOMxiRd5mFH5v1KVcEG/TyXFlmah7RwA4rA4fjeo',
|
||
'OpnbVWp6ciUniRvgLaCMMbmolAoho9zaLbPzCQVQ8F7gkrjnnPm4MKA+AUXmjt7t',
|
||
'VrrYkyTp1pxLZyUWX9+aKoxEO9OIDz7p9Mh02BZ/tznQ7U+IV2bcNhwrL6LPk4Mb',
|
||
'J4YF/cLVxFVVma88GSFikSjPf30AUty5nBQFtbFGqnPctCF0aHJvd2F3YXkgPHRo',
|
||
'cm93YXdheUBleGFtcGxlLmNvbT6IuAQTAQIAIgUCUuot6AIbAwYLCQgHAwIGFQgC',
|
||
'CQoLBBYCAwECHgECF4AACgkQkk2hoj5duD/HZQP/ZXJ8PSlA1oj1NW97ccT0LiNH',
|
||
'WzxPPoH9a/qGQYg61jp+aTa0C5hlYY/GgeFpiZlpwVUtlkZYfslXJqbCcp3os4xt',
|
||
'kiukDbPnq2Y41wNVxXrDw6KbOjohbhzeRUh8txbkiXGiwHtHBSJsPMntN6cB3vn3',
|
||
'08eE69vOiHPQfowa2CmdAf4EUuot6AEEAOQpNjkcTUo14JQ2o+mrpxj5yXbGtZKh',
|
||
'D8Ll+aZZrIDIa44p9KlQ3aFzPxdmFBiBX57m1nQukr58FQ5Y/FuQ1dKYc3M8QdZL',
|
||
'vCKDC8D9ZJf13iwUjYkfn/e/bDqCS2piyd63zI0xDJo+s2bXCIJxgrhbOqFDeFd6',
|
||
'4W8PfBOvUuRjABEBAAH+AwMCuBAcySe6tBfLV0P5MbBesR3Ifu/ppjzLoXKhwkqm',
|
||
'PXf09taLcRfUHeMbPjboj2P2m2UOnSrbXK9qsDQ8XOMtdsEWGLWpmiqnMlkiOchv',
|
||
'MsNRYpZ67iX3JVdxNuhs5+g5bdP1PNVbKiTzx73u1h0SS93IJp1jFj50/kyGl1Eq',
|
||
'tkr0TWe5uXCh6cSZDPwhto0a12GeDHehdTw6Yq4KoZHccneHhN9ySFy0DZOeULIi',
|
||
'Y61qtR0io52T7w69fBe9Q5/d5SwpwWKMpCTOqvvzdHX7JmeFtV+2vRVilIif7AfP',
|
||
'AD+OjQ/OhMu3jYO+XNhm3raPT2tIBsBdl2UiHOnj4AUNuLuUJeVghtz4Qt6dvjyz',
|
||
'PlBvSF+ESqALjM8IqnG15FX4LmEDFrFcfNCsnmeyZ2nr1h2mV5jOON0EmBtCyhCt',
|
||
'D/Ivi4/SZk+tBVhsBI+7ZECZYDJzZQnyPDsUv31MU4OwdWi7FhzHvDj/0bhYY7+I',
|
||
'nwQYAQIACQUCUuot6AIbDAAKCRCSTaGiPl24PwYAA/sGIHvCKWP5+4ZlBHuOdbP9',
|
||
'9v3PXFCm61qFEL0DTSq7NgBcuf0ASRElRI3wIKlfkwaiSzVPfNLiMTexdc7XaiTz',
|
||
'CHaOn1Xl2gmYTq2KiJkgtLuwptYU1iSj7vvSHKy0+nYIckOZB4pRCOjknT08O4ZJ',
|
||
'22q10ausyQXoOxXfDWVwKA==',
|
||
'=IkKW',
|
||
'-----END PGP PRIVATE KEY BLOCK-----'
|
||
].join('\n');
|
||
|
||
it('Decrypt message', async function() {
|
||
const privKey = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key }),
|
||
passphrase: '1234'
|
||
});
|
||
const message = await openpgp.readMessage({ armoredMessage: pgp_msg });
|
||
|
||
return openpgp.decrypt({ decryptionKeys:privKey, message:message }).then(function(decrypted) {
|
||
expect(decrypted.data).to.equal('hello 3des\n');
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
});
|
||
});
|
||
|
||
describe('AES encrypt, decrypt', function() {
|
||
|
||
it('should encrypt and decrypt with one password', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
passwords: password1
|
||
};
|
||
const decOpt = {
|
||
passwords: password1
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
});
|
||
|
||
it('should encrypt and decrypt with two passwords', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
passwords: [password1, password2]
|
||
};
|
||
const decOpt = {
|
||
passwords: password2
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
});
|
||
|
||
it('should encrypt and decrypt with password and not ascii armor', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
passwords: password1,
|
||
format: 'binary'
|
||
};
|
||
const decOpt = {
|
||
passwords: password1
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
});
|
||
|
||
it('should encrypt and decrypt with binary data', async function () {
|
||
const encOpt = {
|
||
message: await openpgp.createMessage({ binary: new Uint8Array([0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01]) }),
|
||
passwords: password1,
|
||
format: 'binary'
|
||
};
|
||
const decOpt = {
|
||
passwords: password1,
|
||
format: 'binary'
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(function (decrypted) {
|
||
expect(decrypted.data).to.deep.equal(new Uint8Array([0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01]));
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
});
|
||
});
|
||
|
||
describe('Encrypt, decrypt with compression', function() {
|
||
withCompression(function (modifyCompressionEncryptOptions, verifyCompressionDecrypted) {
|
||
it('should encrypt and decrypt with one password', async function () {
|
||
const encOpt = modifyCompressionEncryptOptions({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
passwords: password1
|
||
});
|
||
const decOpt = {
|
||
passwords: password1
|
||
};
|
||
return openpgp.encrypt(encOpt).then(async function (encrypted) {
|
||
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
return openpgp.decrypt(decOpt);
|
||
}).then(function (decrypted) {
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
verifyCompressionDecrypted(decrypted);
|
||
});
|
||
});
|
||
|
||
it('Streaming encrypt and decrypt small message roundtrip', async function() {
|
||
const plaintext = [];
|
||
let i = 0;
|
||
await loadStreamsPolyfill();
|
||
const data = new globalThis.ReadableStream({
|
||
pull(controller) {
|
||
if (i++ < 4) {
|
||
const randomBytes = random.getRandomBytes(10);
|
||
controller.enqueue(randomBytes);
|
||
plaintext.push(randomBytes.slice());
|
||
} else {
|
||
controller.close();
|
||
}
|
||
}
|
||
});
|
||
const encrypted = await openpgp.encrypt(modifyCompressionEncryptOptions({
|
||
message: await openpgp.createMessage({ binary: data }),
|
||
passwords: ['test']
|
||
}));
|
||
expect(stream.isStream(encrypted)).to.equal('web');
|
||
|
||
const message = await openpgp.readMessage({ armoredMessage: encrypted });
|
||
const decrypted = await openpgp.decrypt({
|
||
passwords: ['test'],
|
||
message,
|
||
format: 'binary'
|
||
});
|
||
expect(stream.isStream(decrypted.data)).to.equal('web');
|
||
expect(await stream.readToEnd(decrypted.data)).to.deep.equal(util.concatUint8Array(plaintext));
|
||
});
|
||
});
|
||
});
|
||
|
||
}
|
||
|
||
describe('AES / RSA encrypt, decrypt, sign, verify', function() {
|
||
const wrong_pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n' +
|
||
'Version: OpenPGP.js v0.9.0\r\n' +
|
||
'Comment: Hoodiecrow - https://hoodiecrow.com\r\n' +
|
||
'\r\n' +
|
||
'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\r\n' +
|
||
'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\r\n' +
|
||
'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\r\n' +
|
||
'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\r\n' +
|
||
'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' +
|
||
'=6XMW\r\n' +
|
||
'-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n';
|
||
|
||
let decryptedPrivateKey; // to avoid decrypting key before each test
|
||
beforeEach(async function() {
|
||
if (!decryptedPrivateKey) {
|
||
decryptedPrivateKey = await openpgp.decryptKey({ privateKey, passphrase });
|
||
}
|
||
privateKey = decryptedPrivateKey;
|
||
});
|
||
|
||
it('should sign and verify cleartext message', async function () {
|
||
const message = await openpgp.createCleartextMessage({ text: plaintext });
|
||
const signOpt = {
|
||
message,
|
||
signingKeys: privateKey
|
||
};
|
||
const verifyOpt = {
|
||
verificationKeys: publicKey
|
||
};
|
||
return openpgp.sign(signOpt).then(async function (signed) {
|
||
expect(signed).to.match(/-----BEGIN PGP SIGNED MESSAGE-----/);
|
||
verifyOpt.message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function (verified) {
|
||
expect(verified.data).to.equal(plaintext.replace(/[ \t]+$/mg, ''));
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(verified.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await verified.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should sign and verify cleartext message with multiple private keys', async function () {
|
||
const { rejectPublicKeyAlgorithms } = openpgp.config;
|
||
try {
|
||
openpgp.config.rejectPublicKeyAlgorithms = new Set();
|
||
|
||
const privKeyDE = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key_de }),
|
||
passphrase
|
||
});
|
||
|
||
const message = await openpgp.createCleartextMessage({ text: plaintext });
|
||
const signOpt = {
|
||
message,
|
||
signingKeys: [privateKey, privKeyDE]
|
||
};
|
||
const verifyOpt = {
|
||
verificationKeys: [publicKey, privKeyDE.toPublic()]
|
||
};
|
||
await openpgp.sign(signOpt).then(async function (signed) {
|
||
expect(signed).to.match(/-----BEGIN PGP SIGNED MESSAGE-----/);
|
||
verifyOpt.message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function (verified) {
|
||
let signingKey;
|
||
expect(verified.data).to.equal(plaintext.replace(/[ \t]+$/mg, ''));
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
signingKey = await privateKey.getSigningKey();
|
||
expect(verified.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await verified.signatures[0].signature).packets.length).to.equal(1);
|
||
expect(await verified.signatures[1].verified).to.be.true;
|
||
signingKey = await privKeyDE.getSigningKey();
|
||
expect(verified.signatures[1].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await verified.signatures[1].signature).packets.length).to.equal(1);
|
||
});
|
||
} finally {
|
||
openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
|
||
}
|
||
});
|
||
|
||
it('should sign and verify data with detached signatures', async function () {
|
||
const message = await openpgp.createMessage({ text: plaintext });
|
||
const signOpt = {
|
||
message,
|
||
signingKeys: privateKey,
|
||
detached: true
|
||
};
|
||
const verifyOpt = {
|
||
message,
|
||
verificationKeys: publicKey
|
||
};
|
||
return openpgp.sign(signOpt).then(async function (armoredSignature) {
|
||
verifyOpt.signature = await openpgp.readSignature({ armoredSignature });
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function (verified) {
|
||
expect(verified.data).to.equal(plaintext);
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(verified.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await verified.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should sign and fail to verify cleartext message with wrong public pgp key', async function () {
|
||
const message = await openpgp.createCleartextMessage({ text: plaintext });
|
||
const signOpt = {
|
||
message,
|
||
signingKeys: privateKey
|
||
};
|
||
const verifyOpt = {
|
||
verificationKeys: await openpgp.readKey({ armoredKey: wrong_pubkey })
|
||
};
|
||
return openpgp.sign(signOpt).then(async function (signed) {
|
||
verifyOpt.message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function ({ data, signatures }) {
|
||
expect(data).to.equal(plaintext.replace(/[ \t]+$/mg, ''));
|
||
await expect(signatures[0].verified).to.be.rejectedWith(/Could not find signing key/);
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should sign and fail to verify data with wrong public pgp key with detached signature', async function () {
|
||
const message = await openpgp.createMessage({ text: plaintext });
|
||
const signOpt = {
|
||
message,
|
||
signingKeys: privateKey,
|
||
detached: true
|
||
};
|
||
const verifyOpt = {
|
||
message,
|
||
verificationKeys: await openpgp.readKey({ armoredKey: wrong_pubkey })
|
||
};
|
||
return openpgp.sign(signOpt).then(async function (armoredSignature) {
|
||
verifyOpt.signature = await openpgp.readSignature({ armoredSignature });
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function ({ data, signatures }) {
|
||
expect(data).to.equal(plaintext);
|
||
await expect(signatures[0].verified).to.be.rejectedWith(/Could not find signing key/);
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should sign and verify data and not armor', async function () {
|
||
const message = await openpgp.createMessage({ text: plaintext });
|
||
const signOpt = {
|
||
message,
|
||
signingKeys: privateKey,
|
||
format: 'binary'
|
||
};
|
||
const verifyOpt = {
|
||
verificationKeys: publicKey
|
||
};
|
||
return openpgp.sign(signOpt).then(async function (signed) {
|
||
verifyOpt.message = await openpgp.readMessage({ binaryMessage: signed });
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function (verified) {
|
||
expect(verified.data).to.equal(plaintext);
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(verified.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await verified.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should sign and verify data and not armor with detached signatures', async function () {
|
||
const start = util.normalizeDate();
|
||
const message = await openpgp.createMessage({ text: plaintext });
|
||
const signOpt = {
|
||
message,
|
||
signingKeys: privateKey,
|
||
detached: true,
|
||
format: 'binary'
|
||
};
|
||
const verifyOpt = {
|
||
message,
|
||
verificationKeys: publicKey
|
||
};
|
||
return openpgp.sign(signOpt).then(async function (signed) {
|
||
verifyOpt.signature = await openpgp.readSignature({ binarySignature: signed });
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function (verified) {
|
||
expect(verified.data).to.equal(plaintext);
|
||
expect(+(await verified.signatures[0].signature).packets[0].created).to.be.lte(+util.normalizeDate());
|
||
expect(+(await verified.signatures[0].signature).packets[0].created).to.be.gte(+start);
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
const signingKey = await privateKey.getSigningKey();
|
||
expect(verified.signatures[0].keyID.toHex()).to.equal(signingKey.getKeyID().toHex());
|
||
expect((await verified.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should sign and verify data with a date in the past', async function () {
|
||
const message = await openpgp.createMessage({ text: plaintext });
|
||
const past = new Date(2000);
|
||
const signOpt = {
|
||
message,
|
||
signingKeys: privateKey_1337,
|
||
detached: true,
|
||
date: past,
|
||
format: 'binary'
|
||
};
|
||
const verifyOpt = {
|
||
message,
|
||
verificationKeys: publicKey_1337,
|
||
date: past
|
||
};
|
||
return openpgp.sign(signOpt).then(async function (signed) {
|
||
verifyOpt.signature = await openpgp.readSignature({ binarySignature: signed });
|
||
return openpgp.verify(verifyOpt).then(async function (verified) {
|
||
expect(+(await verified.signatures[0].signature).packets[0].created).to.equal(+past);
|
||
expect(verified.data).to.equal(plaintext);
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
expect(await privateKey_1337.getSigningKey(verified.signatures[0].keyID, past))
|
||
.to.be.not.null;
|
||
expect((await verified.signatures[0].signature).packets.length).to.equal(1);
|
||
// now check with expiration checking disabled
|
||
verifyOpt.date = null;
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function (verified) {
|
||
expect(+(await verified.signatures[0].signature).packets[0].created).to.equal(+past);
|
||
expect(verified.data).to.equal(plaintext);
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
expect(await privateKey_1337.getSigningKey(verified.signatures[0].keyID, null))
|
||
.to.be.not.null;
|
||
expect((await verified.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
});
|
||
|
||
it('should sign and verify binary data with a date in the future', async function () {
|
||
const future = new Date(2040, 5, 5, 5, 5, 5, 0);
|
||
const data = new Uint8Array([3, 14, 15, 92, 65, 35, 59]);
|
||
const signOpt = {
|
||
message: await openpgp.createMessage({ binary: data }),
|
||
signingKeys: privateKey_2038_2045,
|
||
detached: true,
|
||
date: future,
|
||
format: 'binary'
|
||
};
|
||
const verifyOpt = {
|
||
verificationKeys: publicKey_2038_2045,
|
||
date: future,
|
||
format: 'binary'
|
||
};
|
||
return openpgp.sign(signOpt).then(async function (signed) {
|
||
verifyOpt.message = await openpgp.createMessage({ binary: data });
|
||
verifyOpt.signature = await openpgp.readSignature({ binarySignature: signed });
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function (verified) {
|
||
expect(+(await verified.signatures[0].signature).packets[0].created).to.equal(+future);
|
||
expect([].slice.call(verified.data)).to.deep.equal([].slice.call(data));
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
expect(await privateKey_2038_2045.getSigningKey(verified.signatures[0].keyID, future))
|
||
.to.be.not.null;
|
||
expect((await verified.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should sign and verify binary data without one-pass signature', async function () {
|
||
const data = new Uint8Array([3, 14, 15, 92, 65, 35, 59]);
|
||
const signOpt = {
|
||
message: await openpgp.createMessage({ binary: data }),
|
||
signingKeys: privateKey,
|
||
format: 'binary'
|
||
};
|
||
const verifyOpt = {
|
||
verificationKeys: publicKey,
|
||
format: 'binary'
|
||
};
|
||
return openpgp.sign(signOpt).then(async function (signed) {
|
||
const message = await openpgp.readMessage({ binaryMessage: signed });
|
||
message.packets.push(...await stream.readToEnd(message.packets.stream, _ => _));
|
||
const packets = new openpgp.PacketList();
|
||
packets.push(message.packets.findPacket(openpgp.enums.packet.signature));
|
||
packets.push(message.packets.findPacket(openpgp.enums.packet.literalData));
|
||
verifyOpt.message = new openpgp.Message(packets);
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function (verified) {
|
||
expect([].slice.call(verified.data)).to.deep.equal([].slice.call(data));
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
expect(await privateKey.getSigningKey(verified.signatures[0].keyID))
|
||
.to.be.not.null;
|
||
expect((await verified.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should streaming sign and verify binary data without one-pass signature', async function () {
|
||
const data = new Uint8Array([3, 14, 15, 92, 65, 35, 59]);
|
||
const dataStream = new globalThis.ReadableStream({
|
||
start(controller) {
|
||
controller.enqueue(data);
|
||
controller.close();
|
||
}
|
||
});
|
||
|
||
const signOpt = {
|
||
message: await openpgp.createMessage({ binary: dataStream }),
|
||
signingKeys: privateKey,
|
||
format: 'binary'
|
||
};
|
||
const verifyOpt = {
|
||
verificationKeys: publicKey,
|
||
format: 'binary'
|
||
};
|
||
return openpgp.sign(signOpt).then(async function (signed) {
|
||
expect(stream.isStream(signed)).to.equal('web');
|
||
const message = await openpgp.readMessage({ binaryMessage: signed });
|
||
message.packets.push(...await stream.readToEnd(message.packets.stream, _ => _));
|
||
const packets = new openpgp.PacketList();
|
||
packets.push(message.packets.findPacket(openpgp.enums.packet.signature));
|
||
packets.push(message.packets.findPacket(openpgp.enums.packet.literalData));
|
||
verifyOpt.message = await openpgp.readMessage({
|
||
binaryMessage: stream.toStream(packets.write())
|
||
});
|
||
return openpgp.verify(verifyOpt);
|
||
}).then(async function (verified) {
|
||
expect(stream.isStream(verified.data)).to.equal('web');
|
||
expect([].slice.call(await stream.readToEnd(verified.data))).to.deep.equal([].slice.call(data));
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
expect(await privateKey.getSigningKey(verified.signatures[0].keyID))
|
||
.to.be.not.null;
|
||
expect((await verified.signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should encrypt and decrypt data with a date in the future', async function () {
|
||
const future = new Date(2040, 5, 5, 5, 5, 5, 0);
|
||
const encryptOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext, date: future }),
|
||
encryptionKeys: publicKey_2038_2045,
|
||
date: future,
|
||
format: 'binary'
|
||
};
|
||
|
||
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||
return message.decrypt([privateKey_2038_2045], undefined, undefined, undefined, openpgp.config);
|
||
}).then(async function (packets) {
|
||
const literals = packets.packets.filterByTag(openpgp.enums.packet.literalData);
|
||
expect(literals.length).to.equal(1);
|
||
expect(+literals[0].date).to.equal(+future);
|
||
expect(await stream.readToEnd(packets.getText())).to.equal(plaintext);
|
||
});
|
||
});
|
||
|
||
it('should encrypt and decrypt binary data with a date in the past', async function () {
|
||
const past = new Date(2005, 5, 5, 5, 5, 5, 0);
|
||
const data = new Uint8Array([3, 14, 15, 92, 65, 35, 59]);
|
||
const encryptOpt = {
|
||
message: await openpgp.createMessage({ binary: data, date: past }),
|
||
encryptionKeys: publicKey_2000_2008,
|
||
date: past,
|
||
format: 'binary'
|
||
};
|
||
|
||
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||
return message.decrypt([privateKey_2000_2008], undefined, undefined, undefined, openpgp.config);
|
||
}).then(async function (packets) {
|
||
const literals = packets.packets.filterByTag(openpgp.enums.packet.literalData);
|
||
expect(literals.length).to.equal(1);
|
||
expect(+literals[0].date).to.equal(+past);
|
||
expect(await stream.readToEnd(packets.getLiteralData())).to.deep.equal(data);
|
||
});
|
||
});
|
||
|
||
it('should sign, encrypt and decrypt, verify data with a date in the past', async function () {
|
||
const past = new Date(2005, 5, 5, 5, 5, 5, 0);
|
||
const encryptOpt = {
|
||
message: await openpgp.createMessage({ text: plaintext, date: past }),
|
||
encryptionKeys: publicKey_2000_2008,
|
||
signingKeys: privateKey_2000_2008,
|
||
date: past,
|
||
format: 'binary'
|
||
};
|
||
|
||
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||
return message.decrypt([privateKey_2000_2008], undefined, undefined, undefined, openpgp.config);
|
||
}).then(async function (message) {
|
||
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
|
||
expect(literals.length).to.equal(1);
|
||
expect(+literals[0].date).to.equal(+past);
|
||
const signatures = await message.verify([publicKey_2000_2008], past, undefined, openpgp.config);
|
||
expect(await stream.readToEnd(message.getText())).to.equal(plaintext);
|
||
expect(+(await signatures[0].signature).packets[0].created).to.equal(+past);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
expect(await privateKey_2000_2008.getSigningKey(signatures[0].keyID, past))
|
||
.to.be.not.null;
|
||
expect((await signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should sign, encrypt and decrypt, verify binary data with a date in the future', async function () {
|
||
const future = new Date(2040, 5, 5, 5, 5, 5, 0);
|
||
const data = new Uint8Array([3, 14, 15, 92, 65, 35, 59]);
|
||
const encryptOpt = {
|
||
message: await openpgp.createMessage({ binary: data, date: future }),
|
||
encryptionKeys: publicKey_2038_2045,
|
||
signingKeys: privateKey_2038_2045,
|
||
date: future,
|
||
format: 'binary'
|
||
};
|
||
|
||
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||
return message.decrypt([privateKey_2038_2045], undefined, undefined, undefined, openpgp.config);
|
||
}).then(async function (message) {
|
||
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
|
||
expect(literals.length).to.equal(1);
|
||
expect(literals[0].format).to.equal(openpgp.enums.literal.binary);
|
||
expect(+literals[0].date).to.equal(+future);
|
||
const signatures = await message.verify([publicKey_2038_2045], future, undefined, openpgp.config);
|
||
expect(await stream.readToEnd(message.getLiteralData())).to.deep.equal(data);
|
||
expect(+(await signatures[0].signature).packets[0].created).to.equal(+future);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
expect(await privateKey_2038_2045.getSigningKey(signatures[0].keyID, future))
|
||
.to.be.not.null;
|
||
expect((await signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should sign, encrypt and decrypt, verify mime data with a date in the future', async function () {
|
||
const future = new Date(2040, 5, 5, 5, 5, 5, 0);
|
||
const data = new Uint8Array([3, 14, 15, 92, 65, 35, 59]);
|
||
const encryptOpt = {
|
||
message: await openpgp.createMessage({ binary: data, date: future, format: 'mime' }),
|
||
encryptionKeys: publicKey_2038_2045,
|
||
signingKeys: privateKey_2038_2045,
|
||
date: future,
|
||
format: 'binary'
|
||
};
|
||
|
||
return openpgp.encrypt(encryptOpt).then(async function (encrypted) {
|
||
const message = await openpgp.readMessage({ binaryMessage: encrypted });
|
||
return message.decrypt([privateKey_2038_2045], undefined, undefined, undefined, openpgp.config);
|
||
}).then(async function (message) {
|
||
const literals = message.packets.filterByTag(openpgp.enums.packet.literalData);
|
||
expect(literals.length).to.equal(1);
|
||
expect(literals[0].format).to.equal(openpgp.enums.literal.mime);
|
||
expect(+literals[0].date).to.equal(+future);
|
||
const signatures = await message.verify([publicKey_2038_2045], future, undefined, openpgp.config);
|
||
expect(await stream.readToEnd(message.getLiteralData())).to.deep.equal(data);
|
||
expect(+(await signatures[0].signature).packets[0].created).to.equal(+future);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
expect(await privateKey_2038_2045.getSigningKey(signatures[0].keyID, future))
|
||
.to.be.not.null;
|
||
expect((await signatures[0].signature).packets.length).to.equal(1);
|
||
});
|
||
});
|
||
|
||
it('should fail to encrypt with revoked key', function() {
|
||
return openpgp.revokeKey({
|
||
key: privateKey,
|
||
format: 'object'
|
||
}).then(async function({ publicKey: revKey }) {
|
||
return openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: revKey
|
||
}).then(function() {
|
||
throw new Error('Should not encrypt with revoked key');
|
||
}).catch(function(error) {
|
||
expect(error.message).to.match(/Primary key is revoked/);
|
||
});
|
||
});
|
||
});
|
||
|
||
it('should fail to encrypt with revoked subkey', async function() {
|
||
const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de });
|
||
const privKeyDE = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key_de }),
|
||
passphrase
|
||
});
|
||
return privKeyDE.subkeys[0].revoke(privKeyDE.keyPacket).then(async function(revSubkey) {
|
||
pubKeyDE.subkeys[0] = revSubkey;
|
||
return openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: pubKeyDE,
|
||
config: { rejectPublicKeyAlgorithms: new Set() }
|
||
}).then(function() {
|
||
throw new Error('Should not encrypt with revoked subkey');
|
||
}).catch(function(error) {
|
||
expect(error.message).to.match(/Could not find valid encryption key packet/);
|
||
});
|
||
});
|
||
});
|
||
|
||
it('should decrypt with revoked subkey', async function() {
|
||
const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de });
|
||
const privKeyDE = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: priv_key_de }),
|
||
passphrase
|
||
});
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: pubKeyDE,
|
||
config: { rejectPublicKeyAlgorithms: new Set() }
|
||
});
|
||
privKeyDE.subkeys[0] = await privKeyDE.subkeys[0].revoke(privKeyDE.keyPacket);
|
||
const decOpt = {
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: privKeyDE,
|
||
config: { rejectPublicKeyAlgorithms: new Set() }
|
||
};
|
||
const decrypted = await openpgp.decrypt(decOpt);
|
||
expect(decrypted.data).to.equal(plaintext);
|
||
});
|
||
|
||
it('should not decrypt with corrupted subkey', async function() {
|
||
const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de });
|
||
const privKeyDE = await openpgp.readKey({ armoredKey: priv_key_de });
|
||
// corrupt the public key params
|
||
privKeyDE.subkeys[0].keyPacket.publicParams.p[0]++;
|
||
// validation will check the primary key -- not the decryption subkey -- and will succeed (for now)
|
||
const decryptedKeyDE = await openpgp.decryptKey({
|
||
privateKey: privKeyDE,
|
||
passphrase
|
||
});
|
||
const encrypted = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: pubKeyDE,
|
||
config: { rejectPublicKeyAlgorithms: new Set() }
|
||
});
|
||
const decOpt = {
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
decryptionKeys: decryptedKeyDE
|
||
};
|
||
// binding signature is invalid
|
||
await expect(openpgp.decrypt(decOpt)).to.be.rejectedWith(/Session key decryption failed/);
|
||
});
|
||
|
||
it('RSA decryption with PKCS1 padding of wrong length should fail', async function() {
|
||
const key = await openpgp.readKey({ armoredKey: rsaPrivateKeyPKCS1 });
|
||
// the paddings of these messages are prefixed by 0x02 and 0x000002 instead of 0x0002
|
||
// the code should discriminate between these cases by checking the length of the padded plaintext
|
||
const padding02 = `-----BEGIN PGP MESSAGE-----
|
||
Version: OpenPGP.js VERSION
|
||
Comment: https://openpgpjs.org
|
||
|
||
wcBMAxbpoSTRSSl3AQf/fepDhqeam4Ecy8GUFChc47U3hbkdgINobI9TORAf
|
||
eGFZVcyTQKVIt7fB8bwQwjxRmU98xCjF7VkLhPQJkzKlkT9cIDBKswU+d3fw
|
||
lHAVYo77yUkFkVLXrQTZj/OjsA12V7lfRagO375XB3EpJUHVPvYQFFr3aSlo
|
||
FbsCrpZoS6FXxRYVjGpIeMjam3a7qDavQpKhjOQ+Sfm0tk2JZkQwpFom6x7c
|
||
9TEn3YSo6+I0ztjiuTBZDyYr8zocHW8imFzZRlcNuuuukesyFzFgHx46eVpO
|
||
6PVjmiN50agZvsV9rgPyyH84nb3zYJ63shnrQWubTOVH4daGbe8uHi+ZM3UU
|
||
J9I8AcH94nE77JUtCm7s1kOlo0EIshZsAqJwGveDGdAuabfViVwVxG4I24M6
|
||
8sqJYJd9FpNjSbYlrLT0R9zy
|
||
=+n/4
|
||
-----END PGP MESSAGE-----`;
|
||
const padding000002 = `-----BEGIN PGP MESSAGE-----
|
||
Version: OpenPGP.js VERSION
|
||
Comment: https://openpgpjs.org
|
||
|
||
wcBMAxbpoSTRSSl3AQf/fepDhqeam4Ecy8GUFChc47U3hbkdgINobI9TORAf
|
||
eGFZVcyTQKVIt7fB8bwQwjxRmU98xCjF7VkLhPQJkzKlkT9cIDBKswU+d3fw
|
||
lHAVYo77yUkFkVLXrQTZj/OjsA12V7lfRagO375XB3EpJUHVPvYQFFr3aSlo
|
||
FbsCrpZoS6FXxRYVjGpIeMjam3a7qDavQpKhjOQ+Sfm0tk2JZkQwpFom6x7c
|
||
9TEn3YSo6+I0ztjiuTBZDyYr8zocHW8imFzZRlcNuuuukesyFzFgHx46eVpO
|
||
6PVjmiN50agZvsV9rgPyyH84nb3zYJ63shnrQWubTOVH4daGbe8uHi+ZM3UU
|
||
J9I8AcH94nE77JUtCm7s1kOlo0EIshZsAqJwGveDGdAuabfViVwVxG4I24M6
|
||
8sqJYJd9FpNjSbYlrLT0R9zy
|
||
=+n/4
|
||
-----END PGP MESSAGE-----`;
|
||
|
||
const decOpt02 = {
|
||
message: await openpgp.readMessage({ armoredMessage: padding02 }),
|
||
decryptionKeys: key
|
||
};
|
||
await expect(openpgp.decrypt(decOpt02)).to.be.rejectedWith(/Decryption error/);
|
||
|
||
const decOpt000002 = {
|
||
message: await openpgp.readMessage({ armoredMessage: padding000002 }),
|
||
decryptionKeys: key
|
||
};
|
||
await expect(openpgp.decrypt(decOpt000002)).to.be.rejectedWith(/Decryption error/);
|
||
});
|
||
|
||
it('should decrypt with two passwords message which GPG fails on', async function() {
|
||
const decOpt = {
|
||
message: await openpgp.readMessage({ armoredMessage: twoPasswordGPGFail }),
|
||
passwords: password2
|
||
};
|
||
return openpgp.decrypt(decOpt).then(function(decrypted) {
|
||
expect(decrypted.data).to.equal('short message\nnext line\n한국어/조선말');
|
||
expect(decrypted.signatures.length).to.equal(0);
|
||
});
|
||
});
|
||
|
||
it('should decrypt with three passwords', async function() {
|
||
const messageBinary = util.hexToUint8Array('c32e04090308125231fe38b0255f60a7f319fc4959c147c7af33817ceb4cf159a00f2efa17b7921961f6ead025c77588d2430166fe9395cd58e9b69a67a30470e2d31bf0bbbb31c7eca31fb9015dddf70c6957036b093d104cbf0b26e218113e69c4fa89dda97a61d0cba364efa77d5144c5b9b701');
|
||
const message = await openpgp.readMessage({ binaryMessage: messageBinary });
|
||
const passwords = ['Test', 'Pinata', 'a'];
|
||
const decrypted = await openpgp.decrypt({ message, passwords });
|
||
expect(decrypted.data).to.equal('Hello world');
|
||
});
|
||
|
||
it('should decrypt broken ECC message from old OpenPGP.js', async function() {
|
||
const key = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: ecdh_dec_key }),
|
||
passphrase: '12345'
|
||
});
|
||
const message = await openpgp.readMessage({ armoredMessage: ecdh_msg_bad });
|
||
const decrypted = await openpgp.decrypt({ message, decryptionKeys: key });
|
||
expect(decrypted.data).to.equal('\n');
|
||
});
|
||
|
||
it('should decrypt broken ECC message from old go crypto', async function() {
|
||
const key = await openpgp.decryptKey({
|
||
privateKey: await openpgp.readKey({ armoredKey: ecdh_dec_key2 }),
|
||
passphrase: '12345'
|
||
});
|
||
const message = await openpgp.readMessage({ armoredMessage: ecdh_msg_bad_2 });
|
||
const decrypted = await openpgp.decrypt({ message, decryptionKeys: key });
|
||
expect(decrypted.data).to.equal('Tesssst<br><br><br>Sent from ProtonMail mobile<br><br><br>');
|
||
});
|
||
|
||
it('should decrypt Blowfish message', async function() {
|
||
const { data } = await openpgp.decrypt({
|
||
passwords: 'test',
|
||
message: await openpgp.readMessage({
|
||
armoredMessage: `-----BEGIN PGP MESSAGE-----
|
||
Version: OpenPGP.js v4.9.0
|
||
Comment: https://openpgpjs.org
|
||
|
||
wx4EBAMI7Di70u7hoDfgBUJQ2+1ig6ym3KMjRS9kAovSPAGRQLIPv2DgkINL
|
||
3DUgMNqtQCA23xWhq7Ly6o9H1lRfoAo7V5UElVCqGEX7cgyZjI97alY6Je3o
|
||
amnR6g==
|
||
=rPIK
|
||
-----END PGP MESSAGE-----`
|
||
})
|
||
});
|
||
expect(data).to.equal('Hello World!');
|
||
});
|
||
|
||
it('should normalize newlines in encrypted text message', async function() {
|
||
const message = await openpgp.createMessage({ text: '"BEGIN:VCALENDAR\nVERSION:2.0\nBEGIN:VEVENT\r\nUID:123\r\nDTSTART:20191211T121212Z\r\nDTEND:20191212T121212Z\r\nEND:VEVENT\nEND:VCALENDAR"' });
|
||
const encrypted = await openpgp.encrypt({
|
||
passwords: 'test',
|
||
message
|
||
});
|
||
const decrypted = await openpgp.decrypt({
|
||
passwords: 'test',
|
||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||
format: 'binary'
|
||
});
|
||
expect(util.decodeUTF8(decrypted.data)).to.equal('"BEGIN:VCALENDAR\r\nVERSION:2.0\r\nBEGIN:VEVENT\r\nUID:123\r\nDTSTART:20191211T121212Z\r\nDTEND:20191212T121212Z\r\nEND:VEVENT\r\nEND:VCALENDAR"');
|
||
});
|
||
});
|
||
|
||
it('should fail to decrypt a message containing a literal packet (and no session key)', async function() {
|
||
const message = await openpgp.createMessage({ text: 'plaintext' });
|
||
await expect(openpgp.decrypt({ message, passwords: 'password' })).to.be.rejectedWith(/Error decrypting message/);
|
||
});
|
||
|
||
it('should fail to decrypt a message containing a literal packet (and a session key)', async function() {
|
||
const skeskPlusLiteralData = `-----BEGIN PGP MESSAGE-----
|
||
|
||
wy4ECQMIjvrInhvTxJwAbkqXp+KWFdBcjoPn03jCdyspVi9qXBDbyGaP1lrM
|
||
habAyxd1AGKaNp1wbGFpbnRleHQgbWVzc2FnZQ==
|
||
=XoUx
|
||
-----END PGP MESSAGE-----
|
||
`;
|
||
|
||
const message = await openpgp.readMessage({ armoredMessage: skeskPlusLiteralData });
|
||
await expect(openpgp.decrypt({ message, passwords: 'password' })).to.be.rejectedWith(/No encrypted data found/);
|
||
});
|
||
|
||
it('should fail to decrypt non-integrity-protected message by default', async function() {
|
||
const key = await openpgp.readKey({
|
||
armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xVgEYD9r8xYJKwYBBAHaRw8BAQdApTaQJ6R/uooTqAuscoxYwbLrtoKndnsX
|
||
ydhqMybJqh0AAQCxNwi9Pezy03OQE0XOooBWaHiuhBtKA1eAuqjJFuuLuQ/+
|
||
zQDCjAQQFgoAHQUCYD9r8wQLCQcIAxUICgQWAgEAAhkBAhsDAh4BACEJEIkB
|
||
BTiDwpvwFiEEvRnmOby6fJ/OxUhSiQEFOIPCm/BidgEAq05ZiPseRsMTxNm7
|
||
IFQwQjmIFiWgLeQ0gKIvfl3SjBAA/iSPyTgWxSY98utXNuq+WoxVOzx3dJwG
|
||
2cflR/UFUlEPx10EYD9r8xIKKwYBBAGXVQEFAQEHQCASw+tMPvnXi904WASv
|
||
wRDUQofh0M7CpgQFqoOXvGlLAwEIBwAA/3gEimwdIet0gXb/hRRyBqOlcq32
|
||
lNREh+n+vZKJyXWYEjrCeAQYFggACQUCYD9r8wIbDAAhCRCJAQU4g8Kb8BYh
|
||
BL0Z5jm8unyfzsVIUokBBTiDwpvwHpEBAObHllPrJu0DqYyt4FKPkijgRpXC
|
||
ESqhlK5rrbc62SmfAQDVf5l1B6IDASBCKtC0VPPpYiK6AUcEISpaSXOa+pNI
|
||
Bw==
|
||
=3Fja
|
||
-----END PGP PRIVATE KEY BLOCK-----`
|
||
});
|
||
const message = await openpgp.readMessage({
|
||
armoredMessage: `-----BEGIN PGP MESSAGE-----
|
||
|
||
wV4D+3VwOibHmagSAQdATlMJlvrkaq46zMkbIuKBOJO5X3ugVwZpEyAterQC
|
||
/RUw0OPWeO+4swh/U7ZurV8cRr/fPnyGUUKI7rI+va3kWUZv4RRpUs7eYE57
|
||
OUr3yoMNyaQEBwu6VXiQrsBN8TyUbXQxb63p7EHFXIgvVDIvOG7bQptrrKlM
|
||
kKcB+fz5hb6mT/tl+cPcYHDOjocQ92pNVm+FilQhiATRxV8ah1DCOIZZ6tgq
|
||
rWwIiEQEBPt+tXOuVF4Peumovp3WgziudrJa5Jxt2Dz+8nicBglbZLXTsZNu
|
||
bsZgJWVlAa5eil6J9ePX2xbo1vVAkLQdzE9+1jL+l7PRIZuVBQ==
|
||
=T4iR
|
||
-----END PGP MESSAGE-----`
|
||
});
|
||
await expect(
|
||
openpgp.decrypt({ message, decryptionKeys: key, verificationKeys: key })
|
||
).to.be.rejectedWith('Error decrypting message: Message is not authenticated.');
|
||
});
|
||
|
||
it('should allow decrypting non-integrity-protected message when enabled', async function() {
|
||
const key = await openpgp.readKey({
|
||
armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xVgEYD9r8xYJKwYBBAHaRw8BAQdApTaQJ6R/uooTqAuscoxYwbLrtoKndnsX
|
||
ydhqMybJqh0AAQCxNwi9Pezy03OQE0XOooBWaHiuhBtKA1eAuqjJFuuLuQ/+
|
||
zQDCjAQQFgoAHQUCYD9r8wQLCQcIAxUICgQWAgEAAhkBAhsDAh4BACEJEIkB
|
||
BTiDwpvwFiEEvRnmOby6fJ/OxUhSiQEFOIPCm/BidgEAq05ZiPseRsMTxNm7
|
||
IFQwQjmIFiWgLeQ0gKIvfl3SjBAA/iSPyTgWxSY98utXNuq+WoxVOzx3dJwG
|
||
2cflR/UFUlEPx10EYD9r8xIKKwYBBAGXVQEFAQEHQCASw+tMPvnXi904WASv
|
||
wRDUQofh0M7CpgQFqoOXvGlLAwEIBwAA/3gEimwdIet0gXb/hRRyBqOlcq32
|
||
lNREh+n+vZKJyXWYEjrCeAQYFggACQUCYD9r8wIbDAAhCRCJAQU4g8Kb8BYh
|
||
BL0Z5jm8unyfzsVIUokBBTiDwpvwHpEBAObHllPrJu0DqYyt4FKPkijgRpXC
|
||
ESqhlK5rrbc62SmfAQDVf5l1B6IDASBCKtC0VPPpYiK6AUcEISpaSXOa+pNI
|
||
Bw==
|
||
=3Fja
|
||
-----END PGP PRIVATE KEY BLOCK-----`
|
||
});
|
||
const message = await openpgp.readMessage({
|
||
armoredMessage: `-----BEGIN PGP MESSAGE-----
|
||
|
||
wV4D+3VwOibHmagSAQdATlMJlvrkaq46zMkbIuKBOJO5X3ugVwZpEyAterQC
|
||
/RUw0OPWeO+4swh/U7ZurV8cRr/fPnyGUUKI7rI+va3kWUZv4RRpUs7eYE57
|
||
OUr3yoMNyaQEBwu6VXiQrsBN8TyUbXQxb63p7EHFXIgvVDIvOG7bQptrrKlM
|
||
kKcB+fz5hb6mT/tl+cPcYHDOjocQ92pNVm+FilQhiATRxV8ah1DCOIZZ6tgq
|
||
rWwIiEQEBPt+tXOuVF4Peumovp3WgziudrJa5Jxt2Dz+8nicBglbZLXTsZNu
|
||
bsZgJWVlAa5eil6J9ePX2xbo1vVAkLQdzE9+1jL+l7PRIZuVBQ==
|
||
=T4iR
|
||
-----END PGP MESSAGE-----`
|
||
});
|
||
const decrypted = await openpgp.decrypt({ message, decryptionKeys: key, verificationKeys: key, config: { allowUnauthenticatedMessages: true } });
|
||
expect(decrypted.data).to.equal('test');
|
||
});
|
||
|
||
it('should allow stream-decrypting non-integrity-protected message when enabled', async function() {
|
||
const key = await openpgp.readKey({
|
||
armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xVgEYD9r8xYJKwYBBAHaRw8BAQdApTaQJ6R/uooTqAuscoxYwbLrtoKndnsX
|
||
ydhqMybJqh0AAQCxNwi9Pezy03OQE0XOooBWaHiuhBtKA1eAuqjJFuuLuQ/+
|
||
zQDCjAQQFgoAHQUCYD9r8wQLCQcIAxUICgQWAgEAAhkBAhsDAh4BACEJEIkB
|
||
BTiDwpvwFiEEvRnmOby6fJ/OxUhSiQEFOIPCm/BidgEAq05ZiPseRsMTxNm7
|
||
IFQwQjmIFiWgLeQ0gKIvfl3SjBAA/iSPyTgWxSY98utXNuq+WoxVOzx3dJwG
|
||
2cflR/UFUlEPx10EYD9r8xIKKwYBBAGXVQEFAQEHQCASw+tMPvnXi904WASv
|
||
wRDUQofh0M7CpgQFqoOXvGlLAwEIBwAA/3gEimwdIet0gXb/hRRyBqOlcq32
|
||
lNREh+n+vZKJyXWYEjrCeAQYFggACQUCYD9r8wIbDAAhCRCJAQU4g8Kb8BYh
|
||
BL0Z5jm8unyfzsVIUokBBTiDwpvwHpEBAObHllPrJu0DqYyt4FKPkijgRpXC
|
||
ESqhlK5rrbc62SmfAQDVf5l1B6IDASBCKtC0VPPpYiK6AUcEISpaSXOa+pNI
|
||
Bw==
|
||
=3Fja
|
||
-----END PGP PRIVATE KEY BLOCK-----`
|
||
});
|
||
const message = await openpgp.readMessage({
|
||
armoredMessage: stream.toStream(`-----BEGIN PGP MESSAGE-----
|
||
|
||
wV4D+3VwOibHmagSAQdATlMJlvrkaq46zMkbIuKBOJO5X3ugVwZpEyAterQC
|
||
/RUw0OPWeO+4swh/U7ZurV8cRr/fPnyGUUKI7rI+va3kWUZv4RRpUs7eYE57
|
||
OUr3yoMNyaQEBwu6VXiQrsBN8TyUbXQxb63p7EHFXIgvVDIvOG7bQptrrKlM
|
||
kKcB+fz5hb6mT/tl+cPcYHDOjocQ92pNVm+FilQhiATRxV8ah1DCOIZZ6tgq
|
||
rWwIiEQEBPt+tXOuVF4Peumovp3WgziudrJa5Jxt2Dz+8nicBglbZLXTsZNu
|
||
bsZgJWVlAa5eil6J9ePX2xbo1vVAkLQdzE9+1jL+l7PRIZuVBQ==
|
||
=T4iR
|
||
-----END PGP MESSAGE-----`)
|
||
});
|
||
const decrypted = await openpgp.decrypt({ message, decryptionKeys: key, verificationKeys: key, config: { allowUnauthenticatedMessages: true } });
|
||
const data = await stream.readToEnd(decrypted.data);
|
||
expect(data).to.equal('test');
|
||
});
|
||
|
||
describe('X25519/Ed25519 (new format)', async function () {
|
||
it('should enforce using AES session keys with x25519 keys (v4 key)', async function () {
|
||
// x25519 key (v4) with cast5 as preferred cipher
|
||
const privateKeyCast5 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xUkEZK8BixuMghYwdEgHl+3ASI4VZkn048KG4DVuugT1bMe4QTtFtQCoKBOG
|
||
JxrZh8E+7I5nK7McXP2U9gyC0+RFcD46AxSmRA46zQDCiAQQGwgAPgWCZK8B
|
||
iwQLAwcICZCaWrTxMIPhVwMVCAoEFgACAQIZAQKbAwIeARYhBDFBS8Xnfotk
|
||
Oun5WZpatPEwg+FXAABwwuNWCdr1WahiGrLupYaOYQO4S9y+FYTxqEV/gsOP
|
||
TKwmNIcIJPROV2LgyxvzQo79//0CocEYojEeUhGn7BH5lwvHSQRkrwGLGbVM
|
||
1JxFUJeQ253sHMko73uPkyyb9DvaeyWHPwgF2k9GACA9caoO8GsZI7KMnVGP
|
||
c4EpytBwVIsr4ck3QaEV/UxvDpnCdAQYGwgAKgWCZK8BiwmQmlq08TCD4VcC
|
||
mwwWIQQxQUvF536LZDrp+VmaWrTxMIPhVwAAXycLtMyiv0lon4qU5/rKWjrq
|
||
MIxMchUbHvktvUqomU0pDDLMPqLFtzBbtHqODPVbLTOygJRVLeHyWTOEfmOD
|
||
kl0L
|
||
=SYJZ
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
|
||
await expect(openpgp.generateSessionKey({
|
||
encryptionKeys: privateKeyCast5,
|
||
config: { preferredSymmetricAlgorithm: openpgp.enums.symmetric.cast5 }
|
||
})).to.be.rejectedWith(/Could not generate a session key compatible with the given `encryptionKeys`/);
|
||
|
||
await expect(openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: privateKeyCast5,
|
||
sessionKey: { data: new Uint8Array(16).fill(1), algorithm: 'cast5' }
|
||
})).to.be.rejectedWith(/X25519 and X448 keys can only encrypt AES session keys/);
|
||
|
||
await expect(openpgp.decryptSessionKeys({
|
||
message: await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
|
||
|
||
wUQD66NYAXF0vfYZNWpc7s9eihtgj7EhHBeLOq2Ktw79artbhN5JMs+9aCIZ
|
||
A7sB7uYCTVCLIMfPFwVZH+c29gpCzPxSXQ==
|
||
=Dr02
|
||
-----END PGP MESSAGE-----` }),
|
||
decryptionKeys: privateKeyCast5
|
||
})).to.be.rejectedWith(/AES session key expected/);
|
||
});
|
||
|
||
it('supports decrypting new x25519 format (v4 key)', async function () {
|
||
// v4 key
|
||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xUkEZIbSkxsHknQrXGfb+kM2iOsOvin8yE05ff5hF8KE6k+saspAZQCy/kfFUYc2
|
||
GkpOHc42BI+MsysKzk4ofjBAfqM+bb7goQ3hzRV1c2VyIDx1c2VyQHRlc3QudGVz
|
||
dD7ChwQTGwgAPQUCZIbSkwmQQezK2iB2tIkWIQRqZza9wQZcwxpjGYNB7MraIHa0
|
||
iQIbAwIeAQIZAQILBwIVCAIWAAMnBwIAAFOeZ7jrKZsCzRfu1ffFa77074st0zRo
|
||
BTJXoXBQ1ZzLjsh+ZO6fB2odnYJtQYstv45H/3JyLVogcMnFeYmHeSP3AMdJBGSG
|
||
0pMZfpd7TiOQv7uKSK+k4HT9lKr5+dmvb7vox/8ids6unEkAF1v8fCKogIrtBWVT
|
||
nVbwnovjM3LLexpXFZSgTKRcNMgPRMJ0BBgbCAAqBQJkhtKTCZBB7MraIHa0iRYh
|
||
BGpnNr3BBlzDGmMZg0HsytogdrSJAhsMAADCYs2I9wBakIu9Hhxs4R3Jq9F8J7AH
|
||
yxsNL0GomZ+hxiE0MOZwRr10DxfVaRabF1fcf9PHSHX2SwEFXUKMIHgbMQs=
|
||
=bJqd
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
|
||
const messageToDecrypt = `-----BEGIN PGP MESSAGE-----
|
||
|
||
wUQDYc6clYlCdtoZ3rAsvBDIwvoLmvM0zwViG8Ec0PgFfN5R6C4BqEZD53UZB1WM
|
||
J68hXSj1Sa235XAUYE1pZerTKhglvdI9Aeve8+L0w5RDMjmBBA50Yv/YT8liqhNi
|
||
mNwbfFbSNhZYWjFada77EKBn60j8QT/xCQzLR1clci7ieW2knw==
|
||
=NKye
|
||
-----END PGP MESSAGE-----`;
|
||
const { data } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: messageToDecrypt }),
|
||
decryptionKeys: privateKey
|
||
});
|
||
expect(data).to.equal('Hello World!');
|
||
});
|
||
|
||
it('supports encrypting/decrypting new x25519 format (v4 key)', async function () {
|
||
// v4 key
|
||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xUkEZIbSkxsHknQrXGfb+kM2iOsOvin8yE05ff5hF8KE6k+saspAZQCy/kfFUYc2
|
||
GkpOHc42BI+MsysKzk4ofjBAfqM+bb7goQ3hzRV1c2VyIDx1c2VyQHRlc3QudGVz
|
||
dD7ChwQTGwgAPQUCZIbSkwmQQezK2iB2tIkWIQRqZza9wQZcwxpjGYNB7MraIHa0
|
||
iQIbAwIeAQIZAQILBwIVCAIWAAMnBwIAAFOeZ7jrKZsCzRfu1ffFa77074st0zRo
|
||
BTJXoXBQ1ZzLjsh+ZO6fB2odnYJtQYstv45H/3JyLVogcMnFeYmHeSP3AMdJBGSG
|
||
0pMZfpd7TiOQv7uKSK+k4HT9lKr5+dmvb7vox/8ids6unEkAF1v8fCKogIrtBWVT
|
||
nVbwnovjM3LLexpXFZSgTKRcNMgPRMJ0BBgbCAAqBQJkhtKTCZBB7MraIHa0iRYh
|
||
BGpnNr3BBlzDGmMZg0HsytogdrSJAhsMAADCYs2I9wBakIu9Hhxs4R3Jq9F8J7AH
|
||
yxsNL0GomZ+hxiE0MOZwRr10DxfVaRabF1fcf9PHSHX2SwEFXUKMIHgbMQs=
|
||
=bJqd
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
const plaintext = 'plaintext';
|
||
|
||
const signed = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: privateKey
|
||
});
|
||
|
||
const { data } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: signed }),
|
||
decryptionKeys: privateKey
|
||
});
|
||
expect(data).to.equal(plaintext);
|
||
});
|
||
|
||
it('should decrypt test vector X25519-AEAD-OCB (PKESK v6, SEIPD v2)', async function() {
|
||
// test vector https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#appendix-A.8
|
||
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
||
|
||
wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO
|
||
WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS
|
||
aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l
|
||
yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo
|
||
bhF30A+IitsxxA==
|
||
-----END PGP MESSAGE-----`;
|
||
|
||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
|
||
exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
|
||
BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||
2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
|
||
RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
|
||
7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
|
||
LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
|
||
GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||
2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
|
||
M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
|
||
k0mXubZvyl4GBg==
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
|
||
const { data: decryptedData } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage }),
|
||
decryptionKeys: privateKey
|
||
});
|
||
|
||
expect(decryptedData).to.equal('Hello, world!');
|
||
});
|
||
});
|
||
|
||
describe('X448/Ed448', async function () {
|
||
it('should enforce using AES session keys with x448 keys (v4 key)', async function () {
|
||
// X448 key (v4) with cast5 as preferred cipher
|
||
const privateKeyCast5 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xXsEZRrtaRyScvyNjK0o5ccICztnWhA1MSij7WdzPfuNy7ryUzB+kqzpziBR
|
||
IIKp5PN0NW3mOYRDnUyo7QHBl4AA30tR5ED8u5v/rNIzKz/mKsD6XeYy+d0Q
|
||
5utwuR8BUxx9mcIUGdS65z9H6PUMGnfCwqAGVCTzBrSCHgTNAMK3BBAcCgA7
|
||
BYJlGu1pAwsDBwmQkFi4G9HqQDwDFQgKAhYAAhkBApsDAh4BFiEE7kZAI1Dd
|
||
SVlLtf4QkFi4G9HqQDwAAPA7E+p0vwVLtUCfT0aBFzapFn8xjoow6jrUNTo3
|
||
8EtaN0fqP2vaeQwW/vv26wobD+hbL2RwyFtAEV6AeeDsPVhbx7WA7yKHPzvl
|
||
GOYEGw0h57DuhvSxGciuyt0Y5PR2Vrz/2/wHGcEHzsrhTNysUetluxEAx3kE
|
||
ZRrtaRrySCLAqKQSATJOXdoRoNKVasJHlKrG3qgMbt1U6uSdctHBitTiHHTf
|
||
GU/Jg0ADA3Eg0bCyDupWNACmHJGu7q0o7O7BTAm0AsMbHxoIkNN9JsijwAp5
|
||
FLtdXK9cAOkNaXPMkEGQkt1hmoW50lUq0iWcGBpzwqYEGBwKACoFgmUa7WkJ
|
||
kJBYuBvR6kA8ApsMFiEE7kZAI1DdSVlLtf4QkFi4G9HqQDwAAD3uf3qdwHY8
|
||
65W22GR17PbqF+9uvkPpXLBi32FVPFkxJqYvIN5/LAQ33xdEE0mzO4As4+Oi
|
||
x8fsFb2AEXLEwlSnL+Eo0O+iUQd3/94yMbMFRlNxrdaqZ3+7CehbnieI/vby
|
||
LIEnN38XBi0HE70uoU5prxUA
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
|
||
await expect(openpgp.generateSessionKey({
|
||
encryptionKeys: privateKeyCast5,
|
||
config: { preferredSymmetricAlgorithm: openpgp.enums.symmetric.cast5 }
|
||
})).to.be.rejectedWith(/Could not generate a session key compatible with the given `encryptionKeys`/);
|
||
|
||
await expect(openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: privateKeyCast5,
|
||
sessionKey: { data: new Uint8Array(16).fill(1), algorithm: 'cast5' }
|
||
})).to.be.rejectedWith(/X25519 and X448 keys can only encrypt AES session keys/);
|
||
|
||
await expect(openpgp.decryptSessionKeys({
|
||
message: await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
|
||
|
||
wVwD2k7TUuqJwZkaXvEGk7B3pklJ5uRcRdKwwDJ40yKT0m5ic1e/2F+Se3xQ
|
||
zDE+N2DZ0B37pu4NUzTGBRo0oLD9EwwZA9+oJpBBOOry3cGmBYWvQHbvBpNE
|
||
5X5l8A==
|
||
-----END PGP MESSAGE-----` }),
|
||
decryptionKeys: privateKeyCast5
|
||
})).to.be.rejectedWith(/AES session key expected/);
|
||
});
|
||
|
||
it('should enforce using 512-bit signature digest', async function () {
|
||
// X448 key using sha256 for self signatures
|
||
const privateKeySHA256 = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xXsEZCWHXBwwtqciq6ZFU13s+dyhkWR5tOEmF1oX8OiP1B5ypfqyGVM8DkQh
|
||
5eTIMwB1oqJCROANoyA0q2dSigAAbDA5xr74DeClPPXC4ZXJ9uzuJWKvQvE8
|
||
x3EflhgoQCGBM7JfvH5zwdrJvPt8RKDvm0QkZzhPvnFoHnzNBHRlc3TCugQQ
|
||
HAgAPgWCZCWHXAQLCQcICZDsN6h/ys3ppwMVCAoEFgACAQIZAQKbAwIeARYh
|
||
BOJyE9P2eIcU2N2Ne+w3qH/KzemnAAAh1hTFCcEU77bU3YelrJTCNIOQnvt7
|
||
Hs6yZz2053CQTOC+wHkUQLaYYBEXSNyLZxoyv+NuGTiwbuYtAOlbE2erM7Cx
|
||
8B2Qz7M29UkFLMBUfb+yi+gTYYUWCXVQ7Um7MGjjgUG8+9p452i6f28mhRD8
|
||
tTgNAMd5BGQlh1wavTIFgILtbzrqQCiwDGx0YcFNzu9+FZ8vK5Mmm7UEZj0a
|
||
y7FWQtZw8tTaU6mY+RrSa52RjzkGLtQAQO++tgYqc+BnCFdCZ3ZYPRvD3mof
|
||
ffoo3l4xmto+iyvJZbQ4wQPXttg7VjCpEfOsL9TW9Xs09aIbysKmBBgcCAAq
|
||
BYJkJYdcCZDsN6h/ys3ppwKbDBYhBOJyE9P2eIcU2N2Ne+w3qH/KzemnAAC0
|
||
6/eZhh/Oj2gRdab2JeFGWACGIRDKxPXsWRCXR4YrSxcvCKK6rOvsyxQsgIsJ
|
||
JyPYkRPfmbKcseUDAEkSBLAfeizDGh7ea0GOdIMhwE/CW4f/H8ULbwi36y13
|
||
x3oMNVaYsI9dZ588Gpi8XYy2jOtqIPQ1AA==
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
|
||
await expect(privateKeySHA256.getSigningKey()).to.be.rejectedWith(/Hash algorithm too weak for EdDSA/);
|
||
});
|
||
|
||
it('supports encrypting/decrypting with x448 (v4 key)', async function () {
|
||
// v4 key
|
||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xXsEZRqJ5BwHESfKnw5YJly5WobjigVm0kKY84NxrP6JKeIvIWiFqqSlozGpKZyR
|
||
50YbVTHmxpUCuJ7YNwX0UoAAoSO8IXmMM/XMd4ph00ju+fbSHdtQfyNhfFTi3UoM
|
||
V5DiFT+uOYDP+zwAwLWCR86csxmCWn6O10DNHcDNF1VzZXJBIDxVc2VyQUB0ZXN0
|
||
LnRlc3Q+wroEExwKAD4FAmUaieQJEC8lwIrxSM+5FiEEGR2s5Bj5WVDN0Px6LyXA
|
||
ivFIz7kCGwMCHgkCGQECCwcDFQoIAhYAAycHAgAA21/PqAuGDL5+3qrf3YoVOP+5
|
||
0BoJ+ZMhzcgax+cQTyndmOZYBfOqV/SJ8mf6CRhbB76JhGIvmRMtyYDQgDMVvcoA
|
||
yojVNs6e/Jco16bVJxM85wKDXJuq6AhtPQ8w/0WaCJtEf1uxqeQPEbOM+KtT/xY2
|
||
KgDHeQRlGonkGuOtAhogSIU3z/+gFzF8U7JQe7QDRYr9VWfi2WXFFarzg/3DMRur
|
||
oIB7mqkaaSatrvVuud1ZmRCWAMM4f57dvSdCKsVqSe+tlS225OmdWmnGLqyErBb6
|
||
44E2oENhDUom9OUGUPm8dXUjQbrmw6ec9hNLHWXCpgQYHAoAKgUCZRqJ5AkQLyXA
|
||
ivFIz7kWIQQZHazkGPlZUM3Q/HovJcCK8UjPuQIbDAAAZka10c8KlmwftJuboIV5
|
||
DalGWrZhbywJpEZRfoikcebSYi5++w1SbpXZGu27sl+BznGyyyqAfxyJjoCZaqCs
|
||
ewbKh04DNAg4v4v0W0a8UvD3j/CuciEMXjK9nUErt91zEwxNZy43yrQY2aAayDs8
|
||
94FqMAA=
|
||
=GBh1
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
const plaintext = 'plaintext';
|
||
|
||
const signed = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: privateKey
|
||
});
|
||
|
||
const { data } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: signed }),
|
||
decryptionKeys: privateKey
|
||
});
|
||
expect(data).to.equal(plaintext);
|
||
});
|
||
|
||
it('supports encrypting/decrypting with x448 (v6 key)', async function () {
|
||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xX0GZRqLYhwAAAA52IEq/TpKiPp6RofQaq4uhCruTtiG+qiVFnwsQgeh0ui34kHD
|
||
Y1E04mBai0pCoDiFVokwsKt3F5sAAC8lDYfVP/p3atbXJDTJB2W9WmZxIS7pUGhS
|
||
bjlWpZB/OVTBsoIfP/2J+Hi4ESwBRfDUDgwK4aJVKsLAIAYfHAoAAAA/BQJlGoti
|
||
IqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwMCHgkCCwcDFQoI
|
||
AhYABScHAwcCAAAAAPiGIG2qmhCULQ/+H4rKV0XEM1x0uVY3l878Pa6ijZLouZU/
|
||
VRd5PnbGyLPL++q3LDViUUdZ1uusRc01f677Q6wpUU90k8MH/oULwI0+KPtqe1N4
|
||
6nr1NTERsAmAaPjUdf4ZUXX/GWiTd/AlsS5JqGnAQxKRJkzCJacOTOElRMjzGUX7
|
||
CGaAnhSC86YRZ68ocTPfZysAzRdVc2VyQiA8VXNlckJAdGVzdC50ZXN0PsLADQYT
|
||
HAoAAAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUC
|
||
GQEAAAAASKwgVzMoPb2Hbr3lbNI1CRWECokYLokL7F8MbYiMnlg+v6QXLdStvT13
|
||
ZjxdrWQAx3MbihSOUSXbdAys90yMOAdtognj+x418J/TaYFMtIGBHwoHv8gQVnx9
|
||
9ICv8ezx1T5VvGBYNuKZ5Ww0WPEpYMf1VA+Y9JxpohdcRenNBdSug4tLWla2y8NH
|
||
aO28Fltpb4AuGQDHewZlGotiGgAAADjdabr1ohAOnbSUUkVhtUM/LVdnYgDLhmaj
|
||
YZ1N7TWY0fqEpMk2LLo2165HOmhddRPeTB1TWbuwBwB8lKc3czFUzYcAgvZ08T5S
|
||
UUHjfIhjeJeY4yd0OZDfzPw1vbegCc7t94bT+XGoIQbC/Bl7HCyAiMLADQYYHAoA
|
||
AAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwwA
|
||
AAAAHh0gf2kdqLoXdFX+aNVORr5VCVgcm2gBw8l68lDJ1ftA71bMllFi6Q5sLPUr
|
||
6UCpJYYk3o3hYUYzIHmCIZGVYe1pxRgIUNqxydXEfzylJmN5NbiJNkjJizrI7oAR
|
||
1mIcEEb/hmRMOUs1V2mcGuoeALBI/r/SyqDE2GRjH6d6g1RS7ZARPPHlZlY4CTqC
|
||
4a7L+8odDwA=
|
||
=chx0
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
const plaintext = 'plaintext';
|
||
|
||
const signed = await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
encryptionKeys: privateKey
|
||
});
|
||
|
||
const { data } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage: signed }),
|
||
decryptionKeys: privateKey
|
||
});
|
||
expect(data).to.equal(plaintext);
|
||
});
|
||
|
||
it('decrypt/verify should succeed using X448/Ed448 (PKESK v4, SEIPD v2, GCM)', async function() {
|
||
// data generated by gopenpgp
|
||
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
||
|
||
wWkGFQQ70agVm6o5r3tEzY5mrYaOV8yHChpUetZ33zrKGtw1F4PeFrE4bYkcTMQM
|
||
IcGoXcZj/0GJDCkOLLleSwrvuAuUwZV11bHBZ6eNTyj+XxhLdVflV/zqPmBhTHY9
|
||
SMn0YYHwgiQFk6PSwGICBwMMRYkTpsy0dE4YKasf6b4Oh9cn6HYY5rjnrtvrwD+F
|
||
LrsELfudYwpwHBA5jnO11Hl5mUyXhhWSdPoLGdeiYP5R/vZjqoZr3P6FL4dCdVni
|
||
fGChUUSYmpO4HIFrRBt2gAxl+f0Q8GCOG8c7EQ7c5600kJOlHM7SuoLqsxd482V1
|
||
H/1Rxd3cPwTDfOjH26KuDv60p0XjdCGyQXcDQMCPV+ZTs0TQl4wTFogZGaRMd9GC
|
||
5D5t/guKzR+H1ipXSFjFdWWTEehx8m0RKKKT3Bl81awKZb8ulR6YKI5x39nwOySN
|
||
azDRR3gn9xlKjcpa83k5sSZbUTxC8lzTeuMP0PkDrU2IpZUZOlzOhGYOGrtTFATK
|
||
PSoZU33h2h3hJqiX9aKrnw==
|
||
=Is5l
|
||
-----END PGP MESSAGE-----`;
|
||
|
||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xXsEZRqJ5BxV/xdxR4KvPofk3EzKaIZqM0Wlw904q+2S6Z84OmXN6Q1xCYurcwN1
|
||
wLOlGJ/CO2QhByEdGlUldwAAIQSMnMITcmXQU3EWK5S81FS+u1IZFP55j51bA5mS
|
||
HZ/A7MOpyN40ybW8mhMIXXUYB7kC/bOTmwVHGt3NF1VzZXJCIDxVc2VyQkB0ZXN0
|
||
LnRlc3Q+wrwEExwKAEAFAmUaieQJEP3WralmOT0PFiEEq4zuQzIBSh+Nk6G9/dat
|
||
qWY5PQ8CGwMCHgkCGQECCwcDFQoIAhYABScHAwcCAADAvnnhLp0DJYk7E0GfksCg
|
||
pUnnCjEePMVvRPVY3dwr9wLpdL/7T70fz541XVE8giYiZD7eiKvfc/nMgOhu1eqK
|
||
uXGUtDGBeabitJcrbquy2Tp/ENuW6rRHP7sAbu0mj6XxYEeCzKjGRT5Iq25AMevm
|
||
yeoIAMd5BGUaieQaqj/dF+uZGt9QLuji2eOlDC0/quq/sAtdJTbI1xj04aF0X7kJ
|
||
lVhEKeWZeAEpD4rVOCsrhMvr21gAu/BaFVKGUOuf0+ZE5jGcFcBvEP7OGyO296ry
|
||
zV7ONWS/FuoZ/NZmgWo9m9ftPtwqKDsgOWxiIj4cesKmBBgcCgAqBQJlGonkCRD9
|
||
1q2pZjk9DxYhBKuM7kMyAUofjZOhvf3WralmOT0PAhsMAADWb+0aY+NblShwsym/
|
||
2geh6XaqQUCJgdRfEl8xYLau/o8QQAzRp0ZBA+KeK3uwhRW3RizuqIw5iribAK3+
|
||
30Si5nvv0TivalPK2C9yAqzh9rkNNUQa9b17IHYs/WwQrvP3F5EZ3V+StqdveAEo
|
||
FecSL/wTAA==
|
||
=FANS
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
|
||
const senderKey = await openpgp.readKey({
|
||
armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||
|
||
xj8EZRqJ5BwHESfKnw5YJly5WobjigVm0kKY84NxrP6JKeIvIWiFqqSlozGpKZyR
|
||
50YbVTHmxpUCuJ7YNwX0UoDNF1VzZXJBIDxVc2VyQUB0ZXN0LnRlc3Q+wroEExwK
|
||
AD4FAmUaieQJEC8lwIrxSM+5FiEEGR2s5Bj5WVDN0Px6LyXAivFIz7kCGwMCHgkC
|
||
GQECCwcDFQoIAhYAAycHAgAA21/PqAuGDL5+3qrf3YoVOP+50BoJ+ZMhzcgax+cQ
|
||
TyndmOZYBfOqV/SJ8mf6CRhbB76JhGIvmRMtyYDQgDMVvcoAyojVNs6e/Jco16bV
|
||
JxM85wKDXJuq6AhtPQ8w/0WaCJtEf1uxqeQPEbOM+KtT/xY2KgDOPgRlGonkGuOt
|
||
AhogSIU3z/+gFzF8U7JQe7QDRYr9VWfi2WXFFarzg/3DMRuroIB7mqkaaSatrvVu
|
||
ud1ZmRCWwqYEGBwKACoFAmUaieQJEC8lwIrxSM+5FiEEGR2s5Bj5WVDN0Px6LyXA
|
||
ivFIz7kCGwwAAGZGtdHPCpZsH7Sbm6CFeQ2pRlq2YW8sCaRGUX6IpHHm0mIufvsN
|
||
Um6V2Rrtu7Jfgc5xsssqgH8ciY6AmWqgrHsGyodOAzQIOL+L9FtGvFLw94/wrnIh
|
||
DF4yvZ1BK7fdcxMMTWcuN8q0GNmgGsg7PPeBajAA
|
||
=VA/P
|
||
-----END PGP PUBLIC KEY BLOCK-----` });
|
||
|
||
const { data: decryptedData, signatures } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: senderKey
|
||
});
|
||
|
||
expect(decryptedData).to.equal('Hello there');
|
||
expect(signatures).to.have.length(1);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
});
|
||
|
||
|
||
it('decrypt/verify should succeed using X448/Ed448 (PKESK v6, SEIPD v2, GCM)', async function() {
|
||
// data generated by gopenpgp
|
||
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
||
|
||
wXUGIQZh4qTsn8glFgGNbIdCTl8gH2OtkI/PAGCQ0gi9s9k/rhrDhXo7kUKDJ39F
|
||
fNp3kmAaM24Ce3bcYXwLy0gF2i6rxfL20D+g3cxv0i3CuXQCgcbojTN/8KY8ExiV
|
||
Xdfo+OWIZ5XndtyMpJW28BiLHru+n9bSwM8CBwMMENh7cT8lILXteh885FrUUD1Q
|
||
JMtD7xJUn2y78cVGgFSIkLbvFPDerB37xuhtMRkykuWgbUoJH/kcgBPdeCoYzJmf
|
||
LV9FyATv0/AYq0yWpQ0VUfNLTFyeHIGxz7NHvrzJSrOy1Gm31PXqWvb4sBROjnOX
|
||
oAk12JdPudz3l1QZT/DX947f4h6hwkVv7RRT0oOS2pMaz/mekRuD6utUcpsjFQ/M
|
||
EDphnhOsB4RH0il8YPVc9DCnf3GhSs66h+Z699MXHBaUmdtiN1IgoEgLfb/900U2
|
||
TfI6dvrvC56WIMA8EA1COvLGc9Ge4owW0UE8jIuqWLzA2nVg5belbzhNnOEh9b1c
|
||
OcDUh8CfBuXqHEi/ANMUOMmaIGfcHfQFVu5v/UMcLxcH/fSVF6DvtOxEoUxASWBS
|
||
mp6yC4A778BFuDFXb+/T8FjuJBaUj9rCSkYqt1TYVKG1XZPI4OdIvGtneo+vH/Cq
|
||
F6bxlLWU6oskZ5SE+xJblmmO01ObM9JRi9D8jZnXedTHExAnXHXIb8I=
|
||
=5RQw
|
||
-----END PGP MESSAGE-----`;
|
||
|
||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xX0GZRqLYhwAAAA52IEq/TpKiPp6RofQaq4uhCruTtiG+qiVFnwsQgeh0ui34kHD
|
||
Y1E04mBai0pCoDiFVokwsKt3F5sAAC8lDYfVP/p3atbXJDTJB2W9WmZxIS7pUGhS
|
||
bjlWpZB/OVTBsoIfP/2J+Hi4ESwBRfDUDgwK4aJVKsLAIAYfHAoAAAA/BQJlGoti
|
||
IqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwMCHgkCCwcDFQoI
|
||
AhYABScHAwcCAAAAAPiGIG2qmhCULQ/+H4rKV0XEM1x0uVY3l878Pa6ijZLouZU/
|
||
VRd5PnbGyLPL++q3LDViUUdZ1uusRc01f677Q6wpUU90k8MH/oULwI0+KPtqe1N4
|
||
6nr1NTERsAmAaPjUdf4ZUXX/GWiTd/AlsS5JqGnAQxKRJkzCJacOTOElRMjzGUX7
|
||
CGaAnhSC86YRZ68ocTPfZysAzRdVc2VyQiA8VXNlckJAdGVzdC50ZXN0PsLADQYT
|
||
HAoAAAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUC
|
||
GQEAAAAASKwgVzMoPb2Hbr3lbNI1CRWECokYLokL7F8MbYiMnlg+v6QXLdStvT13
|
||
ZjxdrWQAx3MbihSOUSXbdAys90yMOAdtognj+x418J/TaYFMtIGBHwoHv8gQVnx9
|
||
9ICv8ezx1T5VvGBYNuKZ5Ww0WPEpYMf1VA+Y9JxpohdcRenNBdSug4tLWla2y8NH
|
||
aO28Fltpb4AuGQDHewZlGotiGgAAADjdabr1ohAOnbSUUkVhtUM/LVdnYgDLhmaj
|
||
YZ1N7TWY0fqEpMk2LLo2165HOmhddRPeTB1TWbuwBwB8lKc3czFUzYcAgvZ08T5S
|
||
UUHjfIhjeJeY4yd0OZDfzPw1vbegCc7t94bT+XGoIQbC/Bl7HCyAiMLADQYYHAoA
|
||
AAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwwA
|
||
AAAAHh0gf2kdqLoXdFX+aNVORr5VCVgcm2gBw8l68lDJ1ftA71bMllFi6Q5sLPUr
|
||
6UCpJYYk3o3hYUYzIHmCIZGVYe1pxRgIUNqxydXEfzylJmN5NbiJNkjJizrI7oAR
|
||
1mIcEEb/hmRMOUs1V2mcGuoeALBI/r/SyqDE2GRjH6d6g1RS7ZARPPHlZlY4CTqC
|
||
4a7L+8odDwA=
|
||
=chx0
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
|
||
const senderKey = await openpgp.readKey({
|
||
armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||
|
||
xkMGZRqLYhwAAAA5U/IaIOge/FoLzCetXKx029bdJHCz2hMFBRMuzq4msjaT+hLe
|
||
V6puyC/PeSEfaanqTuo31vvsti2AwsAeBh8cCgAAAD0FAmUai2IioQYDGJ2wdEcO
|
||
zIVPDVDs6gYQASdGfG2EozBUGqEgvaj4dQIbAwIeCQILBwMVCggCFgADJwcCAAAA
|
||
ADYqIL5j5+FD/jwKRP1atdNf1IKfe8fPjdZv74CSalYvUdCaskTdLiAaW17NkrYT
|
||
2i9qDPErFWsvXi4LqGzqQnQkiJZBJ4x57EJPL4Z2vqPTBvgWEU2egi7fK7YAGZmk
|
||
Vf/n/X3Vh5ZSvIoUMChRmYqBBNI7MkS/I7QAJHkvi9XcANx44B0bz+yqETz2tNJ6
|
||
8VeeDgkAzRdVc2VyQSA8VXNlckFAdGVzdC50ZXN0PsLADQYTHAoAAAAsBQJlGoti
|
||
IqEGAxidsHRHDsyFTw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUCGQEAAAAAXD8gfvYz
|
||
WLLMxaFuC3C/RJH9fG84hb9mtPgjH3bfqW+g4Ti1ov8PjoJtk6ObtUB45J9J3G3X
|
||
FIqegAtGwI1Dy1U+M9dyXOqvpHwxs8iAFbEpwxLZ5K1ikFsbmoCZz4rmN0DbFyX2
|
||
JbltaV5nUtNqHiUXqoKIPvch98ANe3PDyIAxNf7TAzk3W0lQQa+Cp7TSiFEqJADO
|
||
QgZlGotiGgAAADjKb5lwMEt0ubSvwydaAF89wsn6H8NJO7kox5ioWW2Grn88CUZD
|
||
YaRBZj3ZH8HMdaih5kN4hJAeCMLADQYYHAoAAAAsBQJlGotiIqEGAxidsHRHDsyF
|
||
Tw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUCGwwAAAAAFIQgGYYweuBej4XHAgZrcez8
|
||
8VoTbIZDjMv6Qbj9g6jjW16Fyp10DKda10FFmbY+YjbNvQNYksF9bN/KFSS/PTYt
|
||
AVaOZDfW4fiN5s1QaYmA/xCT/zLHEYGryYCJLoLd7KLw28LS1KAWrC9h5cY6+fZE
|
||
05cavO/D/WqBLVPuA+5bftXnDvGcVS1p7buaMtQjKz4hAwA=
|
||
=GUIG
|
||
-----END PGP PUBLIC KEY BLOCK-----` });
|
||
|
||
const { data: decryptedData, signatures } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: senderKey
|
||
});
|
||
|
||
expect(decryptedData).to.equal('Hello there');
|
||
expect(signatures).to.have.length(1);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
});
|
||
|
||
it('decrypt/verify should succeed using X448/Ed448 (PKESK v6, SEIPD v2, OCB)', async function() {
|
||
// data generated by gopenpgp
|
||
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
||
|
||
wXUGIQaYemlYu2ObOZ2IjFbL77NygqexwaCgtb0COZ0EnXfXlBri0wADNxbvwCnJ
|
||
GDlRX9VhIy46oPAvVJjm2d7ZC6wqxNfFuzQEB8KzwYBkExmZuAfO5KJ8la6+DRhc
|
||
OUH3A9cBGzq0eiKaKRqjHkiLHY5pFNPSwNoCBwIM98RL63I8iMyxcXpXQlBrYlBx
|
||
5uegrENlleNg6UJFr7rBT4eJH+Qeksb//V87eZymzqXZBsrTYmUjsFgYd5kL8NlU
|
||
wovy+qQnZmEaUKieDx3w+orR8b32ub5CNjHJa5lCdNWsIK825S5JUifZDd3hR6lC
|
||
EgtZRwxY/1CyQU94LR9j6w/YVF0W31+LxGGkL+uJEx0khJUzpxUM9QSEREOY7Frs
|
||
EegHNwDvxvxEwWpfkJOPIDME6Y7UcpsNp6xgiZ/XF06IRsliCRbeYaH1IWW+y0OS
|
||
CmPvvTFUzjwTxWogDccHz8YLHU0y6TKxf14YMvVLg2tf2P/BVVZSg0ejz6pfDKA5
|
||
AP+Q/eXBAH272SpBjKo7YcVpTsz0KpWyhB6Jra4xaUFkt6pg39ydR3RJMvxbQVlR
|
||
aZqV/+1rwIiIauyHKiJFdCiXYPDU3xibVkFIFhuk5JwHm29XvOV1r8FFx7d78X5P
|
||
yJnXcXsl+GxwOojcLXSL0CEIU/iRqyAIyyhvUyyss3glehhgx0fENV2P/Ygi/naN
|
||
nJUJgg==
|
||
=m19C
|
||
-----END PGP MESSAGE-----`;
|
||
|
||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||
|
||
xX0GZRqLYhwAAAA5U/IaIOge/FoLzCetXKx029bdJHCz2hMFBRMuzq4msjaT+hLe
|
||
V6puyC/PeSEfaanqTuo31vvsti2AAIttr4GDGXF4vfPzbzkWV9dT4VVsIU7QqLv1
|
||
hzwZ+k7pHroRyXnUiYxRYHuzlg7Vw4CrAtN/8T65OMLAHgYfHAoAAAA9BQJlGoti
|
||
IqEGAxidsHRHDsyFTw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUCGwMCHgkCCwcDFQoI
|
||
AhYAAycHAgAAAAA2KiC+Y+fhQ/48CkT9WrXTX9SCn3vHz43Wb++AkmpWL1HQmrJE
|
||
3S4gGltezZK2E9ovagzxKxVrL14uC6hs6kJ0JIiWQSeMeexCTy+Gdr6j0wb4FhFN
|
||
noIu3yu2ABmZpFX/5/191YeWUryKFDAoUZmKgQTSOzJEvyO0ACR5L4vV3ADceOAd
|
||
G8/sqhE89rTSevFXng4JAM0XVXNlckEgPFVzZXJBQHRlc3QudGVzdD7CwA0GExwK
|
||
AAAALAUCZRqLYiKhBgMYnbB0Rw7MhU8NUOzqBhABJ0Z8bYSjMFQaoSC9qPh1AhkB
|
||
AAAAAFw/IH72M1iyzMWhbgtwv0SR/XxvOIW/ZrT4Ix9236lvoOE4taL/D46CbZOj
|
||
m7VAeOSfSdxt1xSKnoALRsCNQ8tVPjPXclzqr6R8MbPIgBWxKcMS2eStYpBbG5qA
|
||
mc+K5jdA2xcl9iW5bWleZ1LTah4lF6qCiD73IffADXtzw8iAMTX+0wM5N1tJUEGv
|
||
gqe00ohRKiQAx3sGZRqLYhoAAAA4ym+ZcDBLdLm0r8MnWgBfPcLJ+h/DSTu5KMeY
|
||
qFlthq5/PAlGQ2GkQWY92R/BzHWooeZDeISQHggAuraV/u+CE642fcbcq90OY+qg
|
||
n739wkHcBps/s/MgMI+Q2H13vEsFpYZ/kuBIIYP39xkdU48/1GbCwA0GGBwKAAAA
|
||
LAUCZRqLYiKhBgMYnbB0Rw7MhU8NUOzqBhABJ0Z8bYSjMFQaoSC9qPh1AhsMAAAA
|
||
ABSEIBmGMHrgXo+FxwIGa3Hs/PFaE2yGQ4zL+kG4/YOo41tehcqddAynWtdBRZm2
|
||
PmI2zb0DWJLBfWzfyhUkvz02LQFWjmQ31uH4jebNUGmJgP8Qk/8yxxGBq8mAiS6C
|
||
3eyi8NvC0tSgFqwvYeXGOvn2RNOXGrzvw/1qgS1T7gPuW37V5w7xnFUtae27mjLU
|
||
Iys+IQMA
|
||
=iwhO
|
||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||
|
||
const senderKey = await openpgp.readKey({
|
||
armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||
|
||
xkMGZRqLYhwAAAA52IEq/TpKiPp6RofQaq4uhCruTtiG+qiVFnwsQgeh0ui34kHD
|
||
Y1E04mBai0pCoDiFVokwsKt3F5sAwsAgBh8cCgAAAD8FAmUai2IioQahuzG3xYqw
|
||
y4lYA3JNelYx0LVA3/sTIkKV9yz6cGCp1QIbAwIeCQILBwMVCggCFgAFJwcDBwIA
|
||
AAAA+IYgbaqaEJQtD/4fispXRcQzXHS5VjeXzvw9rqKNkui5lT9VF3k+dsbIs8v7
|
||
6rcsNWJRR1nW66xFzTV/rvtDrClRT3STwwf+hQvAjT4o+2p7U3jqevU1MRGwCYBo
|
||
+NR1/hlRdf8ZaJN38CWxLkmoacBDEpEmTMIlpw5M4SVEyPMZRfsIZoCeFILzphFn
|
||
ryhxM99nKwDNF1VzZXJCIDxVc2VyQkB0ZXN0LnRlc3Q+wsANBhMcCgAAACwFAmUa
|
||
i2IioQahuzG3xYqwy4lYA3JNelYx0LVA3/sTIkKV9yz6cGCp1QIZAQAAAABIrCBX
|
||
Myg9vYduveVs0jUJFYQKiRguiQvsXwxtiIyeWD6/pBct1K29PXdmPF2tZADHcxuK
|
||
FI5RJdt0DKz3TIw4B22iCeP7HjXwn9NpgUy0gYEfCge/yBBWfH30gK/x7PHVPlW8
|
||
YFg24pnlbDRY8Slgx/VUD5j0nGmiF1xF6c0F1K6Di0taVrbLw0do7bwWW2lvgC4Z
|
||
AM5CBmUai2IaAAAAON1puvWiEA6dtJRSRWG1Qz8tV2diAMuGZqNhnU3tNZjR+oSk
|
||
yTYsujbXrkc6aF11E95MHVNZu7AHwsANBhgcCgAAACwFAmUai2IioQahuzG3xYqw
|
||
y4lYA3JNelYx0LVA3/sTIkKV9yz6cGCp1QIbDAAAAAAeHSB/aR2ouhd0Vf5o1U5G
|
||
vlUJWBybaAHDyXryUMnV+0DvVsyWUWLpDmws9SvpQKklhiTejeFhRjMgeYIhkZVh
|
||
7WnFGAhQ2rHJ1cR/PKUmY3k1uIk2SMmLOsjugBHWYhwQRv+GZEw5SzVXaZwa6h4A
|
||
sEj+v9LKoMTYZGMfp3qDVFLtkBE88eVmVjgJOoLhrsv7yh0PAA==
|
||
=2Usy
|
||
-----END PGP PUBLIC KEY BLOCK-----` });
|
||
|
||
const { data: decryptedData, signatures } = await openpgp.decrypt({
|
||
message: await openpgp.readMessage({ armoredMessage }),
|
||
decryptionKeys: privateKey,
|
||
verificationKeys: senderKey
|
||
});
|
||
|
||
expect(decryptedData).to.equal('Hello nice to meet you');
|
||
expect(signatures).to.have.length(1);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
});
|
||
});
|
||
|
||
describe('Sign and verify with each curve', function() {
|
||
const curves = ['secp256k1' , 'nistP256', 'nistP384', 'nistP521', 'curve25519Legacy', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
|
||
curves.forEach(curve => {
|
||
it(`sign/verify with ${curve}`, async function() {
|
||
const config = { rejectCurves: new Set() };
|
||
const plaintext = 'short message';
|
||
const { privateKey: key } = await openpgp.generateKey({ curve, userIDs: { name: 'Alice', email: 'info@alice.com' }, format: 'object', config });
|
||
const signed = await openpgp.sign({ signingKeys:[key], message: await openpgp.createCleartextMessage({ text: plaintext }), config });
|
||
const verified = await openpgp.verify({ verificationKeys:[key], message: await openpgp.readCleartextMessage({ cleartextMessage: signed }), config });
|
||
expect(await verified.signatures[0].verified).to.be.true;
|
||
});
|
||
});
|
||
|
||
it('sign/verify with new Ed25519 format', async function () {
|
||
const userIDs = { name: 'Alice', email: 'info@alice.com' };
|
||
const { privateKey } = await openpgp.generateKey({ type: 'curve25519', userIDs, format: 'object' });
|
||
const plaintext = 'plaintext';
|
||
|
||
const signed = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey
|
||
});
|
||
|
||
const { signatures, data } = await openpgp.verify({
|
||
message: await openpgp.readMessage({ armoredMessage: signed }),
|
||
verificationKeys: privateKey
|
||
});
|
||
expect(data).to.equal(plaintext);
|
||
expect(signatures).to.have.length(1);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
});
|
||
|
||
it('sign/verify with Ed448', async function () {
|
||
const userIDs = { name: 'Alice', email: 'info@alice.com' };
|
||
const { privateKey } = await openpgp.generateKey({ type: 'curve448', userIDs, format: 'object' });
|
||
const plaintext = 'plaintext';
|
||
|
||
const signed = await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: plaintext }),
|
||
signingKeys: privateKey
|
||
});
|
||
|
||
const { signatures, data } = await openpgp.verify({
|
||
message: await openpgp.readMessage({ armoredMessage: signed }),
|
||
verificationKeys: privateKey
|
||
});
|
||
expect(data).to.equal(plaintext);
|
||
expect(signatures).to.have.length(1);
|
||
expect(await signatures[0].verified).to.be.true;
|
||
});
|
||
});
|
||
|
||
describe('Errors', function() {
|
||
|
||
it('Error message should contain the original error message', async function() {
|
||
return openpgp.encrypt({
|
||
message: await openpgp.createMessage({ binary: new Uint8Array([0x01, 0x01, 0x01]) }),
|
||
passwords: null
|
||
}).then(function() {
|
||
throw new Error('Error expected.');
|
||
}).catch(function(error) {
|
||
expect(error.message).to.match(/No keys, passwords, or session key provided/);
|
||
});
|
||
});
|
||
|
||
});
|
||
|
||
describe('Specific encryption/signing key testing', async function () {
|
||
const encryptionKeyIDs = [
|
||
keyIDType.fromID('87EAE0977B2185EA'),
|
||
keyIDType.fromID('F94F9B34AF93FA14'),
|
||
keyIDType.fromID('08F7D4C7C59545C0')
|
||
];
|
||
const signingKeyIDs = [
|
||
keyIDType.fromID('663277AF60400638'),
|
||
keyIDType.fromID('BBE14491E6EE6366'),
|
||
keyIDType.fromID('3E0F20F1A71D6DFD')
|
||
];
|
||
const getPrimaryKey = async () => openpgp.readKey({
|
||
armoredKey: multipleEncryptionAndSigningSubkeys
|
||
});
|
||
|
||
it('Encrypt message with a specific encryption key id', async function () {
|
||
const primaryKey = await getPrimaryKey();
|
||
let m;
|
||
let p;
|
||
for (let i = 0; i < encryptionKeyIDs.length; i++) {
|
||
m = await openpgp.readMessage({
|
||
armoredMessage: await openpgp.encrypt({
|
||
message: await openpgp.createMessage({ text: 'Hello World\n' }),
|
||
encryptionKeys: primaryKey,
|
||
encryptionKeyIDs: [encryptionKeyIDs[i]]
|
||
})
|
||
});
|
||
p = m.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey);
|
||
expect(p.length).equals(1);
|
||
expect(p[0].publicKeyID.equals(encryptionKeyIDs[i])).to.be.true;
|
||
}
|
||
});
|
||
|
||
it('Sign message with a specific signing key id', async function () {
|
||
const primaryKey = await getPrimaryKey();
|
||
let s;
|
||
let p;
|
||
for (let i = 0; i < signingKeyIDs.length; i++) {
|
||
s = await openpgp.readSignature({
|
||
armoredSignature: await openpgp.sign({
|
||
message: await openpgp.createMessage({ text: 'Hello World\n' }),
|
||
signingKeys: primaryKey,
|
||
signingKeyIDs: [signingKeyIDs[i]],
|
||
detached: true
|
||
})
|
||
});
|
||
p = s.packets.filterByTag(openpgp.enums.packet.signature);
|
||
expect(p.length).equals(1);
|
||
expect(p[0].issuerKeyID.equals(signingKeyIDs[i])).to.be.true;
|
||
}
|
||
});
|
||
|
||
it('Encrypt and sign with specific encryption/signing key ids', async function () {
|
||
const primaryKey = await getPrimaryKey();
|
||
const plaintextMessage = await openpgp.createMessage({ text: 'Hello World\n' });
|
||
|
||
const checkEncryptedPackets = (encryptionKeyIDs, pKESKList) => {
|
||
pKESKList.forEach(({ publicKeyID }, i) => {
|
||
expect(publicKeyID.equals(encryptionKeyIDs[i])).to.be.true;
|
||
});
|
||
};
|
||
const checkSignatures = (signingKeyIDs, signatures) => {
|
||
signatures.forEach(({ keyID }, i) => {
|
||
expect(keyID.equals(signingKeyIDs[i])).to.be.true;
|
||
});
|
||
};
|
||
|
||
const kIds = [encryptionKeyIDs[1], encryptionKeyIDs[0], encryptionKeyIDs[2]];
|
||
const sIds = [signingKeyIDs[2], signingKeyIDs[1], signingKeyIDs[0]];
|
||
const message = await openpgp.readMessage({
|
||
armoredMessage: await openpgp.encrypt({
|
||
message: plaintextMessage,
|
||
signingKeys: [primaryKey, primaryKey, primaryKey],
|
||
encryptionKeys: [primaryKey, primaryKey, primaryKey],
|
||
encryptionKeyIDs: kIds,
|
||
signingKeyIDs: sIds
|
||
})
|
||
});
|
||
const pKESKList = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey);
|
||
expect(pKESKList.length).equals(3);
|
||
checkEncryptedPackets(kIds, pKESKList);
|
||
const { signatures } = await openpgp.decrypt({
|
||
message,
|
||
decryptionKeys: [primaryKey, primaryKey, primaryKey]
|
||
});
|
||
expect(signatures.length).equals(3);
|
||
checkSignatures(sIds, signatures);
|
||
});
|
||
});
|
||
});
|
||
});
|