Refactoring and Bugfixing:
- CryptoUtils:
- removing hard coded keylength from append_padding in CryptoUtils
- rewrote append_padding, slightly modified strip_padding in CryptoUtils
- added get_cipher_keylen and get_cipher_blocklen to CryptoUtils
- Updated UnitTest in CryptoUtils. Note: PBKDF2.self_test() fails!!!
- added new function protect_string to encrypt and authenticate a string
- Removed hard coded padding pattern
- VirtualICC:
- Added and integrated functions to load and save VirtualICC objects
- Added exception handling for opening of the socket
- SmartcardSAM:
- Removed all object persistance functionaliy from SmartcardSAM
- Changed the constructors of the *SAM classes
- Moved all the functionality to create cards (especially the pre-initialized filesystems for each card type) to the new file GenerateCards.py
- Added minimal command line based interface to GenerateCards.py to generate customized cards and store them in a file
- Removed default sam and mf files (testconfig.mf and testconfig.sam)
git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@35 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
188
virtualsmartcard/vpicc/CardGenerator.py
Normal file
188
virtualsmartcard/vpicc/CardGenerator.py
Normal file
@@ -0,0 +1,188 @@
|
||||
#
|
||||
# Copyright (C) 2009 Dominik Oepen
|
||||
#
|
||||
# This file is part of virtualsmartcard.
|
||||
#
|
||||
# virtualsmartcard is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# virtualsmartcard is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# virtualsmartcard. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import sys, getpass, anydbm
|
||||
from pickle import loads, dumps
|
||||
from TLVutils import pack
|
||||
from utils import inttostring
|
||||
from SmartcardFilesystem import MF, TransparentStructureEF
|
||||
|
||||
# pgp directory
|
||||
#self.mf.append(DF(parent=self.mf,
|
||||
#fid=4, dfname='\xd2\x76\x00\x01\x24\x01', bertlv_data=[]))
|
||||
# pkcs-15 directories
|
||||
#self.mf.append(DF(parent=self.mf,
|
||||
#fid=1, dfname='\xa0\x00\x00\x00\x01'))
|
||||
#self.mf.append(DF(parent=self.mf,
|
||||
#fid=2, dfname='\xa0\x00\x00\x03\x08\x00\x00\x10\x00'))
|
||||
#self.mf.append(DF(parent=self.mf,
|
||||
#fid=3, dfname='\xa0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00'))
|
||||
|
||||
def generate_iso_card():
|
||||
from SmartcardSAM import SAM
|
||||
|
||||
print "Using default SAM. Insecure!!!"
|
||||
sam = SAM("1234", "1234567890") #FIXME: Use user provided data
|
||||
|
||||
mf = MF(filedescriptor=FDB["DF"], lifecycle=LCB["ACTIVATED"], dfname=None)
|
||||
self.SAM.set_MF(self.mf)
|
||||
|
||||
return mf, sam
|
||||
|
||||
def generate_ePass():
|
||||
from PIL import Image
|
||||
from SmartcardFilesystem import DF
|
||||
from SmartcardSAM import PassportSAM
|
||||
|
||||
MRZ1 = "P<UTOERIKSSON<<ANNA<MARIX<<<<<<<<<<<<<<<<<<<"
|
||||
MRZ2 = "L898902C<3UTO6908061F9406236ZE184226B<<<<<14"
|
||||
MRZ = MRZ1 + MRZ2
|
||||
|
||||
picturepath = "jp2.jpg"
|
||||
try:
|
||||
im = Image.open(picturepath)
|
||||
pic_width, pic_height = im.size
|
||||
fd = open(picturepath,"rb")
|
||||
picture = fd.read()
|
||||
fd.close()
|
||||
except IOError:
|
||||
print "Could not find picture %s" % picturepath
|
||||
pic_width = 0
|
||||
pic_height = 0
|
||||
picture = None
|
||||
|
||||
mf = MF()
|
||||
|
||||
#We need a MF with Application DF \xa0\x00\x00\x02G\x10\x01
|
||||
mf.append(DF(parent=mf, fid=4, dfname='\xa0\x00\x00\x02G\x10\x01', bertlv_data=[]))
|
||||
df = mf.currentDF()
|
||||
mf.append(TransparentStructureEF(parent=df, fid=0x011E, filedescriptor=0, data=""))#EF.COM
|
||||
mf.append(TransparentStructureEF(parent=df, fid=0x0101, filedescriptor=0, data=""))#EF.DG1
|
||||
mf.append(TransparentStructureEF(parent=df, fid=0x0102, filedescriptor=0, data=""))#EF.DG2
|
||||
mf.append(TransparentStructureEF(parent=df, fid=0x010D, filedescriptor=0, data=""))#EF.SOD
|
||||
#EF.COM
|
||||
COM = pack([(0x5F01,4,"0107"),(0x5F36,6,"040000"),(0x5C,2,"6175")])
|
||||
COM = pack(((0x60,len(COM),COM),))
|
||||
fid = df.select("fid",0x011E)
|
||||
fid.writebinary([0],[COM])
|
||||
#EF.DG1
|
||||
DG1 = pack([(0x5F1F,len(MRZ),MRZ)])
|
||||
DG1 = pack([(0x61,len(DG1),DG1)])
|
||||
fid = df.select("fid",0x0101)
|
||||
fid.writebinary([0],[DG1])
|
||||
#EF.DG2
|
||||
if picture != None:
|
||||
IIB = "\x00\x01" + inttostring(pic_width,2) + inttostring(pic_height,2) + 6 * "\x00"
|
||||
length = 32 + len(picture) #32 is the length of IIB + FIB
|
||||
FIB = inttostring(length,4) + 16 * "\x00"
|
||||
FRH = "FAC" + "\x00" + "010" + "\x00" + inttostring(14+length,4) + inttostring(1,2)
|
||||
picture = FRH + FIB + IIB + picture
|
||||
DG2 = pack([(0xA1,8,"\x87\x02\x01\x01\x88\x02\x05\x01"),(0x5F2E,len(picture),picture)])
|
||||
DG2 = pack([(0x02,1,"\x01"),(0x7F60,len(DG2),DG2)])
|
||||
DG2 = pack([(0x7F61,len(DG2),DG2)])
|
||||
fid = df.select("fid",0x0102)
|
||||
fid.writebinary([0],[DG2])
|
||||
|
||||
sam = PassportSAM(mf)
|
||||
return mf, sam
|
||||
|
||||
def generate_cryptoflex():
|
||||
from SmartcardFilesystem import CryptoflexMF
|
||||
from SmartcardSAM import CryptoflexSAM
|
||||
|
||||
mf = CryptoflexMF()
|
||||
mf.append(TransparentStructureEF(parent=mf, fid=0x0002, filedescriptor=0x01,
|
||||
data="\x00\x00\x00\x01\x00\x01\x00\x00")) #EF.ICCSN
|
||||
sam = CryptoflexSAM(mf)
|
||||
|
||||
return mf, sam
|
||||
|
||||
def loadCard(filename, password=None):
|
||||
from CryptoUtils import read_protected_string
|
||||
|
||||
try:
|
||||
db = anydbm.open(filename, 'r')
|
||||
except anydbm.error:
|
||||
print "Failed to open " + filename
|
||||
|
||||
if password is None:
|
||||
password = getpass.getpass("Please enter your password.")
|
||||
|
||||
serializedMF = read_protected_string(db["mf"], password)
|
||||
serializedSAM = read_protected_string(db["sam"], password)
|
||||
SAM = loads(serializedSAM)
|
||||
MF = loads(serializedMF)
|
||||
#self.type = db["type"]
|
||||
|
||||
return SAM, MF
|
||||
|
||||
def saveCard(mf, sam, filename, password=None):
|
||||
from CryptoUtils import protect_string
|
||||
|
||||
if filename != None:
|
||||
print "Saving smartcard configuration to %s" % filename
|
||||
else: #TODO: Ask user for filename
|
||||
pass
|
||||
|
||||
if password is None:
|
||||
passwd1 = getpass.getpass("Please enter a password.")
|
||||
passwd2 = getpass.getpass("Please retype your password.")
|
||||
if (passwd1 != passwd2):
|
||||
raise ValueError, "Passwords did not match. Will now exit"
|
||||
else:
|
||||
password = passwd1
|
||||
|
||||
mf_string = dumps(mf)
|
||||
sam_string = dumps(sam)
|
||||
protectedMF = protect_string(mf_string, password)
|
||||
protectedSAM = protect_string(sam_string, password)
|
||||
|
||||
try:
|
||||
db = anydbm.open(filename, 'c')
|
||||
db["mf"] = protectedMF
|
||||
db["sam"] = protectedSAM
|
||||
#db["type"] = self.type
|
||||
db.close()
|
||||
except anydbm.error:
|
||||
print "Failed to write data to disk"
|
||||
|
||||
if __name__ == "__main__":
|
||||
from optparse import OptionParser
|
||||
parser = OptionParser()
|
||||
parser.add_option("-t", "--type", action="store", type="choice",
|
||||
default='iso7816',
|
||||
choices=['iso7816', 'cryptoflex', 'ePass'],
|
||||
help="Type of Smartcard [default: %default]")
|
||||
parser.add_option("-f", "--file", action="store", type="string",
|
||||
dest="filename", default=None,
|
||||
help="Where to save the generated card")
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.filename == None:
|
||||
print "You have to provide a filename using the -f option"
|
||||
sys.exit()
|
||||
|
||||
if options.type == 'iso7816':
|
||||
mf, sam = generate_iso_card()
|
||||
elif options.type == 'ePass':
|
||||
mf, sam = generate_ePass()
|
||||
elif options.type == 'cryptoflex':
|
||||
mf, sam = generate_cryptoflex()
|
||||
|
||||
saveCard(mf, sam, options.filename)
|
||||
@@ -23,6 +23,7 @@ from binascii import b2a_hex
|
||||
from random import randint
|
||||
from utils import inttostring, stringtoint, hexdump
|
||||
import string
|
||||
import re
|
||||
|
||||
try:
|
||||
# Use PyCrypto (if available)
|
||||
@@ -33,8 +34,7 @@ except ImportError:
|
||||
import hmac as HMAC
|
||||
import sha as SHA1
|
||||
|
||||
iv = '\x00' * 8
|
||||
PADDING = '\x80' + '\x00' * 7
|
||||
CYBERFLEX_IV = '\x00' * 8
|
||||
|
||||
## *******************************************************************
|
||||
## * Generic methods *
|
||||
@@ -63,31 +63,57 @@ def get_cipher(cipherspec, key, iv = None):
|
||||
|
||||
return cipher
|
||||
|
||||
def append_padding(cipherspec, data, padding_class=0x01,keylength = 16):
|
||||
def get_cipher_keylen(cipherspec):
|
||||
cipherparts = cipherspec.split("-")
|
||||
|
||||
if len(cipherparts) > 2:
|
||||
raise ValueError, 'cipherspec must be of the form "cipher-mode" or "cipher"'
|
||||
|
||||
cipher = cipherparts[0].upper()
|
||||
#cipher = globals().get(cipherparts[0].upper(), None)
|
||||
#Note: return cipher.key_size does not work on Ubuntu, because e.g. AES.key_size == 0
|
||||
if cipher == "AES": #Pycrypto uses AES128
|
||||
return 16
|
||||
elif cipher == "DES":
|
||||
return 8
|
||||
elif cipher == "DES3":
|
||||
return 16
|
||||
else:
|
||||
raise ValueError, "Unsupported Encryption Algorithm: " + cipher
|
||||
|
||||
def get_cipher_blocklen(cipherspec):
|
||||
cipherparts = cipherspec.split("-")
|
||||
|
||||
if len(cipherparts) > 2:
|
||||
raise ValueError, 'cipherspec must be of the form "cipher-mode" or "cipher"'
|
||||
|
||||
cipher = globals().get(cipherparts[0].upper(), None)
|
||||
return cipher.block_size
|
||||
|
||||
def append_padding(cipherspec, data, padding_class=0x01):
|
||||
"""Append padding to the data.
|
||||
Length of padding depends on length of data and the block size of the
|
||||
specified encryption algorithm.
|
||||
Different types of padding may be selected via the padding_class parameter
|
||||
"""
|
||||
key = "DUMMYKEY" * (keylength / 8) #Key doesn't matter for padding
|
||||
cipher = get_cipher(cipherspec,key,iv)
|
||||
if padding_class == 0x01: #ISO padding
|
||||
last_block_length = len(data) % cipher.block_size
|
||||
padding_length = cipher.block_size - last_block_length
|
||||
if padding_length == 0:
|
||||
padding = PADDING
|
||||
else:
|
||||
padding = PADDING[:padding_length]
|
||||
blocklen = get_cipher_blocklen(cipherspec)
|
||||
|
||||
if padding_class == 0x01: #ISO padding
|
||||
last_block_length = len(data) % blocklen
|
||||
padding_length = blocklen - last_block_length
|
||||
if padding_length == 0:
|
||||
padding = '\x80' + '\x00' * (blocklen - 1)
|
||||
else:
|
||||
padding = '\x80' + '\x00' * (blocklen - last_block_length - 1)
|
||||
|
||||
del cipher
|
||||
return data + padding
|
||||
|
||||
def strip_padding(cipherspec,data,padding_class=0x01,keylength = 16):
|
||||
def strip_padding(cipherspec,data,padding_class=0x01):
|
||||
"""
|
||||
Strip the padding of decrypted data. Returns data without padding
|
||||
"""
|
||||
key = "DUMMYKEY" * (keylength / 8) #Key doesn't matter for padding
|
||||
cipher = get_cipher(cipherspec,key,iv)
|
||||
|
||||
#TODO: Sanity check
|
||||
if padding_class == 0x01:
|
||||
tail = len(data) - 1
|
||||
while data[tail] != '\x80':
|
||||
@@ -148,37 +174,92 @@ def operation_on_string(string1, string2, op):
|
||||
result.append( chr(op(ord(string1[i]),ord(string2[i]))) )
|
||||
return "".join(result)
|
||||
|
||||
def protect_string(string, password, cipherspec=None):
|
||||
"""
|
||||
Encrypt and authenticate a string
|
||||
"""
|
||||
|
||||
#Derive a key and a salt from password
|
||||
pbk = crypt(password)
|
||||
regex = re.compile('\$p5k2\$\$[\w./]*\$')
|
||||
match = regex.match(pbk)
|
||||
if match != None:
|
||||
salt = pbk[7:match.end()-1]
|
||||
key = pbk[match.end():]
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
#Encrypt the string, authenticate and format it
|
||||
if cipherspec == None:
|
||||
cipherspec = "AES-CBC"
|
||||
else:
|
||||
pass #TODO: Sanity check for cipher
|
||||
paddedString = append_padding(cipherspec, string)
|
||||
cryptedString = cipher(True, cipherspec, key, paddedString)
|
||||
hmac = crypto_checksum("HMAC", key, cryptedString)
|
||||
protectedString = "$p5k2$$" + salt + "$" + cryptedString + hmac
|
||||
|
||||
return protectedString
|
||||
|
||||
def read_protected_string(string, password, cipherspec=None):
|
||||
"""
|
||||
Decrypt a protected string and verify the authentication data
|
||||
"""
|
||||
hmac_length = 32 #FIXME: Ugly
|
||||
|
||||
#Check if the string has the structure, that is generated by protect_string
|
||||
|
||||
regex = re.compile('\$p5k2\$\$[\w./]*\$') #TODO: Ensure the right format!
|
||||
match = regex.match(string)
|
||||
if match != None:
|
||||
crypted = string[match.end():len(string) - hmac_length]
|
||||
salt = string[7:match.end() - 1]
|
||||
hmac = string[len(string) - hmac_length:]
|
||||
else:
|
||||
raise ValueError, "Wrong string format"
|
||||
|
||||
#Derive key
|
||||
pbk = crypt(password, salt)
|
||||
match = regex.match(pbk)
|
||||
key = pbk[match.end():]
|
||||
|
||||
#Verify HMAC
|
||||
checksum = crypto_checksum("HMAC", key, crypted)
|
||||
if checksum != hmac:
|
||||
print "Found HMAC %s expected %s" % (str(hmac), str(checksum))
|
||||
raise ValueError, "Failed to authenticate data. Wrong password?"
|
||||
|
||||
#Decrypt data
|
||||
if cipherspec == None:
|
||||
cipherspec = "AES-CBC"
|
||||
decrypted = cipher(False, cipherspec, key, crypted)
|
||||
|
||||
return strip_padding(cipherspec, decrypted)
|
||||
|
||||
## *******************************************************************
|
||||
## * Cyberflex specific methods *
|
||||
## *******************************************************************
|
||||
def verify_card_cryptogram(session_key, host_challenge,
|
||||
card_challenge, card_cryptogram):
|
||||
def verify_card_cryptogram(session_key, host_challenge, card_challenge, card_cryptogram):
|
||||
message = host_challenge + card_challenge
|
||||
expected = calculate_MAC(session_key, message, iv)
|
||||
|
||||
print >>sys.stderr, "Original: %s" % binascii.b2a_hex(card_cryptogram)
|
||||
print >>sys.stderr, "Expected: %s" % binascii.b2a_hex(expected)
|
||||
expected = calculate_MAC(session_key, message, CYBERFLEX_IV)
|
||||
|
||||
return card_cryptogram == expected
|
||||
|
||||
def calculate_host_cryptogram(session_key, card_challenge,
|
||||
host_challenge):
|
||||
def calculate_host_cryptogram(session_key, card_challenge, host_challenge):
|
||||
message = card_challenge + host_challenge
|
||||
return calculate_MAC(session_key, message, iv)
|
||||
return calculate_MAC(session_key, message, CYBERFLEX_IV)
|
||||
|
||||
def calculate_MAC(session_key, message, iv):
|
||||
print >>sys.stderr, "Doing MAC for: %s" % utils.hexdump(message, indent = 17)
|
||||
def calculate_MAC(session_key, message, iv=CYBERFLEX_IV):
|
||||
""""
|
||||
Cyberflex MAC is the last Block of the input encrypted with DES3-CBC
|
||||
"""
|
||||
|
||||
cipher = DES3.new(session_key, DES3.MODE_CBC, iv)
|
||||
block_count = len(message) / cipher.block_size
|
||||
for i in range(block_count):
|
||||
cipher.encrypt(message[i*cipher.block_size:(i+1)*cipher.block_size])
|
||||
padded = append_padding("DES3", message, 0x01)
|
||||
block_count = len(padded) / cipher.block_size
|
||||
crypted = cipher.encrypt(padded)
|
||||
|
||||
last_block_length = len(message) % cipher.block_size
|
||||
last_block = (message[len(message)-last_block_length:]+PADDING)[:cipher.block_size]
|
||||
|
||||
return cipher.encrypt( last_block )
|
||||
return crypted[len(padded) - cipher.block_size : ]
|
||||
|
||||
def get_derivation_data(host_challenge, card_challenge):
|
||||
return card_challenge[4:8] + host_challenge[:4] + \
|
||||
@@ -546,11 +627,22 @@ if __name__ == "__main__":
|
||||
print "Host-Crypto: ", utils.hexdump( host_crypto )
|
||||
|
||||
external_authenticate = binascii.a2b_hex("".join("84 82 01 00 10".split())) + host_crypto
|
||||
print utils.hexdump(calculate_MAC(session_key, external_authenticate, iv))
|
||||
print utils.hexdump(calculate_MAC(session_key, external_authenticate))
|
||||
|
||||
too_short = binascii.a2b_hex("".join("89 45 19 BF".split()))
|
||||
padded = append_padding("DES3-ECB",len(too_short),too_short)
|
||||
padded = append_padding("DES3-ECB", too_short)
|
||||
print "Padded data: " + utils.hexdump(padded)
|
||||
unpadded = strip_padding("DES3-ECB", padded)
|
||||
print "Without padding: " + utils.hexdump(unpadded)
|
||||
test_pbkdf2()
|
||||
|
||||
teststring = "DEADBEEFistatsyksdvhihewohfwoehcowc8hw8rogfq8whv75tsgohsav8wress"
|
||||
foo = append_padding("AES", teststring)
|
||||
print len(foo)
|
||||
print strip_padding("AES", foo)
|
||||
testpass = "SomeRandomPassphrase"
|
||||
protectedString = protect_string(teststring, testpass)
|
||||
unprotectedString = read_protected_string(protectedString, testpass)
|
||||
if teststring != unprotectedString:
|
||||
print "protect_string test failed"
|
||||
|
||||
#test_pbkdf2()
|
||||
|
||||
@@ -26,16 +26,6 @@ from Crypto.Cipher import DES3
|
||||
from ConstantDefinitions import *
|
||||
from SEutils import ControlReferenceTemplate as CRT
|
||||
|
||||
def generate_SAM_config(cardNumber,PIN,cardSecret,path,password):
|
||||
"""
|
||||
This method generates a new SAM configuration using the given parameters,
|
||||
stores it in a KeyContainer, serialises the container, encrypts it and
|
||||
writes it to the disk.
|
||||
"""
|
||||
container = CardContainer(cardNumber,PIN,cardSecret)
|
||||
container.saveConfiguration(path,password)
|
||||
del container
|
||||
|
||||
def get_referenced_cipher(p1):
|
||||
"""
|
||||
P1 defines the algorithm and mode to use. We dispatch it and return a
|
||||
@@ -43,6 +33,7 @@ def get_referenced_cipher(p1):
|
||||
"""
|
||||
|
||||
ciphertable = {
|
||||
0x00: "DES3-ECB",
|
||||
0x01: "DES3-ECB",
|
||||
0x02: "DES3-CBC",
|
||||
0x03: "DES-ECB",
|
||||
@@ -67,18 +58,27 @@ class CardContainer:
|
||||
to the corresponding container.
|
||||
"""
|
||||
|
||||
def __init__(self,cardNumber=None,PIN=None,cardSecret=None):
|
||||
def __init__(self, PIN=None, cardNumber=None, cardSecret=None):
|
||||
from os import urandom
|
||||
|
||||
self.cardNumber = cardNumber
|
||||
self.PIN = PIN
|
||||
self.cardSecret = cardSecret
|
||||
self.FSkeys = {}
|
||||
self.cipher = 0x01 # Algorithm reference defined in __get_referenced_algorithm(p1)
|
||||
self.block_size = 16 #Need to be set according to the needs of self.cipher. Ugly!
|
||||
self.master_password = None
|
||||
self.master_key = None
|
||||
self.salt = None
|
||||
self.asym_key = None
|
||||
|
||||
keylen = CryptoUtils.get_cipher_keylen(get_referenced_cipher(self.cipher))
|
||||
if cardSecret is None: #Generate a random card secret
|
||||
self.cardSecret = urandom(keylen)
|
||||
else:
|
||||
if len(cardSecret) != keylen:
|
||||
raise ValueError, "cardSecret has the wrong key length for: " + get_referenced_cipher(self.cipher)
|
||||
else:
|
||||
self.cardSecret = cardSecret
|
||||
|
||||
def __delete__(self):
|
||||
print "Smartcard configuration is NOT saved!!!"
|
||||
|
||||
@@ -120,134 +120,20 @@ class CardContainer:
|
||||
else:
|
||||
return None
|
||||
|
||||
def loadConfiguration(self,path,password):
|
||||
"""
|
||||
Reads the configuration of a key container from the disk, decrypts
|
||||
it and applies it to the current key_ container.
|
||||
The current configuration gets overwritten. The HMAC is used to verify
|
||||
data integrity.
|
||||
"""
|
||||
decryptedContainer = self.loadFromDisk(path, password, True)
|
||||
container = loads(decryptedContainer)
|
||||
self.PIN = container.PIN
|
||||
self.cardNumber = container.cardNumber
|
||||
self.cardSecret = container.cardSecret
|
||||
self.FSkeys = container.FSkeys
|
||||
self.master_password = password
|
||||
del decryptedContainer
|
||||
del container
|
||||
|
||||
def saveConfiguration(self,path,password=None):
|
||||
"""
|
||||
Encrypts the configuration of the current key container and writes it
|
||||
to the disk. Password is used to derivate a key using PBKDF2. A salt and
|
||||
a HMAC is stored along with the data
|
||||
"""
|
||||
serialisedContainer = dumps(self)
|
||||
if self.master_key == None: #New Configuration
|
||||
if password == None:
|
||||
raise ValueError, "Need password but none specified"
|
||||
pbk = CryptoUtils.crypt(password)
|
||||
regex = re.compile('\$p5k2\$\$[\w./]*\$')
|
||||
match = regex.match(pbk)
|
||||
if match != None:
|
||||
self.salt = pbk[7:match.end()-1]
|
||||
self.master_key = pbk[match.end():]
|
||||
else:
|
||||
raise ValueError
|
||||
del pbk
|
||||
|
||||
self.saveToDisk(serialisedContainer,path)
|
||||
|
||||
def saveToDisk(self,data,path,password=None):
|
||||
if password == None:
|
||||
key = self.master_key
|
||||
salt = self.salt
|
||||
else:
|
||||
regex = re.compile('\$p5k2\$\$[\w./]*\$')
|
||||
pbk = CryptoUtils.crypt(password)
|
||||
match = regex.match(pbk)
|
||||
salt = pbk[7:match.end()-1]
|
||||
print salt
|
||||
key = pbk[match.end():]
|
||||
|
||||
cipher = get_referenced_cipher(self.cipher)
|
||||
paddedData = CryptoUtils.append_padding(cipher,data)
|
||||
cryptedData = CryptoUtils.cipher(True,cipher,key,paddedData)
|
||||
hmac = CryptoUtils.crypto_checksum("HMAC",key,cryptedData)
|
||||
data = "$p5k2$$" + salt + "$" + cryptedData + hmac
|
||||
|
||||
try:
|
||||
fd = open(path,"w")
|
||||
fd.write(data)
|
||||
fd.close()
|
||||
except IOError:
|
||||
print "Failed to write data to disk"
|
||||
|
||||
|
||||
def loadFromDisk(self,path,password=None,loading_sam=False):
|
||||
hmac_length = 32 #FIXME: Ugly
|
||||
#Read data
|
||||
try:
|
||||
fd = open(path,"r")
|
||||
data = fd.read()
|
||||
fd.close()
|
||||
except IOError:
|
||||
print "Failed to read data from disk"
|
||||
#Check file structure, ectract components
|
||||
regex = re.compile('\$p5k2\$\$[\w./]*\$') #TODO: Ensure the right format!
|
||||
match = regex.match(data)
|
||||
if match != None:
|
||||
crypted = data[match.end():len(data) - hmac_length]
|
||||
salt = data[7:match.end() - 1]
|
||||
hmac = data[len(data) - hmac_length:]
|
||||
else:
|
||||
raise ValueError, "Wrong file format"
|
||||
if password == None:
|
||||
if salt != self.salt:
|
||||
raise ValueError, "Could not decode data"
|
||||
else:
|
||||
key = self.master_key
|
||||
else:
|
||||
pbk = CryptoUtils.crypt(password,salt)
|
||||
match = regex.match(pbk)
|
||||
key = pbk[match.end():]
|
||||
#Verify HMAC
|
||||
checksum = CryptoUtils.crypto_checksum("HMAC",key,crypted)
|
||||
if checksum != hmac:
|
||||
print "Found HMAC %s expected %s" % (str(hmac), str(checksum))
|
||||
raise ValueError, "Failed to authenticate data. Wrong password?"
|
||||
#Decrypt data
|
||||
cipher = get_referenced_cipher(self.cipher)
|
||||
decrypted = CryptoUtils.cipher(False,cipher,key,crypted)
|
||||
|
||||
#If we are loading the SAM config (paramter loading_sam) we set
|
||||
#the master key and the salt
|
||||
#This is ugly and should be changed
|
||||
if loading_sam:
|
||||
self.master_key = key
|
||||
self.salt = salt
|
||||
|
||||
return decrypted
|
||||
|
||||
|
||||
class SAM(object):
|
||||
|
||||
def __init__(self,path,password,mf=None):
|
||||
"""
|
||||
Reads the encrypted SAM configuration from the disk and applies it.
|
||||
"""
|
||||
self.CardContainer = CardContainer()
|
||||
if len(password) % self.CardContainer.block_size != 0:
|
||||
print "Wrong key length, must be a multiple of %s Bytes" % self.CardContainer.block_size
|
||||
raise ValueError
|
||||
def __init__(self, PIN, cardNumber, mf=None):
|
||||
|
||||
self.CardContainer.loadConfiguration(path, password)
|
||||
self.CardContainer = CardContainer(PIN, cardNumber)
|
||||
#self.CardContainer.loadConfiguration(path, password)
|
||||
self.mf = mf
|
||||
self.card_number = self.CardContainer.cardNumber
|
||||
|
||||
self.cardNumber = cardNumber
|
||||
self.cardSecret = self.CardContainer.cardSecret
|
||||
|
||||
self.last_challenge = None #Will contain non-readable binary string
|
||||
self.counter = 3 #Number of tries for PIN validation
|
||||
self.cardSecret = self.CardContainer.cardSecret
|
||||
|
||||
self.SM_handler = Secure_Messaging(self.mf)
|
||||
|
||||
def set_MF(self,mf):
|
||||
@@ -322,6 +208,7 @@ class SAM(object):
|
||||
return SW["NORMAL"], ""
|
||||
else:
|
||||
self.counter -= 1
|
||||
print self.CardContainer.getPIN() + " != " + PIN
|
||||
raise SwError(SW["WARN_NOINFO63"])
|
||||
#raise SwError(0X63C0 + self.counter) #Be verbose
|
||||
else:
|
||||
@@ -442,7 +329,7 @@ class SAM(object):
|
||||
return SW["NORMAL"], self.last_challenge
|
||||
|
||||
def get_card_number(self):
|
||||
return SW["NORMAL"], inttostring(self.card_number)
|
||||
return SW["NORMAL"], inttostring(self.cardNumber)
|
||||
|
||||
def _get_referenced_key(self,p1,p2):
|
||||
"""
|
||||
@@ -464,8 +351,7 @@ class SAM(object):
|
||||
key = None
|
||||
qualifier = p2 & 0x1F
|
||||
algo = get_referenced_cipher(p1)
|
||||
cipher = CryptoUtils.get_cipher(p1)
|
||||
keylength = cipher.key_size
|
||||
keylength = CryptoUtils.get_cipher_keylen(algo)
|
||||
|
||||
if (p2 == 0x00): #No information given, use the global card key
|
||||
key = self.CardContainer.cardSecret
|
||||
@@ -507,19 +393,6 @@ class SAM(object):
|
||||
sw, result = file.readbinary(0)
|
||||
return sw, result
|
||||
|
||||
#The following commands define the interface to the CardContainer functions
|
||||
def saveConfiguration(self,path,password=None):
|
||||
return self.CardContainer.saveConfiguration(path, password)
|
||||
|
||||
def loadConfiguration(self,path,password):
|
||||
return self.CardContainer.loadConfiguration(path, password)
|
||||
|
||||
def loadFromDisk(self,path,password=None):
|
||||
return self.CardContainer.loadFromDisk(path, password)
|
||||
|
||||
def saveToDisk(self,data,path,password=None):
|
||||
return self.CardContainer.saveToDisk(data, path, password)
|
||||
|
||||
#The following commands define the interface to the Secure Messaging functions
|
||||
def generate_public_key_pair(self,p1,p2,data):
|
||||
return self.SM_handler.generate_public_key_pair(p1, p2, data)
|
||||
@@ -537,7 +410,7 @@ class SAM(object):
|
||||
return self.SM_handler.manage_security_environment(p1, p2, data)
|
||||
|
||||
class PassportSAM(SAM):
|
||||
def __init__(self,mf,path="testconfig.sam",key="DUMMYKEYDUMMYKEY"):
|
||||
def __init__(self, mf):
|
||||
df = mf.currentDF()
|
||||
ef_dg1 = df.select("fid", 0x0101)
|
||||
dg1 = ef_dg1.readbinary(5)
|
||||
@@ -549,7 +422,8 @@ class PassportSAM(SAM):
|
||||
self.KSenc = None
|
||||
self.KSmac = None
|
||||
self.__computeKeys()
|
||||
SAM.__init__(self,path,key,None)
|
||||
#SAM.__init__(self, path, key,None)
|
||||
SAM.__init__(self, None, None, mf)
|
||||
self.SM_handler = ePass_SM(mf, None, None, None)
|
||||
self.SM_handler.CAPDU_SE.cct.algo = "CC"
|
||||
self.SM_handler.RAPDU_SE.cct.algo = "CC"
|
||||
@@ -634,8 +508,8 @@ class PassportSAM(SAM):
|
||||
return c
|
||||
|
||||
class CryptoflexSAM(SAM):
|
||||
def __init__(self,path="testconfig.sam",key="DUMMYKEYDUMMYKEY",mf=None):
|
||||
SAM.__init__(self,path,key,mf)
|
||||
def __init__(self, mf=None):
|
||||
SAM.__init__(self, None, None, mf)
|
||||
self.SM_handler = CryptoflexSM(mf)
|
||||
|
||||
def generate_public_key_pair(self,p1,p2,data):
|
||||
@@ -847,7 +721,7 @@ class Secure_Messaging(object):
|
||||
|
||||
if header_authentication:
|
||||
to_authenticate = inttostring(CAPDU.cla) + inttostring(CAPDU.ins) + inttostring(CAPDU.p1) + inttostring(CAPDU.p2)
|
||||
to_authenticate = CryptoUtils.append_padding("DES-CBC",to_authenticate,0x01,8)
|
||||
to_authenticate = CryptoUtils.append_padding("DES-CBC", to_authenticate)
|
||||
else:
|
||||
to_authenticate = ""
|
||||
|
||||
@@ -915,7 +789,7 @@ class Secure_Messaging(object):
|
||||
|
||||
#SM data objects for authentication
|
||||
if tag == SM_Class["CHECKSUM"]:
|
||||
auth = CryptoUtils.append_padding("DES-CBC",to_authenticate,0x01,8)
|
||||
auth = CryptoUtils.append_padding("DES-CBC", to_authenticate)
|
||||
sw, checksum = self.compute_cryptographic_checksum(0x8E, 0x80, auth)
|
||||
if checksum != value:
|
||||
print "Failed to verify checksum!"
|
||||
@@ -1002,7 +876,7 @@ class Secure_Messaging(object):
|
||||
raise SwError(SW["CONDITIONSNOTSATISFIED"])
|
||||
elif self.CAPDU_SE.cct.algo == "CCT":
|
||||
tag = SM_Class["CHECKSUM"]
|
||||
to_auth = CryptoUtils.append_padding("DES-ECB",return_data,0x01,8)
|
||||
to_auth = CryptoUtils.append_padding("DES-ECB", return_data)
|
||||
sw, auth = self.compute_cryptographic_checksum(0x8E, 0x80, to_auth)
|
||||
length = len(auth)
|
||||
return_data += TLVutils.pack([(tag,length,auth)])
|
||||
@@ -1344,11 +1218,10 @@ if __name__ == "__main__":
|
||||
Unit test:
|
||||
"""
|
||||
|
||||
path = "testconfig.sam"
|
||||
password = "DUMMYKEYDUMMYKEY"
|
||||
generate_SAM_config("1234567890","1234","keykeykeykeykeyk",path,password)
|
||||
#generate_SAM_config("1234567890", "1234", "keykeykeykeykeyk", path, password)
|
||||
|
||||
MyCard = SAM(path,password,None)
|
||||
MyCard = SAM("1234", "1234567890")
|
||||
try:
|
||||
print MyCard.verify(0x00, 0x00, "5678")
|
||||
except SwError, e:
|
||||
|
||||
@@ -25,42 +25,17 @@ from SmartcardSAM import CardContainer, SAM, PassportSAM, CryptoflexSAM
|
||||
from pickle import dumps, loads
|
||||
import socket, struct, sys, signal, atexit, traceback
|
||||
import struct
|
||||
|
||||
import getpass
|
||||
import shelve, anydbm
|
||||
|
||||
class SmartcardOS(object): # {{{
|
||||
def __init__(self, filename,mf=None,ins2handler=None, maxle=MAX_SHORT_LE,sam=None):
|
||||
self.config_key = "DUMMYKEYDUMMYKEY" #TODO: Let user enter password
|
||||
self.filename = filename
|
||||
def __init__(self, mf=None, sam=None, ins2handler=None, maxle=MAX_SHORT_LE):
|
||||
from CardGenerator import generate_iso_card
|
||||
self.mf = mf
|
||||
self.SAM = sam
|
||||
|
||||
if self.filename != None:
|
||||
try:
|
||||
self.load(filename,self.config_key)
|
||||
except ValueError:
|
||||
print "Failed to load configuration %s" % filename
|
||||
|
||||
if self.SAM == None:
|
||||
print "Using default SAM. Insecure!!!"
|
||||
self.SAM = SAM("testconfig.sam",self.config_key) #FIXME: Replace by defaul_SAM()
|
||||
if self.mf == None:
|
||||
print "Using default MF."
|
||||
self.mf = MF(filedescriptor=FDB["DF"], lifecycle=LCB["ACTIVATED"], dfname=None)
|
||||
self.SAM.set_MF(self.mf)
|
||||
|
||||
# pgp directory
|
||||
#self.mf.append(DF(parent=self.mf,
|
||||
#fid=4, dfname='\xd2\x76\x00\x01\x24\x01', bertlv_data=[]))
|
||||
# pkcs-15 directories
|
||||
#self.mf.append(DF(parent=self.mf,
|
||||
#fid=1, dfname='\xa0\x00\x00\x00\x01'))
|
||||
#self.mf.append(DF(parent=self.mf,
|
||||
#fid=2, dfname='\xa0\x00\x00\x03\x08\x00\x00\x10\x00'))
|
||||
#self.mf.append(DF(parent=self.mf,
|
||||
#fid=3, dfname='\xa0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00'))
|
||||
|
||||
#import imp, os.path
|
||||
#SAM_config = os.path.join(os.path.dirname(imp.find_module("SmartcardSAM")[1]), "testconfig.sam") #Path to initial SAM configuration, stored on disk
|
||||
if self.mf == None and self.SAM == None:
|
||||
self.mf, self.SAM = generate_iso_card()
|
||||
|
||||
if not ins2handler:
|
||||
self.ins2handler = {
|
||||
@@ -109,41 +84,6 @@ class SmartcardOS(object): # {{{
|
||||
histChars = chr(0x80) + chr(0x70 + len(card_capabilities)) +
|
||||
card_capabilities)
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
Save the configuration of the current Smartcard (MF + SAM) to disk.
|
||||
To files will be stored: <filename>.mf for the mf and <filename>.sam
|
||||
for the SAM.
|
||||
Both files will be encrypted.
|
||||
"""
|
||||
if self.filename == None:
|
||||
raise ValueError, "No filename specified"
|
||||
else:
|
||||
mf = dumps(self.mf)
|
||||
path = self.filename + ".mf"
|
||||
mf = self.SAM.saveToDisk(mf,path)
|
||||
path = self.filename + ".sam"
|
||||
self.SAM.saveConfiguration(path)
|
||||
#self.SAM.saveConfiguration(path,"DUMMYKEYDUMMYKEY")
|
||||
|
||||
def load(self,filename,password):
|
||||
"""
|
||||
Try to load a configuration from the filesystem. MF or SAM are only loaded if
|
||||
they aren't yet specified.
|
||||
"""
|
||||
if self.SAM == None:
|
||||
self.SAM = SAM("testconfig.sam","DUMMYKEYDUMMYKEY",None) #FIXME: replace by default_SAM()
|
||||
path = filename + ".sam"
|
||||
try:
|
||||
self.SAM.loadConfiguration(path,password)
|
||||
except IOError:
|
||||
print "Failed to open %s" % path
|
||||
if self.mf == None:
|
||||
path = filename + ".mf"
|
||||
data = self.SAM.loadFromDisk(path,password)
|
||||
self.mf = loads(data)
|
||||
print "Succesfully loaded MF from %s" % path
|
||||
|
||||
def powerUp(self):
|
||||
pass
|
||||
|
||||
@@ -363,72 +303,32 @@ class PassportOS(SmartcardOS):
|
||||
Basic Access Control (BAC) mechanisms.
|
||||
"""
|
||||
|
||||
def __init__(self, filename,mf=None, ins2handler=None, maxle=MAX_SHORT_LE):
|
||||
if filename == None and mf == None:
|
||||
mf = MF()
|
||||
else:
|
||||
pass #TODO: Load data from disk
|
||||
self.generate_data_structure(mf)
|
||||
self.SAM = PassportSAM(mf)
|
||||
SmartcardOS.__init__(self, None, mf=mf, ins2handler=ins2handler, maxle=maxle,sam=self.SAM)
|
||||
def __init__(self, mf=None, sam=None, ins2handler=None, maxle=MAX_SHORT_LE):
|
||||
from CardGenerator import generate_ePass
|
||||
|
||||
def generate_data_structure(self,mf):
|
||||
MRZ1 = "P<UTOERIKSSON<<ANNA<MARIX<<<<<<<<<<<<<<<<<<<"
|
||||
MRZ2 = "L898902C<3UTO6908061F9406236ZE184226B<<<<<14"
|
||||
MRZ = MRZ1+MRZ2
|
||||
from PIL import Image
|
||||
picturepath = "jp2.jpg"
|
||||
try:
|
||||
im = Image.open(picturepath)
|
||||
pic_width, pic_height = im.size
|
||||
fd = open(picturepath,"rb")
|
||||
picture = fd.read()
|
||||
fd.close()
|
||||
except IOError:
|
||||
print "Could not find picture %s" % picturepath
|
||||
pic_width = 0
|
||||
pic_height = 0
|
||||
picture = None
|
||||
|
||||
#We need a MF with Application DF \xa0\x00\x00\x02G\x10\x01
|
||||
mf.append(DF(parent=mf,fid=4, dfname='\xa0\x00\x00\x02G\x10\x01', bertlv_data=[]))
|
||||
df = mf.currentDF()
|
||||
mf.append(TransparentStructureEF(parent=df, fid=0x011E, filedescriptor=0, data=""))#EF.COM
|
||||
mf.append(TransparentStructureEF(parent=df, fid=0x0101, filedescriptor=0, data=""))#EF.DG1
|
||||
mf.append(TransparentStructureEF(parent=df, fid=0x0102, filedescriptor=0, data=""))#EF.DG2
|
||||
mf.append(TransparentStructureEF(parent=df, fid=0x010D, filedescriptor=0, data=""))#EF.SOD
|
||||
#EF.COM
|
||||
COM = pack([(0x5F01,4,"0107"),(0x5F36,6,"040000"),(0x5C,2,"6175")])
|
||||
COM = pack(((0x60,len(COM),COM),))
|
||||
fid = df.select("fid",0x011E)
|
||||
fid.writebinary([0],[COM])
|
||||
#EF.DG1
|
||||
DG1 = pack([(0x5F1F,len(MRZ),MRZ)])
|
||||
DG1 = pack([(0x61,len(DG1),DG1)])
|
||||
fid = df.select("fid",0x0101)
|
||||
fid.writebinary([0],[DG1])
|
||||
#EF.DG2
|
||||
if picture != None:
|
||||
IIB = "\x00\x01" + inttostring(pic_width,2) + inttostring(pic_height,2) + 6 * "\x00"
|
||||
length = 32 + len(picture) #32 is the length of IIB + FIB
|
||||
FIB = inttostring(length,4) + 16 * "\x00"
|
||||
FRH = "FAC" + "\x00" + "010" + "\x00" + inttostring(14+length,4) + inttostring(1,2)
|
||||
picture = FRH + FIB + IIB + picture
|
||||
DG2 = pack([(0xA1,8,"\x87\x02\x01\x01\x88\x02\x05\x01"),(0x5F2E,len(picture),picture)])
|
||||
DG2 = pack([(0x02,1,"\x01"),(0x7F60,len(DG2),DG2)])
|
||||
DG2 = pack([(0x7F61,len(DG2),DG2)])
|
||||
fid = df.select("fid",0x0102)
|
||||
fid.writebinary([0],[DG2])
|
||||
if mf == None and sam == None:
|
||||
mf, sam = generate_ePass()
|
||||
else: #TODO: Sanity check if mf or sam are provided
|
||||
if mf == None:
|
||||
mf, tmp = generate_ePass()
|
||||
if sam == None:
|
||||
sam = PassportSAM(mf)
|
||||
SmartcardOS.__init__(self, mf=mf, sam=sam, ins2handler=ins2handler, maxle=maxle)
|
||||
|
||||
class CryptoflexOS(SmartcardOS): # {{{
|
||||
def __init__(self, filename, mf=None, ins2handler=None, maxle=MAX_SHORT_LE):
|
||||
if filename == None and mf == None:
|
||||
mf = CryptoflexMF()
|
||||
mf.append(TransparentStructureEF(parent=mf, fid=0x0002, filedescriptor=0x01,
|
||||
data="\x00\x00\x00\x01\x00\x01\x00\x00"))#EF.ICCSN
|
||||
#TODO: Load objects from disk
|
||||
SmartcardOS.__init__(self, None,mf=mf, ins2handler=ins2handler, maxle=maxle,
|
||||
sam=CryptoflexSAM("testconfig.sam","DUMMYKEYDUMMYKEY"))
|
||||
def __init__(self, mf=None, sam=None, ins2handler=None, maxle=MAX_SHORT_LE):
|
||||
from GenerateCard import generate_cryptoflex
|
||||
|
||||
if mf == None and sam == None:
|
||||
mf, sam = generate_cryptoflex()
|
||||
else:
|
||||
if mf == None:
|
||||
mf, tmp = generate_cryptoflex()
|
||||
del tmp
|
||||
if sam == None:
|
||||
sam = CryptoflexSAM(mf)
|
||||
|
||||
SmartcardOS.__init__(self, mf, sam, ins2handler, maxle)
|
||||
self.atr = '\x3B\xE2\x00\x00\x40\x20\x49\x06'
|
||||
|
||||
def execute(self, msg):
|
||||
@@ -485,28 +385,55 @@ VPCD_CTRL_ATR = 4
|
||||
|
||||
class VirtualICC(object): # {{{
|
||||
|
||||
def __init__(self, filename,os=None, lenlen=3, host="localhost", port=35963):
|
||||
if os == None:
|
||||
self.os = SmartcardOS(filename)
|
||||
def __init__(self, filename, type, lenlen=3, host="localhost", port=35963):
|
||||
from os.path import exists
|
||||
from CardGenerator import loadCard
|
||||
|
||||
self.filename = None
|
||||
SAM = None
|
||||
MF = None
|
||||
|
||||
#If a filename is specified, try to load the card from disk
|
||||
if filename == None:
|
||||
print "No filename specified. The card will not be safed!"
|
||||
else:
|
||||
self.os = os
|
||||
self.filename = filename
|
||||
if exists(filename):
|
||||
print "Found existing card " + filename + ". Will try to open it"
|
||||
SAM, MF = loadCard(filename)
|
||||
else:
|
||||
print "No file " + filename + " found. Will create new file at termination of program."
|
||||
|
||||
#Generate an OS object of the correct type
|
||||
if type == "iso7816":
|
||||
self.os = SmartcardOS(MF, SAM)
|
||||
elif type == "ePass":
|
||||
self.os = PassportOS(MF, SAM)
|
||||
elif type == "cryptoflex":
|
||||
self.os = CryptoflexOS(MF, SAM)
|
||||
else:
|
||||
print "Unknown cardtype " + type + ". Will use standard ISO 7816 cardtype"
|
||||
type = "iso7816"
|
||||
self.os = SmartcardOS(MF, SAM)
|
||||
self.type = type
|
||||
|
||||
#Connect to the VPCD
|
||||
try:
|
||||
self.sock = self.connectToPort(host, port)
|
||||
self.sock.settimeout(None)
|
||||
except socket.error as e:
|
||||
print "Failed to open socket: " + str(e) + ". Is pcscd running? Is vpcd installed?"
|
||||
sys.exit()
|
||||
|
||||
self.lenlen = lenlen
|
||||
signal.signal(signal.SIGINT, self.signalHandler)
|
||||
atexit.register(self.signalHandler)
|
||||
atexit.register(self.saveCard)
|
||||
|
||||
def saveCard(self):
|
||||
if self.filename != None:
|
||||
print "Saving smartcard configuration to %s" % self.filename
|
||||
self.os.save()
|
||||
else:
|
||||
print "No filename specified, card configuration will not be saved."
|
||||
#atexit.register(self.signalHandler)
|
||||
#atexit.register(saveCard)
|
||||
|
||||
def signalHandler(self, signal=None, frame=None):
|
||||
from CardGenerator import saveCard
|
||||
self.sock.close()
|
||||
saveCard(self.os.mf, self.os.SAM, self.filename)
|
||||
sys.exit()
|
||||
|
||||
@staticmethod
|
||||
@@ -567,11 +494,6 @@ if __name__ == "__main__":
|
||||
dest="filename", default=None,
|
||||
help="Name of a smartcard stored in the filesystem. The card will be loaded")
|
||||
(options, args) = parser.parse_args()
|
||||
if options.type == 'cryptoflex':
|
||||
vicc = VirtualICC(options.filename,os=CryptoflexOS(options.filename))
|
||||
elif options.type == 'ePass':
|
||||
#raise ValueError, "Not implemented yet!"
|
||||
vicc = VirtualICC(options.filename,os=PassportOS(options.filename))
|
||||
else:
|
||||
vicc = VirtualICC(options.filename)
|
||||
|
||||
vicc = VirtualICC(options.filename, options.type)
|
||||
vicc.run()
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
$p5k2$$RGHiUkhA$<24>U<EFBFBD>x<01>U<EFBFBD><55><EFBFBD><EFBFBD><EFBFBD>3I^낎P(<28>f<EFBFBD>Kc<4B><63>iveY/0<><30><EFBFBD><EFBFBD>l<EFBFBD><6C>h<EFBFBD><05>{?<0E>gy<67><79><EFBFBD><EFBFBD>a<EFBFBD><61><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<><50><EFBFBD><EFBFBD><12>?Z<><1F>U!<21><>o<EFBFBD><6F>KΦP<CEA6>,<2C><><EFBFBD><EFBFBD>c<63>o<EFBFBD>{0F<30>\<5C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>g#<23><>~<7E><>r˹<72>l<EFBFBD>/}<7D>l<EFBFBD><6C>3<19><><EFBFBD>#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>%<06>ѱ@<40>OG
|
||||
@@ -1,2 +0,0 @@
|
||||
$p5k2$$kj3EFei1$F<>M?<3F><><EFBFBD>?06ՋD<D58B>A֥
|
||||
#6$<24>2vz<76><7A>t<EFBFBD>(<28>\rCiKs<4B><73><EFBFBD>:<3A>8<EFBFBD>D<03><>DF<44>poR<6F><52>+<<3C>Y2-<2D>kF<6B><46>$<24><><EFBFBD>C<EFBFBD>C߯<><16>'<27><>#,<2C>
|
||||
Reference in New Issue
Block a user