Skip to content

Commit

Permalink
tiny step towards future port to Py3.4
Browse files Browse the repository at this point in the history
  • Loading branch information
8go committed May 21, 2017
1 parent 14ac368 commit 11305d2
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 49 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Below a sample screenshot. More screenshots [here](screenshots).
# Build and runtime requirements

* Use of passphrases must have been already enabled on your [Trezor](https://www.trezor.io) device.
* [Python](https://www.python.org/)
* [Python](https://www.python.org/) v2.7
* PyCrypto
* PyQt4
* [trezorlib from python-trezor](https://github.com/trezor/python-trezor)
Expand All @@ -73,7 +73,7 @@ Run-time command line options are

```
TrezorSymmetricFileEncryption.py [-v] [-h] [-l <level>] [-t] [-e | -o | -d | -m | -n] [-2] [-s] [-w] [-p <passphrase>] [-r] [-R] <files>
-v, --verion
-v, --version
print the version number
-h, --help
print short help text
Expand Down Expand Up @@ -266,7 +266,7 @@ single-file-executablefile.
- - -
**Question:** In which language is TrezorSymmetricFileEncryption written?

**Answer:** [Python](https://www.python.org/).
**Answer:** [Python](https://www.python.org/) 2.7. It wil currently not run on Python 3.
- - -
**Question:** Do I need to have a [Trezor](https://www.trezor.io/) in
order to use TrezorSymmetricFileEncryption?
Expand Down
22 changes: 13 additions & 9 deletions TrezorSymmetricFileEncryption.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
'''

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import sys
import logging
import getpass
Expand Down Expand Up @@ -46,17 +50,17 @@ def callback_ButtonRequest(self, msg):

def callback_PassphraseRequest(self, msg):
if self.passphrase is not None:
return proto.PassphraseAck(passphrase=unicode(self.passphrase))
return proto.PassphraseAck(passphrase=str(self.passphrase))

if self.readpassphrasefromstdin:
# read passphrase from stdin
try:
passphrase = getpass.getpass("Please enter passphrase: ")
passphrase = unicode(passphrase)
passphrase = str(passphrase)
except KeyboardInterrupt:
sys.stderr.write("\nKeyboard interrupt: passphrase not read. Aborting.\n")
sys.exit(3)
except Exception, e:
except Exception as e:
sys.stderr.write("Critical error: Passphrase not read. Aborting. (%s)" % e)
sys.exit(3)
else:
Expand All @@ -65,22 +69,22 @@ def callback_PassphraseRequest(self, msg):
sys.exit(3)
else:
passphrase = dialog.passphraseEdit.text()
passphrase = unicode(passphrase)
passphrase = str(passphrase)

return proto.PassphraseAck(passphrase=passphrase)

def callback_PinMatrixRequest(self, msg):
if self.readpinfromstdin:
# read PIN from stdin
print " 7 8 9"
print " 4 5 6"
print " 1 2 3"
print(" 7 8 9")
print(" 4 5 6")
print(" 1 2 3")
try:
pin = getpass.getpass("Please enter PIN: ")
except KeyboardInterrupt:
sys.stderr.write("\nKeyboard interrupt: PIN not read. Aborting.\n")
sys.exit(7)
except Exception, e:
except Exception as e:
sys.stderr.write("Critical error: PIN not read. Aborting. (%s)" % e)
sys.exit(7)
else:
Expand Down Expand Up @@ -234,7 +238,7 @@ def showGui(trezor, settings, fileMap, logger):
try:
trezorChooser = TrezorChooser()
trezor = trezorChooser.getDevice()
except (ConnectionError, RuntimeError), e:
except (ConnectionError, RuntimeError) as e:
processing.reportLogging("Connection to Trezor failed: %s" % e.message,
logging.CRITICAL, "Trezor Error", settings, logger)
sys.exit(1)
Expand Down
6 changes: 5 additions & 1 deletion basics.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import logging

# file extension for encrypted files with plaintext filename
Expand All @@ -7,7 +11,7 @@
TSFEFILEFORMATVERSION = 1

# Name of software version, must be less than 16 long
TSFEVERSION = "v0.4.3"
TSFEVERSION = "v0.5.0"

# Date of software version, only used in GUI
TSFEVERSIONTEXT = "May 2017"
Expand Down
32 changes: 32 additions & 0 deletions comments.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,35 @@ The Trezor chip is slow. It takes the Trezor (model 1) device about 75 seconds
- [x] make the image smaller on main window
- [x] more Testing
- [ ] get help with getting the word out, anyone wants to spread the word on Twitter, Reddit, with Trezor, Facebook, etc.?

# Migrating to Python3

Doing only Python 2.7 or only 3.4 is okay, but making both work on the same code base is cumbersome.
The combination would be Py2.7 | Py3.4 + PyQt4.11.

* Basic description of the problem is [here](https://docs.python.org/3/howto/pyporting.html) with some pointers as how to start.
* [2to3](https://docs.python.org/3/library/2to3.html) has been done. It was trivial. Only a few lines of code changed.
* [modernize](https://python-modernize.readthedocs.io/en/latest/) has been done. Again, it was just suggesting a few new lines related to the `range` operator.
* [futurize](http://python-future.org/automatic_conversion.html) was also done. It suggested only a few `import` lines. The 3 lines were added to all .py files.
```
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
```
* Changes related to GUI are:
PyQt4.11 for Py3.4 does not have class QString. It expects unicode objects. Simple hacks like
the folowing are not likely to work.
```
try:
from PyQt4.QtCore import QString
except ImportError:
# we are using Python3 so QString is not defined
QString = type("")
```
* Since Py2.7 does not have bytes and handles everything as strings. A common layer would have to be introduced
that simulates bytes on Py2.7. Some good code starting points can be found at
[python3porting.com](http://python3porting.com/problems.html#bytes-strings-and-unicode).
* In Debian 9 Py2 will remain the default Py version, so Py2.7 does not seem to be going away.

In short, for the time being it does not seem worth it to add code to make it run on both 2.7 and 3.4.
It seems one can wait until 2.7 becomes outdated and then port to 3.5, breaking and leaving 2.7 behind.
4 changes: 4 additions & 0 deletions dialogs.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
import os.path
import logging
Expand Down
21 changes: 12 additions & 9 deletions encoding.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import struct

from PyQt4 import QtCore
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
import os.path
import random
import struct

from PyQt4 import QtCore


def q2s(s):
def q2s(q):
"""Convert QString to UTF-8 string object"""
return str(s.toUtf8())
return str(q.toUtf8())


def s2q(s):
Expand All @@ -33,21 +36,21 @@ class Magic(object):
for keys.
"""

headerStr = "TSFE"
headerStr = b'TSFE'
hdr = u("!I", headerStr)

# first level encryption
# unlock key for first level AES encryption, key from Trezor, en/decryption on PC
levelOneNode = [hdr, u("!I", "DEC1")]
levelOneNode = [hdr, u("!I", b'DEC1')]
levelOneKey = "Decrypt file for first time?" # string to derive wrapping key from

# second level encryption
# second level AES encryption, de/encryption on trezor device
levelTwoNode = [hdr, u("!I", "DEC2")]
levelTwoNode = [hdr, u("!I", b'DEC2')]
levelTwoKey = "Decrypt file for second time?"

# only used for filename encryption (no confirm button click desired)
fileNameNode = [hdr, u("!I", "FLNM")] # filename encryption for filename obfuscation
fileNameNode = [hdr, u("!I", b'FLNM')] # filename encryption for filename obfuscation
fileNameKey = "Decrypt filename only?"


Expand Down
24 changes: 14 additions & 10 deletions file_map.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
import os.path
import sys
Expand Down Expand Up @@ -80,7 +84,7 @@ def createDecFile(self, fname):
"Change file permissions and try again." % (fname))

self.loadBlobFromEncFile(originalFilename)
with open(fname, 'w+b') as f:
with open(fname, "wb") as f:
s = len(self.blob)
f.write(self.blob)
if f.tell() != s:
Expand Down Expand Up @@ -118,7 +122,7 @@ def loadBlobFromEncFile(self, fname):
@throws IOError: if reading file failed
"""
with open(fname, 'rb') as f:
with open(fname, "rb") as f:
header = f.read(len(Magic.headerStr))
if header != Magic.headerStr:
raise IOError("Bad header in storage file")
Expand Down Expand Up @@ -202,7 +206,7 @@ def createEncFile(self, fname, obfuscate, twice, outerKey=None, outerIv=None, in
@param innerIv: see outerKey
"""

with open(fname, 'rb') as f:
with open(fname, "rb") as f:
# Size 0 will read the ENTIRE file into memory!
# File is open read-only
# mmap does not implement __exit__ so we cannot use "with mmap... as m:"
Expand Down Expand Up @@ -427,15 +431,15 @@ def encryptOnTrezorDevice(self, blob, keystring, innerIv=None):
try:
encrypted += self.trezor.encrypt_keyvalue(Magic.levelTwoNode,
ukeystring, padded, ask_on_encrypt=False, ask_on_decrypt=first, iv=rndBlock)
except Exception, e:
except Exception as e:
self.logger.critical('Trezor failed. (%s)', e)
raise
first = False
curr += 1
if self.logger.getEffectiveLevel() == logging.DEBUG:
print >> sys.stderr, "\rencrypting block", curr, "of", max,
sys.stderr.write("\rencrypting block %d of %d" % (curr, max),)
if self.logger.getEffectiveLevel() == logging.DEBUG:
print >> sys.stderr, "done"
sys.stderr.write(" --> done\n")
ret = rndBlock + encrypted
self.logger.debug("Trezor encryption: plain-size = %d, encrypted-size = %d", len(blob), len(ret))
self.logger.debug('time leaving encryptOnTrezorDevice: %s', datetime.datetime.now())
Expand All @@ -453,7 +457,7 @@ def decryptOnTrezorDevice(self, encryptedblob, keystring):
"Decrypting each Megabyte on the Trezor (model 1) takes about 75 seconds, "
"or 0.8MB/min. This file will take about %d minutes. If you want to "
"en/decrypt fast the next time around, remove the `-2` or `--twice` "
"option when you encrypt a file.", len(encryptedblob) / 819200)
"option when you encrypt a file.", len(encryptedblob) // 819200)
self.logger.debug('time entering decryptOnTrezorDevice: %s', datetime.datetime.now())
ukeystring = keystring.decode("utf-8")
iv, encryptedblob = encryptedblob[:BLOCKSIZE], encryptedblob[BLOCKSIZE:]
Expand All @@ -469,16 +473,16 @@ def decryptOnTrezorDevice(self, encryptedblob, keystring):
try:
plain = self.trezor.decrypt_keyvalue(Magic.levelTwoNode,
ukeystring, junk, ask_on_encrypt=False, ask_on_decrypt=first, iv=iv)
except Exception, e:
except Exception as e:
self.logger.critical('Trezor failed. (%s)', e)
raise
first = False
blob += Padding(BLOCKSIZE).unpad(plain)
curr += 1
if self.logger.getEffectiveLevel() == logging.DEBUG:
print >> sys.stderr, "\rdecrypting block", curr, "of", max,
sys.stderr.write("\rdecrypting block %d of %d" % (curr, max),)
if self.logger.getEffectiveLevel() == logging.DEBUG:
print >> sys.stderr, "done"
sys.stderr.write(" --> done\n")
self.logger.debug("Trezor decryption: encrypted-size = %d, plain-size = %d",
len(encryptedblob), len(blob))
if len(blob) == 0:
Expand Down
Loading

0 comments on commit 11305d2

Please sign in to comment.