Generating secure short activation code for offline applications My application is as follows


User has a hardware system (with an unique ID) that does not have
connectivity but has a keypad for input.
To make the hardware operational, the user has to go to central authority and get a code (7-8 digits) in exchange for money
The user enters this code through the keypad and the system is operational for a certain period of time after which the user has to repeat the process.


Requirements


The code has to be short and numeric (7-8 digits)
The code should work for a specific hardware only (unique to each user)
To keep things simple at the beginning, we can assume that every code generated will run the hardware for the same amount of time (as opposed to codes which give the time for which the hardware should run)
Availability of standard libraries to implement this. 


Here's what I've done so far


I thought of using the ISO 7064 Mod 97,10 formula to generate codes (in the central authority) and the use the same formula on the hardware to see if it is valid. Based on this post. However, this means the same code is not unique to a hardware system. This is just an error detection algorithm. 
I can generate the code using the above formula and use RSA with digital certificate. However, the output will be too long correct? Besides, this means that the central authority has to have access to public keys of all hardware systems.
Let's examine the propositions in the question:


I thought of using the ISO 7064 Mod 97,10 formula
That provides no cryptographic protection against determined adversaries. ISO/IEC 7064 merely


  specifies a set of check character systems capable of protecting strings against errors which occur when people copy or type data.

I can generate the code using the above formula and use RSA with digital certificate. However, the output will be too long correct?
Yes. RSA signatures are at minimum roughly the width of the public modulus, that is for modern security 2048-bit or $2048\log2/\log10\approx617$ decimal characters. That's way too much to key in.
Besides, this means that the central authority has to have access to public keys of all hardware systems.
No. Verification of an RSA signature requires the public key of the authority entitled to produce it. Ignoring the size problem, there would be need for a single public/private key pair, with the private key held by the signing authority, and the same public key in all devices. Devices can recognize their serial number in the signed data.




While there are signature systems more compact than RSA, all yield a signature at least 10 times above the target "7-8 digits". Thus we can't use public-key cryptography.

The standard option there will be symmetric cryptography, with a secret key in each device. Standard practice is that the device key is derived from a master key known by the issuing authority, and the device's serial number, by some key derivation function (the Smart Card industry does this since the 1980s, under the name diversification). A single master key has to be kept, yet extraction of a device's key does not compromise the others. HMAC-SHA-256 would be a suitable derivation method. $\mathsf{DeviceKey}=\operatorname{HMAC}(\mathsf{MasterKey},\mathsf{SerialNumber})$ will do.

The unlock code can be some kind of Message Authentication Code of an index incremented at each reload and held in permanent memory by the device (and the authority's emission system), and truncated. That could be the decimal expression of $\mathsf{UnlockCode}=\operatorname{HMAC}(\mathsf{DeviceKey},\mathsf{Index})\bmod10^8$.

Normal operation is that the authority gets payment, finds $\mathsf{Index}$ for the $\mathsf{SerialNumber}$ in its database, computes $\mathsf{DeviceKey}$ then $\mathsf{UnlockCode}$, increment the $\mathsf{Index}$ for this device in the database. The device checks what's keyed-in against the $\mathsf{UnlockCode}$, and if there's a match activates and increment its $\mathsf{Index}$ in permanent memory.

Some issues need to be addressed:


The $\mathsf{MasterKey}$ and the $\mathsf{DeviceKey}$s are sensitive targets, and that might be vulnerable at the authority and manufacturing site. A HSM or Smart Card might help. In particular, a Smart Card good for a limited number of $\mathsf{UnlockCode}$s could be what clerks at the authority really use.
There should be significant redundancy in $\mathsf{SerialNumber}$ or whatever identifies devices in order to avoid clerical errors at the authority; ISO 7064 might be adequate there.
There is a risk that an attacker tries codes at random to unlock a device, perhaps automatically. A countermeasure is a delay between entries, perhaps increasing after a number of consecutive errors. It is also possible that there are two codes, a short one with a limit of 3 tries (6 digits will be fine), and a long one (say 12 digits) used as backup (similar to the PIN in a mobile phone SIM, with the PUK as backup).
The device should have appropriate mitigation for a variety of threats: unauthorized use with bypass of the payment, $\mathsf{DeviceKey}$ extraction, setting $\mathsf{DeviceKey}$ to a known value, setting $\mathsf{Index}$ to earlier value allowing reuse of an earlier code, resetting the aforementioned delay between entries by battery removal or other upset, side channel.. A classical goof is comparing the code keyed-in to $\mathsf{UnlockCode}$ using strcmp or similar library/language feature that leaks the position of the first mismatch by timing, which might be observable without opening the box, e.g. thanks to a LED or the keyboard scan EMI, allowing to find an 8-digit code in about 40 tries rather than 50 millions. Security engineering is not easy!
Users will loose or temporarily misplace codes, and rather than bother asking for a duplicate, will pay for a new one. The device should thus accept a few codes ahead. And then it's desirable to accept slightly out-of-order codes; that complicates the algorithm, especially for short codes (since all codes in the acceptable window need to be distinct). A simple option if a window of $w$ codes must be accepted is that $\mathsf{UnlockCode}=w(\operatorname{HMAC}(\mathsf{DeviceKey},\mathsf{Index})\bmod\lfloor10^8/w\rfloor)+(\mathsf{Index}\bmod w)$.
More generally it is possible to encode ancillary information within the code (e.g. reload amount). While we are at that, the length of the code can be variable, perhaps larger by one or two extra digits for high-value codes, for higher security.


Note: I do not see that Format Preserving Encryption really helps here, even when there is ancillary information to convey, since confidentiality of that seems to be more of a nuisance than a useful feature.