We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Wordlists are not being parsed correctly
# Bug

## Description

`crypo_util.{words,nouns,adjectives}` all contain an empty string as their last element.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `securedrop/crypto_util.py`
Content:
```
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 
4 from base64 import b32encode
5 import os
6 import subprocess
7 
8 from Crypto.Random import random
9 import gnupg
10 from gnupg._util import _is_stream, _make_binary_stream
11 import scrypt
12 
13 import config
14 import store
15 
16 # to fix gpg error #78 on production
17 os.environ['USERNAME'] = 'www-data'
18 
19 GPG_KEY_TYPE = "RSA"
20 if os.environ.get('SECUREDROP_ENV') == 'test':
21     # Optimize crypto to speed up tests (at the expense of security - DO NOT
22     # use these settings in production)
23     GPG_KEY_LENGTH = 1024
24     SCRYPT_PARAMS = dict(N=2**1, r=1, p=1)
25 else:  # pragma: no cover
26     GPG_KEY_LENGTH = 4096
27     SCRYPT_PARAMS = config.SCRYPT_PARAMS
28 
29 SCRYPT_ID_PEPPER = config.SCRYPT_ID_PEPPER
30 SCRYPT_GPG_PEPPER = config.SCRYPT_GPG_PEPPER
31 
32 DEFAULT_WORDS_IN_RANDOM_ID = 8
33 
34 
35 # Make sure these pass before the app can run
36 # TODO: Add more tests
37 def do_runtime_tests():
38     assert(config.SCRYPT_ID_PEPPER != config.SCRYPT_GPG_PEPPER)
39     # crash if we don't have srm:
40     try:
41         subprocess.check_call(['srm'], stdout=subprocess.PIPE)
42     except subprocess.CalledProcessError:
43         pass
44 
45 do_runtime_tests()
46 
47 gpg = gnupg.GPG(binary='gpg2', homedir=config.GPG_KEY_DIR)
48 
49 words = open(config.WORD_LIST).read().split('\n')
50 nouns = open(config.NOUNS).read().split('\n')
51 adjectives = open(config.ADJECTIVES).read().split('\n')
52 
53 
54 class CryptoException(Exception):
55     pass
56 
57 
58 def clean(s, also=''):
59     """
60     >>> clean("Hello, world!")
61     Traceback (most recent call last):
62       ...
63     CryptoException: invalid input: Hello, world!
64     >>> clean("Helloworld")
65     'Helloworld'
66     """
67     # safe characters for every possible word in the wordlist includes capital
68     # letters because codename hashes are base32-encoded with capital letters
69     ok = (' !#%$&)(+*-1032547698;:=?@acbedgfihkjmlonqpsrutwvyxzABCDEFGHIJ'
70           'KLMNOPQRSTUVWXYZ')
71     for c in s:
72         if c not in ok and c not in also:
73             raise CryptoException("invalid input: {0}".format(s))
74     # scrypt.hash requires input of type str. Since the wordlist is all ASCII
75     # characters, this conversion is not problematic
76     return str(s)
77 
78 
79 def genrandomid(words_in_random_id=DEFAULT_WORDS_IN_RANDOM_ID):
80     return ' '.join(random.choice(words) for x in range(words_in_random_id))
81 
82 
83 def display_id():
84     return ' '.join([random.choice(adjectives), random.choice(nouns)])
85 
86 
87 def hash_codename(codename, salt=SCRYPT_ID_PEPPER):
88     """Salts and hashes a codename using scrypt.
89 
90     :param str codename: A source's codename.
91     :param str salt: The salt to mix with the codename when hashing.
92     :returns: A base32 encoded string; the salted codename hash.
93     """
94     return b32encode(scrypt.hash(clean(codename), salt, **SCRYPT_PARAMS))
95 
96 
97 def genkeypair(name, secret):
98     """Generate a GPG key through batch file key generation. A source's
99     codename is salted with SCRYPT_GPG_PEPPER and hashed with scrypt to
100     provide the passphrase used to encrypt their private key. Their name
101     should be their filesystem id.
102 
103     >>> if not gpg.list_keys(hash_codename('randomid')):
104     ...     genkeypair(hash_codename('randomid'), 'randomid').type
105     ... else:
106     ...     u'P'
107     u'P'
108 
109     :param str name: The source's filesystem id (their codename, salted
110                      with SCRYPT_ID_PEPPER, and hashed with scrypt).
111     :param str secret: The source's codename.
112     :returns: a :class:`GenKey <gnupg._parser.GenKey>` object, on which
113               the ``__str__()`` method may be called to return the
114               generated key's fingeprint.
115 
116     """
117     name = clean(name)
118     secret = hash_codename(secret, salt=SCRYPT_GPG_PEPPER)
119     return gpg.gen_key(gpg.gen_key_input(
120         key_type=GPG_KEY_TYPE, key_length=GPG_KEY_LENGTH,
121         passphrase=secret,
122         name_email=name
123     ))
124 
125 
126 def delete_reply_keypair(source_filesystem_id):
127     key = getkey(source_filesystem_id)
128     # If this source was never flagged for review, they won't have a reply
129     # keypair
130     if not key:
131         return
132     # The private key needs to be deleted before the public key can be deleted
133     # http://pythonhosted.org/python-gnupg/#deleting-keys
134     gpg.delete_keys(key, True)  # private key
135     gpg.delete_keys(key)  # public key
136     # TODO: srm?
137 
138 
139 def getkey(name):
140     for key in gpg.list_keys():
141         for uid in key['uids']:
142             if name in uid:
143                 return key['fingerprint']
144     return None
145 
146 
147 def encrypt(plaintext, fingerprints, output=None):
148     # Verify the output path
149     if output:
150         store.verify(output)
151 
152     if not isinstance(fingerprints, (list, tuple)):
153         fingerprints = [fingerprints, ]
154     # Remove any spaces from provided fingerprints GPG outputs fingerprints
155     # with spaces for readability, but requires the spaces to be removed when
156     # using fingerprints to specify recipients.
157     fingerprints = [fpr.replace(' ', '') for fpr in fingerprints]
158 
159     if not _is_stream(plaintext):
160         plaintext = _make_binary_stream(plaintext, "utf_8")
161 
162     out = gpg.encrypt(plaintext,
163                       *fingerprints,
164                       output=output,
165                       always_trust=True,
166                       armor=False)
167     if out.ok:
168         return out.data
169     else:
170         raise CryptoException(out.stderr)
171 
172 
173 def decrypt(secret, ciphertext):
174     """
175     >>> key = genkeypair('randomid', 'randomid')
176     >>> decrypt('randomid',
177     ...   encrypt('Goodbye, cruel world!', str(key))
178     ... )
179     'Goodbye, cruel world!'
180     """
181     hashed_codename = hash_codename(secret, salt=SCRYPT_GPG_PEPPER)
182     return gpg.decrypt(ciphertext, passphrase=hashed_codename).data
183 
184 if __name__ == "__main__":  # pragma: no cover
185     import doctest
186     doctest.testmod()
187
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/securedrop/crypto_util.py b/securedrop/crypto_util.py
--- a/securedrop/crypto_util.py
+++ b/securedrop/crypto_util.py
@@ -46,9 +46,9 @@
 
 gpg = gnupg.GPG(binary='gpg2', homedir=config.GPG_KEY_DIR)
 
-words = open(config.WORD_LIST).read().split('\n')
-nouns = open(config.NOUNS).read().split('\n')
-adjectives = open(config.ADJECTIVES).read().split('\n')
+words = open(config.WORD_LIST).read().rstrip('\n').split('\n')
+nouns = open(config.NOUNS).read().rstrip('\n').split('\n')
+adjectives = open(config.ADJECTIVES).read().rstrip('\n').split('\n')
 
 
 class CryptoException(Exception):

{"golden_diff": "diff --git a/securedrop/crypto_util.py b/securedrop/crypto_util.py\n--- a/securedrop/crypto_util.py\n+++ b/securedrop/crypto_util.py\n@@ -46,9 +46,9 @@\n \n gpg = gnupg.GPG(binary='gpg2', homedir=config.GPG_KEY_DIR)\n \n-words = open(config.WORD_LIST).read().split('\\n')\n-nouns = open(config.NOUNS).read().split('\\n')\n-adjectives = open(config.ADJECTIVES).read().split('\\n')\n+words = open(config.WORD_LIST).read().rstrip('\\n').split('\\n')\n+nouns = open(config.NOUNS).read().rstrip('\\n').split('\\n')\n+adjectives = open(config.ADJECTIVES).read().rstrip('\\n').split('\\n')\n \n \n class CryptoException(Exception):\n", "issue": "Wordlists are not being parsed correctly\n# Bug\r\n\r\n## Description\r\n\r\n`crypo_util.{words,nouns,adjectives}` all contain an empty string as their last element.\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nfrom base64 import b32encode\nimport os\nimport subprocess\n\nfrom Crypto.Random import random\nimport gnupg\nfrom gnupg._util import _is_stream, _make_binary_stream\nimport scrypt\n\nimport config\nimport store\n\n# to fix gpg error #78 on production\nos.environ['USERNAME'] = 'www-data'\n\nGPG_KEY_TYPE = \"RSA\"\nif os.environ.get('SECUREDROP_ENV') == 'test':\n    # Optimize crypto to speed up tests (at the expense of security - DO NOT\n    # use these settings in production)\n    GPG_KEY_LENGTH = 1024\n    SCRYPT_PARAMS = dict(N=2**1, r=1, p=1)\nelse:  # pragma: no cover\n    GPG_KEY_LENGTH = 4096\n    SCRYPT_PARAMS = config.SCRYPT_PARAMS\n\nSCRYPT_ID_PEPPER = config.SCRYPT_ID_PEPPER\nSCRYPT_GPG_PEPPER = config.SCRYPT_GPG_PEPPER\n\nDEFAULT_WORDS_IN_RANDOM_ID = 8\n\n\n# Make sure these pass before the app can run\n# TODO: Add more tests\ndef do_runtime_tests():\n    assert(config.SCRYPT_ID_PEPPER != config.SCRYPT_GPG_PEPPER)\n    # crash if we don't have srm:\n    try:\n        subprocess.check_call(['srm'], stdout=subprocess.PIPE)\n    except subprocess.CalledProcessError:\n        pass\n\ndo_runtime_tests()\n\ngpg = gnupg.GPG(binary='gpg2', homedir=config.GPG_KEY_DIR)\n\nwords = open(config.WORD_LIST).read().split('\\n')\nnouns = open(config.NOUNS).read().split('\\n')\nadjectives = open(config.ADJECTIVES).read().split('\\n')\n\n\nclass CryptoException(Exception):\n    pass\n\n\ndef clean(s, also=''):\n    \"\"\"\n    >>> clean(\"Hello, world!\")\n    Traceback (most recent call last):\n      ...\n    CryptoException: invalid input: Hello, world!\n    >>> clean(\"Helloworld\")\n    'Helloworld'\n    \"\"\"\n    # safe characters for every possible word in the wordlist includes capital\n    # letters because codename hashes are base32-encoded with capital letters\n    ok = (' !#%$&)(+*-1032547698;:=?@acbedgfihkjmlonqpsrutwvyxzABCDEFGHIJ'\n          'KLMNOPQRSTUVWXYZ')\n    for c in s:\n        if c not in ok and c not in also:\n            raise CryptoException(\"invalid input: {0}\".format(s))\n    # scrypt.hash requires input of type str. Since the wordlist is all ASCII\n    # characters, this conversion is not problematic\n    return str(s)\n\n\ndef genrandomid(words_in_random_id=DEFAULT_WORDS_IN_RANDOM_ID):\n    return ' '.join(random.choice(words) for x in range(words_in_random_id))\n\n\ndef display_id():\n    return ' '.join([random.choice(adjectives), random.choice(nouns)])\n\n\ndef hash_codename(codename, salt=SCRYPT_ID_PEPPER):\n    \"\"\"Salts and hashes a codename using scrypt.\n\n    :param str codename: A source's codename.\n    :param str salt: The salt to mix with the codename when hashing.\n    :returns: A base32 encoded string; the salted codename hash.\n    \"\"\"\n    return b32encode(scrypt.hash(clean(codename), salt, **SCRYPT_PARAMS))\n\n\ndef genkeypair(name, secret):\n    \"\"\"Generate a GPG key through batch file key generation. A source's\n    codename is salted with SCRYPT_GPG_PEPPER and hashed with scrypt to\n    provide the passphrase used to encrypt their private key. Their name\n    should be their filesystem id.\n\n    >>> if not gpg.list_keys(hash_codename('randomid')):\n    ...     genkeypair(hash_codename('randomid'), 'randomid').type\n    ... else:\n    ...     u'P'\n    u'P'\n\n    :param str name: The source's filesystem id (their codename, salted\n                     with SCRYPT_ID_PEPPER, and hashed with scrypt).\n    :param str secret: The source's codename.\n    :returns: a :class:`GenKey <gnupg._parser.GenKey>` object, on which\n              the ``__str__()`` method may be called to return the\n              generated key's fingeprint.\n\n    \"\"\"\n    name = clean(name)\n    secret = hash_codename(secret, salt=SCRYPT_GPG_PEPPER)\n    return gpg.gen_key(gpg.gen_key_input(\n        key_type=GPG_KEY_TYPE, key_length=GPG_KEY_LENGTH,\n        passphrase=secret,\n        name_email=name\n    ))\n\n\ndef delete_reply_keypair(source_filesystem_id):\n    key = getkey(source_filesystem_id)\n    # If this source was never flagged for review, they won't have a reply\n    # keypair\n    if not key:\n        return\n    # The private key needs to be deleted before the public key can be deleted\n    # http://pythonhosted.org/python-gnupg/#deleting-keys\n    gpg.delete_keys(key, True)  # private key\n    gpg.delete_keys(key)  # public key\n    # TODO: srm?\n\n\ndef getkey(name):\n    for key in gpg.list_keys():\n        for uid in key['uids']:\n            if name in uid:\n                return key['fingerprint']\n    return None\n\n\ndef encrypt(plaintext, fingerprints, output=None):\n    # Verify the output path\n    if output:\n        store.verify(output)\n\n    if not isinstance(fingerprints, (list, tuple)):\n        fingerprints = [fingerprints, ]\n    # Remove any spaces from provided fingerprints GPG outputs fingerprints\n    # with spaces for readability, but requires the spaces to be removed when\n    # using fingerprints to specify recipients.\n    fingerprints = [fpr.replace(' ', '') for fpr in fingerprints]\n\n    if not _is_stream(plaintext):\n        plaintext = _make_binary_stream(plaintext, \"utf_8\")\n\n    out = gpg.encrypt(plaintext,\n                      *fingerprints,\n                      output=output,\n                      always_trust=True,\n                      armor=False)\n    if out.ok:\n        return out.data\n    else:\n        raise CryptoException(out.stderr)\n\n\ndef decrypt(secret, ciphertext):\n    \"\"\"\n    >>> key = genkeypair('randomid', 'randomid')\n    >>> decrypt('randomid',\n    ...   encrypt('Goodbye, cruel world!', str(key))\n    ... )\n    'Goodbye, cruel world!'\n    \"\"\"\n    hashed_codename = hash_codename(secret, salt=SCRYPT_GPG_PEPPER)\n    return gpg.decrypt(ciphertext, passphrase=hashed_codename).data\n\nif __name__ == \"__main__\":  # pragma: no cover\n    import doctest\n    doctest.testmod()\n", "path": "securedrop/crypto_util.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nfrom base64 import b32encode\nimport os\nimport subprocess\n\nfrom Crypto.Random import random\nimport gnupg\nfrom gnupg._util import _is_stream, _make_binary_stream\nimport scrypt\n\nimport config\nimport store\n\n# to fix gpg error #78 on production\nos.environ['USERNAME'] = 'www-data'\n\nGPG_KEY_TYPE = \"RSA\"\nif os.environ.get('SECUREDROP_ENV') == 'test':\n    # Optimize crypto to speed up tests (at the expense of security - DO NOT\n    # use these settings in production)\n    GPG_KEY_LENGTH = 1024\n    SCRYPT_PARAMS = dict(N=2**1, r=1, p=1)\nelse:  # pragma: no cover\n    GPG_KEY_LENGTH = 4096\n    SCRYPT_PARAMS = config.SCRYPT_PARAMS\n\nSCRYPT_ID_PEPPER = config.SCRYPT_ID_PEPPER\nSCRYPT_GPG_PEPPER = config.SCRYPT_GPG_PEPPER\n\nDEFAULT_WORDS_IN_RANDOM_ID = 8\n\n\n# Make sure these pass before the app can run\n# TODO: Add more tests\ndef do_runtime_tests():\n    assert(config.SCRYPT_ID_PEPPER != config.SCRYPT_GPG_PEPPER)\n    # crash if we don't have srm:\n    try:\n        subprocess.check_call(['srm'], stdout=subprocess.PIPE)\n    except subprocess.CalledProcessError:\n        pass\n\ndo_runtime_tests()\n\ngpg = gnupg.GPG(binary='gpg2', homedir=config.GPG_KEY_DIR)\n\nwords = open(config.WORD_LIST).read().rstrip('\\n').split('\\n')\nnouns = open(config.NOUNS).read().rstrip('\\n').split('\\n')\nadjectives = open(config.ADJECTIVES).read().rstrip('\\n').split('\\n')\n\n\nclass CryptoException(Exception):\n    pass\n\n\ndef clean(s, also=''):\n    \"\"\"\n    >>> clean(\"Hello, world!\")\n    Traceback (most recent call last):\n      ...\n    CryptoException: invalid input: Hello, world!\n    >>> clean(\"Helloworld\")\n    'Helloworld'\n    \"\"\"\n    # safe characters for every possible word in the wordlist includes capital\n    # letters because codename hashes are base32-encoded with capital letters\n    ok = (' !#%$&)(+*-1032547698;:=?@acbedgfihkjmlonqpsrutwvyxzABCDEFGHIJ'\n          'KLMNOPQRSTUVWXYZ')\n    for c in s:\n        if c not in ok and c not in also:\n            raise CryptoException(\"invalid input: {0}\".format(s))\n    # scrypt.hash requires input of type str. Since the wordlist is all ASCII\n    # characters, this conversion is not problematic\n    return str(s)\n\n\ndef genrandomid(words_in_random_id=DEFAULT_WORDS_IN_RANDOM_ID):\n    return ' '.join(random.choice(words) for x in range(words_in_random_id))\n\n\ndef display_id():\n    return ' '.join([random.choice(adjectives), random.choice(nouns)])\n\n\ndef hash_codename(codename, salt=SCRYPT_ID_PEPPER):\n    \"\"\"Salts and hashes a codename using scrypt.\n\n    :param str codename: A source's codename.\n    :param str salt: The salt to mix with the codename when hashing.\n    :returns: A base32 encoded string; the salted codename hash.\n    \"\"\"\n    return b32encode(scrypt.hash(clean(codename), salt, **SCRYPT_PARAMS))\n\n\ndef genkeypair(name, secret):\n    \"\"\"Generate a GPG key through batch file key generation. A source's\n    codename is salted with SCRYPT_GPG_PEPPER and hashed with scrypt to\n    provide the passphrase used to encrypt their private key. Their name\n    should be their filesystem id.\n\n    >>> if not gpg.list_keys(hash_codename('randomid')):\n    ...     genkeypair(hash_codename('randomid'), 'randomid').type\n    ... else:\n    ...     u'P'\n    u'P'\n\n    :param str name: The source's filesystem id (their codename, salted\n                     with SCRYPT_ID_PEPPER, and hashed with scrypt).\n    :param str secret: The source's codename.\n    :returns: a :class:`GenKey <gnupg._parser.GenKey>` object, on which\n              the ``__str__()`` method may be called to return the\n              generated key's fingeprint.\n\n    \"\"\"\n    name = clean(name)\n    secret = hash_codename(secret, salt=SCRYPT_GPG_PEPPER)\n    return gpg.gen_key(gpg.gen_key_input(\n        key_type=GPG_KEY_TYPE, key_length=GPG_KEY_LENGTH,\n        passphrase=secret,\n        name_email=name\n    ))\n\n\ndef delete_reply_keypair(source_filesystem_id):\n    key = getkey(source_filesystem_id)\n    # If this source was never flagged for review, they won't have a reply\n    # keypair\n    if not key:\n        return\n    # The private key needs to be deleted before the public key can be deleted\n    # http://pythonhosted.org/python-gnupg/#deleting-keys\n    gpg.delete_keys(key, True)  # private key\n    gpg.delete_keys(key)  # public key\n    # TODO: srm?\n\n\ndef getkey(name):\n    for key in gpg.list_keys():\n        for uid in key['uids']:\n            if name in uid:\n                return key['fingerprint']\n    return None\n\n\ndef encrypt(plaintext, fingerprints, output=None):\n    # Verify the output path\n    if output:\n        store.verify(output)\n\n    if not isinstance(fingerprints, (list, tuple)):\n        fingerprints = [fingerprints, ]\n    # Remove any spaces from provided fingerprints GPG outputs fingerprints\n    # with spaces for readability, but requires the spaces to be removed when\n    # using fingerprints to specify recipients.\n    fingerprints = [fpr.replace(' ', '') for fpr in fingerprints]\n\n    if not _is_stream(plaintext):\n        plaintext = _make_binary_stream(plaintext, \"utf_8\")\n\n    out = gpg.encrypt(plaintext,\n                      *fingerprints,\n                      output=output,\n                      always_trust=True,\n                      armor=False)\n    if out.ok:\n        return out.data\n    else:\n        raise CryptoException(out.stderr)\n\n\ndef decrypt(secret, ciphertext):\n    \"\"\"\n    >>> key = genkeypair('randomid', 'randomid')\n    >>> decrypt('randomid',\n    ...   encrypt('Goodbye, cruel world!', str(key))\n    ... )\n    'Goodbye, cruel world!'\n    \"\"\"\n    hashed_codename = hash_codename(secret, salt=SCRYPT_GPG_PEPPER)\n    return gpg.decrypt(ciphertext, passphrase=hashed_codename).data\n\nif __name__ == \"__main__\":  # pragma: no cover\n    import doctest\n    doctest.testmod()\n", "path": "securedrop/crypto_util.py"}]}