BbTS notes

Oh look, information I'm not supposed to have.

This page is a collection of notes and observations related to Blackboard Transact.

To sort

BbTS Service Point API

Blackboard runs a few hosted services for universities that use Transact. The first of these is eAccounts, which is an online service for checking account balances (and a few other optional features, like making deposits). A web interface for eAccounts is hosted at a domain like eacct-<institution>-sp.blackboard.com. It's not very interesting, containing no real API.

What's more interesting is the API used by the eAccounts mobile app, located at <institution>-sp.blackboard.com. This requires OAuth v1 credentials to use (hardcoded into the mobile app). Aside from the eAccounts API on this domain, the Service Point API (official Blackboard documentation) is hosted here. Making requests to the endpoints listed there using the

BbTS Transaction protocol

This is what I've been able to find about how transactions are made. At some point I should probably clean this up.

Source

The source of all of the information here is ext-payment-gateway.jar from the Papercut print management system. I had to run the installer binary for the payment gateway module in a Windows VM, then found this jar in %INSTALLDIR%\lib-ext.

Summary

The protocol is a simple request-response protocol. Requests have a sequence number; the Transact server responds with this sequence number so that the client can correlate responses to requests. Messages can be encrypted with a shared AES key (in CBC mode, with custom padding). Messages are not authenticated, only encrypted.

Since the messages are not authenticated, and the AES IV is constant, and timestamps aren't verified, replay attacks on the protocol are possible even when the messages are encrypted.

Fields contained in a message

A request message consists of a few fields:

The actual request message is sent in this format:

Fields are separated by ASCII "~" (0x7e). Field separators are in the encrypted field, and are encrypted along with the rest of the data. There is a field separator after the last element of data.

Example

0068~0~3112~44~0~2~2~1010~11~20170417020627~T~0~USD~F~25244293~0~0~k

This is a balance inquiry for account 25244293 (me). It is 62 bytes long, plus 4 for the length, plus 1 for the separator and 1 for the checksum, making 68 be the final length of the message. It is not encrypted, uses vendor ID 3112 and terminal ID 44, and since it's not encrypted, there is no encrypted field length (it's 0). The arbitrary string "2" comes next, then the string "2" indicating that this is a balance inquiry. We're on sequence number 1010, and would like to query account 11 (flex dollars). The time is 2017-04-17 02:06:27. The unknown boolean field comes next, then the value of the transaction in cents (which is 0 since this is a balance inquiry). Next is the currency, then whether or not this card number was manually entered, and then the actual card number. We finish with the PIN (there isn't one, so just zero), then the unknown field value "0". XORing all the bytes together in the message (not including the length field and field separator) gives us 0x6b = 'k'.

Crypto

Appendix

Tables

vendor number organization
2513 goprint
3112 papercut
3133 tapingo
type code meaning
1 debit account
2 balance inquiry
3 "count" (unknown)
4 unknown/unused?
5 unknown/unused?
6 credit account
7 query credit limit

OAuth credentials