Skip to content

Commit

Permalink
Merge pull request #47 from SEL-Columbia/new_card_format
Browse files Browse the repository at this point in the history
New card format
  • Loading branch information
vr2262 authored Jun 22, 2017
2 parents fc2d336 + 774ed80 commit 0c33ffd
Show file tree
Hide file tree
Showing 10 changed files with 421 additions and 185 deletions.
2 changes: 1 addition & 1 deletion dev/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
echo "Installing dependencies..."
pip install -r requirements.txt 1&> /dev/null
npm install
node node_modules/webpack/bin/webpack.js --cache=False 1&> /dev/null
node node_modules/webpack/bin/webpack.js
echo "Installing dependencies done"
python server.py \
--application_debug=True \
Expand Down
280 changes: 171 additions & 109 deletions minigrid/device_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

import minigrid.models as models


AES = algorithms.AES

Expand All @@ -15,162 +17,222 @@ def _wrap_binary(binary):
return b'qS' + binary.hex().encode('ascii') + b'EL'


def write_vendor_card(cache, key, minigrid_id, payment_id, vendor):
def write_vendor_card(session, cache, key, minigrid_id, payment_id, vendor):
"""Write information to a vendor ID card."""
block_4 = b''.join((
sector_1 = b''.join((
b'\x00\x01', # System ID
b'\x00\x01', # Application ID
b'A', # A for vendor
vendor.vendor_user_id.encode('ascii'), # 0000-9999 ASCII
b'\x08', # Offset
b'\x00\x14', # Length
int(time.time()).to_bytes(4, 'big'), # card produced time
bytes(3), # intentionally empty
bytes(4), # card read time TODO
uuid.UUID(payment_id).bytes,
))
sector_2 = b''.join((
vendor.vendor_user_id.encode('ascii'), # 0000-9999 ASCII
uuid.UUID(minigrid_id).bytes,
bytes(12),
))
#block_5 = uuid.UUID(minigrid_id).bytes
block_5 = unhexlify(uuid.UUID(minigrid_id).bytes).hex().upper().encode()
#block_6 = bytes(16) # other information
block_6 = uuid.UUID(payment_id).bytes

#message = _wrap_binary(block_4 + block_5 + block_6)
message = block_4 + block_5
cipher = Cipher(AES(key), modes.ECB(), backend=default_backend())
encryptor = cipher.encryptor()
ciphertext = encryptor.update(message) + encryptor.finalize()
payload = _wrap_binary(ciphertext + block_6)

cache.set('device_info', payload, 5)

# TODO write to device
print('=' * 60)
print(message.hex())
print('=' * 60)
sector_2_enc = encryptor.update(sector_2) + encryptor.finalize()
naive_payload = sector_1 + sector_2_enc
actual_payload = b''.join((
naive_payload[:15],
(sum(naive_payload[:15]) & 0xFF).to_bytes(1, 'big'),
naive_payload[15:30],
(sum(naive_payload[15:30]) & 0xFF).to_bytes(1, 'big'),
naive_payload[30:32],
bytes(13),
(sum(naive_payload[30:32]) & 0xFF).to_bytes(1, 'big'),
naive_payload[32:47],
(sum(naive_payload[32:47]) & 0xFF).to_bytes(1, 'big'),
naive_payload[47:62],
(sum(naive_payload[47:62]) & 0xFF).to_bytes(1, 'big'),
naive_payload[62:64],
bytes(13),
(sum(naive_payload[62:64]) & 0xFF).to_bytes(1, 'big'),
))
cache.set('device_info', _wrap_binary(actual_payload), 5)
with models.transaction(session) as tx_session:
tx_session.add(models.VendorCardHistory(
vendor_card_minigrid_id=minigrid_id,
vendor_card_vendor_id=vendor.vendor_id,
vendor_card_user_id=vendor.vendor_user_id,
))


def write_customer_card(cache, key, minigrid_id, payment_id, customer):
def write_customer_card(session, cache, key, minigrid_id, payment_id, customer):
"""Write information to a customer ID card."""
block_4 = b''.join((
sector_1 = b''.join((
b'\x00\x01', # System ID
b'\x00\x01', # Application ID
b'B', # B for customer
customer.customer_user_id.encode('ascii'), # 0000-9999 ASCII
b'\x08', # Offset
b'\x00\x14', # Length
int(time.time()).to_bytes(4, 'big'), # card produced time
bytes(3), # intentionally empty
bytes(4), # card read time TODO
uuid.UUID(payment_id).bytes,
))
sector_2 = b''.join((
customer.customer_user_id.encode('ascii'), # 0000-9999 ASCII
uuid.UUID(minigrid_id).bytes,
bytes(12),
))
#block_5 = uuid.UUID(minigrid_id).bytes
block_5 = unhexlify(uuid.UUID(minigrid_id).bytes).hex().upper().encode()
#block_6 = bytes(16) # other information
block_6 = uuid.UUID(payment_id).bytes

#message = _wrap_binary(block_4 + block_5 + block_6)
message = block_4 + block_5
cipher = Cipher(AES(key), modes.ECB(), backend=default_backend())
encryptor = cipher.encryptor()
ciphertext = encryptor.update(message) + encryptor.finalize()
payload = _wrap_binary(ciphertext + block_6)

cache.set('device_info', payload, 5)

# TODO write to device
print('=' * 60)
print(cache.get('device_active'))
print(cache.get('device_info'))
print(cache.get('received_info'))
print(message.hex())
print('=' * 60)
sector_2_enc = encryptor.update(sector_2) + encryptor.finalize()
naive_payload = sector_1 + sector_2_enc
actual_payload = b''.join((
naive_payload[:15],
(sum(naive_payload[:15]) & 0xFF).to_bytes(1, 'big'),
naive_payload[15:30],
(sum(naive_payload[15:30]) & 0xFF).to_bytes(1, 'big'),
naive_payload[30:32],
bytes(13),
(sum(naive_payload[30:32]) & 0xFF).to_bytes(1, 'big'),
naive_payload[32:47],
(sum(naive_payload[32:47]) & 0xFF).to_bytes(1, 'big'),
naive_payload[47:62],
(sum(naive_payload[47:62]) & 0xFF).to_bytes(1, 'big'),
naive_payload[62:64],
bytes(13),
(sum(naive_payload[62:64]) & 0xFF).to_bytes(1, 'big'),
))
cache.set('device_info', _wrap_binary(actual_payload), 5)
with models.transaction(session) as tx_session:
tx_session.add(models.CustomerCardHistory(
customer_card_minigrid_id=minigrid_id,
customer_card_customer_id=customer.customer_id,
customer_card_user_id=customer.customer_user_id,
))


def write_maintenance_card_card(cache, key, payment_system_id, maintenance_card):
def write_maintenance_card_card(session, cache, key, minigrid_id, payment_id, maintenance_card):
"""Write information to a maintenance card card."""
block_4 = b''.join((
sector_1 = b''.join((
b'\x00\x01', # System ID
b'\x00\x01', # Application ID
b'D', # D for maintenance card
maintenance_card.maintenance_card_card_id.encode('ascii'), # 0000-9999 ASCII
b'\x08', # Offset
b'\x00\xd0', # Length
int(time.time()).to_bytes(4, 'big'), # card produced time
bytes(3), # intentionally empty
bytes(4), # card read time TODO
uuid.UUID(payment_id).bytes,
))
sector_2 = b''.join((
maintenance_card.maintenance_card_card_id.encode('ascii'), # 0000-9999 ASCII
uuid.UUID(minigrid_id).bytes,
bytes(12),
))
block_5 = bytes(16)
#block_6 = bytes(16) # other information
block_6 = uuid.UUID(payment_system_id).bytes

#message = _wrap_binary(block_4 + block_5 + block_6)
message = block_4
cipher = Cipher(AES(key), modes.ECB(), backend=default_backend())
encryptor = cipher.encryptor()
ciphertext = encryptor.update(message) + encryptor.finalize()
payload = _wrap_binary(ciphertext + block_5 + block_6)

cache.set('device_info', payload, 5)

# TODO write to device
print('=' * 60)
print(cache.get('device_active'))
print(cache.get('device_info'))
print(cache.get('received_info'))
print(message.hex())
print('=' * 60)
sector_2_enc = encryptor.update(sector_2) + encryptor.finalize()
naive_payload = sector_1 + sector_2_enc
actual_payload = b''.join((
naive_payload[:15],
(sum(naive_payload[:15]) & 0xFF).to_bytes(1, 'big'),
naive_payload[15:30],
(sum(naive_payload[15:30]) & 0xFF).to_bytes(1, 'big'),
naive_payload[30:32],
bytes(13),
(sum(naive_payload[30:32]) & 0xFF).to_bytes(1, 'big'),
naive_payload[32:47],
(sum(naive_payload[32:47]) & 0xFF).to_bytes(1, 'big'),
naive_payload[47:62],
(sum(naive_payload[47:62]) & 0xFF).to_bytes(1, 'big'),
naive_payload[62:64],
bytes(13),
(sum(naive_payload[62:64]) & 0xFF).to_bytes(1, 'big'),
))
cache.set('device_info', _wrap_binary(actual_payload), 5)
with models.transaction(session) as tx_session:
tx_session.add(models.MaintenanceCardHistory(
mc_minigrid_id=minigrid_id,
mc_maintenance_card_id=maintenance_card.maintenance_card_id,
mc_maintenance_card_card_id=maintenance_card.maintenance_card_card_id,
))


def _hour_on_epoch_day(hour_int):
return (hour_int * 3600).to_bytes(4, 'big')


def write_credit_card(
session,
cache, key,
minigrid_id,
payment_id, credit_amount,
day_tariff, day_tariff_start,
night_tariff, night_tariff_start,
tariff_creation_timestamp, tariff_activation_timestamp):
"""Write information to a credit card."""
block_4 = b''.join((
sector_1 = b''.join((
b'\x00\x01', # System ID
b'\x00\x01', # Application ID
b'C', # C for credit
b'\1', # 1 for int
credit_amount.to_bytes(4, 'big'), # 4 byte unsigned int
b'\x08', # Offset
b'\x00\xf4', # Length
int(time.time()).to_bytes(4, 'big'), # card produced time
bytes(2), # intentionally empty
bytes(4), # card read time TODO
uuid.UUID(payment_id).bytes,
))
block_5 = uuid.uuid4().bytes
block_6 = uuid.UUID(payment_id).bytes
block_8 = b''.join((
b'\1', # 1 for int
credit_card_id = uuid.uuid4()
sector_2 = b''.join((
credit_amount.to_bytes(4, 'big'), # 4 byte unsigned int
credit_card_id.bytes,
bytes(12),
))
sector_3 = b''.join((
_hour_on_epoch_day(day_tariff_start), # tariff 1 validate time
(int(day_tariff * 100)).to_bytes(4, 'big'), # day tariff in cents
bytes(7), # intentionally empty
))
block_9 = b''.join((
b'\1', # 1 for int
_hour_on_epoch_day(night_tariff_start), # tariff 2 validate time
(int(night_tariff * 100)).to_bytes(4, 'big'), # night tariff in cents
bytes(7), # intentionally empty
))
block_10 = b''.join((
int(tariff_creation_timestamp.timestamp()).to_bytes(4, 'big'),
int(tariff_activation_timestamp.timestamp()).to_bytes(4, 'big'),
bytes(8), # intentionally empty
bytes(8),
))

#message = _wrap_binary(
# block_4 + block_5 + block_6 + block_8 + block_9 + block_10
#)

#message = (
# block_4 + block_5 + block_6 + block_8 + block_9 + block_10
#)
#encryptor = cipher.encryptor()
#ciphertext = encryptor.update(message) + encryptor.finalize()
#payload = _wrap_binary(ciphertext)

message_1 = block_4 + block_5
message_2 = block_8 + block_9 + block_10
cipher = Cipher(AES(key), modes.ECB(), backend=default_backend())
encryptor_1 = cipher.encryptor()
ciphertext_1 = encryptor_1.update(message_1) + encryptor_1.finalize()
encryptor_2 = cipher.encryptor()
ciphertext_2 = encryptor_2.update(message_2) + encryptor_2.finalize()
payload = _wrap_binary(ciphertext_1 + block_6 + ciphertext_2)

cache.set('device_info', payload, 5)

# TODO write to device
print('=' * 60)
print(message_1.hex())
print(block_6.hex())
print(message_2.hex())
print('=' * 60)
encryptor2 = cipher.encryptor()
sector_2_enc = encryptor2.update(sector_2) + encryptor2.finalize()
encryptor3 = cipher.encryptor()
sector_3_enc = encryptor3.update(sector_3) + encryptor3.finalize()
naive_payload = sector_1 + sector_2_enc + sector_3_enc
actual_payload = b''.join((
naive_payload[:15],
(sum(naive_payload[:15]) & 0xFF).to_bytes(1, 'big'),
naive_payload[15:30],
(sum(naive_payload[15:30]) & 0xFF).to_bytes(1, 'big'),
naive_payload[30:32],
bytes(13),
(sum(naive_payload[30:32]) & 0xFF).to_bytes(1, 'big'),
naive_payload[32:47],
(sum(naive_payload[32:47]) & 0xFF).to_bytes(1, 'big'),
naive_payload[47:62],
(sum(naive_payload[47:62]) & 0xFF).to_bytes(1, 'big'),
naive_payload[62:64],
bytes(13),
(sum(naive_payload[62:64]) & 0xFF).to_bytes(1, 'big'),
naive_payload[64:79],
(sum(naive_payload[64:79]) & 0xFF).to_bytes(1, 'big'),
naive_payload[79:94],
(sum(naive_payload[79:94]) & 0xFF).to_bytes(1, 'big'),
naive_payload[94:96],
bytes(13),
(sum(naive_payload[94:96]) & 0xFF).to_bytes(1, 'big'),
bytes(32), # maybe more?
))
cache.set('device_info', _wrap_binary(actual_payload), 5)
with models.transaction(session) as tx_session:
tx_session.add(models.CreditCardHistory(
credit_card_id=credit_card_id,
credit_minigrid_id=minigrid_id,
credit_amount=credit_amount,
credit_day_tariff=day_tariff,
credit_day_tariff_start=day_tariff_start,
credit_night_tariff=night_tariff,
credit_night_tariff_start=night_tariff_start,
credit_tariff_creation_timestamp=tariff_creation_timestamp,
credit_tariff_activation_timestamp=tariff_activation_timestamp,
))
4 changes: 4 additions & 0 deletions minigrid/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ def __init__(self,
*, reason, **template_kwargs):
"""Create a login error (400 by default)."""
super().__init__(reason, status_code, template_name, **template_kwargs)


class CardReadError(Exception):
"""Error while reading a card"""
Loading

0 comments on commit 0c33ffd

Please sign in to comment.