From 475fad371a4adaeb249a6c23a050ca356274c8d5 Mon Sep 17 00:00:00 2001 From: fabio rodrigues Date: Tue, 18 Aug 2020 13:12:13 +0100 Subject: [PATCH 1/7] [vpicc] Python 3 updates and code fixing - Use pycryptodome instead of pycrypto - Fixed some unit tests asserts - fixed some instances that sending message to vpcd the msg is considered a string object instead of byte array - make TLVutils.pack work in python 3 --- .../src/vpicc/virtualsmartcard/SEutils.py | 21 +++++++++---------- .../src/vpicc/virtualsmartcard/TLVutils.py | 8 +++---- .../virtualsmartcard/VirtualSmartcard.py | 5 ++++- .../tests/SmartcardSAM_test.py | 8 +++---- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py b/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py index fd89f6c..a37567f 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py @@ -684,8 +684,7 @@ class Security_Environment(object): """ from Crypto.PublicKey import RSA, DSA - from Crypto.Util.randpool import RandomPool - rnd = RandomPool() + from Crypto.Random import get_random_bytes cipher = self.ct.algorithm @@ -694,7 +693,7 @@ class Security_Environment(object): raise SwError(SW["ERR_CONDITIONNOTSATISFIED"]) if p1 & 0x01 == 0x00: # Generate key - PublicKey = c_class.generate(self.dst.keylength, rnd.get_bytes) + PublicKey = c_class.generate(self.dst.keylength) self.dst.key = PublicKey else: pass # Read key @@ -702,23 +701,23 @@ class Security_Environment(object): # Encode keys if cipher == "RSA": # Public key - n = inttostring(PublicKey.__getstate__()['n']) - e = inttostring(PublicKey.__getstate__()['e']) + n = inttostring(PublicKey.n) + e = inttostring(PublicKey.e) pk = ((0x81, len(n), n), (0x82, len(e), e)) result = bertlv_pack(pk) # Private key - d = PublicKey.__getstate__()['d'] + d = PublicKey.d elif cipher == "DSA": # DSAParams - p = inttostring(PublicKey.__getstate__()['p']) - q = inttostring(PublicKey.__getstate__()['q']) - g = inttostring(PublicKey.__getstate__()['g']) + p = inttostring(PublicKey.p) + q = inttostring(PublicKey.q) + g = inttostring(PublicKey.g) # Public key - y = inttostring(PublicKey.__getstate__()['y']) + y = inttostring(PublicKey.y) pk = ((0x81, len(p), p), (0x82, len(q), q), (0x83, len(g), g), (0x84, len(y), y)) # Private key - x = inttostring(PublicKey.__getstate__()['x']) + x = inttostring(PublicKey.x) # Add more algorithms here # elif cipher = "ECDSA": else: diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py b/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py index eb7be9d..b2971d5 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py @@ -114,7 +114,7 @@ def tlv_find_tag(tlv_data, tag, num_results=None): def pack(tlv_data, recalculate_length=False): - result = b"" + result = [] for data in tlv_data: tag, length, value = data[:3] @@ -143,9 +143,9 @@ def pack(tlv_data, recalculate_length=False): assert len(l) < 0x7f l = inttostring(0x80 | len(l)) + l - result = result + t - result = result + l - result = result + value + result.append(t) + result.append(l) + result.append(value) return b"".join(result) diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/VirtualSmartcard.py b/virtualsmartcard/src/vpicc/virtualsmartcard/VirtualSmartcard.py index ccd330e..c4d0f95 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/VirtualSmartcard.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/VirtualSmartcard.py @@ -503,7 +503,10 @@ class VirtualICC(object): def __sendToVPICC(self, msg): """ Send a message to the vpcd """ - self.sock.sendall(struct.pack('!H', len(msg)) + msg) + if isinstance(msg, str): + self.sock.sendall(struct.pack('!H', len(msg)) + msg.encode()) + else: + self.sock.sendall(struct.pack('!H', len(msg)) + msg) def __recvFromVPICC(self): """ Receive a message from the vpcd """ diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/tests/SmartcardSAM_test.py b/virtualsmartcard/src/vpicc/virtualsmartcard/tests/SmartcardSAM_test.py index 9181622..992ed8a 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/tests/SmartcardSAM_test.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/tests/SmartcardSAM_test.py @@ -40,14 +40,14 @@ class TestSmartcardSAM(unittest.TestCase): self.myCard.verify(0x00, 0x00, "3456".encode('ascii')) except SwError as e: pass - self.assertEquals(self.myCard.counter, ctr1 - 1) + self.assertEqual(self.myCard.counter, ctr1 - 1) def test_internal_authenticate(self): sw, challenge = self.myCard.get_challenge(0x00, 0x00, b"") blocklen = vsCrypto.get_cipher_blocklen("DES3-ECB") padded = vsCrypto.append_padding(blocklen, challenge) sw, result_data = self.myCard.internal_authenticate(0x00, 0x00, padded) - self.assertEquals(sw, SW["NORMAL"]) + self.assertEqual(sw, SW["NORMAL"]) def test_external_authenticate(self): sw, challenge = self.myCard.get_challenge(0x00, 0x00, b"") @@ -56,7 +56,7 @@ class TestSmartcardSAM(unittest.TestCase): sw, result_data = self.myCard.internal_authenticate(0x00, 0x00, padded) sw, result_data = self.myCard.external_authenticate(0x00, 0x00, result_data) - self.assertEquals(sw, SW["NORMAL"]) + self.assertEqual(sw, SW["NORMAL"]) def test_security_environment(self): hash = self.secEnv.hash(0x90, 0x80, self.password) @@ -74,7 +74,7 @@ class TestSmartcardSAM(unittest.TestCase): self.secEnv.ct.algorithm = "RSA" self.secEnv.dst.keylength = 1024 sw, pk = self.secEnv.generate_public_key_pair(0x00, 0x00, b"") - self.assertEquals(sw, SW["NORMAL"]) + self.assertEqual(sw, SW["NORMAL"]) if __name__ == "__main__": From 919c13c907aa5e497da95f79613341bc5ed5a060 Mon Sep 17 00:00:00 2001 From: fabio rodrigues Date: Tue, 18 Aug 2020 15:19:23 +0100 Subject: [PATCH 2/7] [vpicc] Python 3 linting Some additional code linting - remove unused imports - remove unecessary parenthesis from if statements - created TLVutils TAG dictionary in creation time --- .../src/vpicc/virtualsmartcard/SEutils.py | 7 +- .../vpicc/virtualsmartcard/SmartcardSAM.py | 14 ++-- .../src/vpicc/virtualsmartcard/TLVutils.py | 69 ++++++++++--------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py b/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py index a37567f..36deb2d 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py @@ -239,11 +239,11 @@ class Security_Environment(object): if se & 0x08: self.external_auth = True return self._set_SE(p2, data) - elif(cmd == 0x02): + elif cmd == 0x02: return self.sam.store_SE(p2) - elif(cmd == 0x03): + elif cmd == 0x03: return self.sam.restore_SE(p2) - elif(cmd == 0x04): + elif cmd == 0x04: return self.sam.erase_SE(p2) else: raise SwError(SW["ERR_INCORRECTP1P2"]) @@ -684,7 +684,6 @@ class Security_Environment(object): """ from Crypto.PublicKey import RSA, DSA - from Crypto.Random import get_random_bytes cipher = self.ct.algorithm diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/SmartcardSAM.py b/virtualsmartcard/src/vpicc/virtualsmartcard/SmartcardSAM.py index 51baad6..3723e7d 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/SmartcardSAM.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/SmartcardSAM.py @@ -229,7 +229,7 @@ class SAM(object): blocklen = vsCrypto.get_cipher_blocklen(cipher) reference = vsCrypto.append_padding(blocklen, self.last_challenge) reference = vsCrypto.encrypt(cipher, key, reference) - if(reference == data): + if reference == data: # Invalidate last challenge self.last_challenge is None return SW["NORMAL"], "" @@ -249,20 +249,20 @@ class SAM(object): key = self._get_referenced_key(p1, p2) card_number = self.get_card_number() - if (key is None): + if key is None: raise SwError(SW["ERR_INCORRECTP1P2"]) if p1 == 0x00: # No information given cipher = get_referenced_cipher(self.cipher) else: cipher = get_referenced_cipher(p1) - if (cipher is None): + if cipher is None: raise SwError(SW["ERR_INCORRECTP1P2"]) plain = vsCrypto.decrypt(cipher, key, mutual_challenge) last_challenge_len = len(self.last_challenge) - terminal_challenge = plain[:last_challenge_len-1] - card_challenge = plain[last_challenge_len:-len(card_number)-1] + terminal_challenge = plain[:last_challenge_len - 1] + card_challenge = plain[last_challenge_len:-len(card_number) - 1] serial_number = plain[-len(card_number):] if terminal_challenge != self.last_challenge: @@ -277,7 +277,7 @@ class SAM(object): """ Generate a random number of maximum 8 Byte and return it. """ - if (p1 != 0x00 or p2 != 0x00): # RFU + if p1 != 0x00 or p2 != 0x00: # RFU raise SwError(SW["ERR_INCORRECTP1P2"]) length = 8 # Length of the challenge in Byte @@ -315,7 +315,7 @@ class SAM(object): algo = get_referenced_cipher(p1) keylength = vsCrypto.get_cipher_keylen(algo) - if (p2 == 0x00): # No information given, use the global card key + if p2 == 0x00: # No information given, use the global card key key = self.cardSecret # We treat global and specific reference data alike else: diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py b/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py index b2971d5..725f9ab 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py @@ -19,35 +19,36 @@ from virtualsmartcard.utils import stringtoint, inttostring -TAG = {} -TAG["FILECONTROLPARAMETERS"] = 0x62 -TAG["FILEMANAGEMENTDATA"] = 0x64 -TAG["FILECONTROLINFORMATION"] = 0x6F -TAG["BYTES_EXCLUDINGSTRUCTURE"] = 0x80 -TAG["BYTES_INCLUDINGSTRUCTURE"] = 0x81 -TAG["FILEDISCRIPTORBYTE"] = 0x82 -TAG["FILEIDENTIFIER"] = 0x83 -TAG["DFNAME"] = 0x84 -TAG["PROPRIETARY_NOTBERTLV"] = 0x85 -TAG["PROPRIETARY_SECURITY"] = 0x86 -TAG["FIDEF_CONTAININGFCI"] = 0x87 -TAG["SHORTFID"] = 0x88 -TAG["LIFECYCLESTATUS"] = 0x8A -TAG["SA_EXPANDEDFORMAT"] = 0x8B -TAG["SA_COMPACTFORMAT"] = 0x8C -TAG["FIDEF_CONTAININGSET"] = 0x8D -TAG["CHANNELSECURITY"] = 0x8E -TAG["SA_DATAOBJECTS"] = 0xA0 -TAG["PROPRIETARY_SECURITYTEMP"] = 0xA1 -TAG["PROPRIETARY_BERTLV"] = 0xA5 -TAG["SA_EXPANDEDFORMAT_TEMP"] = 0xAB -TAG["CRYPTIDENTIFIER_TEMP"] = 0xAC -TAG["DISCRETIONARY_DATA"] = 0x53 -TAG["DISCRETIONARY_TEMPLATE"] = 0x73 -TAG["OFFSET_DATA"] = 0x54 -TAG["TAG_LIST"] = 0x5C -TAG["HEADER_LIST"] = 0x5D -TAG["EXTENDED_HEADER_LIST"] = 0x4D +TAG = { + "FILECONTROLPARAMETERS": 0x62, + "FILEMANAGEMENTDATA": 0x64, + "FILECONTROLINFORMATION": 0x6F, + "BYTES_EXCLUDINGSTRUCTURE": 0x80, + "BYTES_INCLUDINGSTRUCTURE": 0x81, + "FILEDISCRIPTORBYTE": 0x82, + "FILEIDENTIFIER": 0x83, + "DFNAME": 0x84, + "PROPRIETARY_NOTBERTLV": 0x85, + "PROPRIETARY_SECURITY": 0x86, + "FIDEF_CONTAININGFCI": 0x87, + "SHORTFID": 0x88, + "LIFECYCLESTATUS": 0x8A, + "SA_EXPANDEDFORMAT": 0x8B, + "SA_COMPACTFORMAT": 0x8C, + "FIDEF_CONTAININGSET": 0x8D, + "CHANNELSECURITY": 0x8E, + "SA_DATAOBJECTS": 0xA0, + "PROPRIETARY_SECURITYTEMP": 0xA1, + "PROPRIETARY_BERTLV": 0xA5, + "SA_EXPANDEDFORMAT_TEMP": 0xAB, + "CRYPTIDENTIFIER_TEMP": 0xAC, + "DISCRETIONARY_DATA": 0x53, + "DISCRETIONARY_TEMPLATE": 0x73, + "OFFSET_DATA": 0x54, + "TAG_LIST": 0x5C, + "HEADER_LIST": 0x5D, + "EXTENDED_HEADER_LIST": 0x4D +} def tlv_unpack(data): @@ -180,7 +181,7 @@ def unpack(data, with_marks=None, offset=0, include_filler=False): for type, mark_start, mark_stop in with_marks: if (mark_start, mark_stop) == (start, stop): marks.append(type) - marks = (marks, ) + marks = (marks,) else: marks = () @@ -239,11 +240,11 @@ def simpletlv_unpack(data): length = rest[1] if length == 0xff: length = (rest[2] << 8) + rest[3] - newvalue = rest[4:4+length] - rest = rest[4+length:] + newvalue = rest[4:4 + length] + rest = rest[4 + length:] else: - newvalue = rest[2:2+length] - rest = rest[2+length:] + newvalue = rest[2:2 + length] + rest = rest[2 + length:] result.append((tag, length, newvalue)) return result From 9b310f00d3f20efa22cf75ffcf47367ce13bfadc Mon Sep 17 00:00:00 2001 From: fabio rodrigues Date: Tue, 18 Aug 2020 15:31:40 +0100 Subject: [PATCH 3/7] [vpicc] update Appveyor Updated AppVeyor with * Usage of VS2019 * Usage of PyCryptodome --- appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 31e3b38..81bc137 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ platform: - x86 - x64 -os: Visual Studio 2015 +os: Visual Studio 2019 install: - date /T & time /T @@ -27,7 +27,7 @@ install: - python -m pip install --upgrade pip - pip install virtualenv - pip install -U setuptools - - easy_install PyCrypto + - pip install pycryptodome - pip install pbkdf2 - pip install Pillow - pip install pyreadline @@ -36,7 +36,7 @@ install: - set PATH=C:\cygwin\bin;%PATH% # set Visual Studio 2015 build environment - - set VSVER=14 + - set VSVER=19 - ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS")) - echo "Using Visual Studio %VSVER%.0 at %VSCOMNTOOLS%" - call "%VSCOMNTOOLS%\..\..\VC\vcvarsall.bat" %VCVARS_PLATFORM% From db8d6f269921a0227bdde7d7231dc0ad2d824b29 Mon Sep 17 00:00:00 2001 From: fabio rodrigues Date: Tue, 18 Aug 2020 16:15:52 +0100 Subject: [PATCH 4/7] [vpicc] update Appveyor with better swig install choco install of swig only give us the executable, not the libraries needed for package compilation Best way is to direct download it from sourceforge, extract it to a folder and then add that folder to PATH env variable. --- appveyor.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 81bc137..20bca77 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,7 +23,10 @@ install: # BUGFIX: wdf directory was renamed to 00wdf, rename it back (see github.com/appveyor/ci/issues/414) #- ps: ren 'C:\Program Files (x86)\Windows Kits\10\include\00wdf' 'wdf' - - choco install swig + + - (new-object net.webclient).DownloadFile('https://sourceforge.net/projects/swig/', '..\swig.zip') + - Expand-Archive -LiteralPath ..\swig.zip -DestinationPath ..\swig_folder + - $env:Path += "..\swig_folder" - python -m pip install --upgrade pip - pip install virtualenv - pip install -U setuptools From d6d8f3164513e331cbbf0e19cea01f33db503ba4 Mon Sep 17 00:00:00 2001 From: fabio rodrigues Date: Tue, 18 Aug 2020 16:30:35 +0100 Subject: [PATCH 5/7] [vpicc] Fix swig download path and use recommended PS applet --- appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 20bca77..d96dc5e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,9 +24,9 @@ install: #- ps: ren 'C:\Program Files (x86)\Windows Kits\10\include\00wdf' 'wdf' - - (new-object net.webclient).DownloadFile('https://sourceforge.net/projects/swig/', '..\swig.zip') - - Expand-Archive -LiteralPath ..\swig.zip -DestinationPath ..\swig_folder - - $env:Path += "..\swig_folder" + - Start-FileDownload "https://kumisystems.dl.sourceforge.net/project/swig/swigwin/swigwin-4.0.2/swigwin-4.0.2.zip" + - Expand-Archive -LiteralPath swigwin-4.0.2.zip -DestinationPath swig_folder + - $env:Path += ".\swig_folder" - python -m pip install --upgrade pip - pip install virtualenv - pip install -U setuptools From cec72cd29ac512a94c6b47c357fc8710676863d3 Mon Sep 17 00:00:00 2001 From: fabio rodrigues Date: Tue, 18 Aug 2020 17:05:27 +0100 Subject: [PATCH 6/7] [vpicc] Fix swig download path and use recommended PS applet --- appveyor.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index d96dc5e..48274f4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,9 +24,12 @@ install: #- ps: ren 'C:\Program Files (x86)\Windows Kits\10\include\00wdf' 'wdf' - - Start-FileDownload "https://kumisystems.dl.sourceforge.net/project/swig/swigwin/swigwin-4.0.2/swigwin-4.0.2.zip" - - Expand-Archive -LiteralPath swigwin-4.0.2.zip -DestinationPath swig_folder - - $env:Path += ".\swig_folder" + - $current_path = Get-Location | select -ExpandProperty Path + - $full_path = $current_path + "\swigwin-4.0.2.zip" + - $folder_path = $current_path + "\swig_win" + - (new-object net.webclient).DownloadFile("https://kumisystems.dl.sourceforge.net/project/swig/swigwin/swigwin-4.0.2/swigwin-4.0.2.zip", $full_path) + - Expand-Archive -LiteralPath $full_path -DestinationPath $folder_path + - $env:Path += ";"+$folder_path+"\swigwin-4.0.2" - python -m pip install --upgrade pip - pip install virtualenv - pip install -U setuptools From 83e03a69384ec81ce1e6df90260942f0eea9bdf9 Mon Sep 17 00:00:00 2001 From: sorcerer86pt Date: Tue, 8 Sep 2020 10:49:49 +0100 Subject: [PATCH 7/7] [vpicc] Updaye Appveyor.yml Visual Studio edition comment --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 48274f4..c76c01a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -41,7 +41,7 @@ install: - pip install pyinstaller - set PATH=C:\cygwin\bin;%PATH% - # set Visual Studio 2015 build environment + # set Visual Studio 2019 build environment - set VSVER=19 - ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS")) - echo "Using Visual Studio %VSVER%.0 at %VSCOMNTOOLS%"