1
$\begingroup$

I'm trying to implement a simple command-line tool to calculate the (Key Check Value) KCV of some encryption keys. The algorithm for the KCV is simply to encrypt a block of 8 zeros with DES and get the first three bytes of it (this is called VISA KCV, and there are a bunch of other KCV algorithms).

So, I wrote this code:

/*----------------------------------------------------------------------------*/
static void
str2DES_cblock_(const char *str, DES_cblock* out)
{
    // Make a char pointer and point it at the start of the array
    unsigned char *o;
    o = out[0];
    // Read the string
    int i;
    for (i = 0; i < 8; i++)
        sscanf(&(str[i*2]),"%2hhx", o++);
}

static int
getVisaKcv_( const char* key, const int keyStrLen, unsigned char* kcv )
{
    DES_cblock key1, key2;    
    DES_key_schedule keySchedule1, keySchedule2;        
    DES_cblock encryptedBlock; 

    int rc = EXIT_SUCCESS;
       
    static const_DES_cblock blockToEncrypt_ = { 0x00, 0x00, 0x00, 0x00,
                                                0x00, 0x00, 0x00, 0x00 };                                                
  
    memset( encryptedBlock, 0x00, sizeof(encryptedBlock) );
    
    if( 16 == keyStrLen )
    {
        str2DES_cblock_( key, &key1 );
        DES_set_key_unchecked( &key1, &keySchedule1 );
        DES_ecb_encrypt(    
                            &blockToEncrypt_,
                            &encryptedBlock,
                            &keySchedule1,
                            DES_ENCRYPT
                        );
                 
        kcv[0] = encryptedBlock[0];
        kcv[1] = encryptedBlock[1];
        kcv[2] = encryptedBlock[2];
       
    }
    else if( 32 == keyStrLen )
    {      
        str2DES_cblock_( key,    &key1 );
        str2DES_cblock_( key+16, &key2 );
        
        DES_set_key_unchecked( &key1, &keySchedule1 );      
        DES_set_key_unchecked( &key2, &keySchedule2 );
        
        DES_ecb2_encrypt(   &blockToEncrypt_,
                            &encryptedBlock,
                            &keySchedule1,
                            &keySchedule2,
                            DES_ENCRYPT );                            
                    
        kcv[0] = encryptedBlock[0];
        kcv[1] = encryptedBlock[1];
        kcv[2] = encryptedBlock[2];        
    }
    else
    {
        rc = ERROR_INVALID_PARAM;
    } 
              
    return rc;
}

It uses OpenSSL's functions to perform encryption. The things is that it is giving me wrong results. For exemple, encrypting "19c7221b33c1b2b4c68bc48deb86234b" results in encryptedBlock = [ 33 4D 78 7E FB C0 ED E8 ]. Some high quality validation tools I have (it is called BP-Tools and works for all things payment-industry related) gives encryptedBlock = [ 90 D4 49 08 A7 9F 45 44 ] as result. I'm not sure where the problem is (it is a very simple encryption). Did I forget something in the sequence of OpenSSL API calls? It gives wrong results for 8-byte keys also.

Here are some test cases (they match both EFTLab's and BP-Tools results):

Enc( plaintext=[0000000000000000], key=[9be8ec942f9f7791]                   )   = [F4E94D2A2901D6C6]
Enc( plaintext=[0000000000000000], key=[6afbadf94fd06945d365856382898c25]   )   = [F65EC8B0B78F2C0A]
Enc( plaintext=[0000000000000000], key=[8f40053aae44e017]                   )   = [4A83D7F98644363E]
Enc( plaintext=[0000000000000000], key=[19c7221b33c1b2b4c68bc48deb86234b]   )   = [90D44908A79F4544]
Enc( plaintext=[0000000000000000], key=[b0e9c35e20171642]                   )   = [7FBA49A7CD6A8AEB]
Enc( plaintext=[0000000000000000], key=[a12815befca06412f357db3ab41d7cf9]   )   = [67F735CD1696E114]
Enc( plaintext=[0000000000000000], key=[e5c82dbe8c0b3c17]                   )   = [4CACBD023C95FD7C]
Enc( plaintext=[0000000000000000], key=[c74b48ebfa79f8ca46d06f8436597230]   )   = [7FD3FA9F5B338E13]
$\endgroup$
3
  • 2
    $\begingroup$ This is not a crypto question. You don't show str2DES_cblock_ but it must be wrong, because if I add a correct one your code exactly as posted works. It does give compile warnings (which you should always check) because you omitted the & on the first two args to des_ecb2_encrypt and thus pass pointers of the wrong type; the C standard allows these to be different and cause Undefined Behavior, but in practice on all systems 'normal' programmers use today all data pointers are the same. $\endgroup$ Mar 11, 2021 at 9:55
  • $\begingroup$ Actually I wrote str2DES_cblock because I can't get DES_string_to_key to work properly. Anyway it is a valid point and I will update the question. Thank you. $\endgroup$ Mar 11, 2021 at 16:59
  • $\begingroup$ Your modified code works for me, with no change beyond adding main(). Check that you're actually running the code you posted -- if you use an IDE, or a source and/or build management system or tools, make sure you don't have a stale or wrong version someplace. $\endgroup$ Mar 12, 2021 at 3:32

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.