Installation Numbers
From TheLinuxVault
Red Hat Enterprise Linux 5 introduces "Installation Numbers."
The Installation Number is a code that you receive from Red Hat when you buy an RHN subscription for RHEL 5. This code configures the installer to install only the packages for which you purchased support. Contrary to some public misunderstanding, the Installation Number is not an activation key. All of the packages that make up the Red Hat Enterprise Linux operating system may be installed and used without any Installation Number (the core OS with anaconda, the Red Hat installer, and the rest of the packages with rpm or yum).
The sole purpose of these numbers is to cause the installer to limit the available packages to only those for which you have purchased support. This is generally desired by corporate and government users who need to ensure that they are only using software for which they have support. The use of these numbers was to fulfill the demands of some of Red Hat's biggest customers.
It is important to understand that the use of these Installation Numbers by Red Hat in no way limits the use of the software included on the CDs or DVD. Although certain packages may not be available in the installer, any user may use rpm or yum to install any additional desired software from the CDs or DVD. Further, using the RHN website, a machine may be subscribed to any channel for which you have a subscription, whether or not you have ever entered an Installation Number.
This is Open Source. Anaconda, the installer is GPL'd and needs to be able to parse these codes. Tools on the system also need to be able to parse these codes when they communicate with RHN. So there's no hiding of the magic behind these installation numbers. In fact you can find this very easily on a RHEL 5 machine.
$ head /usr/lib/python2.4/site-packages/instnum.py #!/usr/bin/python # instnum.py - parse and decode RHEL Installation Numbers # Copyright (c) 2006 Red Hat, Inc. # Authors: Dave Lehman <email hidden> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. instnum.py
Its even covered under the GPL. I've included a link to the complete file for your reading pleasure. It contains detailed documentation for how these codes work. To quote:
16 hex digits: KK KK KK CC OO OS VT PP | | | || |- Product defining the format. | | | ||- Virt limit code used to look up the limit | | | | in a dictionary. The least bit actually is | | | | used for the Type field. | | | |- Socket (phys. CPUs) limit code used to look | | | up the limit in the list of all possible limits. | | |- Option code to look up the combination of | | options in a dictionary. | |- Checksum - Keyed hash Key and the other fields. |- Key generated with Peter's algorithm
On a bit level it looks like this:
60 56 52 48 44 40 36 32 28 24 20 16 12 8 4 0
0 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60
KKKK KKKK KKKK KKKK KKKK KKKK CCCC CCCC OOOO OOOO OOOO OOSS SSVV VTTP PPPP PPPP
Bits:
Key part:
[40 - 63] - K
- Key generated with the old HACK algorithm. Source of entropy
and used to 'encrypt' parts of the payload.
Checksum:
[32 - 39] - C
- Checksum - first two hex digits of the keyed sha1 hash of the
payload with the key.
Payload:
[18 - 31] - O
- Options - Index of the actual option combination in the list
of all possible combinations for the product. Xored with the
highest 14 bits of the key.
[14 - 17] - S
- Socket (physical CPU) limit. Encoded as the index of the
limit in the list of all possible socket limits. Xored with
the next highest 4 bit of the key.
[11 - 13] - V
- Virt Limit - Limit of the number of virtual instances allowed.
Encoded as the index of the limit in the list of all possible
virtualization limits. Xored with the next highest 3 bits of
the key.
[9 - 10] - T
- EN type - 0 => does not create Entitlement,
1 => creates Entitlement,
2 => installeronly.
Not Xored.
[0 - 8] - P
- Product code - 0 for Server and 1 for Client. Defines the
format. Xored with the lowest 9 bits of the key.
See the file for even more gory details about how these codes work. To compound matters more, Red Hat's web app that customers can use to find their Installation Numbers does not provide folks under academic contracts with codes that activate the features that the academic contracts cover. The codes will not work on the Client version and only alow up to 2 CPU sockets and 4 VMs on Server. Folks at Red Hat are aware and working on the problem.
- Generating Installation Numbers
- genkey.py
After a couple hours I can generate my own Installation Numbers. Here's some code:
# genkey.py - Generate fake RHEL 5 installation numbers # Copyright (c) 2007 Jack Neely # Authors: Jack Neely <jjneely@gmail.com> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import hmac import sha # 24 bits key = 0x0 # The following class taken from ASPN: # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/113799 class BitField(object): def __init__(self,value=0): self._d = value def __getitem__(self, index): return (self._d >> index) & 1 def __setitem__(self,index,value): value = (value&1L)<<index mask = (1L)<<index self._d = (self._d & ~mask) | value def __getslice__(self, start, end): mask = 2L**(end - start) -1 return (self._d >> start) & mask def __setslice__(self, start, end, value): mask = 2L**(end - start) -1 value = (value & mask) << start mask = mask << start self._d = (self._d & ~mask) | value return (self._d >> start) & mask def __int__(self): return self._d def checksum(regkey): keystr = "%06x" % regkey[40:64] payloadstr = "%08x" % regkey[0:32] hash = hmac.new(keystr, payloadstr, sha) sum = hash.hexdigest()[:2] return int(sum, 16) def generateKey(key, options, sockets, virtlimit, type, product): """Create an installation number based from the given codes. All parameters are int.""" # Okay we are using python slices here so 0:3 represents bits 0, 1, and 2 # and does not include/modify bit 3 regkey = BitField() # Make the payload regkey[18:32] = options regkey[14:18] = sockets regkey[11:14] = virtlimit regkey[9:11] = type regkey[0:9] = product # Tack on the key regkey[40:64] = key # calculate checksum regkey[32:40] = checksum(regkey) return "%016x" % int(regkey) def main(): print "a client key" print generateKey(key, 0x5, 0xf, 0xf, 0x2, 0x1) print print "a server key" print generateKey(key, 0x1, 0xf, 0xf, 0x2, 0x0) print print "A server key with Cluster" print generateKey(key, 0x2, 0xf, 0xf, 0x2, 0x0) print print "A server key with ClusterStorage" print generateKey(key, 0x3, 0xf, 0xf, 0x2, 0x0) print print "server with HPC" print generateKey(key, 0x4, 0xf, 0xf, 0x2, 0x0) print print "server with Directory" print generateKey(key, 0x5, 0xf, 0xf, 0x2, 0x0) print print "server with SMB" print generateKey(key, 0x6, 0xf, 0xf, 0x2, 0x0) if __name__ == "__main__": main(
Once you know where to place the bits and generate the checksum its pretty easy. This generates the following table of keys. Each key below has unlimited CPU sockets and unlimited VM guests.
Client 0000000e0017fc01 Server 000000e90007fc00 Server with Cluster 00000065000bfc00 Server with ClusterStorage 000000ab000ffc00 Server with HPC 000000e30013fc00 Server with Directory 000000890017fc00 Server with SMB 00000052001bfc00
These codes are purposely generated with the key field equal to 0. They are perfectly valid but anyone in the "know" should be able to realize these are not installtion numbers from Red Hat. Creating codes with other key values (used to more obscure the fields and generate many different codes that unlock the same features) or creating a handy web app that I would post here is left as an exercise for the reader.
The codes don't really contain much information. Instead they contain a series of indexes into tables containing feature combinations, socket limits, etc. Those tables are all in the above instnum.py file. For socket limits and VM limits a value of -1 represents an unlimited value. What's the 2's complment of 1? 0xFF. The type and product fields are not indexes. Values for the type field represent if the code can create an RHN entitlement and the product field is simply 1 for Client and 0 for Server. That's how I create the hex values used in the generateKey() function.
- Looking at Your Installation Numbers
Finally any key you create or have been given by Red Hat can be examined by the code in instnum.py. This gives you all the gory details about what the key activates. For example, I'll run it on my first Client key.
$ python instnum.py 0000000e0017fc01
Product: RHEL Client
Type: Installer Only
Options: NoSLA FullProd Virt Workstation
Allowed CPU Sockets: Unlimited
Allowed Virtual Instances: Unlimited
Package Repositories: Client VT Workstation
key: 0 '000000'
checksum: 14 '0e'
options: 4865 'NoSLA FullProd Virt Workstation'
socklimit: -1 'Unlimited'
virtlimit: -1 'Unlimited'
type: 2 'Installer Only'
product: 1 'client'
{'Virt': 'VT', 'Workstation': 'Workstation', 'Base': 'Client'}
0000-000e-0017-fc01
From a normal RHEL 5 install you can also call this script like so:
$ python /usr/lib/python2.4/site-packages/instnum.py <Installation Number>

