My area of expertise is reverse engineering, specifically embedded systems. I do attack cryptographic systems, but this largely involves key recovery or exploiting the implementation.
I was asked to reverse engineer a simple Windows executable used as part of a challenge-response protocol used for intruder alarm systems. This was trivially easy. I would like some assistance in describing the protocol/algorithm, so that I can look into the security of the system more.
The protocol
The protocol is designed to stop users resetting their alarm without contacting their alarm receiving centre.
When the alarm is triggered, a message is displayed:
CONTACT ARC QUOTE 83647This is called the "quote code" and is always numeric and 5 digits long. I don't know how it is chosen, but it appears random.
- The alarm user calls the alarm receiving centre and informs them of the quote code.
- The alarm receiving centre inputs the quote code into a piece of software (the "decoder") which returns the numeric 5 digit "reset code".
The user is informed of the "reset code" and inputs it into the alarm. It is accepted and the alarm is disarmed.
The alarm and alarm receiving center share a secret which is a number from 0-255, this is called the "version".
So at a superficial level, both the alarm and alarm receiving centre are doing:
ResetCode = F(QuoteCode, Version)Where the QuoteCode and ResetCode are integers in the range 00000-99999 and the Version is a number between 0-255.
Algorithm implementation
This is my basic implementation of the algorithm used to generate the reset code given the quote code. The vector at the top is altered, but the rest is the same.
# Taken from the data in the exe
vector = [3,3,5,5,8,1,3,9,8,0,5,9,3,9,4,1,1,0,9,4,3,0,2,2,8,4,3,2,8,4,9,4,1,3,3,3,3,8,5,3,0,2,4,3,2,1,8,9,0,5,4,3,9,5,8,3,9,9,1,0,0,9,9,3,3,8,2,
1,4,9,1,4,9,2,9,0,9,5,3,9,5,3,3,5,9,1,0,2,9,3,2,1,2,9,8,0,4,9,4,2,3,9,4,0,1,8,5,3,3,9,9,1,0,5,9,3,8,9,4,8,4,2,3,1,0,3,9,4,8,2,0,4,3,3,
1,0,5,2,8,3,3,5,2,8,3,2,9,5,2,1,2,4,4,3,0,4,2,3,4,1,8,2,9,1,0,5,1,8,2,4,3,5,1,0,3,8,5,3,2,1,1,3,9,3,2,3,5,8,3,9,0,3,2,3,5,3,8,4,0,3,9,
1,9,3,0,2,9,3,8,1,4,2,8,4,0,1,9,1,0,1,2,1,3,5,3,3,9,0,2,1,4,1,2,3,4,3,4,9,5,3,5,9,3,1,3,9,4,0,3,2,3,3,4,4,2,1]
def generate_reset(quote, version):
i = 0
tens = 0
reset = []
while i <= 4 :
j = 0
result = 0
while j <= 4:
offset = (version + tens + quote[j]) % 256
result = result + vector[offset]
tens = tens + 10
j = j + 1
reset.append(result%10)
i = i + 1
return reset
print(generate_reset(quote = [0,0,0,0,2], version=131))
I have run several simulations (simply by looping through all combinations of inputs), and noted the following:
- The coverage of reset codes for any given version number across all quote codes is ~63%. This means that you have a higher than 1/100000 chance of guessing the correct reset code randomly.
- Given a quote code and reset code, most of the time there is only a single valid version number. At most, two pairs of quote and reset codes are needed to derive the version number. The "version" isn't very secret as a result.
Questions
I hope these aren't too vague, or broad.
- What would you call the type of algorithm? To me it looks like a hash with a key - does this make it a MAC?
- Does this specific implementation have a name? It looks very "roll your own" but the vendor uses the phrase "military grade".
- Are there any glaring issues with this algorithm? (I'm not expecting someone to do a full analysis, just some pointers would be great). My gut feeling is that the secret "version number" is not long enough to provide adequate secrecy.