]>
gitweb.pimeys.fr Git - NK2015_Client_Python_Alpha.git/blob - rsa_source/rsa/cli.py
1 # -*- coding: utf-8 -*-
3 # Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 '''Commandline scripts.
19 These scripts are called by the executables defined in setup.py.
24 from optparse
import OptionParser
30 HASH_METHODS
= sorted(rsa
.pkcs1
.HASH_METHODS
.keys())
35 # Parse the CLI options
36 parser
= OptionParser(usage
='usage: %prog [options] keysize',
37 description
='Generates a new RSA keypair of "keysize" bits.')
39 parser
.add_option('--pubout', type='string',
40 help='Output filename for the public key. The public key is '
41 'not saved if this option is not present. You can use '
42 'pyrsa-priv2pub to create the public key file later.')
44 parser
.add_option('-o', '--out', type='string',
45 help='Output filename for the private key. The key is '
46 'written to stdout if this option is not present.')
48 parser
.add_option('--form',
49 help='key format of the private and public keys - default PEM',
50 choices
=('PEM', 'DER'), default
='PEM')
52 (cli
, cli_args
) = parser
.parse_args(sys
.argv
[1:])
54 if len(cli_args
) != 1:
59 keysize
= int(cli_args
[0])
62 print >>sys
.stderr
, 'Not a valid number: %s' % cli_args
[0]
65 print >>sys
.stderr
, 'Generating %i-bit key' % keysize
66 (pub_key
, priv_key
) = rsa
.newkeys(keysize
)
71 print >>sys
.stderr
, 'Writing public key to %s' % cli
.pubout
72 data
= pub_key
.save_pkcs1(format
=cli
.form
)
73 with
open(cli
.pubout
, 'w') as outfile
:
77 data
= priv_key
.save_pkcs1(format
=cli
.form
)
80 print >>sys
.stderr
, 'Writing private key to %s' % cli
.out
81 with
open(cli
.out
, 'w') as outfile
:
84 print >>sys
.stderr
, 'Writing private key to stdout'
85 sys
.stdout
.write(data
)
88 class CryptoOperation(object):
89 '''CLI callable that operates with input, output, and a key.'''
91 __metaclass__
= abc
.ABCMeta
93 keyname
= 'public' # or 'private'
94 usage
= 'usage: %%prog [options] %(keyname)s_key'
97 operation_past
= 'decrypted'
98 operation_progressive
= 'decrypting'
99 input_help
= 'Name of the file to %(operation)s. Reads from stdin if ' \
101 output_help
= 'Name of the file to write the %(operation_past)s file ' \
102 'to. Written to stdout if this option is not present.'
103 expected_cli_args
= 1
106 key_class
= rsa
.PublicKey
109 self
.usage
= self
.usage
% self
.__class
__.__dict
__
110 self
.input_help
= self
.input_help
% self
.__class
__.__dict
__
111 self
.output_help
= self
.output_help
% self
.__class
__.__dict
__
114 def perform_operation(self
, indata
, key
, cli_args
=None):
115 '''Performs the program's operation.
117 Implement in a subclass.
119 :returns: the data to write to the output.
123 '''Runs the program.'''
125 (cli
, cli_args
) = self
.parse_cli()
127 key
= self
.read_key(cli_args
[0], cli
.keyform
)
129 indata
= self
.read_infile(cli
.input)
131 print >>sys
.stderr
, self
.operation_progressive
.title()
132 outdata
= self
.perform_operation(indata
, key
, cli_args
)
135 self
.write_outfile(outdata
, cli
.output
)
138 '''Parse the CLI options
140 :returns: (cli_opts, cli_args)
143 parser
= OptionParser(usage
=self
.usage
, description
=self
.description
)
145 parser
.add_option('-i', '--input', type='string', help=self
.input_help
)
148 parser
.add_option('-o', '--output', type='string', help=self
.output_help
)
150 parser
.add_option('--keyform',
151 help='Key format of the %s key - default PEM' % self
.keyname
,
152 choices
=('PEM', 'DER'), default
='PEM')
154 (cli
, cli_args
) = parser
.parse_args(sys
.argv
[1:])
156 if len(cli_args
) != self
.expected_cli_args
:
160 return (cli
, cli_args
)
162 def read_key(self
, filename
, keyform
):
163 '''Reads a public or private key.'''
165 print >>sys
.stderr
, 'Reading %s key from %s' % (self
.keyname
, filename
)
166 with
open(filename
) as keyfile
:
167 keydata
= keyfile
.read()
169 return self
.key_class
.load_pkcs1(keydata
, keyform
)
171 def read_infile(self
, inname
):
172 '''Read the input file'''
175 print >>sys
.stderr
, 'Reading input from %s' % inname
176 with
open(inname
, 'rb') as infile
:
179 print >>sys
.stderr
, 'Reading input from stdin'
180 return sys
.stdin
.read()
182 def write_outfile(self
, outdata
, outname
):
183 '''Write the output file'''
186 print >>sys
.stderr
, 'Writing output to %s' % outname
187 with
open(outname
, 'wb') as outfile
:
188 outfile
.write(outdata
)
190 print >>sys
.stderr
, 'Writing output to stdout'
191 sys
.stdout
.write(outdata
)
193 class EncryptOperation(CryptoOperation
):
194 '''Encrypts a file.'''
197 description
= ('Encrypts a file. The file must be shorter than the key '
198 'length in order to be encrypted. For larger files, use the '
199 'pyrsa-encrypt-bigfile command.')
200 operation
= 'encrypt'
201 operation_past
= 'encrypted'
202 operation_progressive
= 'encrypting'
205 def perform_operation(self
, indata
, pub_key
, cli_args
=None):
206 '''Encrypts files.'''
208 return rsa
.encrypt(indata
, pub_key
)
210 class DecryptOperation(CryptoOperation
):
211 '''Decrypts a file.'''
214 description
= ('Decrypts a file. The original file must be shorter than '
215 'the key length in order to have been encrypted. For larger '
216 'files, use the pyrsa-decrypt-bigfile command.')
217 operation
= 'decrypt'
218 operation_past
= 'decrypted'
219 operation_progressive
= 'decrypting'
220 key_class
= rsa
.PrivateKey
222 def perform_operation(self
, indata
, priv_key
, cli_args
=None):
223 '''Decrypts files.'''
225 return rsa
.decrypt(indata
, priv_key
)
227 class SignOperation(CryptoOperation
):
231 usage
= 'usage: %%prog [options] private_key hash_method'
232 description
= ('Signs a file, outputs the signature. Choose the hash '
233 'method from %s' % ', '.join(HASH_METHODS
))
235 operation_past
= 'signature'
236 operation_progressive
= 'Signing'
237 key_class
= rsa
.PrivateKey
238 expected_cli_args
= 2
240 output_help
= ('Name of the file to write the signature to. Written '
241 'to stdout if this option is not present.')
243 def perform_operation(self
, indata
, priv_key
, cli_args
):
244 '''Decrypts files.'''
246 hash_method
= cli_args
[1]
247 if hash_method
not in HASH_METHODS
:
248 raise SystemExit('Invalid hash method, choose one of %s' %
249 ', '.join(HASH_METHODS
))
251 return rsa
.sign(indata
, priv_key
, hash_method
)
253 class VerifyOperation(CryptoOperation
):
254 '''Verify a signature.'''
257 usage
= 'usage: %%prog [options] private_key signature_file'
258 description
= ('Verifies a signature, exits with status 0 upon success, '
259 'prints an error message and exits with status 1 upon error.')
261 operation_past
= 'verified'
262 operation_progressive
= 'Verifying'
263 key_class
= rsa
.PublicKey
264 expected_cli_args
= 2
267 def perform_operation(self
, indata
, pub_key
, cli_args
):
268 '''Decrypts files.'''
270 signature_file
= cli_args
[1]
272 with
open(signature_file
, 'rb') as sigfile
:
273 signature
= sigfile
.read()
276 rsa
.verify(indata
, signature
, pub_key
)
277 except rsa
.VerificationError
:
278 raise SystemExit('Verification failed.')
280 print >>sys
.stderr
, 'Verification OK'
283 class BigfileOperation(CryptoOperation
):
284 '''CryptoOperation that doesn't read the entire file into memory.'''
287 CryptoOperation
.__init
__(self
)
289 self
.file_objects
= []
292 '''Closes any open file handles.'''
294 for fobj
in self
.file_objects
:
298 '''Runs the program.'''
300 (cli
, cli_args
) = self
.parse_cli()
302 key
= self
.read_key(cli_args
[0], cli
.keyform
)
304 # Get the file handles
305 infile
= self
.get_infile(cli
.input)
306 outfile
= self
.get_outfile(cli
.output
)
309 print >>sys
.stderr
, self
.operation_progressive
.title()
310 self
.perform_operation(infile
, outfile
, key
, cli_args
)
312 def get_infile(self
, inname
):
313 '''Returns the input file object'''
316 print >>sys
.stderr
, 'Reading input from %s' % inname
317 fobj
= open(inname
, 'rb')
318 self
.file_objects
.append(fobj
)
320 print >>sys
.stderr
, 'Reading input from stdin'
325 def get_outfile(self
, outname
):
326 '''Returns the output file object'''
329 print >>sys
.stderr
, 'Will write output to %s' % outname
330 fobj
= open(outname
, 'wb')
331 self
.file_objects
.append(fobj
)
333 print >>sys
.stderr
, 'Will write output to stdout'
338 class EncryptBigfileOperation(BigfileOperation
):
339 '''Encrypts a file to VARBLOCK format.'''
342 description
= ('Encrypts a file to an encrypted VARBLOCK file. The file '
343 'can be larger than the key length, but the output file is only '
344 'compatible with Python-RSA.')
345 operation
= 'encrypt'
346 operation_past
= 'encrypted'
347 operation_progressive
= 'encrypting'
349 def perform_operation(self
, infile
, outfile
, pub_key
, cli_args
=None):
350 '''Encrypts files to VARBLOCK.'''
352 return rsa
.bigfile
.encrypt_bigfile(infile
, outfile
, pub_key
)
354 class DecryptBigfileOperation(BigfileOperation
):
355 '''Decrypts a file in VARBLOCK format.'''
358 description
= ('Decrypts an encrypted VARBLOCK file that was encrypted '
359 'with pyrsa-encrypt-bigfile')
360 operation
= 'decrypt'
361 operation_past
= 'decrypted'
362 operation_progressive
= 'decrypting'
363 key_class
= rsa
.PrivateKey
365 def perform_operation(self
, infile
, outfile
, priv_key
, cli_args
=None):
366 '''Decrypts a VARBLOCK file.'''
368 return rsa
.bigfile
.decrypt_bigfile(infile
, outfile
, priv_key
)
371 encrypt
= EncryptOperation()
372 decrypt
= DecryptOperation()
373 sign
= SignOperation()
374 verify
= VerifyOperation()
375 encrypt_bigfile
= EncryptBigfileOperation()
376 decrypt_bigfile
= DecryptBigfileOperation()