Browse Source

Added pass support for mouseless password management

tags/v0.1.1
Micah Halter 1 year ago
parent
commit
c83773f5a8
3 changed files with 142 additions and 4 deletions
  1. 1
    0
      README.md
  2. 3
    4
      i3/.config/i3/config
  3. 138
    0
      pass/.enpass2pass.py

+ 1
- 0
README.md View File

@@ -48,6 +48,7 @@ My dotfiles for my Linux rice, managed using stow.
48 48
     - neofetch
49 49
     - offlineimap
50 50
     - oomox
51
+    - pass
51 52
     - pdfpc
52 53
     - py-wal
53 54
     - R

+ 3
- 4
i3/.config/i3/config View File

@@ -362,8 +362,8 @@ bindsym $mod+Shift+Control+bracketleft  exec --no-startup-id light -U 10
362 362
 #bindsym $mod+Shift+bracketright
363 363
 bindsym $mod+Shift+Control+bracketright exec --no-startup-id light -A 10
364 364
 
365
-#bindsym $mod+backslash
366
-#bindsym $mod+Shift+backslash
365
+bindsym $mod+backslash                  exec --no-startup-id passmenu -i -nb '$dmenu-bg-color' -nf '$dmenu-text-color' -sb '$dmenu-text-color' -sf '$dmenu-bg-color' -fn 'System San Francisco Display-13'
366
+bindsym $mod+Shift+backslash            exec --no-startup-id networkmanager_dmenu -i -nb '$dmenu-bg-color' -nf '$dmenu-text-color' -sb '$dmenu-text-color' -sf '$dmenu-bg-color' -fn 'System San Francisco Display-13'
367 367
 #bindsym $mod+Shift+Control+backslash
368 368
 
369 369
 #bindsym $mod+semicolon
@@ -477,5 +477,4 @@ bindsym XF86MonBrightnessDown           exec --no-startup-id light -U 10
477 477
 
478 478
 bindsym XF86ScreenSaver                 exec --no-startup-id ~/.config/i3/scripts/lock/lock.sh
479 479
 
480
-bindsym XF86Launch1                     exec --no-startup-id networkmanager_dmenu -i -nb '$dmenu-bg-color' -nf '$dmenu-text-color' -sb '$dmenu-text-color' -sf '$dmenu-bg-color' -fn 'System San Francisco Display-13'
481
-bindsym $mod+XF86Launch1                exec --no-startup-id ~/.config/polybar/launch.sh
480
+bindsym XF86Launch1                exec --no-startup-id ~/.config/polybar/launch.sh

+ 138
- 0
pass/.enpass2pass.py View File

@@ -0,0 +1,138 @@
1
+#!/usr/bin/env python
2
+#
3
+# This program is free software: you can redistribute it and/or modify
4
+# it under the terms of the GNU General Public License as published by
5
+# the Free Software Foundation, either version 3 of the License, or
6
+# (at your option) any later version.
7
+# This program is distributed in the hope that it will be useful,
8
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
+# GNU General Public License for more details.
11
+# You should have received a copy of the GNU General Public License
12
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
13
+#
14
+# This script based on the Enpassant
15
+# script written by Steffen Zerbe.
16
+#
17
+# $Id: enpass2pass.py,v 1.1 2016/09/11 23:02:12 dhn Exp $
18
+
19
+from subprocess import Popen, PIPE, check_output
20
+from pysqlcipher import dbapi2 as sqlite
21
+from Crypto.Cipher import AES
22
+import hashlib
23
+import binascii
24
+import json
25
+
26
+
27
+class enpass2pass:
28
+
29
+    def __init__(self, filename, gpg):
30
+        self.initDb(filename, gpg)
31
+        self.crypto = self.getCryptoParams()
32
+
33
+    def getpasswd(self, gpg):
34
+        passphrase = "/home/micah/.gnupg/passphrase"
35
+        return check_output(["gpg2", "--pinentry-mode", "loopback", "--passphrase-file", passphrase, "--quiet", "--batch", "-d", gpg]).strip()
36
+
37
+    # Sets up SQLite DB
38
+    def initDb(self, filename, gpg):
39
+        self.conn = sqlite.connect(filename)
40
+        self.c = self.conn.cursor()
41
+        self.c.row_factory = sqlite.Row
42
+        self.c.execute("PRAGMA key='" + self.getpasswd(gpg) + "'")
43
+        self.c.execute("PRAGMA kdf_iter = 24000")
44
+
45
+    def generateKey(self, key, salt):
46
+        # 2 Iterations of PBKDF2 SHA256
47
+        return hashlib.pbkdf2_hmac('sha256', key, salt, 2)
48
+
49
+    def getCryptoParams(self):
50
+        ret = {}
51
+        # Identity contains stuff to decrypt data columns
52
+        self.c.execute("SELECT * FROM Identity")
53
+        identity = self.c.fetchone()
54
+
55
+        # Info contains more parameters
56
+        info = identity["Info"]
57
+
58
+        # Get params from stream
59
+        i = 16  # First 16 bytes are for "mHashData", which is unused
60
+        ret["iv"] = ""
61
+        salt = ""
62
+        while i <= 31:
63
+            ret["iv"] += info[i]
64
+            i += 1
65
+        while i <= 47:
66
+            salt += info[i]
67
+            i += 1
68
+
69
+        ret["key"] = self.generateKey(identity["Hash"], salt)
70
+
71
+        return ret
72
+
73
+    def unpad(self, s):
74
+        return s[0:-ord(s[-1])]
75
+
76
+    def decrypt(self, enc, key, iv):
77
+        # PKCS5
78
+        cipher = AES.new(key, AES.MODE_CBC, iv)
79
+        return self.unpad(cipher.decrypt(enc))
80
+
81
+    def passImportEntry(self, path, data):
82
+        proc = Popen(['pass', 'insert', '--multiline', path],
83
+                     stdin=PIPE, stdout=PIPE)
84
+        proc.communicate(data.encode('utf8'))
85
+        proc.wait()
86
+
87
+    def getCards(self):
88
+        self.c.execute("SELECT * FROM Cards")
89
+        cards = self.c.fetchall()
90
+        ret = []
91
+        for card in cards:
92
+            # Decrypted string
93
+            dec = self.decrypt(card["Data"], self.crypto[
94
+                               "key"], self.crypto["iv"])
95
+            # Parsing as object
96
+            item = json.loads(dec)
97
+            ret.append(item)
98
+        return ret
99
+
100
+    def dumpCards(self):
101
+        cards = self.getCards()
102
+        for card in cards:
103
+            if card["fields"] != []:
104
+                templatetype = card['templatetype']
105
+                type_ = card["fields"][0]['type']
106
+
107
+                if templatetype == "login.default":
108
+                    pwd = card['fields'][2]['value']
109
+                    name = card['name']
110
+
111
+                    if type_ == "username":
112
+                        value = card['fields'][0]['value']
113
+                        if value == "":
114
+                            email = card['fields'][1]['value']
115
+                            path = name + "/" + email
116
+                        else:
117
+                            username = card['fields'][0]['value']
118
+                            path = name + "/" + username
119
+
120
+                    path = "Login/" + path
121
+                    data = pwd + "\n"
122
+                    self.passImportEntry(path, data)
123
+                elif templatetype == "computer.wifi":
124
+                    name = card['fields'][0]['value']
125
+                    pwd = card['fields'][1]['value']
126
+
127
+                    path = "Wifi/" + name
128
+                    data = pwd + "\n"
129
+                    self.passImportEntry(path, data)
130
+
131
+if __name__ == "__main__":
132
+    import sys
133
+    if len(sys.argv) < 3:
134
+        print("\nusage: " + str(sys.argv[0]) + " walletx.db gpgfile\n")
135
+        sys.exit()
136
+    else:
137
+        en = enpass2pass(sys.argv[1], sys.argv[2])
138
+        en.dumpCards()

Loading…
Cancel
Save