A Keeloq / HCS301 thread

Hi

There is always someone on the internet who is interested in Keeloq and the encoder chip HCS301. I will share my experiences here as I think I have found at least one thing the others have not. Possibly, someone found it but didn’t publish it anywhere.

A HCS301 is programmed, usually once. A set of data is stored in the chip, such as a 64-bit encryption key, serial number, initial value of the syncronization counter, and the discriminator (usually lowest 10 bits of the serial number).

The documentation does not say that the value of the syncronization counter is changed during programming. It is usually set to zero and then you get zero. If you set it to something other than zero or one it will be changed. That will change the encryption, but you will not notice this unless you decode the PWM output and decrypt the hopping code. I guess it is meant to throw off an attacker who wants to encrypt random data.

Fortunately, you can compute the value you should use during programming to get the desired value. In C (for arduino) you do the following to your value before programming it:

uint16_t u16GetFakeSync(uint16_t uSync)
{
    uint16_t uMask = 0x0002;
    while (uMask != 0x0000) {
        if (uSync&uMask) uSync ^= (uMask>>1);
        uMask <<= 1;
    }
    return uSync;
}
1 Like

There are a number of implementations of the Keeloq encryption/decryption algorithms to be found on the net. Many of them have the same bug and doesn’t work. The bug must come from a common ancestor.

I therefore publish my own functions written in C (for Arduino). They have been tested and verified to work. Hopefully, I haven’t introduced a bug while formatting the functions before posting them here.

uint32_t KeeloqEncrypt(uint64_t ullKey, uint32_t ulPlain)
{
    static unsigned long  NLF = 0x3a5c742eL;
    unsigned char         nlfidx, nlfbit, databit, keybit;
    char                  shift;
    unsigned long         ulData;

    ulData = ulPlain;
    for (int i = 0; i < 528; i++) {
//      nlfidx = (((ulData>>31)&1)<<4) | (((ulData>>26)&1)<<3) | (((ulData>>20)&1)<<2) | (((ulData>>9)&1)<<1) | ((ulData>>1)&1);
        nlfidx = ((ulData>>27)&0x10) | ((ulData>>23)&0x08) | ((ulData>>18)&0x04) | ((ulData>>8)&0x02) | ((ulData>>1)&0x01);
        nlfbit = (NLF>>nlfidx)&1;  
        databit = (ulData&1) ^ ((ulData>>16)&1);
        shift = i&63;
        keybit = (ullKey>>shift)&1;
        ulData = (ulData>>1) | ((unsigned long)(nlfbit ^ databit ^ keybit)<<31);
    }
    return ulData;
}


uint32_t KeeloqDecrypt(uint64_t ullKey, uint32_t ulCipher)
{
    static unsigned long  NLF = 0x3a5c742eL;
    unsigned char         nlfidx, nlfbit, databit, keybit;
    char                  shift;
    unsigned long         ulData;

    ulData=ulCipher;
    for (int i = 0; i < 528; i++) {
//      nlfidx = (((ulData>>30)&1)<<4) | (((ulData>>25)&1)<<3) | (((ulData>>19)&1)<<2) | (((ulData>>8)&1)<<1) | (ulData&1);
        nlfidx = ((ulData>>26)&0x10) | ((ulData>>22)&0x08) | ((ulData>>17)&0x04) | ((ulData>>7)&0x02) | (ulData&0x01);
        nlfbit = (NLF>>nlfidx)&1;  
        databit = ((ulData>>31)&1) ^ ((ulData>>15)&1);
        shift = (528-1-i)&63;
        keybit = (ullKey>>shift)&1;
        ulData = (ulData<<1) | (nlfbit ^ databit ^ keybit);
    }
    return ulData;
}

This is an example of how to encrypt a 32-it value that contains the sync counter 0x5375. You actually want to program it to be one less as the HCS301 will add one when triggered. Making the call u16GetFakeSync(0x5375-1) will return 0x7ACE. Use that value when programming the HCS301 and the first encryption after will contain the encrypted sync counter 0x5375. One will be added to the sync counter every time the chip is triggered (button pressed).

It has been claimed in other threads that the clock frequency of the HCS301 is around 1 MHz.

When I look at samples graphically I see about two samples per period with default sampling speed. That speed is around 7.384 MHz. If I increase the sampling frequency to around 50 MHz and run a FFT on the result, I find that the clock of the HCS301 is around 4.15 MHz. If that is not the clock then what is it?

I made an Arduino shield that in combination with an Arduino Uno becomes an HCS301 target. The board has an Si5351 clock generator, two bidirectional level changers (5V-3V3), an HCS301, 4 buttons, a beeper, and the trigger circuit. The Arduino is running Simple Serial 1.1, can set the frequency of the Si5351 oscillator, can program the HCS301, etc.

Soldering this board was a challenge!

1 Like

Thank you for this. I’m just starting out, but this information will definitely give me a head start.

I am glad you found the information useful and I hope you will post your own findings!