AS2805 Standards for EFT

Australia Standards 2805 (AS2805) is the standard for Electronic Funds Transfer (EFT) and Payments in Australia and New Zealand. AS2805 is also used for some implementations in South Africa and SE Asian.

AS2805 is owned by Australia Standards and was developed by various voluntary working groups within Committee IT/5. The implementation of AS2805 standards across all industries is clearly defined by the Australian Payments Clearing Association (APCA) as part of the Consumer Electronic Clearing System (CECS) and detailed in the CECS Manual.

Contrary to popular belief AS2805 is not a rename of the ISO8583 standard in the Australia Standards numbering system, as is the case with most international standards.

ISO8583 was first published in 1987, while AS2805 was published two years earlier in 1985, after a lengthy period of draft and review in Australia, New Zealand and South Africa. ISO8583 consists of three (3) parts:

  • Part 1: Messages, Data Elements and Code Values
  • Part 2: Application and Registration Procedures for Institution Identification Codes (IIC)
  • Part 3: Maintenance Procedures for Messages, Data Elements and Code Values

All three (3) parts of ISO8583 are concentrated on only message formats between devices (EFTPOS and ATM) and an acquiring host. ISO8583 can be seen as a small subset of the AS2805 standard and there is no clear guide for uniform implementation as is the case with CECS. AS2805 on the other hand consist of at least thirty three (33) separate published parts and covers general EFT topics such as:

  • Card Management & Authorisation
  • Card Detail Updating
  • PIN Management
  • Key Management and Security
  • Message Authentication
  • Privacy and Data Encryption
  • Communications
  • Message Structure between Devices and Acquiring Host
  • Message Structure between Hosts
  • File Transfers

The thirty three (33) AS2805 standards published so far are the following:

2805.1 Part 1: Communications
2805.2 Part 2: Message Structure, format and content
2805.3.1 Part 3.1: PIN Management and Security – General
2805.3.2 Part 3.2: PIN Management and Security – Offline
2805.4.1 Part 4.1: Message Authentication – Mechanisms Using a Block Cipher
2805.4.2 Part 4.2: Message Authentication – Mechanisms Using a Hash Function
2805.5.1 Part 5.1: Ciphers – Data Encipherment Algorithm 1 (DEA 1)
2805.5.2 Part 5.2: Ciphers – Modes of Operation for an n-bit block cipher algorithm
2805.5.3 Part 5.3: Ciphers – Data Encipherment Algorithm 2 (DEA 2)
2805.5.4 Part 5.4: Ciphers – Data Encipherment Algorithm 3 (DEA 3) & related techniques
2805.6.1.1 Part 6.1.1: Key Management – Principles
2805.6.1.2 Part 6.1.2: Key Management – Symmetric Ciphers, their Key Management & Life Cycle
2805.6.1.4 Part 6.1.4: Key Management – Asymmetric Cryptosystems – Key Management & Life Cycle
2805.6.2 Part 6.2: Key Management – Transaction keys
2805.6.3 Part 6.3: Key Management – Session Keys – Node to Node
2805.6.4 Part 6.4: Key Management – Session Keys – Terminal to Acquirer
2805.6.5.1 Part 6.5.1: Key Management – TCU Initialisation – Principles
2805.6.5.2 Part 6.5.2: Key Management – TCU Initialisation – Symmetric
2805.6.5.3 Part 6.5.3: Key Management – TCU Initialisation – Asymmetric
2805.6.6 Part 6.6: Key Management – Session Keys – Node to Node with KEK Replacement
2805.9 Part 9: Privacy of Communications
2805.10.1 Part 10.1: File Transfer Integrity Validation
2805.10.2 Part 10.2: Secure File Transfer (Retail)
2805.11 Part 11: Card Parameter Table
2805.12.1 Part 12.1: Message Content – Structure and Format
2805.12.2 Part 12.2: Message Content – Codes
2805.12.3 Part 12.3: Message Content – Maintenance of Codes
2805.13.1 Part 13.1: Secure Hash Functions – General
2805.13.2 Part 13.2: Secure Hash Functions – MD5
2805.13.3 Part 13.3: Secure Hash Functions – SHA-1
2805.14.1 Part 14.1: Secure Cryptographic Devices (Retail) – Concepts, Requirements and Evaluation Methods
2805.14.2 Part 14.2: Secure Cryptographic Devices (Retail) – Security Compliance Checklist for Devices used in Financial Transactions
2805.16 Part 16: Merchant Category Codes

The AS2805 standard also provides three (3) published Handbooks related to the AS2805 standard:

HB 127 EFT – Implementing Message Content Standards – Conversion Handbook
HB 128 EFT – Implementing Message Content Standards – Terminal Handbook
HB 129 EFT – Implementing Message Content Standards – Interchange Handbook

There are a number of guideline white papers available to assist the implementation of EFT related functionality such as:

  • Card Management & Production
  • EFTPOS/POS Software Management
  • EFTPOS and POS Product Management
  • Software and Configuration File Downloading
  • Retail Electronic Data Exchange (EDT) that covers price downloads, ordering and statistics
  • Retail Automation
  • Terminal Management
  • Merchant Management
  • Cashier Management
  • Fraud Monitoring and Management

Trace your ATM Transactions

Introduction

Generally when entrepreneurs decide to become ATM deployers, they do not have sufficient knowledge about ATM protocols and specifications. This is not needed as there are switching providers that can switch their ATM’s  transactions and provide them with adequate reporting.

Following this approach generally leaves them with a massive gap in terms of managing their terminals and merchants  correctly. ATM switching providers have the ability to decode the terminal status messages in real time and determine for example is a terminal has ran out of cash, if hardware is busy failing or even if a processing bank has gone offline.

This allows switching providers to have the upper hand over the smaller ATM deployers.

In this post I will show you how to develop a middleware where this pro active approach can be followed even with small ATM deployers. You will be able to see live cash levels of your terminals and monitor ATM transactions.

 

ATM Languages

ATM’s  and EFTPOS devices speak different languages and each terminal manufacturer might have their own custom implementation. Terminal developers  normally follow a few types of language implementations: Triton / NDC+ / AS2805 / ISO8583. As all of these will run on TCP using some sort of control protocol (VISAII / ACK Controlled) we need to decode the control elements of the protocol as well.

I will be using the Standard Triton Protocol over VISAII to demonstrate the ability to trace transactional protocols.

Most ATM’s have an TCP/IP setting that will enable you to point the ATM to an IP Address and port. Writing an Server component to listen to this is of course as easy as pie.

Conversion to ASCII

It is an easy approach to write a server application and listen on a post for incoming transactions but we will quickly notice that these message are encoded. This encoding it an easy hurdle (as long as there is no SSL component on the ATM)

StringToAscii Class – The readable encoding

The first class I’m going to create is an class that can convert encoded strings to readable ascii, this need the be based on the control characters specified in your protocol specification.

Each Hex encoded string needs to be mapped to the format you require. (<ETX> / <STX>) and a simple function can provide the conversion.

controls_dic = {
 0: '<NUL>', 1: '<SOH>', 2: '<STX>', 3: '<ETX>', 4: '<EOT>', 5: '<ENQ>', 6: '<ACK>',
 7: '<BEL>', 8: '<BS>' , 9: '<HT>' , 10: '<LF>' , 11: '<VT>' , 12: '<FF>' , 13: '<CR>' ,
14: '<SO>' , 15: '<SI>' , 16: '<DLE>', 17: '<DC1>', 18: '<DC2>', 19: '<DC3>',
20: '<DC4>', 21: '<NAK>', 22: '<SYN>', 23: '<ETB>', 24: '<CAN>', 25: '<EM>',
26: '<SUB>', 27: '<ESC>', 28: '<FS>' , 29: '<GS>' , 30: '<RS>' , 31: '<US>'
}

def Str2Ascii(s):
 r = ''
 for c in s:
 if ord(c) < 32:
 r = r + controls_dic[ord(c)]
 elif ord(c) >= 127:
 r = r + '<%d>' % ord(c)
 else:
 r = r + c
 return r

The reverse conversion is slightly more complex, but in essence its just a reverse function of the above.

reverse_dic5 = { 
'<NUL>': 0, '<SOH>': 1, '<STX>': 2, '<ETX>': 3, '<EOT>': 4, '<ENQ>': 5, '<ACK>': 6,
'<BEL>': 7, '<DLE>': 16, '<DC1>': 17, '<DC2>': 18, '<DC3>': 19,
'<DC4>': 20, '<NAK>': 21, '<SYN>': 22, '<ETB>': 23, '<CAN>': 24, 
'<SUB>': 26, '<ESC>': 27
}

reverse_dic4 = {
'<BS>' : 8, '<HT>' : 9, '<LF>' : 10, '<VT>' : 11, '<FF>' : 12, '<CR>' : 13,
'<SO>' : 14, '<SI>' : 15, '<EM>' : 25, '<FS>' : 28, '<GS>' : 29, '<RS>' : 30, '<US>' : 31
}

reverse_dicN = {
 '<130>':130, '<140>':140, '<150>':150, '<160>':160, '<170>':170, '<180>':180, '<190>':190, '<200>':200, '<210>':210, '<220>':220, '<230>':230, '<240>':240, '<250>':250, 
 '<131>':131, '<141>':141, '<151>':151, '<161>':161, '<171>':171, '<181>':181, '<191>':191, '<201>':201, '<211>':211, '<221>':221, '<231>':231, '<241>':241, '<251>':251, 
 '<132>':132, '<142>':142, '<152>':152, '<162>':162, '<172>':172, '<182>':182, '<192>':192, '<202>':202, '<212>':212, '<222>':222, '<232>':232, '<242>':242, '<252>':252, 
 '<133>':133, '<143>':143, '<153>':153, '<163>':163, '<173>':173, '<183>':183, '<193>':193, '<203>':203, '<213>':213, '<223>':223, '<233>':233, '<243>':243, '<253>':253, 
 '<134>':134, '<144>':144, '<154>':154, '<164>':164, '<174>':174, '<184>':184, '<194>':194, '<204>':204, '<214>':214, '<224>':224, '<234>':234, '<244>':244, '<254>':254, 
 '<135>':135, '<145>':145, '<155>':155, '<165>':165, '<175>':175, '<185>':185, '<195>':195, '<205>':205, '<215>':215, '<225>':225, '<235>':235, '<245>':245, '<255>':255, 
 '<136>':136, '<146>':146, '<156>':156, '<166>':166, '<176>':176, '<186>':186, '<196>':196, '<206>':206, '<216>':216, '<226>':226, '<236>':236, '<246>':246, 
'<127>' : 127, '<137>':137, '<147>':147, '<157>':157, '<167>':167, '<177>':177, '<187>':187, '<197>':197, '<207>':207, '<217>':217, '<227>':227, '<237>':237, '<247>':247, 
'<128>' : 128, '<138>':138, '<148>':148, '<158>':158, '<168>':168, '<178>':178, '<188>':188, '<198>':198, '<208>':208, '<218>':218, '<228>':228, '<238>':238, '<248>':248, 
'<129>' : 129, '<139>':139, '<149>':149, '<159>':159, '<169>':169, '<179>':179, '<189>':189, '<199>':199, '<209>':209, '<219>':219, '<229>':229, '<239>':239, '<249>':249 
}

def Ascii2Str(s):
 r = ''
 i = 0
 l = len(s)
 while i < l:
 if s[i] == '<':
 try:
 x = reverse_dic5[s[i:i+5]]
 r = r + chr(x)
 i = i + 5
 except KeyError:
 try:
 x = reverse_dic4[s[i:i+4]]
 r = r + chr(x)
 i = i + 4
 except KeyError:
 try:
 x = reverse_dicN[s[i:i+5]]
 r = r + chr(x)
 i = i + 5
 except KeyError:
 r = r + s[i]
 i = i + 1 
 else:
 r = r + s[i]
 i = i + 1
 return r

We can now pass a simulated transaction to the function and test the output and see if the class is correctly implemented acceding to the Triton Standard Protocol.

Message

message = '05 02 39 56 44 44 39 30 30 32 32 30 30 30 30 30 32 1C 31 31 1C 30 34 30 36 1C 34 32 31 36 34 36 30 30 30 30 30 30 30 30 30 38 3D 31 34 31 32 31 30 31 31 31 38 38 35 32 34 39 31 32 33 34 35 1C 30 30 30 30 32 30 30 30 1C 30 30 30 30 30 30 30 30 1C 38 36 32 37 42 38 36 33 34 37 41 30 33 37 37 35 1C 1C 1C 1C 5E 35 45 36 32 20 44 35 37 37 1C 03 6E '.replace(" ", "").decode("hex")

Result

<ENQ><STX>9U00009D       <FS>11<FS>0406<FS>4216460000000008=14121011188524912345<FS>00002000<FS>00000000<FS>8627B86347A03775<FS><FS><FS><FS>^5E62 D577<ETX>

Reversing this back to an encoded string we just need to pass it to the ASCIIToString Function of course.

Tracing Data

Now that we have all the field from the request from the ATM, the next step is to create a server component that can run and pass this transactional information to our processing party.

Creating a Server is not part of this post, but all source code is available in the gitbub repository. But the basic structure should be that you should create a incoming and sending socket, and poll for connections using a daemon thread.  Passing ALL information to the processing party, but saving the requests to the database.

Port Listening for ATM connections

 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

 self.sock.bind(('', int(listening_port)))
 self.sock.listen(5)

 

Port forwarding to Processor with SSL

fwd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 try:

 ssl_sock = ssl.wrap_socket(fwd)
 ssl_sock.settimeout(int(session.destination_timeout))
 ssl_sock.connect((session.destination_ip, int(session.destination_port)))
 ssl_sock.do_handshake()
 self.log.info('SSL Handshake Completed')

 self.log.debug('%s: Connected to switch %s:%s' % (
 session.SessionUUID, session.destination_ip, session.destination_port,))
 except socket.timeout:
 session.error = "Timeout connecting to switch"
 self.log.critical('%s: EE Cant Connect to %s:%s : %s' % (
 session.SessionUUID, session.destination_ip, session.destination_port, session.error,))
 ssl_sock.close()
 except socket.sslerror:
 session.error = "SSL Error connecting to TNS"
 self.log.critical('%s: EE Cant Connect to %s:%s : %s' % (
 session.SessionUUID, session.destination_ip, session.destination_port, session.error,))
 ssl_sock.close()
 except:
 session.error = "Unknown Error connecting to switch"
 self.log.exception('%s: EE Unknown Error Connecting to %s:%s : %s' % (
 session.SessionUUID, session.destination_ip, session.destination_port, session.error,))
 ssl_sock.close()
 else:
 ssl_sock.settimeout(None)
 RequestThread(session, newsock, ssl_sock).start()
 ResponseThread(session, ssl_sock, newsock).start()

When a specific Transaction type is received from the ATM you can dissect the readable ascii and save the request to database, when the corresponding session has a response then you can of course save the response information with the request.

In my code example I provide the implementation of request  and response saving as based on the Triton Specification. If you are using NDC+ or ISO 8583 then this will dramatically change.

Security

The security aspect of this project should be implemented in the raw socket components (SSL Sockets), if there is a need for SSL certificate validation and ACL’s then it should not be difficult to add this to the required class.

PCI DSS require us not to store raw Personal Account numbers in the database so we should in fact use a hash function.

A simple method for doing this is the following:

return pan[:6] + ("*" * (len(pan)-10)) + pan[-4:]

Final Product

The final product is a python implementation of a Transactional Middleware. Allot of changes will be required to make the project work for your environment, but here are basic instructions to make it work for you.

  1. Get a clean Linux installation
  2. Install the LAMP Stack
  3. run the SQL file in the project
  4. copy the project directory to the server
  5. app_get all the project dependencies. (pymysql ect.)
  6. change the config file to point to your database and your switching provider (Middleware.ini)
  7. create a screen session (command: screen -S TransactionServer )
  8. start the Server in the screen session (sudo python pyMiddlewareServer foreground)

When starting it up you should see the following:

2014-05-24 17:53:38,177 MyDaemon INFO run() Start
2014-05-24 17:53:38,180 Pinhole INFO Redirecting: localhost:9100 -> xxx.xxx.xxx.xx:xxxxx
2014-05-24 17:53:38,263 QueueLogger INFO Connected to Database <_mysql.connection open to '127.0.0.1' at 100837020>
2014-05-24 17:53:45,704 Pinhole INFO 8850226b-e318-11e3-8a9a-28cfe91efd87: NN New Session from ('127.0.0.1', 49660)
2014-05-24 17:53:45,817 Pinhole INFO SSL Handshake Completed
2014-05-24 17:53:45,832 Request INFO 8850226b-e318-11e3-8a9a-28cfe91efd87: > AtmID=[9VDD90022000002], Type=[Authorization from Cheque Account], Operation=[CW]
2014-05-24 17:53:45,832 Request INFO 8850226b-e318-11e3-8a9a-28cfe91efd87: > PAN=[216460000000008]
2014-05-24 17:53:46,072 Request INFO 8850226b-e318-11e3-8a9a-28cfe91efd87: > AtmID=[9VDD90022000002], Type=[Authorization from Cheque Account], Operation=[CW]
2014-05-24 17:53:46,072 Request INFO 8850226b-e318-11e3-8a9a-28cfe91efd87: > PAN=[216460000000008]

Source code: https://github.com/Arthurvdmerwe/ATM-Transaction-Trace.git