root/branches/gajim_0.11.1/src/common/GnuPG.py

Revision 7829, 6.3 kB (checked in by asterix, 23 months ago)

merge diff from trunc to 0.11 branch

  • Property svn:eol-style set to LF
Line 
1##      common/GnuPG.py
2##
3## Contributors for this file:
4##      - Yann Le Boulanger <asterix@lagaule.org>
5##      - Nikos Kouremenos <kourem@gmail.com>
6##
7## Copyright (C) 2003-2004 Yann Le Boulanger <asterix@lagaule.org>
8##                         Vincent Hanquez <tab@snarc.org>
9## Copyright (C) 2005 Yann Le Boulanger <asterix@lagaule.org>
10##                    Vincent Hanquez <tab@snarc.org>
11##                    Nikos Kouremenos <kourem@gmail.com>
12##                    Dimitur Kirov <dkirov@gmail.com>
13##                    Travis Shirk <travis@pobox.com>
14##                    Norman Rasmussen <norman@rasmussen.co.za>
15##
16## This program is free software; you can redistribute it and/or modify
17## it under the terms of the GNU General Public License as published
18## by the Free Software Foundation; version 2 only.
19##
20## This program is distributed in the hope that it will be useful,
21## but WITHOUT ANY WARRANTY; without even the implied warranty of
22## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23## GNU General Public License for more details.
24##
25
26import os
27from os import tmpfile
28from common import helpers
29
30USE_GPG = True
31
32try:
33        import GnuPGInterface # Debian package doesn't distribute 'our' file
34except ImportError:
35        try:
36                from common import GnuPGInterface # use 'our' file
37        except ImportError:
38                USE_GPG = False # user can't do OpenGPG only if he or she removed the file!
39       
40else:
41        status = os.system('gpg -h >/dev/null 2>&1')
42        if status != 0:
43                USE_GPG = False
44
45        class GnuPG(GnuPGInterface.GnuPG):
46                def __init__(self, use_agent = False):
47                        GnuPGInterface.GnuPG.__init__(self)
48                        self.use_agent = use_agent
49                        self._setup_my_options()
50
51                def _setup_my_options(self):
52                        self.options.armor = 1
53                        self.options.meta_interactive = 0
54                        self.options.extra_args.append('--no-secmem-warning')
55                        # Nolith's patch - prevent crashs on non fully-trusted keys
56                        self.options.extra_args.append('--always-trust')
57                        if self.use_agent:
58                                self.options.extra_args.append('--use-agent')
59
60                def _read_response(self, child_stdout):
61                        # Internal method: reads all the output from GPG, taking notice
62                        # only of lines that begin with the magic [GNUPG:] prefix.
63                        # (See doc/DETAILS in the GPG distribution for info on GPG's
64                        # output when --status-fd is specified.)
65                        #
66                        # Returns a dictionary, mapping GPG's keywords to the arguments
67                        # for that keyword.
68
69                        resp = {}
70                        while 1:
71                                line = helpers.temp_failure_retry(child_stdout.readline)
72                                if line == "": break
73                                line = line.rstrip()
74                                if line[0:9] == '[GNUPG:] ':
75                                        # Chop off the prefix
76                                        line = line[9:]
77                                        L = line.split(None, 1)
78                                        keyword = L[0]
79                                        if len(L) > 1:
80                                                resp[ keyword ] = L[1]
81                                        else:
82                                                resp[ keyword ] = ""
83                        return resp
84
85                def encrypt(self, str, recipients):
86                        if not USE_GPG:
87                                return str, 'GnuPG not usable'
88                        self.options.recipients = recipients   # a list!
89
90                        proc = self.run(['--encrypt'], create_fhs=['stdin', 'stdout',
91                                'stderr'])
92                        proc.handles['stdin'].write(str)
93                        proc.handles['stdin'].close()
94
95                        output = proc.handles['stdout'].read()
96                        proc.handles['stdout'].close()
97
98                        error = proc.handles['stderr'].read()
99                        proc.handles['stderr'].close()
100
101                        try: proc.wait()
102                        except IOError: pass
103                        return self._stripHeaderFooter(output), error
104
105                def decrypt(self, str, keyID):
106                        if not USE_GPG:
107                                return str
108                        proc = self.run(['--decrypt', '-q', '-u %s'%keyID], create_fhs=['stdin', 'stdout'])
109                        enc = self._addHeaderFooter(str, 'MESSAGE')
110                        proc.handles['stdin'].write(enc)
111                        proc.handles['stdin'].close()
112       
113                        output = proc.handles['stdout'].read()
114                        proc.handles['stdout'].close()
115
116                        try: proc.wait()
117                        except IOError: pass
118                        return output
119
120                def sign(self, str, keyID):
121                        if not USE_GPG:
122                                return str
123                        proc = self.run(['-b', '-u %s'%keyID], create_fhs=['stdin', 'stdout', 'status', 'stderr'])
124                        proc.handles['stdin'].write(str)
125                        try:
126                                proc.handles['stdin'].close()
127                        except IOError:
128                                pass
129
130                        output = proc.handles['stdout'].read()
131                        try:
132                                proc.handles['stdout'].close()
133                                proc.handles['stderr'].close()
134                        except IOError:
135                                pass
136
137                        stat = proc.handles['status']
138                        resp = self._read_response(stat)
139                        try:
140                                proc.handles['status'].close()
141                        except IOError:
142                                pass
143
144                        try: proc.wait()
145                        except IOError: pass
146                        if resp.has_key('GOOD_PASSPHRASE') or resp.has_key('SIG_CREATED'):
147                                return self._stripHeaderFooter(output)
148                        return 'BAD_PASSPHRASE'
149
150                def verify(self, str, sign):
151                        if not USE_GPG:
152                                return str
153                        if str == None:
154                                return ''
155                        f = tmpfile()
156                        fd = f.fileno()
157                        f.write(str)
158                        f.seek(0)
159
160                        proc = self.run(['--verify', '--enable-special-filenames', '-', '-&%s'%fd], create_fhs=['stdin', 'status', 'stderr'])
161
162                        f.close()
163                        sign = self._addHeaderFooter(sign, 'SIGNATURE')
164                        proc.handles['stdin'].write(sign)
165                        proc.handles['stdin'].close()
166                        proc.handles['stderr'].close()
167
168                        stat = proc.handles['status']
169                        resp = self._read_response(stat)
170                        proc.handles['status'].close()
171
172                        try: proc.wait()
173                        except IOError: pass
174
175                        keyid = ''
176                        if resp.has_key('GOODSIG'):
177                                keyid = resp['GOODSIG'].split()[0]
178                        return keyid
179
180                def get_keys(self, secret = False):
181                        if not USE_GPG:
182                                return {}
183                        if secret:
184                                opt = '--list-secret-keys'
185                        else:
186                                opt = '--list-keys'
187                        proc = self.run(['--with-colons', opt],
188                                create_fhs=['stdout'])
189                        output = proc.handles['stdout'].read()
190                        proc.handles['stdout'].close()
191
192                        keys = {}
193                        lines = output.split('\n')
194                        for line in lines:
195                                sline = line.split(':')
196                                if (sline[0] == 'sec' and secret) or \
197                                                (sline[0] == 'pub' and not secret):
198                                        # make it unicode instance
199                                        keys[sline[4][8:]] = helpers.decode_string(sline[9])
200                        return keys
201                        try: proc.wait()
202                        except IOError: pass
203
204                def get_secret_keys(self):
205                        return self.get_keys(True)
206
207                def _stripHeaderFooter(self, data):
208                        """Remove header and footer from data"""
209                        if not data: return ''
210                        lines = data.split('\n')
211                        while lines[0] != '':
212                                lines.remove(lines[0])
213                        while lines[0] == '':
214                                lines.remove(lines[0])
215                        i = 0
216                        for line in lines:
217                                if line:
218                                        if line[0] == '-': break
219                                i = i+1
220                        line = '\n'.join(lines[0:i])
221                        return line
222
223                def _addHeaderFooter(self, data, type):
224                        """Add header and footer from data"""
225                        out = "-----BEGIN PGP %s-----\n" % type
226                        out = out + "Version: PGP\n"
227                        out = out + "\n"
228                        out = out + data + "\n"
229                        out = out + "-----END PGP %s-----\n" % type
230                        return out
Note: See TracBrowser for help on using the browser.