Help me describe/identify this challenge-response protocol/algorithm? 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 83647


This 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 &lt;= 4 :
        j = 0
        result = 0

        while j &lt;= 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.
The intend appears to be that vector is secret and the main key; and version (that, we are told, is secret) is an extension of that key (or variant selector).

1) I could say that ResetCode is a MAC of quote with key vector and version.

2) Never met this particular one. Anyone with common sense should laugh at it as snake oil if it pretends to be military-grade cryptography.

3a) When seen as a MAC, an obvious algorithmic flaw is that adding 1 (mod 256) to version and subtracting 11111 from any quote which has each of its digits non-zero leaves the ResetCode unchanged; this can be classified as a related-key weakness. That observation can make a usable paper tabulation of the function over twice less bulky (only entries with quote including a 0 need to be tabulated). Adding 10 (mod 256) to version also has special properties.

3a') Update: there's much worse! For constant version and vector, changing a particular digit in quote into another digit causes a difference (mod 10) in any particular digit of ResetCode that is independent of the 4 other digits of quote. With this observation, from the ResetCode for a small set of quote values, we can compute the ResetCode for any quote value, without knowing vector or version. The set of 46 quote values having at most one non-zero digit is convenient for hand calculation, but even random quote from a significantly smaller set often allows trivial linear algebra to pull that trick. In fact that MAC is so linear and with poor mixing that it could be broken from examples alone, without knowledge of the algorithm or reverse engineering the code or extracting vector!

3b) In the usage context, after vector has become public (e.g. if it is common to all alarms of the type), most often a single intercept of (ResetCode, quote) is enough to find version, leading to total break. Even a theoretically perfect cryptographic MAC is expected to have this property, given the ridiculously small size of what remains of the key (version), and the larger size of ResetCode. Any theoretical weaknesses of the algorithm seen as a MAC is moot compared to this system weakness of a small version when an adversary can obtain all key material beside version, or has access to a black box computing ResetCode for any chosen input (quote, version).