0
$\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$ – dave_thompson_085 Mar 11 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$ – daniel.franzini Mar 11 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$ – dave_thompson_085 Mar 12 at 3:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.